Compare commits
24 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
d9e6c78adb | |
|
|
d8580be739 | |
|
|
1a16502a69 | |
|
|
5ecf10c022 | |
|
|
e366cf6a4c | |
|
|
7ecebb5dd6 | |
|
|
099d513011 | |
|
|
e45399d347 | |
|
|
7a3717b02a | |
|
|
a062fdcfe0 | |
|
|
29447a35cd | |
|
|
1dcd09e20c | |
|
|
9626b5e8c9 | |
|
|
256955f48e | |
|
|
b983e33be7 | |
|
|
db224105a7 | |
|
|
e5a6cf0df9 | |
|
|
22e182f908 | |
|
|
0013dda92d | |
|
|
85561d0503 | |
|
|
eb83075e16 | |
|
|
8fea20425e | |
|
|
ad14c26597 | |
|
|
19a2d5c57c |
|
|
@ -1,16 +1,11 @@
|
||||||
name: CI-wasm
|
name: CI-wasm
|
||||||
|
|
||||||
# Builds the Magic WebAssembly target on every push and pull request.
|
# Builds the Magic WebAssembly target on every push and pull request.
|
||||||
# On version tags (v*), additionally publishes magic-vlsi-wasm to GitHub
|
# When the VERSION file changes on the default branch, the package is
|
||||||
# Packages (npm.pkg.github.com).
|
# additionally published to GitHub Packages (npm.pkg.github.com) as
|
||||||
#
|
# @<owner>/magic-vlsi-wasm — no manual tag or token required.
|
||||||
# The primary goal of this workflow is to always build a WASM version and
|
# Tim Edwards updates VERSION to trigger a new release; the scope resolves
|
||||||
# verify it against the example test suite. Publishing to a package repo is
|
# automatically to the repo owner, so forks publish under their own namespace.
|
||||||
# an optional, tag-gated extension of the same pipeline.
|
|
||||||
#
|
|
||||||
# Publishing to GitHub Packages first allows testing and evaluation before a
|
|
||||||
# wider release to the public npm registry. Consumers can install from there
|
|
||||||
# via npm with an appropriate .npmrc pointing at npm.pkg.github.com.
|
|
||||||
#
|
#
|
||||||
# WASM is architecture-independent — built once on x86-64, usable everywhere.
|
# WASM is architecture-independent — built once on x86-64, usable everywhere.
|
||||||
|
|
||||||
|
|
@ -34,12 +29,18 @@ on:
|
||||||
env:
|
env:
|
||||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-wasm:
|
build-wasm:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
- name: Set up Node.js
|
- name: Set up Node.js
|
||||||
uses: actions/setup-node@v5
|
uses: actions/setup-node@v5
|
||||||
|
|
@ -111,15 +112,20 @@ jobs:
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
- name: Set package version
|
- name: Set package version and scope
|
||||||
run: |
|
run: |
|
||||||
base=$(cat VERSION) # e.g. 8.3.637
|
base=$(cat VERSION) # e.g. 8.3.637
|
||||||
date=$(git show -s --format=%cs | tr -d '-') # e.g. 20260414
|
date=$(git show -s --format=%cs | tr -d '-') # e.g. 20260414
|
||||||
hash=$(git show -s --format=%h) # e.g. d157eea
|
hash=$(git show -s --format=%h) # e.g. d157eea
|
||||||
# npm requires semver; use pre-release syntax as the closest equivalent
|
|
||||||
# to the AppImage form 8.3.637~20260414~d157eea
|
|
||||||
VERSION="${base}-${date}.${hash}"
|
VERSION="${base}-${date}.${hash}"
|
||||||
|
# Scope the package to the repo owner so it lands in the right
|
||||||
|
# GitHub Packages namespace regardless of who hosts the repo.
|
||||||
|
# e.g. @rtimothyedwards/magic-vlsi-wasm on Tim's repo,
|
||||||
|
# @intubun/magic-vlsi-wasm on a fork.
|
||||||
|
SCOPED_NAME="@${{ github.repository_owner }}/magic-vlsi-wasm"
|
||||||
cd npm
|
cd npm
|
||||||
|
npm pkg set name="$SCOPED_NAME"
|
||||||
|
npm pkg set publishConfig.registry="https://npm.pkg.github.com"
|
||||||
npm version "$VERSION" --no-git-tag-version
|
npm version "$VERSION" --no-git-tag-version
|
||||||
|
|
||||||
- name: Pack
|
- name: Pack
|
||||||
|
|
@ -131,8 +137,24 @@ jobs:
|
||||||
name: magic-vlsi-wasm-npm
|
name: magic-vlsi-wasm-npm
|
||||||
path: npm/*.tgz
|
path: npm/*.tgz
|
||||||
|
|
||||||
|
- name: Check if VERSION changed
|
||||||
|
id: version_changed
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
run: |
|
||||||
|
if echo "${{ github.ref }}" | grep -q '^refs/tags/'; then
|
||||||
|
echo "changed=true" >> $GITHUB_OUTPUT
|
||||||
|
elif [ "${{ github.ref }}" = "refs/heads/${{ github.event.repository.default_branch }}" ]; then
|
||||||
|
if git diff --name-only HEAD~1 HEAD 2>/dev/null | grep -q '^VERSION$'; then
|
||||||
|
echo "changed=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "changed=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "changed=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Publish to GitHub Packages
|
- name: Publish to GitHub Packages
|
||||||
if: startsWith(github.ref, 'refs/tags/v') && github.event.inputs.dry_run != 'true'
|
if: steps.version_changed.outputs.changed == 'true' && github.event.inputs.dry_run != 'true'
|
||||||
run: cd npm && npm publish
|
run: cd npm && npm publish
|
||||||
env:
|
env:
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
|
||||||
|
|
@ -4117,7 +4117,7 @@ cifSrTiles(
|
||||||
* one or more times for the planes being used in processing
|
* one or more times for the planes being used in processing
|
||||||
* where the CIF search should be conducted over "area" scaled
|
* where the CIF search should be conducted over "area" scaled
|
||||||
* to CIF units, rather than the entire plane. Currently used
|
* to CIF units, rather than the entire plane. Currently used
|
||||||
* only for operator CIFOP_INTERACT.
|
* only for operators CIFOP_INTERACT and CIFOP_TAGGED.
|
||||||
*
|
*
|
||||||
* Results:
|
* Results:
|
||||||
* Returns the value returned by the function.
|
* Returns the value returned by the function.
|
||||||
|
|
@ -5681,7 +5681,7 @@ CIFGenLayer(
|
||||||
|
|
||||||
for (label = cellDef->cd_labels; label; label = label->lab_next)
|
for (label = cellDef->cd_labels; label; label = label->lab_next)
|
||||||
if (!strcmp(label->lab_text, text))
|
if (!strcmp(label->lab_text, text))
|
||||||
cifSrTiles(op, &label->lab_rect, cellDef, temps,
|
cifSrTiles2(op, &label->lab_rect, cellDef, temps,
|
||||||
cifBloatAllFunc, (ClientData)&bls);
|
cifBloatAllFunc, (ClientData)&bls);
|
||||||
|
|
||||||
/* Reset marked tiles */
|
/* Reset marked tiles */
|
||||||
|
|
|
||||||
|
|
@ -2324,7 +2324,7 @@ CmdDoProperty(
|
||||||
TxCommand *cmd,
|
TxCommand *cmd,
|
||||||
int argstart)
|
int argstart)
|
||||||
{
|
{
|
||||||
PropertyRecord *proprec;
|
PropertyRecord *proprec = NULL;
|
||||||
char *value;
|
char *value;
|
||||||
bool propfound, dolist;
|
bool propfound, dolist;
|
||||||
int proptype, proplen, propvalue, i;
|
int proptype, proplen, propvalue, i;
|
||||||
|
|
@ -2662,31 +2662,31 @@ CmdDoProperty(
|
||||||
* the valid number of arguments, then again to parse the
|
* the valid number of arguments, then again to parse the
|
||||||
* values, once the property record has been allocated
|
* values, once the property record has been allocated
|
||||||
*/
|
*/
|
||||||
if (proptype == PROPERTY_TYPE_PLANE)
|
value = cmd->tx_argv[argstart + 1];
|
||||||
|
for (proplen = 0; *value != '\0'; )
|
||||||
{
|
{
|
||||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
if (isspace(*value) && (*value != '\0')) value++;
|
||||||
plane = DBNewPlane((ClientData)TT_SPACE);
|
if (!isspace(*value))
|
||||||
proprec->prop_value.prop_plane = plane;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
value = cmd->tx_argv[argstart + 1];
|
|
||||||
for (proplen = 0; *value != '\0'; )
|
|
||||||
{
|
{
|
||||||
if (isspace(*value) && (*value != '\0')) value++;
|
proplen++;
|
||||||
if (!isspace(*value))
|
while (!isspace(*value) && (*value != '\0')) value++;
|
||||||
{
|
|
||||||
proplen++;
|
|
||||||
while (!isspace(*value) && (*value != '\0')) value++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (proplen > 0)
|
}
|
||||||
|
if (proplen > 0)
|
||||||
|
{
|
||||||
|
if (proptype == PROPERTY_TYPE_PLANE)
|
||||||
|
{
|
||||||
|
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||||
|
plane = DBNewPlane((ClientData)TT_SPACE);
|
||||||
|
proprec->prop_value.prop_plane = plane;
|
||||||
|
} else {
|
||||||
proprec = (PropertyRecord *)mallocMagic(
|
proprec = (PropertyRecord *)mallocMagic(
|
||||||
sizeof(PropertyRecord) +
|
sizeof(PropertyRecord) +
|
||||||
(proplen - 2) * sizeof(int));
|
(proplen - 2) * sizeof(int));
|
||||||
|
}
|
||||||
|
proprec->prop_type = proptype;
|
||||||
|
proprec->prop_len = proplen;
|
||||||
}
|
}
|
||||||
proprec->prop_type = proptype;
|
|
||||||
proprec->prop_len = proplen;
|
|
||||||
|
|
||||||
/* Second pass */
|
/* Second pass */
|
||||||
value = cmd->tx_argv[argstart + 1];
|
value = cmd->tx_argv[argstart + 1];
|
||||||
|
|
|
||||||
|
|
@ -635,10 +635,21 @@ cmdSelectArea(
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < DBNumUserLayers; i++)
|
for (i = 0; i < DBNumUserLayers; i++)
|
||||||
{
|
{
|
||||||
if((TTMaskHasType(&mask, i)) && !(TTMaskHasType(&crec->dbw_visibleLayers, i)))
|
if ((TTMaskHasType(&mask, i)) &&
|
||||||
|
!(TTMaskHasType(&crec->dbw_visibleLayers, i)))
|
||||||
TTMaskClearType(&mask, i);
|
TTMaskClearType(&mask, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Remove L_CELL and L_LABEL if crec->dbw_flags indicates that
|
||||||
|
* they are not visible in the layout window.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!(crec->dbw_flags & DBW_SEELABELS)) TTMaskClearType(&mask, L_LABEL);
|
||||||
|
if (!(crec->dbw_flags & DBW_SEECELLS)) TTMaskClearType(&mask, L_CELL);
|
||||||
}
|
}
|
||||||
|
else if (option == SEL_AREA)
|
||||||
|
TTMaskSetType(&mask, L_LABEL);
|
||||||
|
|
||||||
SelectArea(&scx, &mask, crec->dbw_bitmask, globmatch);
|
SelectArea(&scx, &mask, crec->dbw_bitmask, globmatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1027,7 +1038,7 @@ CmdSelect(
|
||||||
|
|
||||||
/*--------------------------------------------------------------------
|
/*--------------------------------------------------------------------
|
||||||
* Select everything under the box, perhaps looking only at
|
* Select everything under the box, perhaps looking only at
|
||||||
* particular layers, but only if its visible.
|
* particular layers, but only if it's visible.
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2016,8 +2016,8 @@ badTransform:
|
||||||
if ((cellDef->cd_file != NULL) && (cellDef->cd_file[0] == '/'))
|
if ((cellDef->cd_file != NULL) && (cellDef->cd_file[0] == '/'))
|
||||||
{
|
{
|
||||||
char *homedir = getenv("HOME");
|
char *homedir = getenv("HOME");
|
||||||
if (strncmp(cellDef->cd_file, homedir, strlen(homedir)) ||
|
if (homedir && (strncmp(cellDef->cd_file, homedir, strlen(homedir)) ||
|
||||||
*(cellDef->cd_file + strlen(homedir)) != '/')
|
*(cellDef->cd_file + strlen(homedir)) != '/'))
|
||||||
{
|
{
|
||||||
char *homeroot = strrchr(homedir, '/');
|
char *homeroot = strrchr(homedir, '/');
|
||||||
int rootlen = (int)(homeroot - homedir) + 1;
|
int rootlen = (int)(homeroot - homedir) + 1;
|
||||||
|
|
@ -2060,9 +2060,10 @@ badTransform:
|
||||||
if (*pathptr == '~')
|
if (*pathptr == '~')
|
||||||
{
|
{
|
||||||
char *homedir = getenv("HOME");
|
char *homedir = getenv("HOME");
|
||||||
if (!strncmp(subCellDef->cd_file, homedir, strlen(homedir))
|
if (homedir && (!strncmp(subCellDef->cd_file, homedir,
|
||||||
&& (!strcmp(subCellDef->cd_file + strlen(homedir),
|
strlen(homedir)) &&
|
||||||
pathptr + 1)))
|
(!strcmp(subCellDef->cd_file + strlen(homedir),
|
||||||
|
pathptr + 1))))
|
||||||
pathOK = TRUE;
|
pathOK = TRUE;
|
||||||
}
|
}
|
||||||
else if (!strcmp(cwddir, pathptr)) pathOK = TRUE;
|
else if (!strcmp(cwddir, pathptr)) pathOK = TRUE;
|
||||||
|
|
@ -2254,9 +2255,9 @@ badTransform:
|
||||||
/* Check if the path is the same as the current directory */
|
/* Check if the path is the same as the current directory */
|
||||||
|
|
||||||
char *homedir = getenv("HOME");
|
char *homedir = getenv("HOME");
|
||||||
if (!strncmp(cwddir, homedir, strlen(homedir))
|
if (homedir && (!strncmp(cwddir, homedir, strlen(homedir))
|
||||||
&& (!strcmp(cwddir + strlen(homedir),
|
&& (!strcmp(cwddir + strlen(homedir),
|
||||||
pathptr + 1)))
|
pathptr + 1))))
|
||||||
pathOK = TRUE;
|
pathOK = TRUE;
|
||||||
}
|
}
|
||||||
else if (!strcmp(cwddir, pathptr)) pathOK = TRUE;
|
else if (!strcmp(cwddir, pathptr)) pathOK = TRUE;
|
||||||
|
|
|
||||||
|
|
@ -830,7 +830,7 @@ drcTile (tile, dinfo, arg)
|
||||||
* an exception area. Exception rules are ignored if
|
* an exception area. Exception rules are ignored if
|
||||||
* the edge is outside an exception area.
|
* the edge is outside an exception area.
|
||||||
*/
|
*/
|
||||||
if (!isinside && (!(cptr->drcc_exception & DRC_EXCEPTION_MASK) == 0))
|
if (!isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) == 0))
|
||||||
continue;
|
continue;
|
||||||
if (isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) != 0))
|
if (isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) != 0))
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -71,10 +71,10 @@ extern const char * const extDevTable[];
|
||||||
#define EXT_DORESISTANCE 0x008 /* Extract lumped resistance */
|
#define EXT_DORESISTANCE 0x008 /* Extract lumped resistance */
|
||||||
#define EXT_DOLENGTH 0x010 /* Extract pathlengths */
|
#define EXT_DOLENGTH 0x010 /* Extract pathlengths */
|
||||||
#define EXT_DOFRINGEHALO 0x020 /* Distributed fringe capacitance */
|
#define EXT_DOFRINGEHALO 0x020 /* Distributed fringe capacitance */
|
||||||
#define EXT_DOALL 0x03f /* ALL OF THE ABOVE */
|
#define EXT_DOUNIQUE 0x100 /* Force unique nodes during extraction */
|
||||||
|
#define EXT_DOALL 0x13f /* ALL OF THE ABOVE */
|
||||||
#define EXT_DOLABELCHECK 0x040 /* Check for connections by label */
|
#define EXT_DOLABELCHECK 0x040 /* Check for connections by label */
|
||||||
#define EXT_DOALIASES 0x080 /* Output all node aliases */
|
#define EXT_DOALIASES 0x080 /* Output all node aliases */
|
||||||
#define EXT_DOUNIQUE 0x100 /* Force unique nodes during extraction */
|
|
||||||
#define EXT_DOEXTRESIST 0x200 /* Do full R-C extraction */
|
#define EXT_DOEXTRESIST 0x200 /* Do full R-C extraction */
|
||||||
|
|
||||||
extern int ExtOptions; /* Bitmask of above */
|
extern int ExtOptions; /* Bitmask of above */
|
||||||
|
|
|
||||||
|
|
@ -26,17 +26,19 @@ StipplePattern begin
|
||||||
/FontMatrix [1 0 0 1 0 0] def
|
/FontMatrix [1 0 0 1 0 0] def
|
||||||
/FontBBox [0 0 1 1] def
|
/FontBBox [0 0 1 1] def
|
||||||
/Encoding 256 array def
|
/Encoding 256 array def
|
||||||
/PattName (P0) def
|
/PattName (P000) def
|
||||||
/tmpStr 1 string def
|
/tmpStr 3 string def
|
||||||
/NoPatt {<00>} def
|
/NoPatt {<00>} def
|
||||||
0 1 255 { Encoding exch /NoPatt put } for
|
0 1 255 { Encoding exch /NoPatt put } for
|
||||||
/BuildChar {
|
/BuildChar {
|
||||||
1 0 0 0 1 1 setcachedevice exch begin Encoding exch get load
|
1 0 0 0 1 1 setcachedevice exch begin Encoding exch get load
|
||||||
64 64 true [64 0 0 64 0 0] 5 -1 roll imagemask end } def
|
64 64 true [64 0 0 64 0 0] 5 -1 roll imagemask end } def
|
||||||
end
|
end
|
||||||
/dp { StipplePattern begin dup 30 tmpStr cvrs PattName exch 1 exch
|
/dp { StipplePattern begin
|
||||||
putinterval PattName cvn dup Encoding exch 4 -1 roll exch put exch
|
dup 10 tmpStr cvrs /num exch def
|
||||||
store end } def
|
PattName 1 num putinterval
|
||||||
|
PattName 0 num length 1 add getinterval cvn
|
||||||
|
dup Encoding exch 4 -1 roll exch put exch store end } def
|
||||||
/sf { findfont exch scalefont setfont } bind def
|
/sf { findfont exch scalefont setfont } bind def
|
||||||
/sp { patterns setfont 2 setlinewidth } def
|
/sp { patterns setfont 2 setlinewidth } def
|
||||||
/lb { gsave translate 0 0 moveto /just exch def gsave dup true charpath
|
/lb { gsave translate 0 0 moveto /just exch def gsave dup true charpath
|
||||||
|
|
@ -68,4 +70,3 @@ end
|
||||||
x y moveto w y lineto w h lineto x h lineto closepath clip bx } def
|
x y moveto w y lineto w h lineto x h lineto closepath clip bx } def
|
||||||
/tb {1 sub 3 1 roll gsave newpath moveto {lineto} repeat closepath clip pathbbox
|
/tb {1 sub 3 1 roll gsave newpath moveto {lineto} repeat closepath clip pathbbox
|
||||||
/h exch def /w exch def /y exch def /x exch def bx } def
|
/h exch def /w exch def /y exch def /x exch def bx } def
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1218,7 +1218,7 @@ PlotVersatec(scx, layers, xMask, user_scale)
|
||||||
|
|
||||||
/* Compute the name of the file to use for output, and open it. */
|
/* Compute the name of the file to use for output, and open it. */
|
||||||
|
|
||||||
sprintf(fileName, "%s/magicPlotXXXXXX", PlotTempDirectory);
|
snprintf(fileName, 200, "%s/magicPlotXXXXXX", PlotTempDirectory);
|
||||||
result = mkstemp(fileName);
|
result = mkstemp(fileName);
|
||||||
if (result == -1)
|
if (result == -1)
|
||||||
{
|
{
|
||||||
|
|
@ -1474,7 +1474,7 @@ PlotVersatec(scx, layers, xMask, user_scale)
|
||||||
|
|
||||||
TxPrintf("\n");
|
TxPrintf("\n");
|
||||||
fclose(file);
|
fclose(file);
|
||||||
sprintf(command, PlotVersCommand, PlotVersPrinter, fileName);
|
snprintf(command, 300, PlotVersCommand, PlotVersPrinter, fileName);
|
||||||
if (system(command) != 0)
|
if (system(command) != 0)
|
||||||
{
|
{
|
||||||
TxError("Couldn't execute spooler command to print \"%s\"\n",
|
TxError("Couldn't execute spooler command to print \"%s\"\n",
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
|
||||||
int xj, yj, direction;
|
int xj, yj, direction;
|
||||||
resNode **PendingList;
|
resNode **PendingList;
|
||||||
{
|
{
|
||||||
resNode *resptr;
|
resNode *resptr = NULL;
|
||||||
resDevice *resDev;
|
resDevice *resDev;
|
||||||
tElement *tcell;
|
tElement *tcell;
|
||||||
int newnode;
|
int newnode;
|
||||||
|
|
@ -64,7 +64,8 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
|
||||||
|
|
||||||
ri = (resInfo *) TiGetClientPTR(tp);
|
ri = (resInfo *) TiGetClientPTR(tp);
|
||||||
resDev = ri->deviceList;
|
resDev = ri->deviceList;
|
||||||
if ((ri->sourceEdge & direction) != 0)
|
if ((((ri->sourceEdge & direction) != 0) && (resDev->rd_nterms == 4))
|
||||||
|
|| (resDev->rd_nterms > 2))
|
||||||
{
|
{
|
||||||
if (resDev->rd_fet_source == (resNode *) NULL)
|
if (resDev->rd_fet_source == (resNode *) NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -73,11 +74,9 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
|
||||||
resDev->rd_fet_source = resptr;
|
resDev->rd_fet_source = resptr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
resptr = resDev->rd_fet_source;
|
resptr = resDev->rd_fet_source;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else if (resDev->rd_nterms > 3)
|
||||||
{
|
{
|
||||||
if (resDev->rd_fet_drain == (resNode *) NULL)
|
if (resDev->rd_fet_drain == (resNode *) NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -86,9 +85,7 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
|
||||||
resDev->rd_fet_drain = resptr;
|
resDev->rd_fet_drain = resptr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
resptr = resDev->rd_fet_drain;
|
resptr = resDev->rd_fet_drain;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (newnode)
|
if (newnode)
|
||||||
{
|
{
|
||||||
|
|
@ -99,7 +96,10 @@ ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
|
||||||
resptr->rn_te = tcell;
|
resptr->rn_te = tcell;
|
||||||
ResAddToQueue(resptr, PendingList);
|
ResAddToQueue(resptr, PendingList);
|
||||||
}
|
}
|
||||||
NEWBREAK(resptr, tile, xj, yj, NULL);
|
if (resptr != NULL)
|
||||||
|
{
|
||||||
|
NEWBREAK(resptr, tile, xj, yj, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -131,20 +131,14 @@ ResNewSubDevice(tile, tp, xj, yj, direction, PendingList)
|
||||||
ri = (resInfo *) TiGetClientPTR(tp);
|
ri = (resInfo *) TiGetClientPTR(tp);
|
||||||
resDev = ri->deviceList;
|
resDev = ri->deviceList;
|
||||||
|
|
||||||
/* Arrived at a device that has a terminal connected to substrate */
|
if (resDev->rd_fet_subs == (resNode *)NULL)
|
||||||
/* that is not a FET bulk terminal (e.g., varactor, diode). */
|
|
||||||
if (resDev->rd_nterms < 4) return;
|
|
||||||
|
|
||||||
if (resDev->rd_fet_subs == (resNode *) NULL)
|
|
||||||
{
|
{
|
||||||
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
|
||||||
newnode = TRUE;
|
newnode = TRUE;
|
||||||
resDev->rd_fet_subs = resptr;
|
resDev->rd_fet_subs = resptr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
resptr = resDev->rd_fet_subs;
|
||||||
resptr = resDev->rd_fet_subs;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newnode)
|
if (newnode)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -148,30 +148,49 @@ void
|
||||||
ResDissolveContacts(contacts)
|
ResDissolveContacts(contacts)
|
||||||
ResContactPoint *contacts;
|
ResContactPoint *contacts;
|
||||||
{
|
{
|
||||||
TileType t, oldtype;
|
TileType t, conttype;
|
||||||
Tile *tp;
|
Tile *tp;
|
||||||
TileTypeBitMask residues;
|
TileType residue[NP][NT];
|
||||||
|
int pNum;
|
||||||
|
|
||||||
|
bzero((char *)residue, NP * NT * sizeof(TileType));
|
||||||
|
|
||||||
for (; contacts != (ResContactPoint *)NULL; contacts = contacts->cp_nextcontact)
|
for (; contacts != (ResContactPoint *)NULL; contacts = contacts->cp_nextcontact)
|
||||||
{
|
{
|
||||||
oldtype=contacts->cp_type;
|
conttype = contacts->cp_type;
|
||||||
|
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
if (oldtype == TT_SPACE)
|
if (conttype == TT_SPACE)
|
||||||
TxError("Error in Contact Dissolving for %s \n",ResCurrentNode);
|
TxError("Error in Contact Dissolving for %s \n",ResCurrentNode);
|
||||||
#endif
|
#endif
|
||||||
DBFullResidueMask(oldtype, &residues);
|
|
||||||
|
|
||||||
DBErase(ResUse->cu_def, &(contacts->cp_rect), oldtype);
|
/* Fill in details of the residue types for each contact type.
|
||||||
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
|
* This is done only once per contact type. This could be refined
|
||||||
if (TTMaskHasType(&residues, t))
|
* further by temporarily changing the paint table directly or
|
||||||
DBPaint(ResUse->cu_def, &(contacts->cp_rect), t);
|
* creating a separate paint table which erases contact cuts and
|
||||||
|
* replaces them with the residues.
|
||||||
|
*/
|
||||||
|
|
||||||
tp = PlaneGetHint(ResDef->cd_planes[DBPlane(contacts->cp_type)]);
|
if (residue[DBPlane(conttype)][conttype] == TT_SPACE)
|
||||||
GOTOPOINT(tp, &(contacts->cp_rect.r_ll));
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||||
|
residue[pNum][conttype] = DBPlaneToResidue(conttype, pNum);
|
||||||
|
|
||||||
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||||
|
{
|
||||||
|
if (DBTypeOnPlane(conttype, pNum))
|
||||||
|
{
|
||||||
|
DBPaintPlane(ResUse->cu_def->cd_planes[pNum], &(contacts->cp_rect),
|
||||||
|
DBStdEraseTbl(conttype, pNum), (PaintUndoInfo *)NULL);
|
||||||
|
DBPaintPlane(ResUse->cu_def->cd_planes[pNum], &(contacts->cp_rect),
|
||||||
|
DBStdPaintTbl(residue[pNum][conttype], pNum),
|
||||||
|
(PaintUndoInfo *)NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
if (TiGetTypeExact(tp) == contacts->cp_type)
|
tp = PlaneGetHint(ResDef->cd_planes[DBPlane(conttype)]);
|
||||||
|
GOTOPOINT(tp, &(contacts->cp_rect.r_ll));
|
||||||
|
if (TiGetTypeExact(tp) == conttype)
|
||||||
TxError("Error in Contact Preprocess Routines\n");
|
TxError("Error in Contact Preprocess Routines\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
@ -378,13 +397,14 @@ ResAddBreakpointFunc(tile, dinfo, node)
|
||||||
*
|
*
|
||||||
* ResFindNewContactTiles --
|
* ResFindNewContactTiles --
|
||||||
*
|
*
|
||||||
|
* Dissolving contacts eliminated the tiles that contacts->nextcontact
|
||||||
|
* pointed to. This procedure finds the tile now under center and sets
|
||||||
|
* that tile's ti_client field to point to the contact. The old value
|
||||||
|
* of clientdata is set to nextTilecontact.
|
||||||
*
|
*
|
||||||
* Results: none
|
* Results: none
|
||||||
*
|
*
|
||||||
* Side Effects: dissolving contacts eliminated the tiles that
|
* Side Effects: modifies information in the contact records.
|
||||||
* contacts->nextcontact pointed to. This procedure finds the tile now under
|
|
||||||
* center and sets that tile's ti_client field to point to the contact. The
|
|
||||||
* old value of clientdata is set to nextTilecontact.
|
|
||||||
*
|
*
|
||||||
*----------------------------------------------------------------------------
|
*----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
@ -396,29 +416,40 @@ ResFindNewContactTiles(contacts)
|
||||||
int pNum;
|
int pNum;
|
||||||
Tile *tile;
|
Tile *tile;
|
||||||
TileTypeBitMask mask;
|
TileTypeBitMask mask;
|
||||||
|
TileType lastType = TT_SPACE;
|
||||||
|
|
||||||
for (; contacts != (ResContactPoint *) NULL; contacts = contacts->cp_nextcontact)
|
for (; contacts != (ResContactPoint *) NULL; contacts = contacts->cp_nextcontact)
|
||||||
{
|
{
|
||||||
DBFullResidueMask(contacts->cp_type, &mask);
|
/* Avoid re-running the following code for the same contact type */
|
||||||
|
if (contacts->cp_type != lastType)
|
||||||
/* Watch for types that connect to the substrate plane or well; */
|
|
||||||
/* e.g., psubstratepdiff connects to nwell but not through a */
|
|
||||||
/* contact. */
|
|
||||||
|
|
||||||
if (ExtCurStyle->exts_globSubstratePlane != -1)
|
|
||||||
{
|
{
|
||||||
TileTypeBitMask cMask;
|
lastType = contacts->cp_type;
|
||||||
TTMaskAndMask3(&cMask, &DBConnectTbl[contacts->cp_type],
|
DBFullResidueMask(contacts->cp_type, &mask);
|
||||||
&DBPlaneTypes[ExtCurStyle->exts_globSubstratePlane]);
|
|
||||||
|
|
||||||
if (!TTMaskIsZero(&cMask))
|
/* Watch for types that connect to the substrate plane or well; */
|
||||||
TTMaskSetMask(&mask, &cMask);
|
/* e.g., psubstratepdiff connects to nwell but not through a */
|
||||||
|
/* contact. */
|
||||||
|
|
||||||
|
if (ExtCurStyle->exts_globSubstratePlane != -1)
|
||||||
|
{
|
||||||
|
TileTypeBitMask cMask;
|
||||||
|
TTMaskAndMask3(&cMask, &DBConnectTbl[contacts->cp_type],
|
||||||
|
&DBPlaneTypes[ExtCurStyle->exts_globSubstratePlane]);
|
||||||
|
|
||||||
|
if (!TTMaskIsZero(&cMask))
|
||||||
|
TTMaskSetMask(&mask, &cMask);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||||
{
|
{
|
||||||
|
if (!DBTypeOnPlane(contacts->cp_type, pNum) &&
|
||||||
|
(pNum != ExtCurStyle->exts_globSubstratePlane))
|
||||||
|
continue;
|
||||||
|
|
||||||
tile = PlaneGetHint(ResDef->cd_planes[pNum]);
|
tile = PlaneGetHint(ResDef->cd_planes[pNum]);
|
||||||
GOTOPOINT(tile, &(contacts->cp_center));
|
GOTOPOINT(tile, &(contacts->cp_center));
|
||||||
|
PlaneSetHint(ResDef->cd_planes[pNum], tile);
|
||||||
#ifdef PARANOID
|
#ifdef PARANOID
|
||||||
if (tile == (Tile *) NULL)
|
if (tile == (Tile *) NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -476,10 +507,11 @@ ResFindNewContactTiles(contacts)
|
||||||
/*
|
/*
|
||||||
*--------------------------------------------------------------------------
|
*--------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* ResProcessTiles--Calls ResEachTile with processed tiles belonging to
|
* ResProcessTiles --
|
||||||
* nodes in ResNodeQueue. When all the tiles corresponding
|
*
|
||||||
* to a node have been processed, the node is moved to
|
* Calls ResEachTile with processed tiles belonging to nodes in ResNodeQueue.
|
||||||
* ResNodeList.
|
* When all the tiles corresponding to a node have been processed, the node
|
||||||
|
* is moved to ResNodeList.
|
||||||
*
|
*
|
||||||
* Results: Return 1 if any error occurred, 0 otherwise.
|
* Results: Return 1 if any error occurred, 0 otherwise.
|
||||||
*
|
*
|
||||||
|
|
@ -1381,6 +1413,7 @@ FindStartTile(resisdata, SourcePoint)
|
||||||
{
|
{
|
||||||
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
|
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
|
||||||
GOTOPOINT(tile, &workingPoint);
|
GOTOPOINT(tile, &workingPoint);
|
||||||
|
PlaneSetHint(ResUse->cu_def->cd_planes[pnum], tile);
|
||||||
SourcePoint->p_x = workingPoint.p_x;
|
SourcePoint->p_x = workingPoint.p_x;
|
||||||
SourcePoint->p_y = workingPoint.p_y;
|
SourcePoint->p_y = workingPoint.p_y;
|
||||||
|
|
||||||
|
|
@ -1414,6 +1447,7 @@ FindStartTile(resisdata, SourcePoint)
|
||||||
|
|
||||||
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
|
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
|
||||||
GOTOPOINT(tile, &workingPoint);
|
GOTOPOINT(tile, &workingPoint);
|
||||||
|
PlaneSetHint(ResUse->cu_def->cd_planes[pnum], tile);
|
||||||
|
|
||||||
if (IsSplit(tile))
|
if (IsSplit(tile))
|
||||||
{
|
{
|
||||||
|
|
@ -1765,6 +1799,7 @@ ResGetDevice(pt, type)
|
||||||
|
|
||||||
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
|
tile = PlaneGetHint(ResUse->cu_def->cd_planes[pnum]);
|
||||||
GOTOPOINT(tile, &workingPoint);
|
GOTOPOINT(tile, &workingPoint);
|
||||||
|
PlaneSetHint(ResUse->cu_def->cd_planes[pnum], tile);
|
||||||
|
|
||||||
const ClientData ticlient = TiGetClient(tile);
|
const ClientData ticlient = TiGetClient(tile);
|
||||||
if (IsSplit(tile))
|
if (IsSplit(tile))
|
||||||
|
|
|
||||||
|
|
@ -76,10 +76,9 @@ ResCalcTileResistance(tile, info, pendingList, doneList)
|
||||||
if (x < MinX) MinX = x;
|
if (x < MinX) MinX = x;
|
||||||
if (y > MaxY) MaxY = y;
|
if (y > MaxY) MaxY = y;
|
||||||
if (y < MinY) MinY = y;
|
if (y < MinY) MinY = y;
|
||||||
|
|
||||||
if (p1->br_this->rn_why == RES_NODE_DEVICE)
|
if (p1->br_this->rn_why == RES_NODE_DEVICE)
|
||||||
{
|
|
||||||
device = TRUE;
|
device = TRUE;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finally, produce resistors for partition. Keep track of */
|
/* Finally, produce resistors for partition. Keep track of */
|
||||||
|
|
@ -125,7 +124,7 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
||||||
resNode **pendingList, **doneList;
|
resNode **pendingList, **doneList;
|
||||||
resResistor **resList;
|
resResistor **resList;
|
||||||
{
|
{
|
||||||
int height;
|
int count, height;
|
||||||
bool merged;
|
bool merged;
|
||||||
TileType ttype;
|
TileType ttype;
|
||||||
Breakpoint *p1, *p2, *p3;
|
Breakpoint *p1, *p2, *p3;
|
||||||
|
|
@ -134,6 +133,8 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
||||||
resNode *currNode;
|
resNode *currNode;
|
||||||
float rArea;
|
float rArea;
|
||||||
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
||||||
|
HashTable BreakTable;
|
||||||
|
HashEntry *he;
|
||||||
|
|
||||||
merged = FALSE;
|
merged = FALSE;
|
||||||
height = TOP(tile) - BOTTOM(tile);
|
height = TOP(tile) - BOTTOM(tile);
|
||||||
|
|
@ -163,21 +164,38 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
||||||
ttype = TiGetTypeExact(tile);
|
ttype = TiGetTypeExact(tile);
|
||||||
|
|
||||||
/* Re-sort nodes left to right. */
|
/* Re-sort nodes left to right. */
|
||||||
|
count = ResSortBreaks(&info->breakList, TRUE);
|
||||||
|
|
||||||
ResSortBreaks(&info->breakList, TRUE);
|
/* For long lists (defined as >= 16 entries), make a hash table of
|
||||||
|
* the node pointer conversions so that each node can be updated
|
||||||
|
* as we walk the list, instead of walking the rest of the list in
|
||||||
|
* a nested loop for each entry.
|
||||||
|
*/
|
||||||
|
if (count >= 16)
|
||||||
|
HashInit(&BreakTable, HT_DEFAULTSIZE, HT_CLIENTKEYS);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Eliminate breakpoints with the same X coordinate and merge
|
* Eliminate breakpoints with the same X coordinate and merge
|
||||||
* their nodes.
|
* their nodes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
p2= info->breakList;
|
p2 = info->breakList;
|
||||||
|
|
||||||
/* Add extra left area to leftmost node */
|
/* Add extra left area to leftmost node */
|
||||||
|
|
||||||
p2->br_this->rn_float.rn_area += height * (p2->br_loc.p_x - LEFT(tile));
|
p2->br_this->rn_float.rn_area += height * (p2->br_loc.p_x - LEFT(tile));
|
||||||
while (p2->br_next != NULL)
|
while (p2->br_next != NULL)
|
||||||
{
|
{
|
||||||
|
/* Has the node been recorded as needing to be replaced? */
|
||||||
|
if (count >= 16)
|
||||||
|
{
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
he = HashLookOnly(&BreakTable, (char *)p2->br_this);
|
||||||
|
if (!he) break;
|
||||||
|
p2->br_this = (resNode *)HashGetValue(he);
|
||||||
|
}
|
||||||
|
}
|
||||||
p1 = p2;
|
p1 = p2;
|
||||||
p2 = p2->br_next;
|
p2 = p2->br_next;
|
||||||
if (p2->br_loc.p_x == p1->br_loc.p_x)
|
if (p2->br_loc.p_x == p1->br_loc.p_x)
|
||||||
|
|
@ -215,25 +233,38 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
||||||
/*
|
/*
|
||||||
* Was the node used in another info or breakpoint?
|
* Was the node used in another info or breakpoint?
|
||||||
* If so, replace the old node with the new one.
|
* If so, replace the old node with the new one.
|
||||||
|
*
|
||||||
|
* Short lists: Walk the list to the end and change
|
||||||
|
* nodes on the fly.
|
||||||
|
* Long lists: Record the change to be made in the
|
||||||
|
* hash table so that it can be executed as each list
|
||||||
|
* entry is encountered.
|
||||||
*/
|
*/
|
||||||
|
if (count >= 16)
|
||||||
p3 = p2->br_next;
|
|
||||||
while (p3 != NULL)
|
|
||||||
{
|
{
|
||||||
if (p3->br_this == currNode)
|
he = HashFind(&BreakTable, (char *)currNode);
|
||||||
p3->br_this = p2->br_this;
|
HashSetValue(he, (char *)p2->br_this);
|
||||||
|
|
||||||
p3 = p3->br_next;
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
p3 = p2->br_next;
|
||||||
|
while (p3 != NULL)
|
||||||
|
{
|
||||||
|
if (p3->br_this == currNode)
|
||||||
|
p3->br_this = p2->br_this;
|
||||||
|
|
||||||
/*
|
p3 = p3->br_next;
|
||||||
* If the X coordinates don't match, make a resistor between
|
}
|
||||||
* the breakpoints.
|
}
|
||||||
*/
|
}
|
||||||
|
|
||||||
else
|
/*
|
||||||
{
|
* If the X coordinates don't match, make a resistor between
|
||||||
|
* the breakpoints.
|
||||||
|
*/
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
resistor = (resResistor *)mallocMagic((unsigned)sizeof(resResistor));
|
resistor = (resResistor *)mallocMagic((unsigned)sizeof(resResistor));
|
||||||
resistor->rr_nextResistor = (*resList);
|
resistor->rr_nextResistor = (*resList);
|
||||||
resistor->rr_lastResistor = NULL;
|
resistor->rr_lastResistor = NULL;
|
||||||
|
|
@ -276,6 +307,8 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (count >= 16) HashKill(&BreakTable);
|
||||||
|
|
||||||
p2->br_this->rn_float.rn_area += height * (RIGHT(tile) - p2->br_loc.p_x);
|
p2->br_this->rn_float.rn_area += height * (RIGHT(tile) - p2->br_loc.p_x);
|
||||||
freeMagic((char *)p2);
|
freeMagic((char *)p2);
|
||||||
info->breakList = NULL;
|
info->breakList = NULL;
|
||||||
|
|
@ -301,7 +334,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
||||||
resNode **pendingList, **doneList;
|
resNode **pendingList, **doneList;
|
||||||
resResistor **resList;
|
resResistor **resList;
|
||||||
{
|
{
|
||||||
int width;
|
int count, width;
|
||||||
bool merged;
|
bool merged;
|
||||||
TileType ttype;
|
TileType ttype;
|
||||||
Breakpoint *p1, *p2, *p3;
|
Breakpoint *p1, *p2, *p3;
|
||||||
|
|
@ -310,6 +343,8 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
||||||
resNode *currNode;
|
resNode *currNode;
|
||||||
float rArea;
|
float rArea;
|
||||||
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
resInfo *info = (resInfo *)TiGetClientPTR(tile);
|
||||||
|
HashTable BreakTable;
|
||||||
|
HashEntry *he;
|
||||||
|
|
||||||
merged = FALSE;
|
merged = FALSE;
|
||||||
width = RIGHT(tile) - LEFT(tile);
|
width = RIGHT(tile) - LEFT(tile);
|
||||||
|
|
@ -329,7 +364,15 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Re-sort nodes south to north. */
|
/* Re-sort nodes south to north. */
|
||||||
ResSortBreaks(&info->breakList, FALSE);
|
count = ResSortBreaks(&info->breakList, FALSE);
|
||||||
|
|
||||||
|
/* For long lists (defined as >= 16 entries), make a hash table of
|
||||||
|
* the node pointer conversions so that each node can be updated
|
||||||
|
* as we walk the list, instead of walking the rest of the list in
|
||||||
|
* a nested loop for each entry.
|
||||||
|
*/
|
||||||
|
if (count >= 16)
|
||||||
|
HashInit(&BreakTable, HT_DEFAULTSIZE, HT_CLIENTKEYS);
|
||||||
|
|
||||||
/* Simplified split tile handling */
|
/* Simplified split tile handling */
|
||||||
if (IsSplit(tile))
|
if (IsSplit(tile))
|
||||||
|
|
@ -353,51 +396,75 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
|
||||||
p2->br_this->rn_float.rn_area += width * (p2->br_loc.p_y - BOTTOM(tile));
|
p2->br_this->rn_float.rn_area += width * (p2->br_loc.p_y - BOTTOM(tile));
|
||||||
while (p2->br_next != NULL)
|
while (p2->br_next != NULL)
|
||||||
{
|
{
|
||||||
|
/* Has the node been recorded as needing to be replaced? */
|
||||||
|
if (count >= 16)
|
||||||
|
{
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
he = HashLookOnly(&BreakTable, (char *)p2->br_this);
|
||||||
|
if (!he) break;
|
||||||
|
p2->br_this = (resNode *)HashGetValue(he);
|
||||||
|
}
|
||||||
|
}
|
||||||
p1 = p2;
|
p1 = p2;
|
||||||
p2 = p2->br_next;
|
p2 = p2->br_next;
|
||||||
if (p1->br_loc.p_y == p2->br_loc.p_y)
|
if (p1->br_loc.p_y == p2->br_loc.p_y)
|
||||||
{
|
{
|
||||||
if (p2->br_this == p1->br_this)
|
if (p2->br_this == p1->br_this)
|
||||||
{
|
{
|
||||||
currNode = NULL;
|
currNode = NULL;
|
||||||
p1->br_next = p2->br_next;
|
p1->br_next = p2->br_next;
|
||||||
freeMagic((char *)p2);
|
freeMagic((char *)p2);
|
||||||
p2 = p1;
|
p2 = p1;
|
||||||
}
|
}
|
||||||
else if (p2->br_this == resCurrentNode)
|
else if (p2->br_this == resCurrentNode)
|
||||||
{
|
{
|
||||||
currNode = p1->br_this;
|
currNode = p1->br_this;
|
||||||
ResMergeNodes(p2->br_this, p1->br_this, pendingList, doneList);
|
ResMergeNodes(p2->br_this, p1->br_this, pendingList, doneList);
|
||||||
freeMagic((char *)p1);
|
freeMagic((char *)p1);
|
||||||
merged = TRUE;
|
merged = TRUE;
|
||||||
}
|
}
|
||||||
else if (p1->br_this == resCurrentNode)
|
else if (p1->br_this == resCurrentNode)
|
||||||
{
|
{
|
||||||
currNode = p2->br_this;
|
currNode = p2->br_this;
|
||||||
p1->br_next = p2->br_next;
|
p1->br_next = p2->br_next;
|
||||||
ResMergeNodes(p1->br_this, p2->br_this, pendingList, doneList);
|
ResMergeNodes(p1->br_this, p2->br_this, pendingList, doneList);
|
||||||
merged = TRUE;
|
merged = TRUE;
|
||||||
freeMagic((char *)p2);
|
freeMagic((char *)p2);
|
||||||
p2 = p1;
|
p2 = p1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
currNode = p1->br_this;
|
currNode = p1->br_this;
|
||||||
ResMergeNodes(p2->br_this, p1->br_this, pendingList, doneList);
|
ResMergeNodes(p2->br_this, p1->br_this, pendingList, doneList);
|
||||||
freeMagic((char *)p1);
|
freeMagic((char *)p1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Was the node used in another info or breakpoint?
|
* Was the node used in another info or breakpoint?
|
||||||
* If so, replace the old node with the new one.
|
* If so, replace the old node with the new one.
|
||||||
|
*
|
||||||
|
* Short lists: Walk the list to the end and change
|
||||||
|
* nodes on the fly.
|
||||||
|
* Long lists: Record the change to be made in the
|
||||||
|
* hash table so that it can be executed as each list
|
||||||
|
* entry is encountered.
|
||||||
*/
|
*/
|
||||||
p3 = p2->br_next;
|
if (count >= 16)
|
||||||
while (p3 != NULL)
|
|
||||||
{
|
{
|
||||||
if (p3->br_this == currNode)
|
he = HashFind(&BreakTable, (char *)currNode);
|
||||||
p3->br_this = p2->br_this;
|
HashSetValue(he, (char *)p2->br_this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p3 = p2->br_next;
|
||||||
|
while (p3 != NULL)
|
||||||
|
{
|
||||||
|
if (p3->br_this == currNode)
|
||||||
|
p3->br_this = p2->br_this;
|
||||||
|
|
||||||
p3 = p3->br_next;
|
p3 = p3->br_next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -491,7 +558,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
||||||
* breakpoint, then return.
|
* breakpoint, then return.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (info->breakList->br_next == NULL)
|
if (info->breakList->br_next == NULL)
|
||||||
{
|
{
|
||||||
freeMagic((char *)info->breakList);
|
freeMagic((char *)info->breakList);
|
||||||
info->breakList = NULL;
|
info->breakList = NULL;
|
||||||
|
|
@ -525,7 +592,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
|
||||||
(devedge & TOPEDGE) == devedge ||
|
(devedge & TOPEDGE) == devedge ||
|
||||||
(devedge & BOTTOMEDGE) == devedge)
|
(devedge & BOTTOMEDGE) == devedge)
|
||||||
{
|
{
|
||||||
ResSortBreaks(&info->breakList,TRUE);
|
ResSortBreaks(&info->breakList, TRUE);
|
||||||
p2 = NULL;
|
p2 = NULL;
|
||||||
for (p1 = info->breakList; p1 != NULL; p1 = p1->br_next)
|
for (p1 = info->breakList; p1 != NULL; p1 = p1->br_next)
|
||||||
{
|
{
|
||||||
|
|
@ -919,21 +986,207 @@ ResDoContacts(contact, nodes, resList)
|
||||||
/*
|
/*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* ResSortBreaks --
|
* BreakCompare --
|
||||||
|
*
|
||||||
|
* Helper routine for MergeSortBreaks() (below). Simple
|
||||||
|
* comparison of the breakpoint position. Comparison is
|
||||||
|
* done for the X position if "xsort" is TRUE, and the Y
|
||||||
|
* position if "xsort" is FALSE.
|
||||||
|
*
|
||||||
|
* Return value:
|
||||||
|
* Return -1 if the (x or y) position of a is less than the
|
||||||
|
* (x or y) position of b; return +1 if the position of a is
|
||||||
|
* greater than the position of b; and return 0 if they have
|
||||||
|
* equal positions.
|
||||||
|
*
|
||||||
|
* Side effect:
|
||||||
|
* None.
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
BreakCompare(
|
||||||
|
Breakpoint *a,
|
||||||
|
Breakpoint *b,
|
||||||
|
int xsort)
|
||||||
|
{
|
||||||
|
if (xsort == TRUE)
|
||||||
|
{
|
||||||
|
if (a->br_loc.p_x < b->br_loc.p_x) return -1;
|
||||||
|
if (a->br_loc.p_x > b->br_loc.p_x) return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (a->br_loc.p_y < b->br_loc.p_y) return -1;
|
||||||
|
if (a->br_loc.p_y > b->br_loc.p_y) return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* MergeSorted --
|
||||||
|
*
|
||||||
|
* Helper routine for MergeSortBreaks() (below). Merge sort
|
||||||
|
* merging routine.
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
Breakpoint *
|
||||||
|
MergeSorted(
|
||||||
|
Breakpoint *a,
|
||||||
|
Breakpoint *b,
|
||||||
|
int xsort)
|
||||||
|
{
|
||||||
|
Breakpoint head;
|
||||||
|
Breakpoint *tail = &head;
|
||||||
|
|
||||||
|
head.br_next = NULL;
|
||||||
|
|
||||||
|
while (a != NULL && b != NULL)
|
||||||
|
{
|
||||||
|
if (BreakCompare(a, b, xsort) <= 0)
|
||||||
|
{
|
||||||
|
tail->br_next = a;
|
||||||
|
a = a->br_next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tail->br_next = b;
|
||||||
|
b = b->br_next;
|
||||||
|
}
|
||||||
|
tail = tail->br_next;
|
||||||
|
}
|
||||||
|
tail->br_next = (a != NULL) ? a : b;
|
||||||
|
|
||||||
|
return head.br_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* SplitList --
|
||||||
|
*
|
||||||
|
* Helper routine for MergeSortBreaks() (below). Merge sort
|
||||||
|
* splitting routine.
|
||||||
*
|
*
|
||||||
* Results:
|
* Results:
|
||||||
* None
|
* None.
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
|
SplitList(
|
||||||
|
Breakpoint *source,
|
||||||
|
Breakpoint **front,
|
||||||
|
Breakpoint **back)
|
||||||
|
{
|
||||||
|
Breakpoint *slow;
|
||||||
|
Breakpoint *fast;
|
||||||
|
|
||||||
|
if (source == NULL || source->br_next == NULL)
|
||||||
|
{
|
||||||
|
*front = source;
|
||||||
|
*back = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
slow = source;
|
||||||
|
fast = source->br_next;
|
||||||
|
|
||||||
|
while (fast != NULL)
|
||||||
|
{
|
||||||
|
fast = fast->br_next;
|
||||||
|
|
||||||
|
if (fast != NULL)
|
||||||
|
{
|
||||||
|
slow = slow->br_next;
|
||||||
|
fast = fast->br_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*front = source;
|
||||||
|
*back = slow->br_next;
|
||||||
|
slow->br_next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* MergeSortBreaks --
|
||||||
|
*
|
||||||
|
* See "ResSortBreaks" below. Alternative to bubble sort for long
|
||||||
|
* linked lists.
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* Pointer to a sorted breakpoint list.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* The breakpoints are sorted.
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
Breakpoint *
|
||||||
|
MergeSortBreaks(Breakpoint *list, int xsort)
|
||||||
|
{
|
||||||
|
Breakpoint *a, *b;
|
||||||
|
|
||||||
|
if (list == NULL || list->br_next == NULL)
|
||||||
|
return list;
|
||||||
|
|
||||||
|
SplitList(list, &a, &b);
|
||||||
|
|
||||||
|
a = MergeSortBreaks(a, xsort);
|
||||||
|
b = MergeSortBreaks(b, xsort);
|
||||||
|
|
||||||
|
return MergeSorted(a, b, xsort);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* ResSortBreaks --
|
||||||
|
*
|
||||||
|
* Sort breakpoints, either in the X direction (if "xsort" is TRUE)
|
||||||
|
* or in the Y direction (if "xsort" is FALSE). For short lists
|
||||||
|
* (< 16 elements), a simple bubble sort is used. For larger lists,
|
||||||
|
* a merge sort is used. Most resistor networks are short, but
|
||||||
|
* power/ground networks can be huge and cause a performance
|
||||||
|
* bottleneck.
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* Return the length of the list (maximum truncated at 16) so that
|
||||||
|
* the calling routine can determine if this is a long or a short
|
||||||
|
* linked list and treat it accordingly.
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
ResSortBreaks(masterlist, xsort)
|
ResSortBreaks(masterlist, xsort)
|
||||||
Breakpoint **masterlist;
|
Breakpoint **masterlist;
|
||||||
int xsort;
|
int xsort;
|
||||||
{
|
{
|
||||||
Breakpoint *p1, *p2, *p3, *p4;
|
Breakpoint *p1, *p2, *p3, *p4;
|
||||||
bool changed;
|
bool changed;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (p1 = *masterlist; p1; p1 = p1->br_next)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
if (count > 16)
|
||||||
|
{
|
||||||
|
*masterlist = MergeSortBreaks(*masterlist, xsort);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simple bubble sort */
|
||||||
|
|
||||||
changed = TRUE;
|
changed = TRUE;
|
||||||
while (changed == TRUE)
|
while (changed == TRUE)
|
||||||
|
|
@ -970,5 +1223,6 @@ ResSortBreaks(masterlist, xsort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
251
resis/ResMerge.c
251
resis/ResMerge.c
|
|
@ -26,7 +26,6 @@ extern void ResEliminateResistor();
|
||||||
extern void ResCleanNode();
|
extern void ResCleanNode();
|
||||||
extern void ResFixBreakPoint();
|
extern void ResFixBreakPoint();
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -406,13 +405,70 @@ ResSeriesCheck(resptr)
|
||||||
int
|
int
|
||||||
ResParallelCheck(resptr)
|
ResParallelCheck(resptr)
|
||||||
resNode *resptr;
|
resNode *resptr;
|
||||||
|
|
||||||
{
|
{
|
||||||
resResistor *r1,*r2;
|
resResistor *r1, *r2;
|
||||||
resNode *resptr2,*resptr3;
|
resNode *resptr2, *resptr3;
|
||||||
int status = UNTOUCHED;
|
int status = UNTOUCHED;
|
||||||
resElement *rcell1, *rcell2;
|
resElement *rcell1, *rcell2;
|
||||||
|
|
||||||
|
int rcount = 0;
|
||||||
|
|
||||||
|
/* When the number of resistors gets to be large enough, it is more efficient to
|
||||||
|
* sort the resistor list and then do a single pass to see if any two consecutive
|
||||||
|
* items in the sorted list can be merged, than to do a double loop through the
|
||||||
|
* resistor list at ~O(N^2).
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (rcell1 = resptr->rn_re; rcell1 != NULL; rcell1 = rcell1->re_nextEl)
|
||||||
|
{
|
||||||
|
rcount++;
|
||||||
|
if (rcount >= 10) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rcount >= 10)
|
||||||
|
{
|
||||||
|
HashTable NodeResTable;
|
||||||
|
HashEntry *he;
|
||||||
|
|
||||||
|
/* Hash the connections */
|
||||||
|
HashInit(&NodeResTable, HT_DEFAULTSIZE, HT_CLIENTKEYS);
|
||||||
|
|
||||||
|
for (rcell2 = resptr->rn_re; rcell2 != NULL; rcell2 = rcell2->re_nextEl)
|
||||||
|
{
|
||||||
|
/* One connection is always resptr; find the other one */
|
||||||
|
resptr3 = rcell2->re_thisEl->rr_connection1;
|
||||||
|
if (resptr3 == resptr) resptr3 = rcell2->re_thisEl->rr_connection2;
|
||||||
|
|
||||||
|
he = HashFind(&NodeResTable, (char *)resptr3);
|
||||||
|
if ((rcell1 = (resElement*)HashGetValue(he)))
|
||||||
|
{
|
||||||
|
r1 = rcell1->re_thisEl;
|
||||||
|
r2 = rcell2->re_thisEl;
|
||||||
|
|
||||||
|
if (TTMaskHasType(ResNoMergeMask+r1->rr_tt, r2->rr_tt)) continue;
|
||||||
|
|
||||||
|
ResFixParallel(r1, r2);
|
||||||
|
status = PARALLEL;
|
||||||
|
resptr2 = NULL;
|
||||||
|
if (resptr3->rn_status & RES_TRUE)
|
||||||
|
{
|
||||||
|
resptr2 = resptr3;
|
||||||
|
resptr2->rn_status &= ~RES_TRUE;
|
||||||
|
}
|
||||||
|
ResDoneWithNode(resptr);
|
||||||
|
if (resptr2 != NULL) ResDoneWithNode(resptr2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
HashSetValue(he, (char *)rcell2);
|
||||||
|
}
|
||||||
|
HashKill(&NodeResTable);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This does the same thing as above, but for a small number of resistors
|
||||||
|
* per node, it avoids the overhead of creating and destroying hash tables.
|
||||||
|
*/
|
||||||
|
|
||||||
for (rcell1 = resptr->rn_re; rcell1->re_nextEl != NULL;
|
for (rcell1 = resptr->rn_re; rcell1->re_nextEl != NULL;
|
||||||
rcell1 = rcell1->re_nextEl)
|
rcell1 = rcell1->re_nextEl)
|
||||||
|
|
@ -447,6 +503,7 @@ ResParallelCheck(resptr)
|
||||||
}
|
}
|
||||||
if (status == PARALLEL) break;
|
if (status == PARALLEL) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -473,6 +530,179 @@ ResTriangleCheck(resptr)
|
||||||
float r1, r2, r3, denom;
|
float r1, r2, r3, denom;
|
||||||
resNode *n1, *n2, *n3;
|
resNode *n1, *n2, *n3;
|
||||||
resElement *rcell1, *rcell2, *rcell3, *element;
|
resElement *rcell1, *rcell2, *rcell3, *element;
|
||||||
|
int rcount = 0;
|
||||||
|
|
||||||
|
/* When the size of the linked list of resistors is long, it is faster to
|
||||||
|
* hash the neighboring connections and then find the first entry in the
|
||||||
|
* neighbor's node list that is another neighbor.
|
||||||
|
*/
|
||||||
|
for (rcell1 = resptr->rn_re; rcell1 != NULL; rcell1 = rcell1->re_nextEl)
|
||||||
|
{
|
||||||
|
rcount++;
|
||||||
|
if (rcount >= 10) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rcount >= 10)
|
||||||
|
{
|
||||||
|
HashTable NodeResTable;
|
||||||
|
HashEntry *he, *he2;
|
||||||
|
HashSearch hs;
|
||||||
|
|
||||||
|
/* Hash the neighboring connections */
|
||||||
|
HashInit(&NodeResTable, HT_DEFAULTSIZE, HT_CLIENTKEYS);
|
||||||
|
|
||||||
|
for (rcell2 = resptr->rn_re; rcell2 != NULL; rcell2 = rcell2->re_nextEl)
|
||||||
|
{
|
||||||
|
rr2 = rcell2->re_thisEl;
|
||||||
|
|
||||||
|
/* One connection is always resptr; find the other one */
|
||||||
|
n2 = rr2->rr_connection1;
|
||||||
|
if (n2 == resptr) n2 = rr2->rr_connection2;
|
||||||
|
|
||||||
|
he = HashFind(&NodeResTable, (char *)n2);
|
||||||
|
if (!(rcell1 = (resElement *)HashGetValue(he)))
|
||||||
|
HashSetValue(he, (char *)rcell2);
|
||||||
|
}
|
||||||
|
|
||||||
|
HashStartSearch(&hs);
|
||||||
|
while ((he = HashNext(&NodeResTable, &hs)))
|
||||||
|
{
|
||||||
|
/* Get each node that neighbors resptr */
|
||||||
|
n1 = (resNode *)he->h_key.h_ptr;
|
||||||
|
rcell1 = (resElement *)HashGetValue(he);
|
||||||
|
rr1 = rcell1->re_thisEl;
|
||||||
|
|
||||||
|
/* Check the list of resistors of neighbor n1 for any resistor whose
|
||||||
|
* other end is also a neighbor of resptr.
|
||||||
|
*/
|
||||||
|
for (rcell3 = n1->rn_re; rcell3 != NULL; rcell3 = rcell3->re_nextEl)
|
||||||
|
{
|
||||||
|
rr3 = rcell3->re_thisEl;
|
||||||
|
|
||||||
|
/* Resistor can't be merged */
|
||||||
|
if (TTMaskHasType(ResNoMergeMask + rr1->rr_tt, rr3->rr_tt))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* One connection is always n1; find the other one */
|
||||||
|
n2 = rr3->rr_connection1;
|
||||||
|
if (n2 == n1) n2 = rr3->rr_connection2;
|
||||||
|
|
||||||
|
he2 = HashLookOnly(&NodeResTable, (char *)n2);
|
||||||
|
if (he2)
|
||||||
|
{
|
||||||
|
/* Found a triangle */
|
||||||
|
rcell2 = (resElement *)HashGetValue(he2);
|
||||||
|
rr2 = rcell2->re_thisEl;
|
||||||
|
|
||||||
|
/* . . . But it can't be merged */
|
||||||
|
if (TTMaskHasType(ResNoMergeMask + rr1->rr_tt, rr2->rr_tt))
|
||||||
|
continue;
|
||||||
|
if (TTMaskHasType(ResNoMergeMask + rr2->rr_tt, rr3->rr_tt))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
status = TRIANGLE;
|
||||||
|
if ((denom = rr1->rr_value + rr2->rr_value + rr3->rr_value) != 0.0)
|
||||||
|
{
|
||||||
|
denom = 1.0 /denom;
|
||||||
|
/* calculate new values for resistors */
|
||||||
|
r1 = (((float)rr1->rr_value) * ((float)rr2->rr_value)) * denom;
|
||||||
|
r2 = (((float)rr2->rr_value) * ((float)rr3->rr_value)) * denom;
|
||||||
|
r3 = (((float)rr1->rr_value) * ((float)rr3->rr_value)) * denom;
|
||||||
|
|
||||||
|
rr1->rr_value = r1 + 0.5;
|
||||||
|
rr2->rr_value = r2 + 0.5;
|
||||||
|
rr3->rr_value = r3 + 0.5;
|
||||||
|
ASSERT(rr1->rr_value >= 0, "Triangle");
|
||||||
|
ASSERT(rr2->rr_value >= 0, "Triangle");
|
||||||
|
ASSERT(rr3->rr_value >= 0, "Triangle");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rr1->rr_value = 0;
|
||||||
|
rr2->rr_value = 0;
|
||||||
|
rr3->rr_value = 0;
|
||||||
|
}
|
||||||
|
n3 = (resNode *)mallocMagic((unsigned)(sizeof(resNode)));
|
||||||
|
|
||||||
|
/* Where should the new node be put? It */
|
||||||
|
/* is arbitrarily assigned to the location */
|
||||||
|
/* occupied by the first node. */
|
||||||
|
|
||||||
|
InitializeResNode(n3, resptr->rn_loc.p_x, resptr->rn_loc.p_y, TRIANGLE);
|
||||||
|
n3->rn_status = RES_FINISHED | RES_TRUE | RES_MARKED;
|
||||||
|
|
||||||
|
n3->rn_less = NULL;
|
||||||
|
n3->rn_more = ResNodeList;
|
||||||
|
ResNodeList->rn_less = n3;
|
||||||
|
ResNodeList = n3;
|
||||||
|
if (resptr == rr1->rr_connection1)
|
||||||
|
{
|
||||||
|
ResDeleteResPointer(rr1->rr_connection2, rr1);
|
||||||
|
rr1->rr_connection2 = n3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ResDeleteResPointer(rr1->rr_connection1, rr1);
|
||||||
|
rr1->rr_connection1 = n3;
|
||||||
|
}
|
||||||
|
if (n2 == rr2->rr_connection1)
|
||||||
|
{
|
||||||
|
ResDeleteResPointer(rr2->rr_connection2, rr2);
|
||||||
|
rr2->rr_connection2 = n3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ResDeleteResPointer(rr2->rr_connection1, rr2);
|
||||||
|
rr2->rr_connection1 = n3;
|
||||||
|
}
|
||||||
|
if (n1 == rr3->rr_connection1)
|
||||||
|
{
|
||||||
|
ResDeleteResPointer(rr3->rr_connection2, rr3);
|
||||||
|
rr3->rr_connection2 = n3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ResDeleteResPointer(rr3->rr_connection1, rr3);
|
||||||
|
rr3->rr_connection1 = n3;
|
||||||
|
}
|
||||||
|
element = (resElement *)mallocMagic((unsigned)(sizeof(resElement)));
|
||||||
|
element->re_nextEl = NULL;
|
||||||
|
element->re_thisEl = rr1;
|
||||||
|
n3->rn_re = element;
|
||||||
|
element = (resElement *)mallocMagic((unsigned)(sizeof(resElement)));
|
||||||
|
element->re_nextEl = n3->rn_re;
|
||||||
|
element->re_thisEl = rr2;
|
||||||
|
n3->rn_re = element;
|
||||||
|
element = (resElement *)mallocMagic((unsigned)(sizeof(resElement)));
|
||||||
|
element->re_nextEl = n3->rn_re;
|
||||||
|
element->re_thisEl = rr3;
|
||||||
|
n3->rn_re = element;
|
||||||
|
if ((n1->rn_status & RES_TRUE) == RES_TRUE)
|
||||||
|
n1->rn_status &= ~RES_TRUE;
|
||||||
|
else
|
||||||
|
n1 = NULL;
|
||||||
|
|
||||||
|
if ((n2->rn_status & RES_TRUE) == RES_TRUE)
|
||||||
|
n2->rn_status &= ~RES_TRUE;
|
||||||
|
else
|
||||||
|
n2 = NULL;
|
||||||
|
|
||||||
|
ResDoneWithNode(resptr);
|
||||||
|
if (n1 != NULL) ResDoneWithNode(n1);
|
||||||
|
if (n2 != NULL) ResDoneWithNode(n2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (status == TRIANGLE) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashKill(&NodeResTable);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This does the same thing as above, but for a small number of resistors
|
||||||
|
* per node, avoiding the overhead of creating and destroying hash tables.
|
||||||
|
*/
|
||||||
|
|
||||||
for (rcell1 = resptr->rn_re; rcell1->re_nextEl != NULL;
|
for (rcell1 = resptr->rn_re; rcell1->re_nextEl != NULL;
|
||||||
rcell1 = rcell1->re_nextEl)
|
rcell1 = rcell1->re_nextEl)
|
||||||
|
|
@ -609,9 +839,9 @@ ResTriangleCheck(resptr)
|
||||||
*
|
*
|
||||||
* ResMergeNodes--
|
* ResMergeNodes--
|
||||||
*
|
*
|
||||||
* results: none
|
* Results: none
|
||||||
*
|
*
|
||||||
* side effects: appends all the cElement, jElement, tElement and
|
* Side Effects: appends all the cElement, jElement, tElement and
|
||||||
* resElement structures from node 2 onto node 1. Node 2 is
|
* resElement structures from node 2 onto node 1. Node 2 is
|
||||||
* then eliminated.
|
* then eliminated.
|
||||||
*
|
*
|
||||||
|
|
@ -780,7 +1010,7 @@ ResMergeNodes(node1, node2, pendingList, doneList)
|
||||||
* ResDeleteResPointer-- Deletes the pointer from a node to a resistor.
|
* ResDeleteResPointer-- Deletes the pointer from a node to a resistor.
|
||||||
* Used when a resistor is deleted.
|
* Used when a resistor is deleted.
|
||||||
*
|
*
|
||||||
* Results:none
|
* Results: none
|
||||||
*
|
*
|
||||||
* Side Effects: Modifies a node's resistor list.
|
* Side Effects: Modifies a node's resistor list.
|
||||||
*
|
*
|
||||||
|
|
@ -788,7 +1018,7 @@ ResMergeNodes(node1, node2, pendingList, doneList)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
ResDeleteResPointer(node,resistor)
|
ResDeleteResPointer(node, resistor)
|
||||||
resNode *node;
|
resNode *node;
|
||||||
resResistor *resistor;
|
resResistor *resistor;
|
||||||
|
|
||||||
|
|
@ -829,7 +1059,7 @@ ResDeleteResPointer(node,resistor)
|
||||||
*
|
*
|
||||||
* ResEliminateResistor--
|
* ResEliminateResistor--
|
||||||
*
|
*
|
||||||
* Results:none
|
* Results: none
|
||||||
*
|
*
|
||||||
* Side Effects: Deletes a resistor. Does not delete pointers from nodes to
|
* Side Effects: Deletes a resistor. Does not delete pointers from nodes to
|
||||||
* resistor.
|
* resistor.
|
||||||
|
|
@ -867,8 +1097,7 @@ ResEliminateResistor(resistor, homelist)
|
||||||
* they are no longer needed. If the 'info' option is used,
|
* they are no longer needed. If the 'info' option is used,
|
||||||
* the node is eradicated.
|
* the node is eradicated.
|
||||||
*
|
*
|
||||||
* Results:
|
* Results: none.
|
||||||
* None.
|
|
||||||
*
|
*
|
||||||
* Side Effects: frees memory
|
* Side Effects: frees memory
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -1356,7 +1356,7 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename)
|
||||||
}
|
}
|
||||||
if (extDev->subs == extNode)
|
if (extDev->subs == extNode)
|
||||||
{
|
{
|
||||||
if ((layoutDev->rd_nterms >= 4) && ((subs = layoutDev->rd_fet_subs) != NULL))
|
if ((subs = layoutDev->rd_fet_subs) != NULL)
|
||||||
{
|
{
|
||||||
if (subs->rn_name != NULL && notdecremented)
|
if (subs->rn_name != NULL && notdecremented)
|
||||||
{
|
{
|
||||||
|
|
@ -1422,7 +1422,7 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename)
|
||||||
extNode->status |= DONTKILL;
|
extNode->status |= DONTKILL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (layoutDev->rd_nterms > 3)
|
||||||
{
|
{
|
||||||
if ((source = layoutDev->rd_fet_source) != NULL)
|
if ((source = layoutDev->rd_fet_source) != NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -1469,7 +1469,7 @@ ResFixUpConnections(extDev, layoutDev, extNode, nodename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (extDev->drain == extNode)
|
else if ((extDev->drain == extNode) && (layoutDev->rd_nterms > 3))
|
||||||
{
|
{
|
||||||
/* Check for devices with only one terminal. If it was cast as source, */
|
/* Check for devices with only one terminal. If it was cast as source, */
|
||||||
/* then swap it with the drain so that the code below handles it */
|
/* then swap it with the drain so that the code below handles it */
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResSimple.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResSimple.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
||||||
#endif /* not lint */
|
#endif /* not lint */
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h> /* for qsort() */
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
@ -386,7 +387,7 @@ ResMoveDevices(node1, node2)
|
||||||
devptr = devptr->te_nextt;
|
devptr = devptr->te_nextt;
|
||||||
if (device->rd_fet_gate == node1)
|
if (device->rd_fet_gate == node1)
|
||||||
device->rd_fet_gate = node2;
|
device->rd_fet_gate = node2;
|
||||||
else if ((device->rd_nterms >= 4) && (device->rd_fet_subs == node1))
|
else if (device->rd_fet_subs == node1)
|
||||||
device->rd_fet_subs = node2;
|
device->rd_fet_subs = node2;
|
||||||
else if (device->rd_fet_source == node1)
|
else if (device->rd_fet_source == node1)
|
||||||
device->rd_fet_source = node2;
|
device->rd_fet_source = node2;
|
||||||
|
|
@ -401,6 +402,29 @@ ResMoveDevices(node1, node2)
|
||||||
node1->rn_te = NULL;
|
node1->rn_te = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* qrescompare ---
|
||||||
|
*
|
||||||
|
* Sort routine for qsort() to be used by ResScrunchNet(). Sorts in
|
||||||
|
* order of the resistor value, smallest to largest.
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
qrescompare(const void *one, const void *two)
|
||||||
|
{
|
||||||
|
int cval;
|
||||||
|
|
||||||
|
resResistor *r1 = *((resResistor **)one);
|
||||||
|
resResistor *r2 = *((resResistor **)two);
|
||||||
|
|
||||||
|
if (r1->rr_value < r2->rr_value) return -1;
|
||||||
|
else if (r1->rr_value == r2->rr_value) return 0;
|
||||||
|
else return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -424,29 +448,82 @@ ResScrunchNet(reslist, pendingList, biglist, tolerance)
|
||||||
float tolerance;
|
float tolerance;
|
||||||
|
|
||||||
{
|
{
|
||||||
resResistor *locallist = NULL, *current, *working;
|
resResistor *current, *working;
|
||||||
resNode *node1, *node2;
|
resNode *node1, *node2;
|
||||||
resElement *rcell1;
|
resElement *rcell1;
|
||||||
int c1, c2;
|
int c1, c2, count = 0;
|
||||||
|
|
||||||
/* Sort resistors by size */
|
/* Method used to sort resistors by size depends on list length */
|
||||||
current = *reslist;
|
for (current = *reslist; current; current = current->rr_nextResistor)
|
||||||
while (current != NULL)
|
|
||||||
{
|
{
|
||||||
working = current;
|
count++;
|
||||||
current = current->rr_nextResistor;
|
if (count >= 10) break;
|
||||||
if (working == *reslist)
|
}
|
||||||
*reslist = current;
|
|
||||||
else
|
/* Sort resistors by size */
|
||||||
working->rr_lastResistor->rr_nextResistor = current;
|
|
||||||
|
|
||||||
if (current != NULL)
|
if (count >= 10)
|
||||||
current->rr_lastResistor = working->rr_lastResistor;
|
{
|
||||||
|
int i;
|
||||||
|
resResistor **resSortList;
|
||||||
|
|
||||||
ResAddResistorToList(working, &locallist);
|
/* For long lists, sort using qsort() */
|
||||||
|
/* NOTE: It might be better to use the same merge sort used for
|
||||||
|
* MergeSortBreaks() in ResMakeRes.c, as it does not incur the
|
||||||
|
* overhead of allocating memory and populating the array.
|
||||||
|
*/
|
||||||
|
count = 0;
|
||||||
|
for (current = *reslist; current; current = current->rr_nextResistor)
|
||||||
|
count++;
|
||||||
|
|
||||||
|
resSortList = (resResistor **)mallocMagic(count * sizeof(resResistor *));
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
for (current = *reslist; current; current = current->rr_nextResistor)
|
||||||
|
{
|
||||||
|
resSortList[count] = current;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sort the list */
|
||||||
|
|
||||||
|
qsort(resSortList, count, sizeof(resResistor *), qrescompare);
|
||||||
|
|
||||||
|
/* Regenerate links on sorted list */
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
current = resSortList[i];
|
||||||
|
current->rr_nextResistor = (i == count - 1) ? NULL : resSortList[i + 1];
|
||||||
|
current->rr_lastResistor = (i == 0) ? NULL : resSortList[i - 1];
|
||||||
|
}
|
||||||
|
*reslist = resSortList[0];
|
||||||
|
|
||||||
|
freeMagic(resSortList);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Original method: Walk the linked list and re-sort by size. */
|
||||||
|
|
||||||
|
resResistor *locallist = NULL;
|
||||||
|
|
||||||
|
current = *reslist;
|
||||||
|
while (current != NULL)
|
||||||
|
{
|
||||||
|
working = current;
|
||||||
|
current = current->rr_nextResistor;
|
||||||
|
if (working == *reslist)
|
||||||
|
*reslist = current;
|
||||||
|
else
|
||||||
|
working->rr_lastResistor->rr_nextResistor = current;
|
||||||
|
|
||||||
|
if (current != NULL)
|
||||||
|
current->rr_lastResistor = working->rr_lastResistor;
|
||||||
|
|
||||||
|
ResAddResistorToList(working, &locallist);
|
||||||
|
}
|
||||||
|
*reslist = locallist;
|
||||||
}
|
}
|
||||||
|
|
||||||
*reslist = locallist;
|
|
||||||
while (*reslist != NULL && (*reslist)->rr_value < tolerance)
|
while (*reslist != NULL && (*reslist)->rr_value < tolerance)
|
||||||
{
|
{
|
||||||
current = *reslist;
|
current = *reslist;
|
||||||
|
|
@ -501,8 +578,8 @@ ResScrunchNet(reslist, pendingList, biglist, tolerance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* If the current resistor isn't a deadend, add its value and
|
* If the current resistor isn't a dead end, add its value and
|
||||||
* area to that of the next smallest one. If it is a deadend,
|
* area to that of the next smallest one. If it is a dead end,
|
||||||
* simply add its area to its node.
|
* simply add its area to its node.
|
||||||
*/
|
*/
|
||||||
if (c1 != 0 && c2 != 0)
|
if (c1 != 0 && c2 != 0)
|
||||||
|
|
@ -567,7 +644,7 @@ ResAddResistorToList(resistor, locallist)
|
||||||
resResistor *resistor, **locallist;
|
resResistor *resistor, **locallist;
|
||||||
|
|
||||||
{
|
{
|
||||||
resResistor *local,*last=NULL;
|
resResistor *local, *last = NULL;
|
||||||
|
|
||||||
for (local = *locallist; local != NULL; local = local->rr_nextResistor)
|
for (local = *locallist; local != NULL; local = local->rr_nextResistor)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,8 @@ ResAddPlumbing(tile, dinfo, arg)
|
||||||
|
|
||||||
resDev = (resDevice *)mallocMagic((unsigned)(sizeof(resDevice)));
|
resDev = (resDevice *)mallocMagic((unsigned)(sizeof(resDevice)));
|
||||||
resDev->rd_nterms = nterms;
|
resDev->rd_nterms = nterms;
|
||||||
resDev->rd_terminals = (resNode **) mallocMagic(nterms * sizeof(resNode *));
|
|
||||||
|
resDev->rd_terminals = (resNode **)mallocMagic(nterms * sizeof(resNode *));
|
||||||
for (i = 0; i != nterms; i++)
|
for (i = 0; i != nterms; i++)
|
||||||
resDev->rd_terminals[i] = (resNode *) NULL;
|
resDev->rd_terminals[i] = (resNode *) NULL;
|
||||||
|
|
||||||
|
|
@ -733,6 +734,7 @@ ResPreProcessDevices(TileList, DeviceList, Def)
|
||||||
|
|
||||||
tile = PlaneGetHint(Def->cd_planes[pNum]);
|
tile = PlaneGetHint(Def->cd_planes[pNum]);
|
||||||
GOTOPOINT(tile, &(TileList->area.r_ll));
|
GOTOPOINT(tile, &(TileList->area.r_ll));
|
||||||
|
PlaneSetHint(Def->cd_planes[pNum], tile);
|
||||||
|
|
||||||
tt = TiGetType(tile);
|
tt = TiGetType(tile);
|
||||||
tstruct = (resInfo *) TiGetClientPTR(tile);
|
tstruct = (resInfo *) TiGetClientPTR(tile);
|
||||||
|
|
|
||||||
|
|
@ -51,16 +51,24 @@ typedef struct resistor
|
||||||
#define rr_connection1 rr_node[0]
|
#define rr_connection1 rr_node[0]
|
||||||
#define rr_connection2 rr_node[1]
|
#define rr_connection2 rr_node[1]
|
||||||
|
|
||||||
/* Definitions for old FET-style MOSFET devices */
|
/* Definitions for old FET-style MOSFET devices. Actual devices may have
|
||||||
|
* any number of terminals. "GATE" is the identifying type; "SUBS" is
|
||||||
|
* the substrate/well connection (if it exists), and the other terminals
|
||||||
|
* make up the remaining entries. Memory will be allocated for the
|
||||||
|
* substrate whether or not one is defined for the device. If the device
|
||||||
|
* does not define a substrate connection, then this entry will remain
|
||||||
|
* NULL.
|
||||||
|
*/
|
||||||
|
|
||||||
#define RT_GATE 0
|
#define RT_GATE 0
|
||||||
#define RT_SOURCE 1
|
#define RT_SUBS 1
|
||||||
#define RT_DRAIN 2
|
#define RT_SOURCE 2
|
||||||
#define RT_SUBS 3
|
#define RT_DRAIN 3
|
||||||
|
|
||||||
#define rd_fet_gate rd_terminals[RT_GATE]
|
#define rd_fet_gate rd_terminals[RT_GATE]
|
||||||
|
#define rd_fet_subs rd_terminals[RT_SUBS]
|
||||||
#define rd_fet_source rd_terminals[RT_SOURCE]
|
#define rd_fet_source rd_terminals[RT_SOURCE]
|
||||||
#define rd_fet_drain rd_terminals[RT_DRAIN]
|
#define rd_fet_drain rd_terminals[RT_DRAIN]
|
||||||
#define rd_fet_subs rd_terminals[RT_SUBS]
|
|
||||||
|
|
||||||
typedef struct device
|
typedef struct device
|
||||||
{
|
{
|
||||||
|
|
@ -543,7 +551,7 @@ extern void ResCheckExtNodes();
|
||||||
extern void ResSortByGate();
|
extern void ResSortByGate();
|
||||||
extern void ResFixDevName();
|
extern void ResFixDevName();
|
||||||
extern void ResWriteLumpFile();
|
extern void ResWriteLumpFile();
|
||||||
extern void ResSortBreaks();
|
extern int ResSortBreaks();
|
||||||
extern Plane *extResPrepSubstrate();
|
extern Plane *extResPrepSubstrate();
|
||||||
|
|
||||||
/* C99 compat */
|
/* C99 compat */
|
||||||
|
|
|
||||||
|
|
@ -471,12 +471,11 @@ SelectArea(scx, types, xMask, globmatch)
|
||||||
if (TTMaskHasType(types, L_LABEL))
|
if (TTMaskHasType(types, L_LABEL))
|
||||||
{
|
{
|
||||||
if (globmatch != NULL)
|
if (globmatch != NULL)
|
||||||
DBCellCopyGlobLabels(scx, &DBAllTypeBits, xMask, SelectUse, &labelArea,
|
DBCellCopyGlobLabels(scx, types, xMask, SelectUse, &labelArea,
|
||||||
globmatch);
|
globmatch);
|
||||||
else
|
else
|
||||||
DBCellCopyAllLabels(scx, &DBAllTypeBits, xMask, SelectUse, &labelArea);
|
DBCellCopyAllLabels(scx, types, xMask, SelectUse, &labelArea);
|
||||||
}
|
}
|
||||||
else (void) DBCellCopyAllLabels(scx, types, xMask, SelectUse, &labelArea);
|
|
||||||
|
|
||||||
/* Select cell uses. */
|
/* Select cell uses. */
|
||||||
|
|
||||||
|
|
@ -835,6 +834,8 @@ chunkdone:
|
||||||
if (DBIsContact(type))
|
if (DBIsContact(type))
|
||||||
TTMaskSetOnlyType(&typeMask, type);
|
TTMaskSetOnlyType(&typeMask, type);
|
||||||
|
|
||||||
|
/* Allow labels to be selected as part of the chunk */
|
||||||
|
TTMaskSetType(&typeMask, L_LABEL);
|
||||||
SelectArea(&newscx, &typeMask, xMask, NULL);
|
SelectArea(&newscx, &typeMask, xMask, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ SimConnectFunc(
|
||||||
TileType loctype, ctype;
|
TileType loctype, ctype;
|
||||||
TileType newdinfo = 0;
|
TileType newdinfo = 0;
|
||||||
int i, pNum;
|
int i, pNum;
|
||||||
static char nodeName[256];
|
static char nodeName[MAXPATHNAME];
|
||||||
CellDef *def;
|
CellDef *def;
|
||||||
TerminalPath *tpath = cx->tc_filter->tf_tpath;
|
TerminalPath *tpath = cx->tc_filter->tf_tpath;
|
||||||
|
|
||||||
|
|
@ -133,7 +133,8 @@ SimConnectFunc(
|
||||||
char c = *n;
|
char c = *n;
|
||||||
|
|
||||||
SigDisableInterrupts();
|
SigDisableInterrupts();
|
||||||
strcpy(nodeName, SimGetNodeName(cx->tc_scx, tile, dinfo, tpath->tp_first));
|
strncpy(nodeName, SimGetNodeName(cx->tc_scx, tile, dinfo, tpath->tp_first),
|
||||||
|
MAXPATHNAME);
|
||||||
SigEnableInterrupts();
|
SigEnableInterrupts();
|
||||||
|
|
||||||
*n = c;
|
*n = c;
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,10 @@ proc magic::libcallback {command} {
|
||||||
|
|
||||||
switch $command {
|
switch $command {
|
||||||
load {$winname load $celldef}
|
load {$winname load $celldef}
|
||||||
place {$winname getcell $celldef}
|
place {$winname getcell $celldef child 0 0}
|
||||||
pick {
|
pick {
|
||||||
magic::tool pick
|
magic::tool pick
|
||||||
$winname getcell $celldef
|
$winname getcell $celldef child 0 0
|
||||||
magic::startselect $winname pick
|
magic::startselect $winname pick
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
%%BeginProlog
|
|
||||||
%
|
|
||||||
% PostScript prolog for output from magic plot
|
|
||||||
% Version: 1.0
|
|
||||||
% written by Tim Edwards 4/05/00 JHU Applied Physics Laboratory
|
|
||||||
%
|
|
||||||
%%BeginResource: procset MAGICproc 1.0 1
|
|
||||||
% supporting definitions
|
|
||||||
|
|
||||||
/MAGICsave save def
|
|
||||||
|
|
||||||
/bop { 1 setlinecap 0 setlinejoin 6 setmiterlimit 0 setgray } def
|
|
||||||
/ninit { /nChars matrix currentmatrix dup 0 get 0 eq {1} {0}
|
|
||||||
ifelse get abs 72 8.5 mul mul 64 div ceiling cvi def } def
|
|
||||||
/minit { 1 1 dtransform abs dup 1 exch div /onePix exch def
|
|
||||||
dup /resY exch def 1 exch div /iresY exch def
|
|
||||||
abs dup /resX exch def 1 exch div /iresX exch def
|
|
||||||
/bX 64 iresX mul def /bY 64 iresY mul def
|
|
||||||
/pattFont StipplePattern definefont pop
|
|
||||||
/patterns /pattFont findfont [iresX 64 mul 0 0 iresY 64 mul 0 0] makefont def
|
|
||||||
/ca nChars 1 add string def
|
|
||||||
} def
|
|
||||||
/StipplePattern 45 dict def
|
|
||||||
StipplePattern begin
|
|
||||||
/FontType 3 def
|
|
||||||
/FontMatrix [1 0 0 1 0 0] def
|
|
||||||
/FontBBox [0 0 1 1] def
|
|
||||||
/Encoding 256 array def
|
|
||||||
/PattName (P0) def
|
|
||||||
/tmpStr 1 string def
|
|
||||||
/NoPatt {<00>} def
|
|
||||||
0 1 255 { Encoding exch /NoPatt put } for
|
|
||||||
/BuildChar {
|
|
||||||
1 0 0 0 1 1 setcachedevice exch begin Encoding exch get load
|
|
||||||
64 64 true [64 0 0 64 0 0] 5 -1 roll imagemask end } def
|
|
||||||
end
|
|
||||||
/dp { StipplePattern begin dup 30 tmpStr cvrs PattName exch 1 exch
|
|
||||||
putinterval PattName cvn dup Encoding exch 4 -1 roll exch put exch
|
|
||||||
store end } def
|
|
||||||
/sf { findfont exch scalefont setfont } bind def
|
|
||||||
/sp { patterns setfont 2 setlinewidth } def
|
|
||||||
/lb { gsave translate 0 0 moveto /just exch def gsave dup true charpath
|
|
||||||
flattenpath pathbbox grestore exch 4 -1 roll exch sub 3 1 roll sub
|
|
||||||
just 4 and 0 gt {just 8 and 0 eq {0.5 mul} if}{pop 0} ifelse exch
|
|
||||||
just 1 and 0 gt {just 2 and 0 eq {0.5 mul} if}{pop 0} ifelse exch
|
|
||||||
rmoveto show grestore } def
|
|
||||||
/sl { 0 1 nChars { exch dup 3 1 roll ca 3 1 roll put } for pop } def
|
|
||||||
/sc { setcmykcolor } bind def
|
|
||||||
/l1 { onePix setlinewidth } def
|
|
||||||
/l2 { onePix 2 mul setlinewidth } def
|
|
||||||
/l3 { onePix 3 mul setlinewidth } def
|
|
||||||
/ml { moveto lineto stroke } bind def
|
|
||||||
/vl { moveto 0 exch rlineto stroke } bind def
|
|
||||||
/hl { moveto 0 rlineto stroke } bind def
|
|
||||||
/mr { rectstroke } bind def
|
|
||||||
/mx { 4 copy rectstroke 4 -1 roll 4 -1 roll 4 copy moveto rlineto stroke
|
|
||||||
3 -1 roll dup neg 4 1 roll add moveto rlineto stroke } bind def
|
|
||||||
/pl { gsave translate /d exch def 0 d neg moveto 0 d lineto stroke
|
|
||||||
d neg 0 moveto d 0 lineto stroke grestore } bind def
|
|
||||||
/bx { x resX mul cvi 63 not and dup iresX mul exch
|
|
||||||
w resX mul sub abs 63 add cvi 64 idiv /w exch def
|
|
||||||
y resY mul cvi 63 not and dup iresY mul exch
|
|
||||||
h resY mul sub abs 63 add cvi 64 idiv /h exch def
|
|
||||||
/ch ca 0 w getinterval def
|
|
||||||
moveto h { ch gsave show grestore 0 bY rmoveto } repeat grestore } def
|
|
||||||
/fb {/h exch def /w exch def /y exch def /x exch def gsave newpath
|
|
||||||
x y moveto w y lineto w h lineto x h lineto closepath clip bx } def
|
|
||||||
/tb {1 sub 3 1 roll gsave newpath moveto {lineto} repeat closepath clip pathbbox
|
|
||||||
/h exch def /w exch def /y exch def /x exch def bx } def
|
|
||||||
|
|
||||||
|
|
@ -249,6 +249,9 @@ proc ::tkcon::Init {} {
|
||||||
if {![info exists PRIV(histfile)]} {
|
if {![info exists PRIV(histfile)]} {
|
||||||
set PRIV(histfile) [file join $env($envHome) $histfile]
|
set PRIV(histfile) [file join $env($envHome) $histfile]
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
set PRIV(rcfile) ""
|
||||||
|
set PRIV(histfile) ""
|
||||||
}
|
}
|
||||||
|
|
||||||
## Handle command line arguments before sourcing resource file to
|
## Handle command line arguments before sourcing resource file to
|
||||||
|
|
|
||||||
|
|
@ -651,9 +651,9 @@ proc magic::startselect {window {option {}}} {
|
||||||
select nocycle
|
select nocycle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set Opts(origin) [cursor]
|
set Opts(origin) [cursor internal]
|
||||||
set Opts(motion) [bind ${window} <Motion>]
|
set Opts(motion) [bind ${window} <Motion>]
|
||||||
bind ${window} <Motion> [subst {$Opts(motion); set p \[cursor\]; \
|
bind ${window} <Motion> [subst {$Opts(motion); set p \[cursor internal\]; \
|
||||||
set x \[expr {\[lindex \$p 0\] - [lindex $Opts(origin) 0]}\]i; \
|
set x \[expr {\[lindex \$p 0\] - [lindex $Opts(origin) 0]}\]i; \
|
||||||
set y \[expr {\[lindex \$p 1\] - [lindex $Opts(origin) 1]}\]i; \
|
set y \[expr {\[lindex \$p 1\] - [lindex $Opts(origin) 1]}\]i; \
|
||||||
*bypass select move \${x} \${y}}]
|
*bypass select move \${x} \${y}}]
|
||||||
|
|
|
||||||
32
utils/args.c
32
utils/args.c
|
|
@ -21,6 +21,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
||||||
#endif /* not lint */
|
#endif /* not lint */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/utils.h"
|
#include "utils/utils.h"
|
||||||
|
|
@ -34,12 +35,13 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
||||||
* ArgStr --
|
* ArgStr --
|
||||||
*
|
*
|
||||||
* Process a single argument that is supposed to have a string value.
|
* Process a single argument that is supposed to have a string value.
|
||||||
* A string argument can appear in two ways:
|
* A string argument can appear in three ways:
|
||||||
*
|
*
|
||||||
* -avalue (a single element of argv)
|
* -avalue (a single element of argv)
|
||||||
* -a value (two elements of argv)
|
* -a value (two elements of argv)
|
||||||
|
* "-a value" (a single element of argv, space-separated)
|
||||||
*
|
*
|
||||||
* Both are recognized.
|
* All three forms are recognized.
|
||||||
*
|
*
|
||||||
* Results:
|
* Results:
|
||||||
* Returns a pointer to the value, or NULL if there wasn't one.
|
* Returns a pointer to the value, or NULL if there wasn't one.
|
||||||
|
|
@ -56,15 +58,29 @@ char *
|
||||||
ArgStr(
|
ArgStr(
|
||||||
int *pargc,
|
int *pargc,
|
||||||
char ***pargv,
|
char ***pargv,
|
||||||
const char *argType)/* For error messages: what the following string is
|
const char *argType) /* For error messages: what the following
|
||||||
* supposed to be interpreted as.
|
* string is supposed to be interpreted as.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
char **argv = *pargv;
|
char **argv = *pargv;
|
||||||
char *result;
|
char *result;
|
||||||
|
char *argptr;
|
||||||
|
|
||||||
if (argv[0][2])
|
argptr = argv[0];
|
||||||
return (&argv[0][2]);
|
argptr++;
|
||||||
|
if (*argptr == '\0')
|
||||||
|
{
|
||||||
|
TxError("Bad argument %s\n", argv[0]);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
argptr++;
|
||||||
|
if (*argptr != '\0')
|
||||||
|
{
|
||||||
|
while (isspace(*argptr) && (*argptr != '\0'))
|
||||||
|
argptr++;
|
||||||
|
|
||||||
|
return argptr;
|
||||||
|
}
|
||||||
|
|
||||||
if ((*pargc)-- > 0)
|
if ((*pargc)-- > 0)
|
||||||
{
|
{
|
||||||
|
|
@ -74,5 +90,5 @@ ArgStr(
|
||||||
}
|
}
|
||||||
|
|
||||||
TxError("-%c requires a following %s\n", argv[0][1], argType);
|
TxError("-%c requires a following %s\n", argv[0][1], argType);
|
||||||
return (NULL);
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -988,7 +988,8 @@ mainInitFinal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getcwd(cwd, 512) == NULL || strcmp(cwd, home) || (RCFileName[0] == '/'))
|
if (getcwd(cwd, 512) == NULL || ((home != NULL) && (strcmp(cwd, home)))
|
||||||
|
|| (RCFileName[0] == '/'))
|
||||||
{
|
{
|
||||||
/* Read in the .magicrc file from the current directory, if */
|
/* Read in the .magicrc file from the current directory, if */
|
||||||
/* different from HOME. */
|
/* different from HOME. */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue