Compare commits

..

No commits in common. "master" and "8.3.640" have entirely different histories.

109 changed files with 1629 additions and 5504 deletions

View File

@ -1,12 +1,14 @@
# CI for native ARM64 Linux build. # This is a basic workflow to help you get started with Actions
name: CI-aarch64 name: CI-aarch64
# Controls when the workflow will run
on: on:
push: push:
pull_request: pull_request:
workflow_dispatch: workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs: jobs:
simple_build_linux_arm: simple_build_linux_arm:
runs-on: ubuntu-24.04-arm runs-on: ubuntu-24.04-arm
@ -21,3 +23,39 @@ jobs:
./configure ./configure
make database/database.h make database/database.h
make -j$(nproc) make -j$(nproc)
simple_build_wasm_arm:
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
- name: Get Dependencies
run: |
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
- name: Emscripten Diagnostic
run: |
source ./emsdk/emsdk_env.sh
echo "===== gcc -dM -E - ====="
echo | gcc -dM -E - | sort
echo "===== g++ -dM -E - ====="
echo | g++ -dM -E - | sort
echo "===== emcc -dM -E - ====="
echo | emcc -dM -E - | sort
echo "===== em++ -dM -E - ====="
echo | em++ -dM -E - | sort
- name: Build
run: |
source ./emsdk/emsdk_env.sh
# The --without and --disable in these build options is due to no WASM library being available for that feature
CFLAGS="--std=c17 -D_DEFAULT_SOURCE=1 -DEMSCRIPTEN=1 -g" emconfigure ./configure --without-cairo --without-opengl --without-x --without-tk --without-tcl --disable-readline --disable-compression --target=asmjs-unknown-emscripten
echo "===== defs.mak ====="
cat defs.mak
echo "===== defs.mak ====="
emmake make
- name: archive wasm bundle
uses: actions/upload-artifact@v4
with:
name: magic-wasm-bundle-arm
path: |
${{ github.workspace }}/magic/magic.wasm

View File

@ -1,160 +0,0 @@
name: CI-wasm
# Builds the Magic WebAssembly target on every push and pull request.
# When the VERSION file changes on the default branch, the package is
# additionally published to GitHub Packages (npm.pkg.github.com) as
# @<owner>/magic-vlsi-wasm — no manual tag or token required.
# Tim Edwards updates VERSION to trigger a new release; the scope resolves
# automatically to the repo owner, so forks publish under their own namespace.
#
# WASM is architecture-independent — built once on x86-64, usable everywhere.
on:
push:
pull_request:
workflow_dispatch:
inputs:
emsdk_version:
description: 'emsdk version to build with (default: latest; pin a version number to bisect)'
type: string
default: 'latest'
dry_run:
description: 'Dry run: pack only, do not publish even on tag pushes'
type: boolean
default: true
# actions/upload-artifact@v5 still runs on Node.js 20. Force Node 24 to
# silence the deprecation warning until upload-artifact ships a Node-24
# release. Drop this once upgraded.
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
permissions:
contents: read
packages: write
jobs:
build-wasm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 2
- name: Set up Node.js
uses: actions/setup-node@v5
with:
node-version: '22'
registry-url: 'https://npm.pkg.github.com'
- name: Install emsdk
env:
# Defaults to latest so CI tracks emsdk HEAD and catches breakage early.
# Override via workflow_dispatch to pin a specific version when needed
# (e.g. to bisect a regression or verify a post-build.sh patch still applies).
EMSDK_VERSION: ${{ github.event.inputs.emsdk_version || 'latest' }}
run: |
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install "$EMSDK_VERSION"
./emsdk activate "$EMSDK_VERSION"
# Dump native + emscripten preprocessor defines. Useful for diagnosing
# WASM-build differences after an emsdk bump.
- name: Emscripten Diagnostic
run: |
source ./emsdk/emsdk_env.sh
echo "===== gcc -dM -E - ====="; echo | gcc -dM -E - | sort
echo "===== g++ -dM -E - ====="; echo | g++ -dM -E - | sort
echo "===== emcc -dM -E - ====="; echo | emcc -dM -E - | sort
echo "===== em++ -dM -E - ====="; echo | em++ -dM -E - | sort
- name: Build WASM
run: |
source ./emsdk/emsdk_env.sh
# --without/--disable flags: no WASM library available for these features
CFLAGS="--std=c17 -D_DEFAULT_SOURCE=1 -DEMSCRIPTEN=1" emconfigure ./configure \
--without-cairo --without-opengl --without-x --without-tk --without-tcl \
--disable-readline --disable-compression \
--host=asmjs-unknown-emscripten \
--target=asmjs-unknown-emscripten
# Append WASM linker flags and activate the WASM link target
cat toolchains/emscripten/defs.mak >> defs.mak
# Echo the merged defs.mak so CI logs show the exact build config
echo "===== defs.mak ====="; cat defs.mak; echo "===== defs.mak ====="
# Build in order: techs must exist before mains (--embed-file embeds them)
emmake make depend
emmake make -j$(nproc) modules libs
emmake make techs
emmake make mains
- name: Copy WASM artifacts into npm/
run: |
cp magic/magic.js npm/
cp magic/magic.wasm npm/
- name: Run example tests
run: cd npm && npm run test
# Dump generated text outputs (.ext, .spice, .cif, …) into the CI log
# so a regression in extraction / netlisting / cifoutput is visible
# without having to download artifacts. The .gds output is binary —
# skip it and just record its size.
- name: Display example outputs
run: |
shopt -s nullglob
for f in npm/examples/output/*; do
name=$(basename "$f")
case "$f" in
*.gds) echo "===== $name (binary, $(wc -c < "$f") bytes — skipped) =====" ;;
*) echo "===== $name ====="; cat "$f" ;;
esac
done
- name: Set package version and scope
run: |
base=$(cat VERSION) # e.g. 8.3.637
date=$(git show -s --format=%cs | tr -d '-') # e.g. 20260414
hash=$(git show -s --format=%h) # e.g. d157eea
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
npm pkg set name="$SCOPED_NAME"
npm pkg set publishConfig.registry="https://npm.pkg.github.com"
npm version "$VERSION" --no-git-tag-version
- name: Pack
run: ./npm/pack.sh
- name: Upload tarball as artifact
uses: actions/upload-artifact@v5
with:
name: magic-vlsi-wasm-npm
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
if: steps.version_changed.outputs.changed == 'true' && github.event.inputs.dry_run != 'true'
run: cd npm && npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,21 +1,60 @@
# This is a basic workflow to help you get started with Actions
name: CI name: CI
# Controls when the workflow will run
on: on:
push: push:
pull_request: pull_request:
workflow_dispatch: workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs: jobs:
simple_build_linux: simple_build_linux:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v5 - 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: |
./configure ./configure
make database/database.h make database/database.h
make -j$(nproc) make -j$(nproc)
simple_build_wasm:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Get Dependencies
run: |
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
- name: Emscripten Diagnostic
run: |
source ./emsdk/emsdk_env.sh
echo "===== gcc -dM -E - ====="
echo | gcc -dM -E - | sort
echo "===== g++ -dM -E - ====="
echo | g++ -dM -E - | sort
echo "===== emcc -dM -E - ====="
echo | emcc -dM -E - | sort
echo "===== em++ -dM -E - ====="
echo | em++ -dM -E - | sort
- name: Build
run: |
source ./emsdk/emsdk_env.sh
# The --without and --disable in these build options is due to no WASM library being available for that feature
CFLAGS="--std=c17 -D_DEFAULT_SOURCE=1 -DEMSCRIPTEN=1 -g" emconfigure ./configure --without-cairo --without-opengl --without-x --without-tk --without-tcl --disable-readline --disable-compression --target=asmjs-unknown-emscripten
echo "===== defs.mak ====="
cat defs.mak
echo "===== defs.mak ====="
emmake make
- name: archive wasm bundle
uses: actions/upload-artifact@v4
with:
name: magic-wasm-bundle
path: |
${{ github.workspace }}/magic/magic.wasm

46
.gitignore vendored
View File

@ -1,33 +1,19 @@
# Autoconf / configure outputs
defs.mak defs.mak
!toolchains/emscripten/defs.mak */Depend
config.cache config.cache
config.log config.log
scripts/config.log scripts/config.log
scripts/config.status scripts/config.status
scripts/defs.mak scripts/defs.mak
install.log
make.log
reconfigure.sh
# Compiled objects / libraries
*.o
*.a
*.so
*/Depend
database/database.h
# Editor / OS cruft
.*.swp .*.swp
.*.swo *.o
*.so
*~ *~
.DS_Store
.vscode/
.idea/
# Magic runtime-generated files
magic/proto.magicrc
scmos/cif_template/objs/* scmos/cif_template/objs/*
database/database.h
install.log
magic/proto.magicrc
make.log
scmos/gdsquery.tech scmos/gdsquery.tech
scmos/minimum.tech scmos/minimum.tech
scmos/scmos-sub.tech scmos/scmos-sub.tech
@ -35,28 +21,14 @@ scmos/scmos-tm.tech
scmos/scmos.tech scmos/scmos.tech
scmos/scmosWR.tech scmos/scmosWR.tech
scmos/nmos.tech scmos/nmos.tech
# Native build artifacts
magic/magic
magic/tclmagic.dylib
tcltk/magic.sh tcltk/magic.sh
tcltk/magic.tcl tcltk/magic.tcl
tcltk/magicdnull tcltk/magicdnull
tcltk/magicexec tcltk/magicexec
tcltk/ext2spice.sh tcltk/ext2spice.sh
tcltk/ext2sim.sh tcltk/ext2sim.sh
magic/tclmagic.dylib
tcltk/magicdnull.dSYM/ tcltk/magicdnull.dSYM/
tcltk/magicexec.dSYM/ tcltk/magicexec.dSYM/
reconfigure.sh
pfx/ pfx/
# WASM build artifacts
magic/magic.js
magic/magic.js.symbols
magic/magic.symbols
magic/magic.wasm
net2ir/net2ir
net2ir/net2ir.js
net2ir/net2ir.wasm
# Generated test output
npm/examples/output/

View File

@ -1 +1 @@
8.3.658 8.3.640

View File

@ -112,7 +112,7 @@ bool CalmaUnique = FALSE; /* If TRUE, then if a cell exists in
extern bool CalmaDoLibrary; /* Also used by GDS write */ extern bool CalmaDoLibrary; /* Also used by GDS write */
extern void calmaUnexpected(int wanted, int got); extern void calmaUnexpected(int wanted, int got);
extern int calmaWriteInitFunc(CellDef *def, ClientData cdata); /* UNUSED */ extern int calmaWriteInitFunc(CellDef *def);
/* /*
* Scaling. * Scaling.

View File

@ -96,7 +96,7 @@ typedef struct {
} calmaOutputStruct; } calmaOutputStruct;
/* Forward declarations */ /* Forward declarations */
extern int calmaWriteInitFunc(CellDef *def, ClientData cdata); /* UNUSED */ extern int calmaWriteInitFunc(CellDef *def);
extern int calmaWritePaintFunc(Tile *tile, TileType dinfo, calmaOutputStruct *cos); extern int calmaWritePaintFunc(Tile *tile, TileType dinfo, calmaOutputStruct *cos);
extern int calmaMergePaintFunc(Tile *tile, TileType dinfo, calmaOutputStruct *cos); extern int calmaMergePaintFunc(Tile *tile, TileType dinfo, calmaOutputStruct *cos);
extern int calmaWriteUseFunc(CellUse *use, FILE *f); extern int calmaWriteUseFunc(CellUse *use, FILE *f);
@ -822,11 +822,9 @@ done:
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/*ARGSUSED*/
int int
calmaWriteInitFunc( calmaWriteInitFunc(
CellDef *def, CellDef *def)
ClientData cdata) /* UNUSED */
{ {
def->cd_client = (ClientData) 0; def->cd_client = (ClientData) 0;
return (0); return (0);

View File

@ -96,7 +96,7 @@ extern int calmaPaintLayerNumber;
extern int calmaPaintLayerType; extern int calmaPaintLayerType;
/* External functions from CalmaWrite.c */ /* External functions from CalmaWrite.c */
extern int calmaWriteInitFunc(CellDef *def, ClientData cdata); /* UNUSED */ extern int calmaWriteInitFunc(CellDef *def);
/* Structure used by calmaWritePaintFuncZ() and others */ /* Structure used by calmaWritePaintFuncZ() and others */

View File

@ -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 operators CIFOP_INTERACT and CIFOP_TAGGED. * only for operator CIFOP_INTERACT.
* *
* Results: * Results:
* Returns the value returned by the function. * Returns the value returned by the function.
@ -4171,21 +4171,12 @@ cifSrTiles2(
} }
cifScale = 1; cifScale = 1;
if (TTMaskIsZero(&cifOp->co_cifMask) && TTMaskIsZero(&cifOp->co_paintMask)) for (t = 0; t < TT_MAXTYPES; t++, temps++)
{ if (TTMaskHasType(&cifOp->co_cifMask, t))
/* Current CIF plane is in *temps */ if (DBSrPaintArea((Tile *)NULL, *temps, area,
if (DBSrPaintArea((Tile *)NULL, *temps, area,
&CIFSolidBits, func, (ClientData)cdArg)) &CIFSolidBits, func, (ClientData)cdArg))
return 1; return 1;
}
else
{
for (t = 0; t < TT_MAXTYPES; t++, temps++)
if (TTMaskHasType(&cifOp->co_cifMask, t))
if (DBSrPaintArea((Tile *)NULL, *temps, area,
&CIFSolidBits, func, (ClientData)cdArg))
return 1;
}
return 0; return 0;
} }
@ -5463,6 +5454,7 @@ CIFGenLayer(
if (bloats->bl_plane < 0) /* Bloat types are CIF types */ if (bloats->bl_plane < 0) /* Bloat types are CIF types */
{ {
bls.temps = temps;
for (ttype = 0; ttype < TT_MAXTYPES; ttype++, bls.temps++) for (ttype = 0; ttype < TT_MAXTYPES; ttype++, bls.temps++)
if (bloats->bl_distance[ttype] > 0) if (bloats->bl_distance[ttype] > 0)
(void) DBSrPaintArea((Tile *)NULL, *bls.temps, &TiPlaneRect, (void) DBSrPaintArea((Tile *)NULL, *bls.temps, &TiPlaneRect,
@ -5668,20 +5660,6 @@ CIFGenLayer(
bloats->bl_distance[ttype] = 0; bloats->bl_distance[ttype] = 0;
} }
} }
else
{
/* Operate on the existing plane. */
bloats->bl_distance[0] = 1;
for (ttype = 1; ttype < TT_MAXTYPES; ttype++)
bloats->bl_distance[ttype] = 0;
bloats->bl_plane = -1;
bls.temps = &curPlane;
DBClearPaintPlane(nextPlane);
cifPlane = nextPlane;
}
/* Replace the client data with the bloat record */ /* Replace the client data with the bloat record */
op->co_client = (ClientData)bloats; op->co_client = (ClientData)bloats;
@ -5702,33 +5680,15 @@ 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,
Rect labr = label->lab_rect;
/* Since cifSrTiles2() searches over an area, the
* area must not be degenerate.
*/
if (labr.r_xbot == labr.r_xtop)
{
labr.r_xbot--;
labr.r_xtop++;
}
if (labr.r_ybot == labr.r_ytop)
{
labr.r_ybot--;
labr.r_ytop++;
}
cifSrTiles2(op, &labr, cellDef, bls.temps,
cifBloatAllFunc, (ClientData)&bls); cifBloatAllFunc, (ClientData)&bls);
}
}
/* Reset marked tiles */ /* Reset marked tiles */
if (bloats->bl_plane < 0) /* Bloat types are CIF types */ if (bloats->bl_plane < 0) /* Bloat types are CIF types */
{ {
bls.temps = temps;
for (ttype = 0; ttype < TT_MAXTYPES; ttype++, bls.temps++) for (ttype = 0; ttype < TT_MAXTYPES; ttype++, bls.temps++)
if (bloats->bl_distance[ttype] > 0) if (bloats->bl_distance[ttype] > 0)
(void) DBSrPaintArea((Tile *)NULL, *bls.temps, &TiPlaneRect, (void) DBSrPaintArea((Tile *)NULL, *bls.temps, &TiPlaneRect,
@ -5746,15 +5706,6 @@ CIFGenLayer(
/* Replace the client data */ /* Replace the client data */
op->co_client = (ClientData)text; op->co_client = (ClientData)text;
/* If operating on the current plane, swap the current
* and next planes.
*/
if (TTMaskIsZero(&op->co_cifMask) && TTMaskIsZero(&op->co_paintMask))
{
temp = curPlane;
curPlane = nextPlane;
nextPlane = temp;
}
break; break;
case CIFOP_BOUNDARY: case CIFOP_BOUNDARY:

View File

@ -284,7 +284,7 @@ cifFlatMaskHints(
oldproprec = (PropertyRecord *)DBPropGet(mhd->mh_def, name, &propfound); oldproprec = (PropertyRecord *)DBPropGet(mhd->mh_def, name, &propfound);
if (propfound) if (propfound)
{ {
ASSERT(oldproprec->prop_type == PROPERTY_TYPE_PLANE, ASSERT(oldproprec->prop_value.prop_type == PROPERTY_TYPE_PLANE,
"cifFlatMaskHints"); "cifFlatMaskHints");
plane = oldproprec->prop_value.prop_plane; plane = oldproprec->prop_value.prop_plane;
} }
@ -735,10 +735,8 @@ CIFGenSubcells(
/* This routine can take a long time, so use the display /* This routine can take a long time, so use the display
* timer to force a 5-second progress check (like is done * timer to force a 5-second progress check (like is done
* with extract). Save and restore GrDisplayStatus so that * with extract)
* a headless (DISPLAY_SUSPEND) build isn't left in DISPLAY_IDLE.
*/ */
unsigned char savedDisplayStatus = GrDisplayStatus;
GrDisplayStatus = DISPLAY_IN_PROGRESS; GrDisplayStatus = DISPLAY_IN_PROGRESS;
SigSetTimer(5); /* Print at 5-second intervals */ SigSetTimer(5); /* Print at 5-second intervals */
cuts = 0; cuts = 0;
@ -863,7 +861,7 @@ CIFGenSubcells(
CIFHierTileOps += CIFTileOps - oldTileOps; CIFHierTileOps += CIFTileOps - oldTileOps;
GrDisplayStatus = savedDisplayStatus; GrDisplayStatus = DISPLAY_IDLE;
SigRemoveTimer(); SigRemoveTimer();
UndoEnable(); UndoEnable();

View File

@ -1032,10 +1032,9 @@ CIFReadTechLine(
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]); newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
break; break;
case CIFOP_TAGGED: case CIFOP_TAGGED:
if ((argc != 2) && (argc != 3)) goto wrongNumArgs; if (argc != 3) goto wrongNumArgs;
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]); newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
if (argc == 3) CIFParseReadLayers(argv[2], &newOp->co_cifMask, TRUE);
CIFParseReadLayers(argv[2], &newOp->co_cifMask, TRUE);
break; break;
} }

View File

@ -1360,11 +1360,10 @@ bloatCheck:
case CIFOP_NET: case CIFOP_NET:
case CIFOP_TAGGED: case CIFOP_TAGGED:
if ((argc != 2) && (argc != 3)) goto wrongNumArgs; if (argc != 3) goto wrongNumArgs;
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]); newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
if (argc == 3) cifParseLayers(argv[2], CIFCurStyle, &newOp->co_paintMask,
cifParseLayers(argv[2], CIFCurStyle, &newOp->co_paintMask, &newOp->co_cifMask, FALSE);
&newOp->co_cifMask, FALSE);
break; break;
case CIFOP_MASKHINTS: case CIFOP_MASKHINTS:

View File

@ -44,7 +44,7 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
#include "textio/textio.h" #include "textio/textio.h"
/* Forward declarations */ /* Forward declarations */
extern int cifWriteInitFunc(CellDef *def, ClientData cdata); /* UNUSED */ extern int cifWriteInitFunc(CellDef *def);
extern int cifWriteMarkFunc(CellUse *use); extern int cifWriteMarkFunc(CellUse *use);
extern int cifWritePaintFunc(Tile *tile, TileType dinfo, FILE *f); extern int cifWritePaintFunc(Tile *tile, TileType dinfo, FILE *f);
extern int cifWriteLabelFunc(Tile *tile, TileType dinfo, FILE *f); extern int cifWriteLabelFunc(Tile *tile, TileType dinfo, FILE *f);
@ -204,11 +204,9 @@ CIFWrite(
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/*ARGSUSED*/
int int
cifWriteInitFunc( cifWriteInitFunc(
CellDef *def, CellDef *def)
ClientData cdata) /* UNUSED */
{ {
def->cd_client = (ClientData) 0; def->cd_client = (ClientData) 0;
return (0); return (0);

View File

@ -217,11 +217,10 @@ CMWdelete(
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/*ARGSUSED*/
void void
CMWreposition( CMWreposition(
MagWindow *window, MagWindow *window,
Rect *newScreenArea, /* UNUSED */ Rect *newScreenArea,
bool final) bool final)
{ {
if (final) if (final)

View File

@ -905,7 +905,7 @@ CmdExpand(
case EXPAND_SELECTION: case EXPAND_SELECTION:
SelectExpand(windowMask, SelectExpand(windowMask,
(doToggle) ? DB_EXPAND_TOGGLE : DB_EXPAND, (doToggle) ? DB_EXPAND_TOGGLE : DB_EXPAND,
(Rect *)NULL); (Rect *)NULL, FALSE);
break; break;
case EXPAND_OVERLAP: case EXPAND_OVERLAP:
if (doToggle) if (doToggle)
@ -914,8 +914,8 @@ CmdExpand(
DB_EXPAND_TOGGLE | DB_EXPAND_OVERLAP, DB_EXPAND_TOGGLE | DB_EXPAND_OVERLAP,
cmdExpandFunc, (ClientData)(pointertype)windowMask); cmdExpandFunc, (ClientData)(pointertype)windowMask);
SelectExpand(windowMask, SelectExpand(windowMask,
DB_EXPAND_TOGGLE | DB_EXPAND_OVERLAP, DB_EXPAND_TOGGLE | DB_EXPAND_OVERLAP,
&rootRect); &rootRect, FALSE);
} }
else else
{ {
@ -923,8 +923,8 @@ CmdExpand(
DB_EXPAND | DB_EXPAND_OVERLAP, DB_EXPAND | DB_EXPAND_OVERLAP,
cmdExpandFunc, (ClientData)(pointertype)windowMask); cmdExpandFunc, (ClientData)(pointertype)windowMask);
SelectExpand(windowMask, SelectExpand(windowMask,
DB_EXPAND | DB_EXPAND_OVERLAP, DB_EXPAND | DB_EXPAND_OVERLAP,
&rootRect); &rootRect, FALSE);
} }
break; break;
case EXPAND_SURROUND: case EXPAND_SURROUND:
@ -934,8 +934,8 @@ CmdExpand(
DB_EXPAND_TOGGLE | DB_EXPAND_SURROUND, DB_EXPAND_TOGGLE | DB_EXPAND_SURROUND,
cmdExpandFunc, (ClientData)(pointertype)windowMask); cmdExpandFunc, (ClientData)(pointertype)windowMask);
SelectExpand(windowMask, SelectExpand(windowMask,
DB_EXPAND_TOGGLE | DB_EXPAND_SURROUND, DB_EXPAND_TOGGLE | DB_EXPAND_SURROUND,
&rootRect); &rootRect, TRUE);
} }
else else
{ {
@ -943,8 +943,8 @@ CmdExpand(
DB_EXPAND | DB_EXPAND_SURROUND, DB_EXPAND | DB_EXPAND_SURROUND,
cmdExpandFunc, (ClientData)(pointertype)windowMask); cmdExpandFunc, (ClientData)(pointertype)windowMask);
SelectExpand(windowMask, SelectExpand(windowMask,
DB_EXPAND | DB_EXPAND_SURROUND, DB_EXPAND | DB_EXPAND_SURROUND,
&rootRect); &rootRect, TRUE);
} }
break; break;
case EXPAND_ALL: case EXPAND_ALL:
@ -954,8 +954,8 @@ CmdExpand(
DB_EXPAND | DB_EXPAND_OVERLAP, DB_EXPAND | DB_EXPAND_OVERLAP,
cmdExpandFunc, (ClientData)(pointertype)windowMask); cmdExpandFunc, (ClientData)(pointertype)windowMask);
SelectExpand(windowMask, SelectExpand(windowMask,
DB_EXPAND | DB_EXPAND_OVERLAP, DB_EXPAND | DB_EXPAND_OVERLAP,
(Rect *)NULL); (Rect *)NULL, FALSE);
} }
else else
{ {
@ -963,8 +963,8 @@ CmdExpand(
DB_EXPAND | DB_EXPAND_OVERLAP, DB_EXPAND | DB_EXPAND_OVERLAP,
cmdExpandFunc, (ClientData)(pointertype)windowMask); cmdExpandFunc, (ClientData)(pointertype)windowMask);
SelectExpand(windowMask, SelectExpand(windowMask,
DB_EXPAND | DB_EXPAND_OVERLAP, DB_EXPAND | DB_EXPAND_OVERLAP,
(Rect *)NULL); (Rect *)NULL, FALSE);
} }
break; break;
} }
@ -1096,7 +1096,7 @@ CmdExtract(
"lumped estimate lumped resistance", "lumped estimate lumped resistance",
"labelcheck check for connections through sticky labels", "labelcheck check for connections through sticky labels",
"aliases output all net name aliases", "aliases output all net name aliases",
"unique [notopports] ensure unique node names during extraction", "unique ensure unique node names during extraction",
"resistance extract resistance (same as \"do extresist\")", "resistance extract resistance (same as \"do extresist\")",
NULL NULL
}; };
@ -1403,7 +1403,6 @@ CmdExtract(
TxPrintf("%s label check\n", OPTSET(EXT_DOLABELCHECK)); TxPrintf("%s label check\n", OPTSET(EXT_DOLABELCHECK));
TxPrintf("%s aliases\n", OPTSET(EXT_DOALIASES)); TxPrintf("%s aliases\n", OPTSET(EXT_DOALIASES));
TxPrintf("%s unique\n", OPTSET(EXT_DOUNIQUE)); TxPrintf("%s unique\n", OPTSET(EXT_DOUNIQUE));
TxPrintf("%s unique notopports\n", OPTSET(EXT_DOUNIQNOTOPPORTS));
TxPrintf("%s resistance (extresist)\n", OPTSET(EXT_DOEXTRESIST)); TxPrintf("%s resistance (extresist)\n", OPTSET(EXT_DOEXTRESIST));
return; return;
#undef OPTSET #undef OPTSET
@ -1434,19 +1433,9 @@ CmdExtract(
case DORESISTANCE: option = EXT_DORESISTANCE; break; case DORESISTANCE: option = EXT_DORESISTANCE; break;
case DOLABELCHECK: option = EXT_DOLABELCHECK; break; case DOLABELCHECK: option = EXT_DOLABELCHECK; break;
case DOALIASES: option = EXT_DOALIASES; break; case DOALIASES: option = EXT_DOALIASES; break;
case DOUNIQUE: option = EXT_DOUNIQUE; break;
case DOEXTRESIST: case DOEXTRESIST:
case DOEXTRESIST2: option = EXT_DOEXTRESIST; break; case DOEXTRESIST2: option = EXT_DOEXTRESIST; break;
case DOUNIQUE:
if (argc == 4)
{
if (!strncmp(argv[3], "notop", 5))
option = EXT_DOUNIQNOTOPPORTS | EXT_DOUNIQUE;
else
TxError("Usage: extract do unique [notopports]\n");
}
else
option = EXT_DOUNIQUE;
break;
case DOLOCAL: case DOLOCAL:
/* "extract do local" and "extract no local" are kept for /* "extract do local" and "extract no local" are kept for
* backwards compatibility, but now effectively implement * backwards compatibility, but now effectively implement

View File

@ -2324,7 +2324,7 @@ CmdDoProperty(
TxCommand *cmd, TxCommand *cmd,
int argstart) int argstart)
{ {
PropertyRecord *proprec = NULL; PropertyRecord *proprec;
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
*/ */
value = cmd->tx_argv[argstart + 1]; if (proptype == PROPERTY_TYPE_PLANE)
for (proplen = 0; *value != '\0'; )
{ {
if (isspace(*value) && (*value != '\0')) value++; proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
if (!isspace(*value)) plane = DBNewPlane((ClientData)TT_SPACE);
{ proprec->prop_value.prop_plane = plane;
proplen++;
while (!isspace(*value) && (*value != '\0')) value++;
}
} }
if (proplen > 0) else
{ {
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 { proplen++;
while (!isspace(*value) && (*value != '\0')) value++;
}
}
if (proplen > 0)
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];

View File

@ -635,21 +635,10 @@ cmdSelectArea(
int i; int i;
for (i = 0; i < DBNumUserLayers; i++) for (i = 0; i < DBNumUserLayers; i++)
{ {
if ((TTMaskHasType(&mask, i)) && if((TTMaskHasType(&mask, i)) && !(TTMaskHasType(&crec->dbw_visibleLayers, 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);
} }
@ -1038,7 +1027,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 it's visible. * particular layers, but only if its visible.
*-------------------------------------------------------------------- *--------------------------------------------------------------------
*/ */

View File

@ -1019,7 +1019,7 @@ CmdSetWindCaption(
* edit cell was selected. * edit cell was selected.
*/ */
{ {
int cmdWindSet(MagWindow *window, ClientData clientData); /* UNUSED */ int cmdWindSet(MagWindow *window);
newEditDef = (newEditUse) ? newEditUse->cu_def : NULL; newEditDef = (newEditUse) ? newEditUse->cu_def : NULL;
newRootDef = rootDef; newRootDef = rootDef;
@ -1053,11 +1053,9 @@ CmdSetWindCaption(
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/*ARGSUSED*/
int int
cmdWindSet( cmdWindSet(
MagWindow *window, MagWindow *window)
ClientData clientData) /* UNUSED */
{ {
char caption[200]; char caption[200];
CellDef *wDef; CellDef *wDef;

View File

@ -777,7 +777,7 @@ CmdUnexpand(
switch (option) switch (option)
{ {
case UNEXPAND_SELECTION: case UNEXPAND_SELECTION:
SelectExpand(windowMask, DB_UNEXPAND, (Rect *)NULL); SelectExpand(windowMask, DB_UNEXPAND, (Rect *)NULL, FALSE);
break; break;
case UNEXPAND_OVERLAP: case UNEXPAND_OVERLAP:
DBExpandAll(((CellUse *)w->w_surfaceID), &rootRect, windowMask, DBExpandAll(((CellUse *)w->w_surfaceID), &rootRect, windowMask,
@ -785,7 +785,7 @@ CmdUnexpand(
cmdUnexpandFunc, (ClientData)(pointertype)windowMask); cmdUnexpandFunc, (ClientData)(pointertype)windowMask);
SelectExpand(windowMask, SelectExpand(windowMask,
DB_UNEXPAND | DB_EXPAND_OVERLAP, DB_UNEXPAND | DB_EXPAND_OVERLAP,
&rootRect); &rootRect, FALSE);
break; break;
case UNEXPAND_SURROUND: case UNEXPAND_SURROUND:
DBExpandAll(((CellUse *)w->w_surfaceID), &rootRect, windowMask, DBExpandAll(((CellUse *)w->w_surfaceID), &rootRect, windowMask,
@ -793,7 +793,7 @@ CmdUnexpand(
cmdUnexpandFunc, (ClientData)(pointertype)windowMask); cmdUnexpandFunc, (ClientData)(pointertype)windowMask);
SelectExpand(windowMask, SelectExpand(windowMask,
DB_UNEXPAND | DB_EXPAND_SURROUND, DB_UNEXPAND | DB_EXPAND_SURROUND,
&rootRect); &rootRect, TRUE);
break; break;
case UNEXPAND_ALL: case UNEXPAND_ALL:
DBExpandAll(((CellUse *)w->w_surfaceID), &TiPlaneRect, windowMask, DBExpandAll(((CellUse *)w->w_surfaceID), &TiPlaneRect, windowMask,

View File

@ -1037,13 +1037,7 @@ dbcConnectFunc(tile, dinfo, cx)
if (++csa2->csa2_top == CSA2_LIST_SIZE) if (++csa2->csa2_top == CSA2_LIST_SIZE)
{ {
/* Reached list size limit---need to push the list and */ /* Reached list size limit---need to push the list and */
/* start a new one. NOTE: Setting lasttop to -1 means */ /* start a new one. */
/* that some entries may be duplicated between the */
/* stacks, which is a small inefficiency. In theory, */
/* lasttop could be left as is, then if lasttop > top */
/* when searching the last 5 entries, pop the stack, do */
/* the search, and then push the stack again. But it's */
/* a lot easier just to be slightly inefficient. */
conSrArea *newlist; conSrArea *newlist;
@ -1051,7 +1045,6 @@ dbcConnectFunc(tile, dinfo, cx)
StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack); StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack);
csa2->csa2_list = newlist; csa2->csa2_list = newlist;
csa2->csa2_top = 0; csa2->csa2_top = 0;
csa2->csa2_lasttop = -1;
} }
csa2->csa2_list[csa2->csa2_top].area = newarea; csa2->csa2_list[csa2->csa2_top].area = newarea;

View File

@ -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 (homedir && (strncmp(cellDef->cd_file, homedir, strlen(homedir)) || if (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,10 +2060,9 @@ badTransform:
if (*pathptr == '~') if (*pathptr == '~')
{ {
char *homedir = getenv("HOME"); char *homedir = getenv("HOME");
if (homedir && (!strncmp(subCellDef->cd_file, homedir, if (!strncmp(subCellDef->cd_file, homedir, strlen(homedir))
strlen(homedir)) && && (!strcmp(subCellDef->cd_file + strlen(homedir),
(!strcmp(subCellDef->cd_file + strlen(homedir), pathptr + 1)))
pathptr + 1))))
pathOK = TRUE; pathOK = TRUE;
} }
else if (!strcmp(cwddir, pathptr)) pathOK = TRUE; else if (!strcmp(cwddir, pathptr)) pathOK = TRUE;
@ -2255,9 +2254,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 (homedir && (!strncmp(cwddir, homedir, strlen(homedir)) if (!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;

View File

@ -574,8 +574,7 @@ DBReOrientLabel(cellDef, area, newPos)
* dbGetLabelArea --- * dbGetLabelArea ---
* *
* Callback function used by DBAdjustLabels. Find all material under a label * Callback function used by DBAdjustLabels. Find all material under a label
* that is *not* the label type, and return the label area adjusted to leave * that is *not* the label type, and return the
* out that amount.
* *
* Note: This clips in a regular order, and does not consider what is the * Note: This clips in a regular order, and does not consider what is the
* largest rectangular area outside the area that has been clipped out. * largest rectangular area outside the area that has been clipped out.
@ -605,26 +604,6 @@ dbGetLabelArea(tile, dinfo, area)
return 0; return 0;
} }
/*
* ----------------------------------------------------------------------------
*
* dbLabelNotEmpty ---
*
* Callback function used by DBAdjustLabels. Finds any material under a
* label that is the label type, and returns 1 to stop the search.
*
* ----------------------------------------------------------------------------
*/
int
dbLabelNotEmpty(tile, dinfo, clientData)
Tile *tile; /* Tile found. */
TileType dinfo; /* Split tile information (unused) */
ClientData clientData; /* (unused) */
{
return 1;
}
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -682,37 +661,28 @@ DBAdjustLabels(def, area)
TTMaskSetOnlyType(&lmask, lab->lab_type); TTMaskSetOnlyType(&lmask, lab->lab_type);
/* To do: Add compatible types (contact, residue) */ /* To do: Add compatible types (contact, residue) */
TTMaskCom(&lmask);
/* If there is no material left inside the label area, then r = lab->lab_rect;
* the label gets reassigned to space. DBSrPaintArea((Tile *) NULL, def->cd_planes[DBPlane(lab->lab_type)],
*/ &lab->lab_rect, &lmask, dbGetLabelArea, (ClientData) &r);
if (DBSrPaintArea((Tile *) NULL, def->cd_planes[DBPlane(lab->lab_type)],
&lab->lab_rect, &lmask, dbLabelNotEmpty, (ClientData)NULL) == 1) if (!GEO_RECTNULL(&r))
{ {
TTMaskCom(&lmask); if ((DBVerbose >= DB_VERBOSE_ALL) && ((def->cd_flags & CDINTERNAL) == 0))
r = lab->lab_rect;
DBSrPaintArea((Tile *) NULL, def->cd_planes[DBPlane(lab->lab_type)],
&lab->lab_rect, &lmask, dbGetLabelArea, (ClientData) &r);
if (!GEO_RECTNULL(&r))
{ {
if ((DBVerbose >= DB_VERBOSE_ALL) && TxPrintf("Adjusting size of label \"%s\" in cell %s.\n",
((def->cd_flags & CDINTERNAL) == 0))
{
TxPrintf("Adjusting size of label \"%s\" in cell %s.\n",
lab->lab_text, def->cd_name); lab->lab_text, def->cd_name);
}
DBUndoEraseLabel(def, lab);
DBWLabelChanged(def, lab, DBW_ALLWINDOWS);
lab->lab_rect = r;
DBFontLabelSetBBox(lab);
DBUndoPutLabel(def, lab);
DBWLabelChanged(def, lab, DBW_ALLWINDOWS);
modified = TRUE;
adjusted = TRUE;
} }
DBUndoEraseLabel(def, lab);
DBWLabelChanged(def, lab, DBW_ALLWINDOWS);
lab->lab_rect = r;
DBFontLabelSetBBox(lab);
DBUndoPutLabel(def, lab);
DBWLabelChanged(def, lab, DBW_ALLWINDOWS);
modified = TRUE;
adjusted = TRUE;
} }
} }

View File

@ -238,11 +238,9 @@ DBUpdateStamps(def)
} }
} }
/*ARGSUSED*/
int int
dbStampFunc(cellDef, cdata) dbStampFunc(cellDef)
CellDef *cellDef; CellDef *cellDef;
ClientData cdata; /* UNUSED */
{ {
CellUse *cu; CellUse *cu;
CellDef *cd; CellDef *cd;

View File

@ -578,20 +578,6 @@ typedef struct extRectList
struct extRectList *r_next; struct extRectList *r_next;
} ExtRectList; } ExtRectList;
/* Structure similar to the above, but adding a pointer to a cell use ID
* and a client data record which can be used to hold a region pointer.
*/
typedef struct extConnList
{
char *r_useid; /* Cell Use being connected to */
TileType r_type; /* Connecting tile type in the parent */
Rect r_r; /* Area of connection */
ClientData r_upnode; /* Parent node making the connection */
ClientData r_downnode; /* Child node making the connection */
struct extConnList *r_next; /* Next item in the linked list */
} ExtConnList;
/* -------------------- Search context information -------------------- */ /* -------------------- Search context information -------------------- */
/* Search contexts are used in hierarchical searches */ /* Search contexts are used in hierarchical searches */

View File

@ -149,9 +149,6 @@ extern void CmdAutoExtToSpice();
#else #else
extern void CmdExtToSpice(); extern void CmdExtToSpice();
#endif #endif
#else /* !MAGIC_WRAPPER */
extern void CmdExtToSim();
extern void CmdExtToSpice();
#endif #endif
/* /*
@ -571,26 +568,8 @@ DBWInitCommands()
"ext2spice [args] convert extracted file(s) to a SPICE format file;" "ext2spice [args] convert extracted file(s) to a SPICE format file;"
" type\n\t\t\t\"ext2spice help\" for information on options", " type\n\t\t\t\"ext2spice help\" for information on options",
CmdExtToSpice, FALSE); CmdExtToSpice, FALSE);
#endif /* EXT2SPICE_AUTO */ #endif /* EXT2SPICE_AUTO */
#else /* !MAGIC_WRAPPER */ #endif /* MAGIC_WRAPPER */
/* In non-Tcl builds (e.g. WASM), register the C implementations directly */
WindAddCommand(DBWclientID,
"exttosim [args] convert extracted file(s) to a sim format file;"
" type\n\t\t\t\"exttosim help\" for information on options",
CmdExtToSim, FALSE);
WindAddCommand(DBWclientID,
"ext2sim [args] convert extracted file(s) to a sim format file;"
" type\n\t\t\t\"ext2sim help\" for information on options",
CmdExtToSim, FALSE);
WindAddCommand(DBWclientID,
"exttospice [args] convert extracted file(s) to a SPICE format file;"
" type\n\t\t\t\"exttospice help\" for information on options",
CmdExtToSpice, FALSE);
WindAddCommand(DBWclientID,
"ext2spice [args] convert extracted file(s) to a SPICE format file;"
" type\n\t\t\t\"ext2spice help\" for information on options",
CmdExtToSpice, FALSE);
#endif /* MAGIC_WRAPPER */
#ifdef USE_READLINE #ifdef USE_READLINE

View File

@ -867,11 +867,8 @@ dbwelemGetTransform(use, transform, cdarg)
return 1; return 1;
} }
/*ARGSUSED*/
int int
dbwElementAlways1(w, clientData) dbwElementAlways1()
MagWindow *w; /* UNUSED */
ClientData clientData; /* UNUSED */
{ {
return 1; return 1;
} }

View File

@ -531,11 +531,8 @@ dbwfbGetTransform(use, transform, cdarg)
* cell. * cell.
*/ */
/*ARGSUSED*/
int int
dbwfbWindFunc(w, clientData) dbwfbWindFunc()
MagWindow *w; /* UNUSED */
ClientData clientData; /* UNUSED */
{ {
return 1; return 1;
} }

View File

@ -357,11 +357,9 @@ DBWHLRedrawPrepWindow(MagWindow *window, Rect *area)
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/*ARGSUSED*/
int int
DBWHLRedrawWind(window, clientData) DBWHLRedrawWind(window)
MagWindow *window; /* Window in which to redraw highlights. */ MagWindow *window; /* Window in which to redraw highlights. */
ClientData clientData; /* UNUSED */
{ {
int i; int i;
DBWclientRec *crec; DBWclientRec *crec;

View File

@ -102,17 +102,16 @@ Circuit netlist extractor
but will usually just slow down processing by commands but will usually just slow down processing by commands
like "ext2spice" that use the .ext file contents, so it like "ext2spice" that use the .ext file contents, so it
is disabled by default. is disabled by default.
<DT> <B>unique</B> [<B>notopports</B>] <DT> <B>unique</B>
<DD> (Added in magic version 8.3.594) This setting replaces <DD> (Added in magic version 8.3.594) This setting replaces
the use of the command option "extract unique" (and the use of the command option "extract unique". Instead
"extract unique notopports"). Instead of changing labels of changing labels in the design, unique labels are
in the design, unique labels are generated for the duration generated for the duration of the extraction, and then
of the extraction, and then reverted back to the original reverted back to the original text. The "extract unique"
text. The "extract unique" command option is maintained command option is maintained for backwards compatibility.
for backwards compatibility. Note the difference: Note the difference: "extract unique" is a command that
"extract unique" is a command that runs immediately, and runs immediately, and cannot be undone;
cannot be undone; "extract do unique" is an option setting "extract do unique" is an option setting for "extract".
for "extract".
<DT> <B>resistance</B> <DT> <B>resistance</B>
<DD> (Added in magic version 8.3.597) This setting replaces <DD> (Added in magic version 8.3.597) This setting replaces
the use of the standalone command "extresist". The the use of the standalone command "extresist". The

View File

@ -30,30 +30,11 @@ information.
<BLOCKQUOTE> <BLOCKQUOTE>
where <I>option</I> may be one of the following: where <I>option</I> may be one of the following:
<DL> <DL>
<DT> <B>tolerance</B> <I>value</I>
<DD> Set the ratio between resistor and transistor tolerance
for determining when to insert resistance into a network route.
<DT> <B>all</B> <DT> <B>all</B>
<DD> Extract all the nets. <DD> Extract all the nets.
<DT> <B>threshold</B> [<I>value</I>]
<DD> With no value given, returns the current lumped resistance
threshold used to determine if a network will or will not be
analyzed for resistance extraction, in milliohms. The default
<B>threshold</B> value is 10000 milliohms (10 ohms). If
<I>value</I> is given, then set the lumped resistance threshold
to <I>value</I> milliohms.
<DT> <B>mindelay</B> [<I>value</I>]
<DD> With no value given, returns the current delay time threshold
used to determine if a network will or will not be analyzed for
resistance extraction, in picoseconds. The default
<B>mindelay</B> value is 1ps. If <I>value</I> is given,
then set the delay threshold to <I>value</I> picoseconds.
<DT> <B>minres</B> [<I>value</I>]
<DD> With no value given, returns the current absolute resistance
threshold used to prune small resistances from a network when
simplifying, in milliohms. The default <B>minres</B> value
is 1000 milliohms (1 ohm). If <I>value</I> is given, then set
the absolute resistance threshold to <I>value</I> milliohms.
Note that resistances smaller than <I>value</I> may still
appear in the output netlist if the algorithm is unable to
simplify the network around the resistor.
<DT> <B>simplify</B> [<B>on</B>|<B>off</B>] <DT> <B>simplify</B> [<B>on</B>|<B>off</B>]
<DD> Turn on/off simplification of resistor nets. <DD> Turn on/off simplification of resistor nets.
<DT> <B>extout</B> [<B>on</B>|<B>off</B>] <DT> <B>extout</B> [<B>on</B>|<B>off</B>]
@ -61,9 +42,7 @@ information.
<DT> <B>lumped</B> [<B>on</B>|<B>off</B>] <DT> <B>lumped</B> [<B>on</B>|<B>off</B>]
<DD> Turn on/off writing of updated lumped resistances. <DD> Turn on/off writing of updated lumped resistances.
<DT> <B>silent</B> [<B>on</B>|<B>off</B>] <DT> <B>silent</B> [<B>on</B>|<B>off</B>]
<DD> Turn off/on printing of nets being processed. <DD> Turn off/on printing of net statistics.
<DT> <B>debug</B> [<B>on</B>|<B>off</B>]
<DD> Turn off/on additional diagnostic information.
<DT> <B>skip</B> <I>mask</I> <DT> <B>skip</B> <I>mask</I>
<DD> Don't extract types indicated in the comma-separated list <I>mask</I> <DD> Don't extract types indicated in the comma-separated list <I>mask</I>
<DT> <B>ignore</B> [<I>netname</I>|<B>none</B>] <DT> <B>ignore</B> [<I>netname</I>|<B>none</B>]
@ -90,8 +69,6 @@ information.
<TT>.fh</TT> file. If <I>freq</I> is specified, the file will <TT>.fh</TT> file. If <I>freq</I> is specified, the file will
be customized for <B>fasthenry</B> analysis at the indicated be customized for <B>fasthenry</B> analysis at the indicated
frequency (in Hz). frequency (in Hz).
<DT> <B>tolerance</B> <I>value</I>
<DD> <I>Deprecated!</I> This option is no longer used by extresist.
<DT> <B>help</B> <DT> <B>help</B>
<DD> Print help information <DD> Print help information
</DL> </DL>
@ -102,9 +79,9 @@ information.
<BLOCKQUOTE> <BLOCKQUOTE>
The normal flow through layout extraction into a simulation file The normal flow through layout extraction into a simulation file
treats routes as nonphysical entities, that is, with infinitesimal treats routes as nonphysical entities, that is, with infinitesimal
impedence through the wires. Standard extraction generates "lumped impedence through the wires. Extraction for digital simulation
resistance" values, a single resistance per network node that, along using <B>irsim</B> generates "lumped resistances", a single
with the node capacitance resistance per network node that, along with the node capacitance
to substrate, provides an <I>RC</I> time constant to approximately to substrate, provides an <I>RC</I> time constant to approximately
model the delay from point to point in the network node. The model the delay from point to point in the network node. The
lumped resistance model is inappropriate for analog (i.e., SPICE) lumped resistance model is inappropriate for analog (i.e., SPICE)
@ -119,9 +96,10 @@ information.
Using <B>extresist</B> as a standalone command is a multi-step Using <B>extresist</B> as a standalone command is a multi-step
process. It is first necessary to run <B>extract</B> to get process. It is first necessary to run <B>extract</B> to get
the initial netlist. After a <TT>.ext</TT> file has been generated, the initial netlist.
the <B>extresist</B> command may be run. The output is a file After a <TT>.ext</TT> file has been generated, the
<TT>.res.ext</TT> for each cell in the hierarchy. <B>extresist</B> command may be run. The output is
a file <TT>.res.ext</TT> for each cell in the hierarchy.
Finally, with the option <B>extresist on</B> set, <B>ext2spice</B> Finally, with the option <B>extresist on</B> set, <B>ext2spice</B>
will generate the final, detailed simulation file. <P> will generate the final, detailed simulation file. <P>
@ -132,42 +110,7 @@ information.
magic version 8.3.597 an option <B>extract do resistance</B> magic version 8.3.597 an option <B>extract do resistance</B>
that runs the resistance extraction in sequence with the regular that runs the resistance extraction in sequence with the regular
extraction, producing both the <TT>.ext</TT> and <TT>.res.ext</TT> extraction, producing both the <TT>.ext</TT> and <TT>.res.ext</TT>
files. When <B>extract do resistance</B> is used, there is no need files.
to run <B>extresist</B> as a separate command. However,
<B>extresist</B> may be run prior to <B>extract</B> to set the
options that affect resistance network extraction, such as
<B>extresist threshold</B>, <B>extresist minres</B>, etc. <P>
As of magic version 8.3.653, the <B>extresist tolerance</B> option
is deprecated and has no effect on network resistance extraction.
Instead, extraction is controlled by three main options: <P>
<B>extresist threshold</B> (value in milliohms) sets a cutoff for
considering a network for detailed resistance extraction based on
the lumped resistance estimate (see above). For point-to-point
wires, the lumped resistance is approximately equal to the actual
wire resistance. For branching networks, it will generally be an
over-estimate. The default <B>threshold</B> value is set to
10 ohms. <P>
<B>extresist minres</B> (value in milliohms) sets a cutoff for
individual resistors in the detailed resistor network. Resistors
below this threshold will get pruned out of the network if the
simplification algorithm is able to remove them. The default
<B>minres</B> value is set to 1 ohm. <P>
<B>extresist mindelay</B> (value in picoseconds) sets a cutoff for
considering a network for detailed resistance extraction based on
the end-to-end delay calculated from the lumped resistance
estimate. Once the network has been extracted, the <B>mindelay</B>
value is again evaluated against a revised calculation of the
delay to determine if the extracted detailed network should be
output. The default <B>mindelay<B> value is set to 0, indicating
that only the lumped resistance threshold should be used for
determining when to extract a detailed resistance network.
<B>mindelay</B> may be used in place of <B>threshold</B>, or both
may be used together, in which case a network is only extracted
if both <B>threshold</B> and <B>mindelay</B> are exceeded. <P>
More details on using <B>extresist</B> can be found in More details on using <B>extresist</B> can be found in
<B>magic</B> Tutorial number 8. <B>magic</B> Tutorial number 8.
@ -191,6 +134,6 @@ information.
<TD> <A HREF=commands.html>Return to command index</A> <TD> <A HREF=commands.html>Return to command index</A>
</TR> </TR>
</TABLE> </TABLE>
<P><I>Last updated:</I> May 29, 2026 at 11:33am <P> <P><I>Last updated:</I> October 4, 2021 at 3:32pm <P>
</BODY> </BODY>
</HTML> </HTML>

View File

@ -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;

View File

@ -757,7 +757,7 @@ spcdevHierVisit(
case DEV_FET: case DEV_FET:
if (source == drain) if (source == drain)
{ {
if (esFormat == NGSPICE) fprintf(esSpiceF, "; "); if (esFormat == NGSPICE) fprintf(esSpiceF, "$ ");
fprintf(esSpiceF, "** SOURCE/DRAIN TIED\n"); fprintf(esSpiceF, "** SOURCE/DRAIN TIED\n");
} }
break; break;
@ -765,7 +765,7 @@ spcdevHierVisit(
default: default:
if (gate == source) if (gate == source)
{ {
if (esFormat == NGSPICE) fprintf(esSpiceF, "; "); if (esFormat == NGSPICE) fprintf(esSpiceF, "$ ");
fprintf(esSpiceF, "** SHORTED DEVICE\n"); fprintf(esSpiceF, "** SHORTED DEVICE\n");
} }
break; break;
@ -1624,14 +1624,12 @@ spcsubHierVisit(
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/*ARGSUSED*/
int int
spcnodeHierVisit( spcnodeHierVisit(
HierContext *hc, HierContext *hc,
EFNode *node, EFNode *node,
int res, int res,
double cap, double cap)
ClientData cdata) /* UNUSED */
{ {
HierName *hierName; HierName *hierName;
bool isConnected = FALSE; bool isConnected = FALSE;
@ -1658,7 +1656,7 @@ spcnodeHierVisit(
static char ntmp[MAX_STR_SIZE]; static char ntmp[MAX_STR_SIZE];
EFHNSprintf(ntmp, hierName); EFHNSprintf(ntmp, hierName);
if (esFormat == NGSPICE) fprintf(esSpiceF, " ; "); if (esFormat == NGSPICE) fprintf(esSpiceF, " $ ");
fprintf(esSpiceF, "** %s == %s\n", ntmp, nsn); fprintf(esSpiceF, "** %s == %s\n", ntmp, nsn);
} }
cap = cap / 1000; cap = cap / 1000;
@ -1668,14 +1666,14 @@ spcnodeHierVisit(
esSIvalue(esSpiceF, 1.0E-15 * cap); esSIvalue(esSpiceF, 1.0E-15 * cap);
if (!isConnected) if (!isConnected)
{ {
if (esFormat == NGSPICE) fprintf(esSpiceF, " ;"); if (esFormat == NGSPICE) fprintf(esSpiceF, " $");
fprintf(esSpiceF, " **FLOATING"); fprintf(esSpiceF, " **FLOATING");
} }
fprintf(esSpiceF, "\n"); fprintf(esSpiceF, "\n");
} }
if (node->efnode_attrs && !esNoAttrs) if (node->efnode_attrs && !esNoAttrs)
{ {
if (esFormat == NGSPICE) fprintf(esSpiceF, " ; "); if (esFormat == NGSPICE) fprintf(esSpiceF, " $ ");
fprintf(esSpiceF, "**nodeattr %s :",nsn ); fprintf(esSpiceF, "**nodeattr %s :",nsn );
for (fmt = " %s", ap = node->efnode_attrs; ap; ap = ap->efa_next) for (fmt = " %s", ap = node->efnode_attrs; ap; ap = ap->efa_next)
{ {

View File

@ -2817,7 +2817,7 @@ spcdevVisit(
case DEV_FET: case DEV_FET:
if (source == drain) if (source == drain)
{ {
if (esFormat == NGSPICE) fprintf(esSpiceF, "; "); if (esFormat == NGSPICE) fprintf(esSpiceF, "$ ");
fprintf(esSpiceF, "** SOURCE/DRAIN TIED\n"); fprintf(esSpiceF, "** SOURCE/DRAIN TIED\n");
} }
break; break;
@ -2825,7 +2825,7 @@ spcdevVisit(
default: default:
if (gate == source) if (gate == source)
{ {
if (esFormat == NGSPICE) fprintf(esSpiceF, "; "); if (esFormat == NGSPICE) fprintf(esSpiceF, "$ ");
fprintf(esSpiceF, "** SHORTED DEVICE\n"); fprintf(esSpiceF, "** SHORTED DEVICE\n");
} }
break; break;
@ -4111,7 +4111,7 @@ spcnodeVisit(
static char ntmp[MAX_STR_SIZE]; static char ntmp[MAX_STR_SIZE];
EFHNSprintf(ntmp, hierName); EFHNSprintf(ntmp, hierName);
if (esFormat == NGSPICE) fprintf(esSpiceF, "; "); if (esFormat == NGSPICE) fprintf(esSpiceF, "$ ");
fprintf(esSpiceF, "** %s == %s\n", ntmp, nsn); fprintf(esSpiceF, "** %s == %s\n", ntmp, nsn);
} }
cap = cap / 1000; cap = cap / 1000;
@ -4121,14 +4121,14 @@ spcnodeVisit(
esSIvalue(esSpiceF, 1.0E-15 * cap); esSIvalue(esSpiceF, 1.0E-15 * cap);
if (!isConnected) if (!isConnected)
{ {
if (esFormat == NGSPICE) fprintf(esSpiceF, " ;"); if (esFormat == NGSPICE) fprintf(esSpiceF, " $");
fprintf(esSpiceF, " **FLOATING"); fprintf(esSpiceF, " **FLOATING");
} }
fprintf(esSpiceF, "\n"); fprintf(esSpiceF, "\n");
} }
if (node->efnode_attrs && !esNoAttrs) if (node->efnode_attrs && !esNoAttrs)
{ {
if (esFormat == NGSPICE) fprintf(esSpiceF, " ; "); if (esFormat == NGSPICE) fprintf(esSpiceF, " $ ");
fprintf(esSpiceF, "**nodeattr %s :",nsn ); fprintf(esSpiceF, "**nodeattr %s :",nsn );
for (fmt = " %s", ap = node->efnode_attrs; ap; ap = ap->efa_next) for (fmt = " %s", ap = node->efnode_attrs; ap; ap = ap->efa_next)
{ {

View File

@ -307,12 +307,6 @@ EFArgs(argc, argv, err_result, argsProc, cdata)
if (inname == NULL) if (inname == NULL)
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
return NULL; return NULL;
#elif defined(EMSCRIPTEN)
{
/* Headless WASM: signal error via err_result, no goto usage path */
if (err_result != NULL) *err_result = TRUE;
return NULL;
}
#else #else
goto usage; goto usage;
#endif #endif
@ -373,7 +367,7 @@ efLoadSearchPath(path)
PaVisitFiles(DOT_MAGIC_PATH, ".magicrc", pv); PaVisitFiles(DOT_MAGIC_PATH, ".magicrc", pv);
PaVisitFree(pv); PaVisitFree(pv);
if (*path == NULL) if (*path == NULL)
StrDup(path, "."); *path = ".";
} }
int int

View File

@ -706,11 +706,6 @@ efBuildEquiv(def, nodeName1, nodeName2, resist, isspice)
dev->dev_terms[n].dterm_node = dev->dev_terms[n].dterm_node =
(nn1->efnn_node == NULL) ? (nn1->efnn_node == NULL) ?
nn2->efnn_node : nn1->efnn_node; nn2->efnn_node : nn1->efnn_node;
/* Also check the substrate terminal */
if (dev->dev_subsnode == lostnode)
dev->dev_subsnode = (nn1->efnn_node == NULL) ?
nn2->efnn_node : nn1->efnn_node;
} }
/* If a node has been merged away, make sure that its name */ /* If a node has been merged away, make sure that its name */
@ -1623,128 +1618,12 @@ efConnectionFreeLinkedList(Connection *conn)
} }
} }
/*
* ----------------------------------------------------------------------------
*
* efConnPointFreeLinkedList --
*
* Release memory for linked-list of ConnectionPoint* based on internal
* list at ConnectionPoint->conn_next. 'connpt' argument must be non-NULL.
*
* Results:
* Deallocates linked-list of ConnectionPoint* starting at 'connpt'
*
* Side effects:
* Deallocates one or more connection point record(s).
*
* ----------------------------------------------------------------------------
*/
void
efConnPointFreeLinkedList(ConnectionPoint *connpt)
{
while (connpt)
{
ConnectionPoint *next = connpt->conn_next;
if (connpt->conn_name != NULL)
freeMagic(connpt->conn_name);
freeMagic(connpt);
connpt = next;
}
}
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
* efBuildConnect -- * efBuildConnect --
* *
* Process a "connect" line from a .ext file. * Process a "connect" line from a .ext file.
* Creates a record of the area and type of the connection. Since the
* extraction at the point of finding connections no longer knows what
* net in the celldef (if any) is part of the connection, only the
* location and type is preserved, and the cell being connected has to
* be recovered by a search on the celldef's layout. These records are
* used only by "extresist".
*
* Results:
* None.
*
* Side effects:
* Allocates a new connection port record for extresist, and prepends
* it to the list for def.
*
* ----------------------------------------------------------------------------
*/
void
efBuildConnect(def, llx, lly, urx, ury, layerName, upnodeName, downnodeName)
Def *def;
int llx, lly, urx, ury;
char *layerName;
char *upnodeName;
char *downnodeName;
{
int tnew;
ConnectionPoint *connpt;
HashEntry *he;
Use *subuse;
char *hierptr, *qptr, *useid;
/* Can't do anything without a node name to connect to */
if (!strcmp(downnodeName, "\"None\"")) return;
/* "downnodeName" should be hierarchical; stop at the first hierarchical
* divider and use the prefix to find the use being connected to.
* NOTE: This will require dealing with connections that are more than
* one hierarchical level deep (to be done).
*/
useid = downnodeName;
if (*useid == '"') useid++;
hierptr = strchr(useid, '/');
if (hierptr != NULL) *hierptr = '\0';
qptr = strrchr(useid, '"');
if (qptr != NULL) *qptr = '\0';
if (layerName)
tnew = efBuildAddStr(EFLayerNames, &EFLayerNumNames, MAXTYPES, layerName);
else
tnew = 0;
connpt = (ConnectionPoint *)mallocMagic(sizeof(ConnectionPoint));
he = HashFind(&def->def_uses, useid);
subuse = (Use *)HashGetValue(he);
connpt->conn_use = subuse;
connpt->conn_r.r_xbot = llx;
connpt->conn_r.r_ybot = lly;
connpt->conn_r.r_xtop = urx;
connpt->conn_r.r_ytop = ury;
connpt->conn_type = tnew;
if (!strcmp(upnodeName, "\"None\""))
connpt->conn_name = (char *)NULL;
else
{
if (*upnodeName == '"') upnodeName++;
connpt->conn_name = StrDup((char **)NULL, upnodeName);
if ((qptr = strrchr(connpt->conn_name, '"')) != NULL) *qptr = '\0';
}
/* To do: Add "downnodeName" to the ConnectionPoint structure. This
* may not be necessary, as it is only being used by "extresist" which
* is not using the extflat parser.
*/
connpt->conn_next = def->def_connpts;
def->def_connpts = connpt;
}
/*
* ----------------------------------------------------------------------------
*
* efBuildMerge --
*
* Process a "merge" line from a .ext file.
* Creates a connection record for the names 'nodeName1' and * Creates a connection record for the names 'nodeName1' and
* 'nodeName2'. * 'nodeName2'.
* *
@ -1759,7 +1638,7 @@ efBuildConnect(def, llx, lly, urx, ury, layerName, upnodeName, downnodeName)
*/ */
void void
efBuildMerge(def, nodeName1, nodeName2, deltaC, av, ac) efBuildConnect(def, nodeName1, nodeName2, deltaC, av, ac)
Def *def; /* Def to which this connection is to be added */ Def *def; /* Def to which this connection is to be added */
char *nodeName1; /* Name of first node in connection */ char *nodeName1; /* Name of first node in connection */
char *nodeName2; /* Name of other node in connection */ char *nodeName2; /* Name of other node in connection */

View File

@ -122,7 +122,6 @@ EFDone(func)
efConnectionFreeLinkedList(def->def_conns); efConnectionFreeLinkedList(def->def_conns);
efConnectionFreeLinkedList(def->def_caps); efConnectionFreeLinkedList(def->def_caps);
efConnectionFreeLinkedList(def->def_resistors); efConnectionFreeLinkedList(def->def_resistors);
efConnPointFreeLinkedList(def->def_connpts);
free_magic1_t mm1 = freeMagic1_init(); free_magic1_t mm1 = freeMagic1_init();
for (kill = def->def_kills; kill; kill = kill->kill_next) for (kill = def->def_kills; kill; kill = kill->kill_next)
@ -249,7 +248,6 @@ efDefNew(name)
newdef->def_conns = (Connection *) NULL; newdef->def_conns = (Connection *) NULL;
newdef->def_caps = (Connection *) NULL; newdef->def_caps = (Connection *) NULL;
newdef->def_resistors = (Connection *) NULL; newdef->def_resistors = (Connection *) NULL;
newdef->def_connpts = (ConnectionPoint *) NULL;
newdef->def_kills = (Kill *) NULL; newdef->def_kills = (Kill *) NULL;
/* Initialize circular list of nodes */ /* Initialize circular list of nodes */

View File

@ -32,7 +32,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/utils.h" #include "utils/utils.h"
#include "extflat/extflat.h" #include "extflat/extflat.h"
#include "extflat/EFint.h" #include "extflat/EFint.h"
#include "textio/textio.h"
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
@ -492,13 +491,7 @@ efHierVisitDevs(hc, ca)
{ {
dev = (Dev *)HashGetValue(he); dev = (Dev *)HashGetValue(he);
if (efHierDevKilled(hc, dev, hc->hc_hierName)) if (efHierDevKilled(hc, dev, hc->hc_hierName))
{ continue;
TxError("Error: Device at (%d %d) is connected to one or more"
" eliminated nodes.\n",
dev->dev_rect.r_xbot, dev->dev_rect.r_ybot);
/* Output the device anyway, but something needs fixing */
// continue;
}
const cb_extflat_hiervisitdevs_t ca_hiervisitdevs_proc = (cb_extflat_hiervisitdevs_t) ca->ca_proc; /* FIXME temporary */ const cb_extflat_hiervisitdevs_t ca_hiervisitdevs_proc = (cb_extflat_hiervisitdevs_t) ca->ca_proc; /* FIXME temporary */
if ((*ca_hiervisitdevs_proc)(hc, dev, scale, ca->ca_cdata)) /* @invoke cb_extflat_hiervisitdevs_t */ if ((*ca_hiervisitdevs_proc)(hc, dev, scale, ca->ca_cdata)) /* @invoke cb_extflat_hiervisitdevs_t */

View File

@ -145,8 +145,6 @@ typedef struct conn
#define conn_res conn_value.conn_val_res #define conn_res conn_value.conn_val_res
#define conn_cap conn_value.conn_val_cap #define conn_cap conn_value.conn_val_cap
typedef struct connpoint ConnectionPoint;
/* -------------------------- Defs and uses --------------------------- */ /* -------------------------- Defs and uses --------------------------- */
/* A Def exists for each .ext file */ /* A Def exists for each .ext file */
@ -164,7 +162,6 @@ typedef struct def
/* The following are all NULL-terminated lists */ /* The following are all NULL-terminated lists */
Connection *def_conns; /* Hierarchical connections/adjustments */ Connection *def_conns; /* Hierarchical connections/adjustments */
ConnectionPoint *def_connpts; /* Position of hierarchical connections */
Connection *def_caps; /* Two-terminal capacitors */ Connection *def_caps; /* Two-terminal capacitors */
Connection *def_resistors; /* Two-terminal resistors */ Connection *def_resistors; /* Two-terminal resistors */
Kill *def_kills; /* Used to modify hierarchical structure Kill *def_kills; /* Used to modify hierarchical structure
@ -209,17 +206,6 @@ typedef struct use
#define IsArray(u) ((u)->use_xlo!=(u)->use_xhi || (u)->use_ylo!=(u)->use_yhi) #define IsArray(u) ((u)->use_xlo!=(u)->use_xhi || (u)->use_ylo!=(u)->use_yhi)
/* Connection point structure (used by "extresist") */
typedef struct connpoint
{
Use *conn_use; /* Use being connected to */
Rect conn_r; /* Area, edge, or point of connection */
int conn_type; /* A tile type at the connection */
char *conn_name; /* Top level name of node, or NULL */
struct connpoint *conn_next; /* Next connection point in list */
} ConnectionPoint;
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/* Structure passed down during hierarchical searching */ /* Structure passed down during hierarchical searching */
@ -321,9 +307,7 @@ extern void CapHashSetValue();
extern DevParam *efGetDeviceParams(); extern DevParam *efGetDeviceParams();
extern void efBuildNode(); extern void efBuildNode();
extern void efConnectionFreeLinkedList(Connection *conn); extern void efConnectionFreeLinkedList(Connection *conn);
extern void efConnPointFreeLinkedList(ConnectionPoint *conn);
extern void efBuildConnect(); extern void efBuildConnect();
extern void efBuildMerge();
extern void efBuildResistor(); extern void efBuildResistor();
extern void efBuildCap(); extern void efBuildCap();
extern HierContext *EFFlatBuildOneLevel(); extern HierContext *EFFlatBuildOneLevel();

View File

@ -275,11 +275,15 @@ readfile:
efBuildCap(def, argv[1], argv[2], (double) cap); efBuildCap(def, argv[1], argv[2], (double) cap);
break; break;
/* connect useid llx lly urx ury type "node" ... */ /* subcap node capacitance */
case CONNECT: case SUBCAP:
efBuildConnect(def, atoi(argv[1]), atoi(argv[2]), cap = cscale*atoCap(argv[2]);
atoi(argv[3]), atoi(argv[4]), argv[5], efAdjustSubCap(def, argv[1], cap);
argv[6], argv[7]); break;
/* equiv node1 node2 */
case EQUIV:
efBuildEquiv(def, argv[1], argv[2], resist, isspice);
break; break;
/* replaces "fet" (below) */ /* replaces "fet" (below) */
@ -333,28 +337,6 @@ readfile:
r.r_xtop = (int)(0.5 + (float)atoi(argv[5]) * locScale); r.r_xtop = (int)(0.5 + (float)atoi(argv[5]) * locScale);
r.r_ytop = (int)(0.5 + (float)atoi(argv[6]) * locScale); r.r_ytop = (int)(0.5 + (float)atoi(argv[6]) * locScale);
if (!strcmp(argv[2], "Short"))
{
/* Device name "Short" is a reserved name indicating
* that the device does not get output but acts as a
* short between the first two terminals. Consequently,
* it acts like an "equiv" statement. However, unlike
* regular "equiv" statements, it should always merge
* the nodes, so do not pass "resis" to efBuildEquiv().
*/
int argstart = 7;
/* "Short" devices should not have parameters, but just in
* case, skip over any that are found.
*/
while (strchr(argv[argstart], '=') != NULL) argstart++;
if (argstart + 4 >= argc)
efReadError("Bad terminal description for Short device\n");
else
efBuildEquiv(def, argv[argstart + 1], argv[argstart + 4],
FALSE, isspice);
break;
}
if (efBuildDevice(def, (char)n, argv[2], &r, argc - 7, &argv[7]) != 0) if (efBuildDevice(def, (char)n, argv[2], &r, argc - 7, &argv[7]) != 0)
{ {
efReadError("Incomplete terminal description for device\n"); efReadError("Incomplete terminal description for device\n");
@ -362,11 +344,6 @@ readfile:
} }
break; break;
/* equiv node1 node2 */
case EQUIV:
efBuildEquiv(def, argv[1], argv[2], resist, isspice);
break;
/* for backwards compatibility */ /* for backwards compatibility */
/* fet type xlo ylo xhi yhi area perim substrate GATE T1 T2 ... */ /* fet type xlo ylo xhi yhi area perim substrate GATE T1 T2 ... */
case FET: case FET:
@ -396,7 +373,7 @@ readfile:
*/ */
cap = (argc > 3) ? atoCap(argv[3]) * cscale : 0; cap = (argc > 3) ? atoCap(argv[3]) * cscale : 0;
efBuildMerge(def, argv[1], argv[2], (double)cap, &argv[4], argc - 4); efBuildConnect(def, argv[1], argv[2], (double)cap, &argv[4], argc - 4);
break; break;
/* node name R C x y layer a1 p1 a2 p2 ... [ attrs ] */ /* node name R C x y layer a1 p1 a2 p2 ... [ attrs ] */
@ -472,12 +449,6 @@ resistChanged:
} }
break; break;
/* subcap node capacitance */
case SUBCAP:
cap = cscale*atoCap(argv[2]);
efAdjustSubCap(def, argv[1], cap);
break;
/* use def use-id T0 .. T5 */ /* use def use-id T0 .. T5 */
case USE: case USE:
efBuildUse(def, argv[1], argv[2], efBuildUse(def, argv[1], argv[2],

View File

@ -25,9 +25,9 @@
*/ */
typedef enum typedef enum
{ {
ABSTRACT, ADJUST, ATTR, CAP, CONNECT, DEVICE, DIST, EQUIV, FET, KILLNODE, ABSTRACT, ADJUST, ATTR, CAP, DEVICE, DIST, EQUIV, FET, KILLNODE, MERGE,
MERGE, NODE, PARAMETERS, PORT, PRIMITIVE, RESISTOR, RESISTCLASS, RNODE, NODE, PARAMETERS, PORT, PRIMITIVE, RESISTOR, RESISTCLASS, RNODE, SCALE,
SCALE, SUBCAP, SUBSTRATE, TECH, TIMESTAMP, USE, VERSION, EXT_STYLE SUBCAP, SUBSTRATE, TECH, TIMESTAMP, USE, VERSION, EXT_STYLE
} Key; } Key;
static const struct static const struct
@ -42,7 +42,6 @@ keyTable[] =
{"adjust", ADJUST, 4}, {"adjust", ADJUST, 4},
{"attr", ATTR, 8}, {"attr", ATTR, 8},
{"cap", CAP, 4}, {"cap", CAP, 4},
{"connect", CONNECT, 7},
{"device", DEVICE, 11}, /* effectively replaces "fet" */ {"device", DEVICE, 11}, /* effectively replaces "fet" */
{"distance", DIST, 4}, {"distance", DIST, 4},
{"equiv", EQUIV, 3}, {"equiv", EQUIV, 3},

View File

@ -147,13 +147,13 @@ NodeRegion *temp_subsnode = NULL; /* Last subsnode found */
/* Forward declarations */ /* Forward declarations */
void extOutputNodes(); void extOutputNodes();
int extTransTileFunc(); int extTransTileFunc();
int extTransPerimFunc(Boundary *, ClientData); /* UNUSED */ int extTransPerimFunc();
int extTransFindSubs(); int extTransFindSubs();
int extTransFindId(); int extTransFindId();
void extTermAPFunc(); void extTermAPFunc();
int extAnnularTileFunc(Tile *, TileType, int, FindRegion *); /* UNUSED */ int extAnnularTileFunc();
int extResistorTileFunc(Tile *, TileType, int, FindRegion *); /* UNUSED */ int extResistorTileFunc();
int extSpecialPerimFunc(); int extSpecialPerimFunc();
void extFindDuplicateLabels(); void extFindDuplicateLabels();
@ -629,8 +629,6 @@ extSetResist(reg)
for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++) for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++)
{ {
ResValue resnew, restot;
reg->nreg_pa[n].pa_area = area = extResistArea[n]; reg->nreg_pa[n].pa_area = area = extResistArea[n];
reg->nreg_pa[n].pa_perim = perim = extResistPerim[n]; reg->nreg_pa[n].pa_perim = perim = extResistPerim[n];
if (area > 0 && perim > 0) if (area > 0 && perim > 0)
@ -641,15 +639,8 @@ extSetResist(reg)
if (v < 0) s = 0; else s = sqrt(v); if (v < 0) s = 0; else s = sqrt(v);
fperim = (float) perim; fperim = (float) perim;
resnew = (fperim + s) / (fperim - s) * reg->nreg_resist += (fperim + s) / (fperim - s)
ExtCurStyle->exts_resistByResistClass[n]; * ExtCurStyle->exts_resistByResistClass[n];
restot = reg->nreg_resist + resnew;
/* Check for integer overflow. There is no point in trying
* to accommodate huge resistance values for an estimate.
* The value just saturates at the maximum integer value.
*/
if (restot > 0) reg->nreg_resist = restot;
} }
/* Reset for the next pass */ /* Reset for the next pass */
@ -731,8 +722,7 @@ extOutputNodes(nodeList, outFile)
/* Check if this node is the substrate */ /* Check if this node is the substrate */
if (reg == glob_subsnode) if (reg == glob_subsnode)
{ {
intR = (reg->nreg_resist + rround) / ExtCurStyle->exts_resistScale; fprintf(outFile, "substrate \"%s\" 0 0", text);
fprintf(outFile, "substrate \"%s\" %d 0", text, intR);
} }
else else
{ {
@ -1120,7 +1110,7 @@ ExtSortTerminals(tran, ll)
do do
{ {
changed = 0; changed = 0;
for (nsd = 0; nsd < tran->tr_nterm-1; nsd++) for( nsd = 0; nsd < tran->tr_nterm-1; nsd++ )
{ {
p1 = &(tran->tr_termpos[nsd]); p1 = &(tran->tr_termpos[nsd]);
p2 = &(tran->tr_termpos[nsd+1]); p2 = &(tran->tr_termpos[nsd+1]);
@ -1165,17 +1155,14 @@ ExtSortTerminals(tran, ll)
* but S,D attributes are not that common so it should not matter * but S,D attributes are not that common so it should not matter
* that much -- Stefanos 5/96 */ * that much -- Stefanos 5/96 */
for (lp = ll; lp; lp = lp->ll_next) for ( lp = ll ; lp ; lp = lp->ll_next )
if (lp->ll_attr == nsd) if ( lp->ll_attr == nsd ) lp->ll_attr = LL_SORTATTR ;
lp->ll_attr = LL_SORTATTR; else if ( lp->ll_attr == nsd+1 ) lp->ll_attr = nsd ;
else if (lp->ll_attr == nsd + 1) for ( lp = ll ; lp ; lp = lp->ll_next )
lp->ll_attr = nsd; if ( lp->ll_attr == LL_SORTATTR ) lp->ll_attr = nsd+1;
for (lp = ll; lp; lp = lp->ll_next)
if (lp->ll_attr == LL_SORTATTR)
lp->ll_attr = nsd + 1;
} }
} }
while (changed); while( changed );
} }
/* /*
@ -2198,13 +2185,11 @@ extDevFindParamMatch(devptr, length, width)
* *
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/*ARGSUSED*/
int int
extSDTileFunc(tile, dinfo, pNum, arg) extSDTileFunc(tile, dinfo, pNum)
Tile *tile; Tile *tile;
TileType dinfo; /* UNUSED */ TileType dinfo; /* (unused) */
int pNum; int pNum;
FindRegion *arg; /* UNUSED */
{ {
LinkedTile *newdevtile; LinkedTile *newdevtile;
@ -2665,6 +2650,30 @@ extOutputDevices(def, transList, outFile)
if (!strcmp(devptr->exts_deviceName, "Ignore")) if (!strcmp(devptr->exts_deviceName, "Ignore"))
continue; continue;
/* Model type "Short" in the techfile indicates a device */
/* to short across the first two nodes (the gate and the */
/* source). This solves the specific issue of a transistor */
/* extended drain where the drain is a resistor but the */
/* resistor is part of the model and should not be output. */
if (!strcmp(devptr->exts_deviceName, "Short"))
{
fprintf(outFile, "equiv ");
/* To do: Use parameters to specify which terminals */
/* are shorted. */
/* gate */
node = (NodeRegion *)ExtGetRegion(reg->treg_tile, reg->treg_dinfo);
fprintf(outFile, "\"%s\" ", extNodeName((LabRegion *)node));
/* First non-gate terminal */
node = (NodeRegion *)extTransRec.tr_termnode[0];
fprintf(outFile, "\"%s\"\n", extNodeName((LabRegion *)node));
continue;
}
/* Original-style FET record backward compatibility */ /* Original-style FET record backward compatibility */
if (devptr->exts_deviceClass != DEV_FET) if (devptr->exts_deviceClass != DEV_FET)
fprintf(outFile, "device "); fprintf(outFile, "device ");
@ -3938,11 +3947,9 @@ extTermAPFunc(tile, dinfo, eapd)
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/*ARGSUSED*/
int int
extTransPerimFunc(bp, cdata) extTransPerimFunc(bp)
Boundary *bp; Boundary *bp;
ClientData cdata; /* UNUSED */
{ {
TileType tinside, toutside, dinfo; TileType tinside, toutside, dinfo;
Tile *tile; Tile *tile;
@ -4218,13 +4225,11 @@ extTransPerimFunc(bp, cdata)
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/*ARGSUSED*/
int int
extAnnularTileFunc(tile, dinfo, pNum, arg) extAnnularTileFunc(tile, dinfo, pNum)
Tile *tile; Tile *tile;
TileType dinfo; TileType dinfo;
int pNum; int pNum;
FindRegion *arg; /* UNUSED */
{ {
TileTypeBitMask mask; TileTypeBitMask mask;
TileType loctype; TileType loctype;
@ -4270,13 +4275,11 @@ extAnnularTileFunc(tile, dinfo, pNum, arg)
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/*ARGSUSED*/
int int
extResistorTileFunc(tile, dinfo, pNum, arg) extResistorTileFunc(tile, dinfo, pNum)
Tile *tile; Tile *tile;
TileType dinfo; TileType dinfo;
int pNum; int pNum;
FindRegion *arg; /* UNUSED */
{ {
TileTypeBitMask mask; TileTypeBitMask mask;
TileType loctype; TileType loctype;

View File

@ -76,19 +76,18 @@ void extHeader();
*/ */
Plane * Plane *
ExtCell(def, outName, isTop) ExtCell(def, outName, doLength)
CellDef *def; /* Cell being extracted */ CellDef *def; /* Cell being extracted */
char *outName; /* Name of output file; if NULL, derive from def name */ char *outName; /* Name of output file; if NULL, derive from def name */
bool isTop; /* If TRUE, cell is the top level cell */ bool doLength; /* If TRUE, extract pathlengths from drivers to
* receivers (the names are stored in ExtLength.c).
* Should only be TRUE for the root cell in a
* hierarchy.
*/
{ {
char *filename; char *filename;
FILE *f = NULL; FILE *f = NULL;
Plane *savePlane; Plane *savePlane;
bool noextract;
/* If marked abstract, then don't extract the cell */
DBPropGet(def, "noextract", &noextract);
if (noextract) return extPrepSubstrate(def);
/* Incremental extraction: If the cell is marked for no extraction, /* Incremental extraction: If the cell is marked for no extraction,
* then just prepare the substrate plane and return it to the caller. * then just prepare the substrate plane and return it to the caller.
@ -112,7 +111,7 @@ ExtCell(def, outName, isTop)
} }
extNumErrors = extNumWarnings = 0; extNumErrors = extNumWarnings = 0;
savePlane = extCellFile(def, f, isTop); savePlane = extCellFile(def, f, doLength);
if (f != NULL) fclose(f); if (f != NULL) fclose(f);
if (extNumErrors > 0 || extNumWarnings > 0) if (extNumErrors > 0 || extNumWarnings > 0)
@ -472,10 +471,13 @@ ExtRevertSubstrate(def, savePlane)
*/ */
Plane * Plane *
extCellFile(def, f, isTop) extCellFile(def, f, doLength)
CellDef *def; /* Def to be extracted */ CellDef *def; /* Def to be extracted */
FILE *f; /* Output to this file */ FILE *f; /* Output to this file */
bool isTop; /* TRUE if the cell is the top level cell */ bool doLength; /* TRUE if we should extract driver-receiver path
* length information for this cell (see ExtCell
* for more details).
*/
{ {
NodeRegion *reg; NodeRegion *reg;
Plane *saveSub; Plane *saveSub;
@ -486,19 +488,8 @@ extCellFile(def, f, isTop)
/* If "extract do unique" was specified, then make labels in the /* If "extract do unique" was specified, then make labels in the
* cell unique. * cell unique.
*/ */
if (ExtOptions & EXT_DOUNIQUE) if (ExtOptions & EXT_DOUNIQUE)
{ extUniqueCell(def, EXT_UNIQ_TEMP);
if (ExtOptions & EXT_DOUNIQNOTOPPORTS)
{
if (isTop)
extUniqueCell(def, EXT_UNIQ_TEMP_NOPORTS);
else
extUniqueCell(def, EXT_UNIQ_TEMP);
}
else
extUniqueCell(def, EXT_UNIQ_TEMP);
}
/* Prep any isolated substrate areas */ /* Prep any isolated substrate areas */
if (ExtOptions & EXT_DOEXTRESIST) if (ExtOptions & EXT_DOEXTRESIST)
@ -528,7 +519,7 @@ extCellFile(def, f, isTop)
ExtResetTiles(def, CLIENTDEFAULT); ExtResetTiles(def, CLIENTDEFAULT);
/* Final pass: extract length information if desired */ /* Final pass: extract length information if desired */
if (!SigInterruptPending && isTop && (ExtOptions & EXT_DOLENGTH)) if (!SigInterruptPending && doLength && (ExtOptions & EXT_DOLENGTH))
extLength(extParentUse, f); extLength(extParentUse, f);
UndoEnable(); UndoEnable();

View File

@ -281,13 +281,6 @@ extHierSubstrate(ha, use, x, y)
nn->nn_next = node2->node_names->nn_next; nn->nn_next = node2->node_names->nn_next;
node2->node_names->nn_next = node1->node_names; node2->node_names->nn_next = node1->node_names;
node2->node_len += node1->node_len; node2->node_len += node1->node_len;
if (node2->node_ports)
{
ExtConnList *nport;
for (nport = node2->node_ports; nport && nport->r_next;
nport = nport->r_next);
if (nport) nport->r_next = node1->node_ports;
}
freeMagic((char *)node1); freeMagic((char *)node1);
} }
else else
@ -301,13 +294,6 @@ extHierSubstrate(ha, use, x, y)
nn->nn_next = node1->node_names; nn->nn_next = node1->node_names;
node1->node_names = node2->node_names; node1->node_names = node2->node_names;
node1->node_len += node2->node_len; node1->node_len += node2->node_len;
if (node1->node_ports)
{
ExtConnList *nport;
for (nport = node1->node_ports; nport && nport->r_next;
nport = nport->r_next);
if (nport) nport->r_next = node2->node_ports;
}
freeMagic((char *)node2); freeMagic((char *)node2);
} }
} }
@ -513,13 +499,6 @@ extHierConnectFunc1(oneTile, dinfo, ha)
nn->nn_next = node2->node_names->nn_next; nn->nn_next = node2->node_names->nn_next;
node2->node_names->nn_next = node1->node_names; node2->node_names->nn_next = node1->node_names;
node2->node_len += node1->node_len; node2->node_len += node1->node_len;
if (node2->node_ports)
{
ExtConnList *nport;
for (nport = node2->node_ports; nport && nport->r_next;
nport = nport->r_next);
if (nport) nport->r_next = node1->node_ports;
}
freeMagic((char *) node1); freeMagic((char *) node1);
} }
else else
@ -535,13 +514,6 @@ extHierConnectFunc1(oneTile, dinfo, ha)
nn->nn_next = node1->node_names; nn->nn_next = node1->node_names;
node1->node_names = node2->node_names; node1->node_names = node2->node_names;
node1->node_len += node2->node_len; node1->node_len += node2->node_len;
if (node1->node_ports)
{
ExtConnList *nport;
for (nport = node1->node_ports; nport && nport->r_next;
nport = nport->r_next);
if (nport) nport->r_next = node2->node_ports;
}
freeMagic((char *) node2); freeMagic((char *) node2);
} }
} }
@ -551,48 +523,6 @@ extHierConnectFunc1(oneTile, dinfo, ha)
} }
/* /*
*------------------------------------------------------------------------
*
* extHierFindTopNode --
*
* Simple callback function used in extHierConnectFunc2() to retrieve
* the node name of a node in the CellDef being extracted at a specific
* point. If there is no node at that point (indicating that there is
* paint in a subcell at that location but no paint in the top level
* cell) then return NULL.
*
* Returns:
* 1 if a node is found, otherwise 0 to keep the search going.
*
* Side effects:
* A pointer to the node is returned in the clientData field.
*
*------------------------------------------------------------------------
*/
int
extHierFindTopNode(Tile *tile,
TileType dinfo,
ExtRegion **nreg)
{
ExtRegion *tireg;
tireg = (ExtRegion *)ExtGetRegion(tile, dinfo);
if ((ClientData)tireg == CLIENTDEFAULT)
{
*nreg = (ExtRegion *)0;
return 0;
}
else
{
*nreg = tireg;
return 1;
}
}
/*
*------------------------------------------------------------------------
*
* extHierConnectFunc2 -- * extHierConnectFunc2 --
* *
* Called once for each tile 'cum' in extHierCumFlat->et_use->cu_def * Called once for each tile 'cum' in extHierCumFlat->et_use->cu_def
@ -608,8 +538,6 @@ extHierFindTopNode(Tile *tile,
* if the types of ha->hierOneTile and 'cum' connect. * if the types of ha->hierOneTile and 'cum' connect.
* Otherwise, if the tiles actually overlap (as opposed * Otherwise, if the tiles actually overlap (as opposed
* to merely abut), mark it with feedback as an error. * to merely abut), mark it with feedback as an error.
*
*------------------------------------------------------------------------
*/ */
int int
@ -680,53 +608,6 @@ extHierConnectFunc2(cum, dinfo, ha)
if (node1 != node2) if (node1 != node2)
{ {
ExtConnList *newport;
int pNum;
if (ExtOptions & EXT_DOEXTRESIST)
{
NodeRegion *topnode = NULL;
/* Record the area of connection for both nodes in their
* respective coordinate systems, and the name of the
* cell use to which the connection is made.
*/
newport = (ExtConnList *)mallocMagic(sizeof(ExtConnList));
newport->r_r = r;
newport->r_type = ttype;
newport->r_useid = ha->ha_subUse->cu_id;
/* Find a node at the given location in et_lookNames (the
* original CellDef being extracted). If there is no node
* in the def itself then the entry is NULL.
*/
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
if (TTMaskHasType(&DBPlaneTypes[pNum], ttype))
{
/* Make sure that the rect is not zero area */
if (r.r_xtop == r.r_xbot)
{
r.r_xtop++;
r.r_xbot--;
}
if (r.r_ytop == r.r_ybot)
{
r.r_ytop++;
r.r_ybot--;
}
DBSrPaintArea((Tile *)NULL,
ha->ha_cumFlat.et_lookNames->cd_planes[pNum],
&r, &DBConnectTbl[ttype], extHierFindTopNode,
(ClientData)PTR2CD(&topnode));
newport->r_upnode = PTR2CD(topnode);
newport->r_downnode = PTR2CD(node2->node_names);
}
}
}
if (node1->node_len < node2->node_len) if (node1->node_len < node2->node_len)
{ {
/* /*
@ -741,12 +622,6 @@ extHierConnectFunc2(cum, dinfo, ha)
node2->node_names->nn_next = node1->node_names; node2->node_names->nn_next = node1->node_names;
node2->node_len += node1->node_len; node2->node_len += node1->node_len;
freeMagic((char *) node1); freeMagic((char *) node1);
if (ExtOptions & EXT_DOEXTRESIST)
{
newport->r_next = node2->node_ports;
node2->node_ports = newport;
}
} }
else else
{ {
@ -762,12 +637,6 @@ extHierConnectFunc2(cum, dinfo, ha)
node1->node_names = node2->node_names; node1->node_names = node2->node_names;
node1->node_len += node2->node_len; node1->node_len += node2->node_len;
freeMagic((char *) node2); freeMagic((char *) node2);
if (ExtOptions & EXT_DOEXTRESIST)
{
newport->r_next = node1->node_ports;
node1->node_ports = newport;
}
} }
} }
} }
@ -864,13 +733,6 @@ extHierConnectFunc3(cum, dinfo, ha)
nn->nn_next = node2->node_names->nn_next; nn->nn_next = node2->node_names->nn_next;
node2->node_names->nn_next = node1->node_names; node2->node_names->nn_next = node1->node_names;
node2->node_len += node1->node_len; node2->node_len += node1->node_len;
if (node2->node_ports)
{
ExtConnList *nport;
for (nport = node2->node_ports; nport && nport->r_next;
nport = nport->r_next);
if (nport) nport->r_next = node1->node_ports;
}
freeMagic((char *) node1); freeMagic((char *) node1);
} }
else else
@ -886,13 +748,6 @@ extHierConnectFunc3(cum, dinfo, ha)
nn->nn_next = node1->node_names; nn->nn_next = node1->node_names;
node1->node_names = node2->node_names; node1->node_names = node2->node_names;
node1->node_len += node2->node_len; node1->node_len += node2->node_len;
if (node1->node_ports)
{
ExtConnList *nport;
for (nport = node1->node_ports; nport && nport->r_next;
nport = nport->r_next);
if (nport) nport->r_next = node2->node_ports;
}
freeMagic((char *) node2); freeMagic((char *) node2);
} }
} }
@ -1061,7 +916,6 @@ extOutputConns(table, outf)
NodeName *nfirst; NodeName *nfirst;
HashSearch hs; HashSearch hs;
HashEntry *he; HashEntry *he;
ExtConnList *nport, *npnext;
HashStartSearch(&hs); HashStartSearch(&hs);
while ((he = HashNext(table, &hs))) while ((he = HashNext(table, &hs)))
@ -1094,6 +948,7 @@ extOutputConns(table, outf)
node->node_pa[n].pa_area, node->node_pa[n].pa_area,
node->node_pa[n].pa_perim); node->node_pa[n].pa_perim);
fprintf(outf, "\n"); fprintf(outf, "\n");
nn->nn_node = (Node *) NULL; /* Processed */ nn->nn_node = (Node *) NULL; /* Processed */
/* Subsequent merges */ /* Subsequent merges */
@ -1105,23 +960,6 @@ extOutputConns(table, outf)
} }
} }
nn->nn_node = (Node *) NULL; nn->nn_node = (Node *) NULL;
for (nport = node->node_ports; nport;)
{
LabRegion *lreg = (LabRegion *)CD2PTR(nport->r_upnode);
NodeName *nn2 = (NodeName *)CD2PTR(nport->r_downnode);
npnext = nport->r_next;
/* Output port positions */
fprintf(outf, "connect %d %d %d %d %s \"%s\" \"%s\"\n",
nport->r_r.r_xbot, nport->r_r.r_ybot,
nport->r_r.r_xtop, nport->r_r.r_ytop,
DBTypeShortName(nport->r_type),
(lreg == (LabRegion *)NULL) ? "None" :
extNodeName(lreg),
(nn2) ? nn2->nn_name : "None");
freeMagic((char *)nport);
nport = npnext;
}
freeMagic((char *) node); freeMagic((char *) node);
} }
freeMagic((char *) nfirst); freeMagic((char *) nfirst);
@ -1167,7 +1005,6 @@ extHierNewNode(he)
node->node_names = nn; node->node_names = nn;
node->node_cap = (CapValue) 0; node->node_cap = (CapValue) 0;
node->node_len = 1; node->node_len = 1;
node->node_ports = (ExtConnList *)NULL;
for (n = 0; n < nclasses; n++) for (n = 0; n < nclasses; n++)
node->node_pa[n].pa_perim = node->node_pa[n].pa_area = 0; node->node_pa[n].pa_perim = node->node_pa[n].pa_area = 0;
HashSetValue(he, (char *) nn); HashSetValue(he, (char *) nn);

View File

@ -272,7 +272,7 @@ extInterSubtreeElement(use, trans, x, y, r)
int int
extInterSubtreeTile(tile, dinfo, cxp) extInterSubtreeTile(tile, dinfo, cxp)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */ TileType dinfo;
TreeContext *cxp; TreeContext *cxp;
{ {
SearchContext newscx; SearchContext newscx;
@ -343,9 +343,8 @@ extInterOverlapSubtree(scx)
*/ */
int int
extInterOverlapTile(tile, dinfo, cxp) extInterOverlapTile(tile, cxp)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */
TreeContext *cxp; TreeContext *cxp;
{ {
SearchContext *scx = cxp->tc_scx; SearchContext *scx = cxp->tc_scx;

View File

@ -85,7 +85,7 @@ typedef struct _linkedDef {
Stack *extDefStack; Stack *extDefStack;
/* Forward declarations */ /* Forward declarations */
int extDefInitFunc(CellDef *, ClientData); /* UNUSED */ int extDefInitFunc();
void extDefPush(); void extDefPush();
void extDefIncremental(); void extDefIncremental();
void extParents(); void extParents();
@ -395,11 +395,9 @@ ExtAll(rootUse)
* cell defs, in preparation for extracting a subtree * cell defs, in preparation for extracting a subtree
* rooted at a particular def. * rooted at a particular def.
*/ */
/*ARGSUSED*/
int int
extDefInitFunc(def, cdata) extDefInitFunc(def)
CellDef *def; CellDef *def;
ClientData cdata; /* UNUSED */
{ {
def->cd_client = (ClientData) 0; def->cd_client = (ClientData) 0;
return (0); return (0);
@ -473,19 +471,6 @@ ExtUnique(rootUse, option)
/* Fix up bounding boxes if they've changed */ /* Fix up bounding boxes if they've changed */
DBFixMismatch(); DBFixMismatch();
/* Because the "extract unique" does the same thing as "extract do unique"
* but the options may be different, disable "extract do unique" when
* "extract unique" is run, on the assumption that no user would
* intentionally use both methods. If "do unique" was set and got
* disabled, then flag a warning.
*/
if (ExtOptions & EXT_DOUNIQUE)
{
ExtOptions &= ~EXT_DOUNIQUE;
TxPrintf("Warning: Extract option \"do unique\" disabled because "
"\"extract unique\" was run.\n");
}
/* Mark all defs as being unvisited */ /* Mark all defs as being unvisited */
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0); (void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);

View File

@ -54,14 +54,12 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
/* C99 compat */ /* C99 compat */
#include "drc/drc.h" #include "drc/drc.h"
/*
* If "exactinteractions" is defined, use an experimental algorithm
* for finding exact interaction areas. Currently it doesn't work
* too well, so it is disabled.
*/
/* #define exactinteractions */
#ifdef exactinteractions #ifdef exactinteractions
/*
* If "exactinteractions" is defined, we use an experimental algorithm
* for finding exact interaction areas. Currently it doesn't work too
* well, so we leave it turned off.
*/
int ExtInterBloat = 10; int ExtInterBloat = 10;
#endif /* exactinteractions */ #endif /* exactinteractions */
@ -176,10 +174,8 @@ extSubtree(parentUse, reg, f)
int cuts, totcuts; int cuts, totcuts;
float pdone, plast; float pdone, plast;
SearchContext scx; SearchContext scx;
int savedDisplayStatus;
/* Use the display timer to force a 5-second progress check */ /* Use the display timer to force a 5-second progress check */
savedDisplayStatus = GrDisplayStatus;
GrDisplayStatus = DISPLAY_IN_PROGRESS; GrDisplayStatus = DISPLAY_IN_PROGRESS;
SigSetTimer(5); /* Print at 5-second intervals */ SigSetTimer(5); /* Print at 5-second intervals */
@ -352,7 +348,7 @@ done:
/* Output connections and node adjustments */ /* Output connections and node adjustments */
extOutputConns(&ha.ha_connHash, f); extOutputConns(&ha.ha_connHash, f);
HashKill(&ha.ha_connHash); HashKill(&ha.ha_connHash);
GrDisplayStatus = savedDisplayStatus; GrDisplayStatus = DISPLAY_IDLE;
SigRemoveTimer(); SigRemoveTimer();
/* Clear the CU_SUB_EXTRACTED flag from all children instances */ /* Clear the CU_SUB_EXTRACTED flag from all children instances */

View File

@ -288,11 +288,9 @@ ExtTimes(rootUse, f)
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/*ARGSUSED*/
int int
extTimesInitFunc(use, cdata) extTimesInitFunc(use)
CellUse *use; CellUse *use;
ClientData cdata; /* UNUSED */
{ {
CellDef *def = use->cu_def; CellDef *def = use->cu_def;
struct cellStats *cs; struct cellStats *cs;

View File

@ -66,8 +66,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
* label. This way, the unique label form can be used by the * label. This way, the unique label form can be used by the
* extraction code but labels (and port indexes) can be reverted * extraction code but labels (and port indexes) can be reverted
* afterward, and no permanent change is made to the circuit. * afterward, and no permanent change is made to the circuit.
* Option EXT_UNIQ_TEMP_NOPORTS is a combination of EXT_UNIQ_TEMP and
* EXT_UNIQ_NOPORTS.
* *
* Results: * Results:
* Returns the number of warnings generated. * Returns the number of warnings generated.
@ -228,9 +226,8 @@ extMakeUnique(def, ll, lreg, lregList, labelHash, option)
text = ll->ll_label->lab_text; text = ll->ll_label->lab_text;
if (option == EXT_UNIQ_ALL || option == EXT_UNIQ_TEMP) if (option == EXT_UNIQ_ALL || option == EXT_UNIQ_TEMP)
goto makeUnique; goto makeUnique;
else if ((option == EXT_UNIQ_NOPORTS || option == EXT_UNIQ_NOTOPPORTS || else if ((option == EXT_UNIQ_NOPORTS || option == EXT_UNIQ_NOTOPPORTS)
option == EXT_UNIQ_TEMP_NOPORTS) && && !(ll->ll_label->lab_flags & PORT_DIR_MASK))
!(ll->ll_label->lab_flags & PORT_DIR_MASK))
goto makeUnique; goto makeUnique;
cpend = strchr(text, '\0'); cpend = strchr(text, '\0');
@ -329,8 +326,7 @@ makeUnique:
saveLab = *lab; saveLab = *lab;
/* Flag this label as having been modified */ /* Flag this label as having been modified */
if ((option == EXT_UNIQ_TEMP) || (option == EXT_UNIQ_TEMP_NOPORTS)) if (option == EXT_UNIQ_TEMP) flags |= LABEL_UNIQUE;
flags |= LABEL_UNIQUE;
DBRemoveLabel(def, lab); DBRemoveLabel(def, lab);
DBPutFontLabel(def, &saveLab.lab_rect, DBPutFontLabel(def, &saveLab.lab_rect,

View File

@ -71,12 +71,11 @@ 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_DOUNIQUE 0x100 /* Force unique nodes during extraction */ #define EXT_DOALL 0x03f /* ALL OF THE ABOVE */
#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 */
#define EXT_DOUNIQNOTOPPORTS 0x400 /* Ignore top cell ports w/EXT_DOUNIQUE */
extern int ExtOptions; /* Bitmask of above */ extern int ExtOptions; /* Bitmask of above */
extern char *ExtLocalPath; /* If non-NULL, location to write .ext files */ extern char *ExtLocalPath; /* If non-NULL, location to write .ext files */
@ -87,7 +86,6 @@ extern char *ExtLocalPath; /* If non-NULL, location to write .ext files */
#define EXT_UNIQ_NOPORTS 2 #define EXT_UNIQ_NOPORTS 2
#define EXT_UNIQ_NOTOPPORTS 3 #define EXT_UNIQ_NOTOPPORTS 3
#define EXT_UNIQ_TEMP 4 /* Used only with "EXT_DOUNIQUE" */ #define EXT_UNIQ_TEMP 4 /* Used only with "EXT_DOUNIQUE" */
#define EXT_UNIQ_TEMP_NOPORTS 5 /* Used only with "EXT_DOUNIQUE" */
extern bool ExtTechLine(); extern bool ExtTechLine();
extern void ExtTechInit(); extern void ExtTechInit();

View File

@ -981,7 +981,6 @@ typedef struct node
* in the list is the "official" node name. * in the list is the "official" node name.
*/ */
int node_len; /* Number of entries in node_names */ int node_len; /* Number of entries in node_names */
ExtConnList *node_ports; /* List of areas that connect to other cells */
CapValue node_cap; /* Capacitance to substrate */ CapValue node_cap; /* Capacitance to substrate */
PerimArea node_pa[1]; /* Dummy; each node actually has PerimArea node_pa[1]; /* Dummy; each node actually has
* ExtCurStyle->exts_numResistClasses * ExtCurStyle->exts_numResistClasses

View File

@ -61,74 +61,6 @@ nullDoNothing()
{ {
} }
/*
* Typed no-op stubs for WASM call_indirect type compatibility.
* WASM enforces exact type signatures at indirect call sites; assigning
* a 0-arg nullDoNothing to a pointer called with arguments causes a
* "null function or function signature mismatch" trap. These stubs
* have the correct arity so the WASM type check passes.
*/
/* 1-argument stub (int or pointer) */
static void
nullDoNothingI(int a)
{
(void) a;
}
/* 2-argument stub */
static void
nullDoNothingII(int a, int b)
{
(void) a; (void) b;
}
/* 4-argument stub */
static void
nullDoNothingIIII(int a, int b, int c, int d)
{
(void) a; (void) b; (void) c; (void) d;
}
/* 7-argument stub (for grFontTextPtr) */
static void
nullDoNothingIIIIIII(int a, int b, int c, int d, int e, int f, int g)
{
(void) a; (void) b; (void) c; (void) d; (void) e; (void) f; (void) g;
}
/* bool-returning stubs — return FALSE so callers treat backing store / window
* creation as unavailable, which is correct for the headless null driver. */
static bool
nullReturnFalseI(int a)
{
(void) a;
return FALSE;
}
static bool
nullReturnFalseII(int a, int b)
{
(void) a; (void) b;
return FALSE;
}
/* 3-argument bool-returning stub (for grDrawGridPtr) */
static bool
nullReturnFalseIII(int a, int b, int c)
{
(void) a; (void) b; (void) c;
return FALSE;
}
/* 1-argument int-returning stub (for GrWindowIdPtr) */
static int
nullReturnZeroI(int a)
{
(void) a;
return 0;
}
/* /*
*--------------------------------------------------------- *---------------------------------------------------------
* *
@ -314,10 +246,8 @@ nullSetDisplay(dispType, outFileName, mouseFileName)
{ {
TxPrintf("Using NULL graphics device.\n"); TxPrintf("Using NULL graphics device.\n");
#ifndef __EMSCRIPTEN__
TxAdd1InputDevice(fileno(stdin), nullStdin, (ClientData) NULL); TxAdd1InputDevice(fileno(stdin), nullStdin, (ClientData) NULL);
if (TxStdinIsatty) SigWatchFile(fileno(stdin), "stdin"); if (TxStdinIsatty) SigWatchFile(fileno(stdin), "stdin");
#endif
/* Set up the procedure values in the indirection table. */ /* Set up the procedure values in the indirection table. */
@ -329,49 +259,25 @@ nullSetDisplay(dispType, outFileName, mouseFileName)
GrEnableTabletPtr = nullDoNothing; GrEnableTabletPtr = nullDoNothing;
GrDisableTabletPtr = nullDoNothing; GrDisableTabletPtr = nullDoNothing;
GrSetCursorPtr = (void (*)()) nullDoNothingI; GrSetCursorPtr = nullDoNothing;
GrTextSizePtr = NullTextSize; GrTextSizePtr = NullTextSize;
GrDrawGlyphPtr = (void (*)()) nullDoNothingII; GrDrawGlyphPtr = nullDoNothing;
GrBitBltPtr = NullBitBlt; GrBitBltPtr = NullBitBlt;
GrReadPixelPtr = nullReturnZero; GrReadPixelPtr = nullReturnZero;
GrFlushPtr = nullDoNothing; GrFlushPtr = nullDoNothing;
/* Window management — null driver has no real windows; return FALSE so
* callers know the operation wasn't performed. */
GrCreateWindowPtr = NULL; /* headless: skip OS window creation, WindCreate stays OK */
GrDeleteWindowPtr = (void (*)()) nullDoNothingI;
GrConfigureWindowPtr = (void (*)()) nullDoNothingI;
GrOverWindowPtr = (void (*)()) nullDoNothingI;
GrUnderWindowPtr = (void (*)()) nullDoNothingI;
GrDamagedPtr = nullDoNothing;
GrUpdateIconPtr = (void (*)()) nullDoNothingII;
GrEventPendingPtr = (bool (*)()) nullReturnFalse;
GrWindowIdPtr = (int (*)()) nullReturnZeroI;
GrWindowNamePtr = NULL; /* protected by callers */
GrGetCursorPosPtr = (bool (*)()) nullReturnFalseII;
GrGetCursorRootPosPtr = (bool (*)()) nullReturnFalseII;
/* Backing store — not available in headless mode */
GrGetBackingStorePtr = (bool (*)()) nullReturnFalseII;
GrScrollBackingStorePtr = (bool (*)()) nullReturnFalseII;
GrPutBackingStorePtr = (void (*)()) nullDoNothingII;
GrFreeBackingStorePtr = (void (*)()) nullDoNothingI;
GrCreateBackingStorePtr = (void (*)()) nullDoNothingI;
/* local indirections */ /* local indirections */
grSetSPatternPtr = (void (*)()) nullDoNothingII; grSetSPatternPtr = nullDoNothing;
grPutTextPtr = (void (*)()) nullDoNothingIIII; grPutTextPtr = nullDoNothing;
grFontTextPtr = (void (*)()) nullDoNothingIIIIIII; grFontTextPtr = nullDoNothing;
grDefineCursorPtr = (void (*)()) nullDoNothingI; grDefineCursorPtr = nullDoNothing;
grFreeCursorPtr = (void (*)()) nullDoNothingI; grDrawGridPtr = nullReturnFalse;
grDrawGridPtr = (bool (*)()) nullReturnFalseIII; grDrawLinePtr = nullDoNothing;
grDrawLinePtr = (void (*)()) nullDoNothingIIII; grSetWMandCPtr = nullDoNothing;
grSetWMandCPtr = (void (*)()) nullDoNothingII; grFillRectPtr = nullDoNothing;
grFillRectPtr = (void (*)()) nullDoNothingI; grSetStipplePtr = nullDoNothing;
grFillPolygonPtr = (void (*)()) nullDoNothingII; grSetLineStylePtr = nullDoNothing;
grSetStipplePtr = (void (*)()) nullDoNothingI; grSetCharSizePtr = nullDoNothing;
grSetLineStylePtr = (void (*)()) nullDoNothingI;
grSetCharSizePtr = (void (*)()) nullDoNothingI;
GrScreenRect.r_xtop = 511; GrScreenRect.r_xtop = 511;
GrScreenRect.r_ytop = 483; GrScreenRect.r_ytop = 483;

View File

@ -4,14 +4,10 @@
MODULE = magic MODULE = magic
MAGICDIR = .. MAGICDIR = ..
SRCS = magicTop.c
include ${MAGICDIR}/defs.mak include ${MAGICDIR}/defs.mak
SRCS = magicTop.c
ifeq (${MAKE_WASM},1)
SRCS += magicWasm.c
endif
EXTRA_LIBS = ${MAGICDIR}/bplane/libbplane.o \ EXTRA_LIBS = ${MAGICDIR}/bplane/libbplane.o \
${MAGICDIR}/cmwind/libcmwind.o \ ${MAGICDIR}/cmwind/libcmwind.o \
${MAGICDIR}/commands/libcommands.o \ ${MAGICDIR}/commands/libcommands.o \
@ -41,18 +37,7 @@ LIBS += ${GR_LIBS} ${READLINE_LIBS} -lm ${LD_EXTRA_LIBS} \
${OA_LIBS} ${ZLIB_FLAG} ${TOP_EXTRA_LIBS} ${OA_LIBS} ${ZLIB_FLAG} ${TOP_EXTRA_LIBS}
CLEANS += tclmagic${SHDLIB_EXT} libtclmagic${SHDLIB_EXT}.a proto.magicrc CLEANS += tclmagic${SHDLIB_EXT} libtclmagic${SHDLIB_EXT}.a proto.magicrc
ifeq (${MAKE_WASM},1)
magic: magic.js
magic.js: lib${MODULE}.o ${EXTRA_LIBS}
@echo --- building main magic WASM
${RM} magic.js magic.wasm
${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} lib${MODULE}.o ${EXTRA_LIBS} -o magic.js ${LIBS}
endif
main: magic proto.magicrc main: magic proto.magicrc
ifeq (${MAKE_WASM},1)
@bash ${MAGICDIR}/toolchains/emscripten/post-build.sh magic.js magic.wasm
endif
tcl-main: tclmagic${SHDLIB_EXT} proto.magicrc tcl-main: tclmagic${SHDLIB_EXT} proto.magicrc

View File

@ -1,122 +0,0 @@
/*
* magicWasm.c --
*
* Headless Emscripten entry points for running Magic without a
* terminal-driven event loop.
*/
#include <stdio.h>
#include <stdlib.h>
#include "utils/main.h"
#include "utils/magic.h"
#include "utils/paths.h"
#include "textio/textio.h"
#include "textio/txcommands.h"
#include "utils/utils.h"
#include "windows/windows.h"
#include "graphics/graphics.h"
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#else
#define EMSCRIPTEN_KEEPALIVE
#endif
static int
magicWasmEnsureCadRoot(void)
{
if (getenv("CAD_ROOT") == NULL)
{
if (setenv("CAD_ROOT", "/", 0) != 0)
{
TxError("Failed to set CAD_ROOT for the WASM runtime.\n");
return -1;
}
}
return 0;
}
EMSCRIPTEN_KEEPALIVE int
magic_wasm_init(void)
{
static char *argv[] = {
"magic",
"-d",
"null",
"-T",
"minimum",
NULL
};
if (magicWasmEnsureCadRoot() != 0)
return -1;
return magicMainInit(5, argv);
}
EMSCRIPTEN_KEEPALIVE int
magic_wasm_run_command(const char *command)
{
int status;
status = magic_wasm_init();
if (status != 0)
return status;
if ((command == NULL) || (*command == '\0'))
return 0;
/* Set the current point to the center of the screen so that
* WindSendCommand routes the command to the layout window client
* (not the window-management border client which handles point 0,0).
*/
TxSetPoint(GrScreenRect.r_xtop / 2, GrScreenRect.r_ytop / 2,
WIND_UNKNOWN_WINDOW);
return TxDispatchString(command, FALSE);
}
EMSCRIPTEN_KEEPALIVE int
magic_wasm_source_file(const char *path)
{
FILE *f;
int status;
status = magic_wasm_init();
if (status != 0)
return status;
if ((path == NULL) || (*path == '\0'))
return -1;
f = PaOpen((char *)path, "r", (char *)NULL, ".", (char *)NULL,
(char **)NULL);
if (f == NULL)
{
TxError("Unable to open command file \"%s\".\n", path);
return -1;
}
/* Set the current point to the centre of the screen so that
* WindSendCommand routes all commands from the file to the layout
* window client, just as magic_wasm_run_command does for single
* commands. Without this, commands arrive with point (0,0) and
* end up in the border/windClient context where most commands are
* unknown.
*/
TxSetPoint(GrScreenRect.r_xtop / 2, GrScreenRect.r_ytop / 2,
WIND_UNKNOWN_WINDOW);
TxDispatch(f);
fclose(f);
return 0;
}
EMSCRIPTEN_KEEPALIVE void
magic_wasm_update(void)
{
if (magic_wasm_init() == 0)
WindUpdate();
}

View File

@ -26,19 +26,17 @@ 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 (P000) def /PattName (P0) def
/tmpStr 3 string def /tmpStr 1 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 /dp { StipplePattern begin dup 30 tmpStr cvrs PattName exch 1 exch
dup 10 tmpStr cvrs /num exch def putinterval PattName cvn dup Encoding exch 4 -1 roll exch put exch
PattName 1 num putinterval store end } def
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
@ -70,3 +68,4 @@ 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

6
npm/.gitignore vendored
View File

@ -1,6 +0,0 @@
magic.js
magic.wasm
*.tgz
node_modules/
package-lock.json
examples/output/

View File

@ -1,10 +0,0 @@
Copyright (C) 1985, 1990 Regents of the University of California.
Permission to use, copy, modify, and distribute this
software and its documentation for any purpose and without
fee is hereby granted, provided that the above copyright
notice appear in all copies. The University of California
makes no representations about the suitability of this
software for any purpose. It is provided "as is" without
express or implied warranty. Export of this software outside
of the United States of America may require an export license.

View File

@ -1,153 +0,0 @@
# magic-vlsi-wasm
[Magic VLSI](http://opencircuitdesign.com/magic/) layout tool, compiled to
WebAssembly as a headless library. Runs in Node.js, browsers, and Web Workers
— no X11, no Tk, no native dependencies.
Use it to programmatically read and write `.mag`, `.gds`, `.cif`, `.ext`, and
SPICE netlists; run DRC; extract parasitics — anywhere JavaScript runs.
## Install
```bash
npm install magic-vlsi-wasm
```
Requires Node.js 18 or newer.
## Quick start
```js
import createMagic from 'magic-vlsi-wasm';
const { runCommand, FS } = await createMagic();
// Drop a layout into Magic's virtual filesystem
FS.mkdirTree('/work');
FS.writeFile('/work/inv.mag', layoutBytes);
// Run Magic commands — scmos is built into the WASM binary, no tech file needed
runCommand('tech load scmos');
runCommand('load /work/inv');
runCommand('gds write /work/inv');
// Read the result back out
const gdsBytes = FS.readFile('/work/inv.gds');
```
The `scmos` technology family (`scmos`, `minimum`, `nmos`, ...) is embedded in
the WASM binary and available out of the box — those names work without
writing any tech file. To use a custom technology, write its `.tech` file into
the VFS at `/magic/sys/current/<name>.tech` before calling `tech load <name>`.
## API
```ts
createMagic(options?): Promise<MagicInstance>
```
`options` is forwarded to the underlying Emscripten module. Useful keys:
| Key | Default | Purpose |
|--------------|------------------|---------|
| `wasmBinary` | fetched lazily | Pre-fetched ArrayBuffer of `magic.wasm` (skips a network round-trip in browsers) |
| `print` | `console.log` | Callback for each stdout line |
| `printErr` | `console.error` | Callback for each stderr line |
The returned `MagicInstance` exposes:
| Method | Description |
|---------------------------|-------------|
| `runCommand(cmd: string)` | Dispatch a single Magic command. Returns 0 on success. |
| `sourceFile(path: string)` | Execute a script from the virtual filesystem. Returns 0 on success, -1 if the file could not be opened. |
| `init()` | Force initialization. Idempotent — `runCommand` and `sourceFile` call it for you. |
| `update()` | Drive a display-update cycle. No-op in this headless build. |
| `FS` | Emscripten virtual filesystem. See the [Emscripten docs](https://emscripten.org/docs/api_reference/Filesystem-API.html). |
Full TypeScript types ship in [`index.d.ts`](index.d.ts).
### Low-level access
`createMagic()` is a thin convenience wrapper over the underlying Emscripten
module. If you need direct access — for example to call `cwrap` yourself or
to drive `magic_wasm_init` manually — import the module factory directly:
```js
import createMagicModule from 'magic-vlsi-wasm/magic.js';
const module = await createMagicModule({ wasmBinary, print, printErr });
module._magic_wasm_init();
const run = module.cwrap('magic_wasm_run_command', 'number', ['string']);
run('tech load scmos');
```
The bundled examples use this lower-level path together with a small helper
class ([`examples/helpers.js`](examples/helpers.js)) that adds a
`runScript(text)` convenience method — it splits a multi-line Tcl block,
strips comments, and dispatches each line via `runCommand`. Useful when you
have a script as a string rather than as a file in the VFS.
## Examples
The package ships runnable examples for the most common workflows. After
installing, run one directly:
```bash
node node_modules/magic-vlsi-wasm/examples/extract.js
node node_modules/magic-vlsi-wasm/examples/gds.js
node node_modules/magic-vlsi-wasm/examples/drc.js
node node_modules/magic-vlsi-wasm/examples/cif.js
```
Or, when developing inside this repo:
```bash
npm test # full suite (extract, gds, drc, cif)
npm run example # extract.js — RC extraction + SPICE netlist
npm run test:gds # GDS write only
npm run test:drc # DRC check only
npm run test:cif # CIF write only
```
Each example loads the bundled [`min.mag`](examples/min.mag) (a small NPN
transistor cell from Magic's own scmos test suite) under the built-in `scmos`
technology — no external tech file required. See [`examples/`](examples/) for
the source; [`example.js`](examples/example.js) is the simplest entry point
(GDS → CIF conversion in ~40 lines).
## Build from source
If you want to rebuild the WASM module yourself, see
[`toolchains/emscripten/README.md`](../toolchains/emscripten/README.md).
The short version:
```bash
bash npm/build.sh # debug build, copies magic.js + magic.wasm into npm/
bash npm/build.sh --release # optimized
bash npm/build.sh --test # build + run tests
bash npm/build.sh --pack # build + produce magic-vlsi-wasm-<version>.tgz
```
You will need an activated [emsdk](https://emscripten.org/docs/getting_started/downloads.html)
checkout (Magic pins emsdk `3.1.56` — see the comment in `npm/build.sh`).
## Limitations
- Headless only. There is no display driver, so commands that draw to a
window (`view`, `findbox`, interactive macros) are no-ops.
- WASM memory starts at 32 MB and grows as needed. Very large GDS imports
may need `INITIAL_MEMORY` bumped (rebuild required).
- Single-threaded. WASM modules are not thread-safe — create one instance
per worker.
## License
[HPND](LICENSE) — Copyright (C) 1985, 1990 Regents of the University of California.
### Bundled test layout
The example layout [`examples/min.mag`](examples/min.mag) is taken from
Magic's own scmos test suite ([`scmos/examples/bipolar/min.mag`](../scmos/examples/bipolar/min.mag))
and is included here as a runnable smoke test for the WASM build. The `scmos`
technology it targets is compiled into the WASM binary, so no external tech
file is shipped.

View File

@ -1,132 +0,0 @@
#!/usr/bin/env bash
# Build Magic WASM and copy artifacts into this npm/ directory.
#
# Usage:
# npm/build.sh [--release] [--test] [--pack]
#
# --release Omit debug symbols (-g).
# --test Run `npm run test` after copying artifacts.
# --pack Run `npm pack` after copying artifacts (and tests, if given).
#
# Requirements (must be on PATH or set via env vars before running):
# emcc / emmake / emconfigure — Emscripten compiler tools
# make, gcc — standard build tools
# node, npm — only required for --test / --pack
#
# Environment:
# EMSDK_DIR Path to an activated emsdk checkout.
# If set, emsdk_env.sh is sourced from there.
# If unset, emcc must already be on PATH (e.g. sourced externally).
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
OPT_RELEASE=0
OPT_TEST=0
OPT_PACK=0
for arg in "$@"; do
case "$arg" in
--release) OPT_RELEASE=1 ;;
--test) OPT_TEST=1 ;;
--pack) OPT_PACK=1 ;;
*) echo "Unknown option: $arg" >&2; exit 1 ;;
esac
done
# --- locate emscripten -------------------------------------------------------
if [ -n "${EMSDK_DIR:-}" ]; then
if [ ! -f "$EMSDK_DIR/emsdk_env.sh" ]; then
echo "Error: EMSDK_DIR is set to '$EMSDK_DIR' but emsdk_env.sh was not found there." >&2
exit 1
fi
# shellcheck source=/dev/null
source "$EMSDK_DIR/emsdk_env.sh"
else
if ! command -v emcc &>/dev/null; then
echo "Error: emcc not found on PATH and EMSDK_DIR is not set." >&2
echo " Either source emsdk_env.sh before running this script," >&2
echo " or set EMSDK_DIR to your emsdk checkout directory." >&2
exit 1
fi
fi
echo "Using emcc: $(command -v emcc)"
emcc --version | head -1
# --- portability helpers -----------------------------------------------------
# CPU count: Linux has nproc, macOS has sysctl, fall back to getconf.
ncpu() {
if command -v nproc &>/dev/null; then
nproc
elif [ "$(uname)" = "Darwin" ]; then
sysctl -n hw.ncpu
else
getconf _NPROCESSORS_ONLN 2>/dev/null || echo 1
fi
}
# Portable in-place sed (BSD sed on macOS disagrees with GNU on -i).
# Uses redirect-back instead of mv so the file's mode bits are preserved
# (configure must stay executable across build.sh invocations).
sed_strip_cr() {
local file=$1 tmp
tmp=$(mktemp)
sed 's/\r//' "$file" > "$tmp" && cat "$tmp" > "$file" && rm "$tmp"
}
# --- clean -------------------------------------------------------------------
cd "$REPO_ROOT"
# Only distclean if there's something to clean. A stale `|| true` here would
# hide real failures (e.g. broken toolchain) on a fresh checkout.
if [ -f defs.mak ]; then
emmake make distclean || true
fi
rm -f defs.mak database/database.h
# --- configure ---------------------------------------------------------------
# Strip Windows CRLF line endings (no-op on Linux-native files).
sed_strip_cr configure
find scripts/ -type f -print0 | while IFS= read -r -d '' f; do sed_strip_cr "$f"; done
if [ $OPT_RELEASE -eq 1 ]; then
EXTRA_CFLAGS=" -O2"
else
EXTRA_CFLAGS=" -g"
fi
CFLAGS="--std=c17 -D_DEFAULT_SOURCE=1 -DEMSCRIPTEN=1${EXTRA_CFLAGS}" \
emconfigure ./configure \
--without-cairo --without-opengl --without-x --without-tk --without-tcl \
--disable-readline --disable-compression \
--host=asmjs-unknown-emscripten \
--target=asmjs-unknown-emscripten
cat toolchains/emscripten/defs.mak >> defs.mak
# --- build -------------------------------------------------------------------
emmake make depend
emmake make -j"$(ncpu)" modules libs
emmake make techs
emmake make mains
# --- copy artifacts ----------------------------------------------------------
cp magic/magic.js "$SCRIPT_DIR/"
cp magic/magic.wasm "$SCRIPT_DIR/"
echo "Copied magic.js and magic.wasm to npm/"
# --- optional test -----------------------------------------------------------
# Runs the same smoke test that CI runs (see .github/workflows/main.yml).
if [ $OPT_TEST -eq 1 ]; then
cd "$SCRIPT_DIR"
npm run test
fi
# --- optional pack -----------------------------------------------------------
if [ $OPT_PACK -eq 1 ]; then
"$SCRIPT_DIR/pack.sh"
echo "npm package tarball created in npm/"
fi

View File

@ -1,50 +0,0 @@
// all.js — Run all Magic WASM example tests and print a summary.
//
// Usage: node examples/all.js
import { run as runExtract } from './extract.js';
import { run as runGds } from './gds.js';
import { run as runDrc } from './drc.js';
import { run as runCif } from './cif.js';
const PAD = 9;
async function test(name, fn) {
process.stdout.write(` ${name.padEnd(PAD)} `);
try {
const result = await fn();
console.log(`PASS ${formatResult(name, result)}`);
return true;
} catch (e) {
console.log(`FAIL ${e.message ?? e}`);
return false;
}
}
function formatResult(name, r) {
if (!r) return '';
switch (name) {
case 'extract': return [r.ext, r.spice].filter(Boolean).map(p => p.split(/[\\/]/).pop()).join(', ');
case 'gds': return `${r.outPath.split(/[\\/]/).pop()} (${r.bytes} B)`;
case 'cif': return `${r.outPath.split(/[\\/]/).pop()} (${r.bytes} B)`;
case 'drc': return r.violations != null ? `${r.violations} violation${r.violations !== 1 ? 's' : ''}` : '';
default: return '';
}
}
console.log('\nMagic WASM — test suite\n');
const suite = [
['extract', runExtract],
['gds', runGds],
['drc', runDrc],
['cif', runCif],
];
const passed = [];
for (const [name, fn] of suite) {
passed.push(await test(name, fn));
}
const ok = passed.filter(Boolean).length;
console.log(`\n${ok}/${suite.length} passed`);
process.exit(ok === suite.length ? 0 : 1);

View File

@ -1,30 +0,0 @@
// cif.js — Export layout to CIF (Caltech Intermediate Form).
//
// Usage: node examples/cif.js [magFile [tech [outputDir]]]
import { createMagic, vfsRead, loadCell, loadScript,
DEFAULT_TECH, DEFAULT_MAG, DEFAULT_OUT } from './helpers.js';
import { writeFileSync, mkdirSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { resolve } from 'node:path';
export async function run({ magFile = DEFAULT_MAG, tech = DEFAULT_TECH, outputDir = DEFAULT_OUT } = {}) {
const { magic } = await createMagic();
const { FS } = magic;
const { tech: techName, cell } = loadCell(FS, tech, magFile);
magic.runScript(loadScript('cif.tcl', techName, cell));
mkdirSync(outputDir, { recursive: true });
const data = vfsRead(FS, `/work/${cell}.cif`);
if (!data) throw new Error(`CIF export failed: /work/${cell}.cif not created`);
const outPath = resolve(outputDir, `${cell}.cif`);
writeFileSync(outPath, data);
return { outPath, bytes: data.length };
}
if (process.argv[1] === fileURLToPath(import.meta.url)) {
const { outPath, bytes } = await run().catch(e => { console.error(e.message ?? e); process.exit(1); });
console.log(`\ncif: ${outPath} (${bytes} bytes)`);
console.log('Done.');
}

View File

@ -1,4 +0,0 @@
# CIF export
tech load __TECH__
load /work/__CELL__
cif write /work/__CELL__

View File

@ -1,31 +0,0 @@
// drc.js — Run design rule checking and report violations.
//
// Usage: node examples/drc.js [magFile [tech]]
import { createMagic, loadCell, loadScript,
DEFAULT_TECH, DEFAULT_MAG } from './helpers.js';
import { fileURLToPath } from 'node:url';
export async function run({ magFile = DEFAULT_MAG, tech = DEFAULT_TECH } = {}) {
const output = [];
const { magic } = await createMagic({
onPrint: msg => { output.push(msg); console.log('[magic]', msg); },
onPrintErr: msg => { output.push(msg); console.error('[magic]', msg); },
});
const { FS } = magic;
const { tech: techName, cell } = loadCell(FS, tech, magFile);
magic.runScript(loadScript('drc.tcl', techName, cell));
// Magic prints "Total DRC errors found: N" at the end of drc listall.
const summary = output.find(l => /Total DRC errors/i.test(l));
const match = summary?.match(/(\d+)/);
const violations = match ? parseInt(match[1], 10) : null;
return { violations, output };
}
if (process.argv[1] === fileURLToPath(import.meta.url)) {
const { violations } = await run().catch(e => { console.error(e.message ?? e); process.exit(1); });
console.log(`\nDRC violations: ${violations ?? '(count not found in output)'}`);
console.log('Done.');
}

View File

@ -1,5 +0,0 @@
# DRC check runs design rule checking and reports violation count.
tech load __TECH__
load /work/__CELL__
drc catchup
drc count total

View File

@ -1,40 +0,0 @@
// example.js — GDS → CIF format conversion using the Magic WASM module.
//
// Usage:
// node examples/example.js [input.gds] [output.cif]
//
// Defaults:
// input: design.gds (in current working directory)
// output: design.cif (in current working directory)
import { readFileSync, writeFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, resolve, basename } from 'node:path';
import createMagicModule from '../magic.js';
const __dirname = dirname(fileURLToPath(import.meta.url));
const wasmBinary = readFileSync(resolve(__dirname, '../magic.wasm'));
const inputGds = process.argv[2] ?? 'design.gds';
const outputCif = process.argv[3] ?? inputGds.replace(/\.gds$/i, '.cif');
const cellName = basename(inputGds, '.gds');
const module = await createMagicModule({
wasmBinary,
print: msg => console.log('[magic]', msg),
printErr: msg => console.error('[magic]', msg),
});
module.FS.mkdirTree('/work');
module.FS.writeFile(`/work/${cellName}.gds`, readFileSync(inputGds));
module._magic_wasm_init();
module.cwrap('magic_wasm_run_command', 'number', ['string'])(`gds read /work/${cellName}`);
module.cwrap('magic_wasm_run_command', 'number', ['string'])(`load ${cellName}`);
module.cwrap('magic_wasm_run_command', 'number', ['string'])(`cif write /work/${cellName}`);
const cifBytes = module.FS.readFile(`/work/${cellName}.cif`);
writeFileSync(outputCif, cifBytes);
console.log(`Converted ${inputGds}${outputCif}`);

View File

@ -1,41 +0,0 @@
// extract.js — RC extraction example (extract → extresist → ext2spice).
//
// Usage: node examples/extract.js [magFile [tech [outputDir]]]
import { createMagic, vfsWrite, vfsRead, loadCell, loadScript,
DEFAULT_TECH, DEFAULT_MAG, DEFAULT_OUT } from './helpers.js';
import { writeFileSync, mkdirSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { resolve } from 'node:path';
export async function run({ magFile = DEFAULT_MAG, tech = DEFAULT_TECH, outputDir = DEFAULT_OUT } = {}) {
const { magic } = await createMagic();
const { FS } = magic;
const { tech: techName, cell } = loadCell(FS, tech, magFile);
magic.runScript(loadScript('extract.tcl', techName, cell));
mkdirSync(outputDir, { recursive: true });
const extData = vfsRead(FS, `/work/${cell}.ext`);
if (!extData) throw new Error(`Extraction failed: /work/${cell}.ext not created`);
writeFileSync(resolve(outputDir, `${cell}.ext`), extData);
const resExtData = vfsRead(FS, `/work/${cell}.res.ext`);
if (resExtData) writeFileSync(resolve(outputDir, `${cell}.res.ext`), resExtData);
const spiceData = vfsRead(FS, `/work/${cell}.spice`) ?? vfsRead(FS, `/work/${cell}.spc`);
const spiceExt = vfsRead(FS, `/work/${cell}.spice`) ? 'spice' : 'spc';
if (spiceData) writeFileSync(resolve(outputDir, `${cell}.${spiceExt}`), spiceData);
return {
ext: resolve(outputDir, `${cell}.ext`),
spice: spiceData ? resolve(outputDir, `${cell}.${spiceExt}`) : null,
};
}
if (process.argv[1] === fileURLToPath(import.meta.url)) {
const { ext, spice } = await run().catch(e => { console.error(e.message ?? e); process.exit(1); });
console.log(`\next: ${ext}`);
if (spice) console.log(`spice: ${spice}`);
console.log('Done.');
}

View File

@ -1,36 +0,0 @@
# extract.tcl
#
# Complete Magic extraction workflow:
# 1. Load technology
# 2. Load layout
# 3. Extract parasitic capacitances (extract all __CELL__.ext)
# 4. Extract parasitic resistances (extresist all __CELL__.res.ext)
# 5. Write SPICE netlist (ext2spice __CELL__.spice)
#
# __TECH__ and __CELL__ are substituted by extract.js before execution.
tech load __TECH__
load /work/__CELL__
# Write all intermediate files to /work/
extract path /work
# Enable resistance extraction
extract do resistance
# Generate __CELL__.ext
extract all
# extresist requires a valid selection/box
select top cell
# Generate __CELL__.res.ext
extresist all
# SPICE generation settings
ext2spice format ngspice
ext2spice extresist on
ext2spice cthresh 0
# Generate __CELL__.spice
ext2spice /work/__CELL__

View File

@ -1,30 +0,0 @@
// gds.js — Export layout to GDS II stream format.
//
// Usage: node examples/gds.js [magFile [tech [outputDir]]]
import { createMagic, vfsRead, loadCell, loadScript,
DEFAULT_TECH, DEFAULT_MAG, DEFAULT_OUT } from './helpers.js';
import { writeFileSync, mkdirSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { resolve } from 'node:path';
export async function run({ magFile = DEFAULT_MAG, tech = DEFAULT_TECH, outputDir = DEFAULT_OUT } = {}) {
const { magic } = await createMagic();
const { FS } = magic;
const { tech: techName, cell } = loadCell(FS, tech, magFile);
magic.runScript(loadScript('gds.tcl', techName, cell));
mkdirSync(outputDir, { recursive: true });
const data = vfsRead(FS, `/work/${cell}.gds`);
if (!data) throw new Error(`GDS export failed: /work/${cell}.gds not created`);
const outPath = resolve(outputDir, `${cell}.gds`);
writeFileSync(outPath, data);
return { outPath, bytes: data.length };
}
if (process.argv[1] === fileURLToPath(import.meta.url)) {
const { outPath, bytes } = await run().catch(e => { console.error(e.message ?? e); process.exit(1); });
console.log(`\ngds: ${outPath} (${bytes} bytes)`);
console.log('Done.');
}

View File

@ -1,4 +0,0 @@
# GDS export
tech load __TECH__
load /work/__CELL__
gds write /work/__CELL__

View File

@ -1,72 +0,0 @@
// Shared utilities for Magic WASM examples.
import createMagicModule from '../magic.js';
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, resolve, basename } from 'node:path';
export const EXAMPLES_DIR = dirname(fileURLToPath(import.meta.url));
export const wasmBinary = readFileSync(resolve(EXAMPLES_DIR, '../magic.wasm'));
export const DEFAULT_TECH = 'scmos';
export const DEFAULT_MAG = resolve(EXAMPLES_DIR, 'min.mag');
export const DEFAULT_OUT = resolve(EXAMPLES_DIR, 'output');
export { basename };
export function vfsWrite(FS, vfsPath, source) {
const dir = vfsPath.substring(0, vfsPath.lastIndexOf('/'));
if (dir) FS.mkdirTree(dir);
FS.writeFile(vfsPath, typeof source === 'string' ? readFileSync(source) : source);
}
export function vfsRead(FS, vfsPath) {
try { return Buffer.from(FS.readFile(vfsPath)); } catch { return null; }
}
export class MagicWasm {
constructor(mod) {
this._init = mod.cwrap('magic_wasm_init', 'number', []);
this._run = mod.cwrap('magic_wasm_run_command', 'number', ['string']);
this.FS = mod.FS;
}
init() {
const rc = this._init();
if (rc !== 0) throw new Error(`magic_wasm_init failed with code ${rc}`);
}
runScript(text) {
for (const line of text.split('\n')) {
const l = line.trim();
if (l && !l.startsWith('#')) this._run(l);
}
}
}
// Creates a fresh Magic WASM instance and calls init().
// onPrint / onPrintErr default to console.log/error with a [magic] prefix.
// All output lines are also collected into the returned `lines` array.
export async function createMagic({ onPrint, onPrintErr } = {}) {
const lines = [];
const mod = await createMagicModule({
wasmBinary,
print: onPrint ?? (msg => { lines.push(msg); console.log('[magic]', msg); }),
printErr: onPrintErr ?? (msg => { lines.push(msg); console.error('[magic]', msg); }),
});
const magic = new MagicWasm(mod);
magic.init();
return { magic, lines };
}
// Loads a layout into the VFS. `tech` is the name of a technology that is
// either built into the WASM binary (e.g. 'scmos', 'minimum', 'nmos') or has
// already been written to /magic/sys/current/<tech>.tech by the caller.
export function loadCell(FS, tech, magFile) {
const cell = basename(magFile, '.mag');
vfsWrite(FS, `/work/${cell}.mag`, magFile);
return { tech, cell };
}
// Reads a TCL script from EXAMPLES_DIR, substitutes __TECH__ and __CELL__.
export function loadScript(name, tech, cell) {
return readFileSync(resolve(EXAMPLES_DIR, name), 'utf8')
.replaceAll('__TECH__', tech)
.replaceAll('__CELL__', cell);
}

View File

@ -1,33 +0,0 @@
magic
tech scmos
timestamp 783737348
<< nwell >>
rect 5 3 46 27
<< metal1 >>
rect 9 0 13 13
rect 22 0 26 13
rect 33 0 37 13
<< collector >>
rect 8 17 14 18
rect 8 13 9 17
rect 13 13 14 17
rect 8 12 14 13
<< pbase >>
rect 18 17 40 21
rect 18 13 22 17
rect 26 13 33 17
rect 37 13 40 17
rect 18 9 40 13
<< collectorcontact >>
rect 9 13 13 17
<< emittercontact >>
rect 22 13 26 17
<< pbasecontact >>
rect 33 13 37 17
<< labels >>
rlabel space 0 17 0 17 3 without
rlabel space 0 13 0 13 3 guardring
rlabel metal1 35 1 35 1 5 base
rlabel metal1 24 1 24 1 5 emitter
rlabel metal1 11 1 11 1 5 collector
<< end >>

57
npm/index.d.ts vendored
View File

@ -1,57 +0,0 @@
export interface MagicInstance {
/**
* Initialize Magic (idempotent safe to call multiple times).
* Returns 0 on success, non-zero on failure.
*/
init(): number;
/**
* Dispatch a single Magic command string.
* Calls init() automatically on the first invocation.
* Returns 0 on success, non-zero on failure.
*/
runCommand(command: string): number;
/**
* Read and execute a command file at the given virtual filesystem path.
* Calls init() automatically on the first invocation.
* Returns 0 on success, -1 if the file could not be opened.
*/
sourceFile(path: string): number;
/**
* Drive a display-update cycle.
* No-op in headless builds the null display driver suspends all redraws.
*/
update(): void;
/**
* Emscripten virtual filesystem.
* Use FS.writeFile / FS.readFile to pass layout files in and out of Magic.
* See https://emscripten.org/docs/api_reference/Filesystem-API.html
*/
FS: any;
}
/**
* Create a Magic WASM instance.
*
* @param options Emscripten module options. Useful keys:
* - `wasmBinary` Pre-fetched ArrayBuffer of magic.wasm (avoids a second fetch)
* - `print` Callback for stdout lines (default: console.log)
* - `printErr` Callback for stderr lines (default: console.error)
*
* @example
* ```js
* import createMagic from 'magic-vlsi-wasm';
*
* const { runCommand, FS } = await createMagic();
* FS.writeFile('/work/inv.mag', layoutBytes);
* runCommand('tech load sky130A');
* runCommand('load /work/inv');
* runCommand('gds write /work/inv');
* const gds = FS.readFile('/work/inv.gds');
* ```
*/
export default function createMagic(options?: Record<string, unknown>): Promise<MagicInstance>;
export { createMagic };

View File

@ -1,15 +0,0 @@
import MagicModuleFactory from './magic.js';
async function createMagic(options = {}) {
const module = await MagicModuleFactory(options);
const init = module.cwrap('magic_wasm_init', 'number', []);
const runCommand = module.cwrap('magic_wasm_run_command', 'number', ['string']);
const sourceFile = module.cwrap('magic_wasm_source_file', 'number', ['string']);
const update = module.cwrap('magic_wasm_update', null, []);
return { init, runCommand, sourceFile, update, FS: module.FS };
}
export { createMagic };
export default createMagic;

View File

@ -1,23 +0,0 @@
#!/usr/bin/env bash
# Pack the magic-vlsi-wasm npm tarball with reproducible-but-current timestamps.
#
# npm/pacote normalizes file mtimes for reproducibility and, when no
# SOURCE_DATE_EPOCH is set, falls back to 1985-10-26. That makes published
# tarballs carry 1985 dates, which confuses users and tooling.
#
# This script:
# 1. touches every file in npm/ so mtimes reflect the build time
# 2. sets SOURCE_DATE_EPOCH to `now` so pacote's normalization uses it
# 3. runs `npm pack`, producing magic-vlsi-wasm-<version>.tgz in npm/
#
# Used by:
# - npm/build.sh --pack (local build)
# - .github/workflows/main-wasm.yml (CI build + tag-triggered publish)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
find . -exec touch {} +
SOURCE_DATE_EPOCH=$(date +%s) npm pack

View File

@ -1,36 +0,0 @@
{
"name": "magic-vlsi-wasm",
"version": "0.0.0-dev",
"description": "Magic VLSI Layout Tool — headless WebAssembly build",
"type": "module",
"main": "index.js",
"types": "index.d.ts",
"exports": {
".": {
"import": "./index.js",
"types": "./index.d.ts"
}
},
"files": [
"index.js",
"index.d.ts",
"magic.js",
"magic.wasm",
"examples/",
"LICENSE",
"README.md"
],
"scripts": {
"example": "node examples/extract.js",
"test": "node examples/all.js",
"test:gds": "node examples/gds.js",
"test:drc": "node examples/drc.js",
"test:cif": "node examples/cif.js"
},
"keywords": ["magic", "vlsi", "eda", "wasm", "webassembly", "layout"],
"license": "HPND",
"engines": {
"node": ">=18"
}
}

View File

@ -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. */
snprintf(fileName, 200, "%s/magicPlotXXXXXX", PlotTempDirectory); sprintf(fileName, "%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);
snprintf(command, 300, PlotVersCommand, PlotVersPrinter, fileName); sprintf(command, 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",

View File

@ -27,24 +27,64 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
/* /*
*-------------------------------------------------------------------------- *--------------------------------------------------------------------------
* *
* resMakePortBreakpoints -- * resNodeIsPort --
* *
* Generate new nodes and breakpoints for every unused port declared * If the given position is inside any port declared on the tile,
* on a tile. However, if "startpoint" is inside the port position, * change the node name to the port name. Remove the port
* then it has already been processed, so ignore it. * declaration if it was used.
*
* Results:
* None.
*
* Side effects:
* Adds breakpoints where ports (drivers, sinks, or labels) have been
* defined as connected to the tile.
* *
*-------------------------------------------------------------------------- *--------------------------------------------------------------------------
*/ */
void void
resMakePortBreakpoints(tile, list) resNodeIsPort(node, x, y, tile)
resNode *node;
int x;
int y;
Tile *tile;
{
Rect *rect;
Point p;
resPort *pl, *lp;
resInfo *info = (resInfo *)TiGetClientPTR(tile);
p.p_x = x;
p.p_y = y;
for (pl = info->portList; pl; pl = pl->rp_nextPort)
{
rect = &(pl->rp_bbox);
if (GEO_ENCLOSE(&p, rect))
{
node->rn_name = pl->rp_nodename;
if (info->portList == pl)
info->portList = pl->rp_nextPort;
else
{
for (lp = info->portList; lp && (lp->rp_nextPort != pl);
lp = lp->rp_nextPort);
lp->rp_nextPort = pl->rp_nextPort;
}
freeMagic(pl);
break;
}
}
}
/*
*--------------------------------------------------------------------------
*
* resAllPortNodes --
*
* Generate new nodes and breakpoints for every unused port declared
* on a tile. However, if "startpoint" is inside the port position,
* then it has already been processed, so ignore it.
*
*--------------------------------------------------------------------------
*/
void
resAllPortNodes(tile, list)
Tile *tile; Tile *tile;
resNode **list; resNode **list;
{ {
@ -52,7 +92,6 @@ resMakePortBreakpoints(tile, list)
resNode *resptr; resNode *resptr;
resPort *pl; resPort *pl;
resInfo *info = (resInfo *)TiGetClientPTR(tile); resInfo *info = (resInfo *)TiGetClientPTR(tile);
ResConnect *connect;
free_magic1_t mm1 = freeMagic1_init(); free_magic1_t mm1 = freeMagic1_init();
for (pl = info->portList; pl; pl = pl->rp_nextPort) for (pl = info->portList; pl; pl = pl->rp_nextPort)
@ -64,30 +103,13 @@ resMakePortBreakpoints(tile, list)
resptr->rn_status = TRUE; resptr->rn_status = TRUE;
resptr->rn_noderes = 0; resptr->rn_noderes = 0;
resptr->rn_name = pl->rp_nodename; resptr->rn_name = pl->rp_nodename;
/* Link back to the resnode from the ResConnect record */
connect = pl->rp_connect;
connect->rc_node = resptr;
ResAddToQueue(resptr, list); ResAddToQueue(resptr, list);
ResNewBreak(resptr, tile, x, y, NULL); NEWBREAK(resptr, tile, x, y, NULL);
freeMagic1(&mm1, pl); freeMagic1(&mm1, pl);
} }
freeMagic1_end(&mm1); freeMagic1_end(&mm1);
} }
/*
* Structure used by ResEachTile for the callback to ResMultiPlaneFunc()
* to pass a pointer to the tile being processed, and the terminal being
* searched.
*/
typedef struct tile_and_term
{
Tile *tat_tile;
int tat_term;
} TileAndTerm;
/* /*
*-------------------------------------------------------------------------- *--------------------------------------------------------------------------
* *
@ -106,13 +128,12 @@ typedef struct tile_and_term
*/ */
int int
ResMultiPlaneFunc(tile, dinfo, tat) ResMultiPlaneFunc(tile, dinfo, tpptr)
Tile *tile; Tile *tile;
TileType dinfo; /* Not used, but needs to be handled */ TileType dinfo; /* Not used, but needs to be handled */
TileAndTerm *tat; Tile **tpptr;
{ {
Tile *tp = tat->tat_tile; Tile *tp = *tpptr;
int term = tat->tat_term;
int xj, yj; int xj, yj;
/* Simplified split tile handling---Ignore the right side of /* Simplified split tile handling---Ignore the right side of
@ -125,7 +146,7 @@ ResMultiPlaneFunc(tile, dinfo, tat)
xj = (LEFT(tile) + RIGHT(tile)) / 2; xj = (LEFT(tile) + RIGHT(tile)) / 2;
yj = (TOP(tile) + BOTTOM(tile)) / 2; yj = (TOP(tile) + BOTTOM(tile)) / 2;
ResNewTermDevice(tp, tile, term, xj, yj, OTHERPLANE, &ResNodeQueue); ResNewSDDevice(tp, tile, xj, yj, OTHERPLANE, &ResNodeQueue);
return 0; return 0;
} }
@ -174,44 +195,7 @@ ResSubstrateFunc(tile, dinfo, tpptr)
/* /*
*-------------------------------------------------------------------------- *--------------------------------------------------------------------------
* *
* ResStartTile -- * ResEachTile--for each tile, make a list of all possible current sources/
*
* For the tile at the starting point of the net, create an initial
* resNode entry.
*
* Results:
* None.
*
* Side Effects:
* creates a node.
*
*
*--------------------------------------------------------------------------
*/
void
ResStartTile(tile, x, y)
Tile *tile;
int x, y;
{
resNode *resptr;
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
InitializeResNode(resptr, x, y, RES_NODE_ORIGIN);
resptr->rn_status = TRUE;
resptr->rn_noderes = 0;
ResAddToQueue(resptr, &ResNodeQueue);
ResNewBreak(resptr, tile, x, y, NULL);
if (resCurrentNode == NULL) resCurrentNode = resptr;
}
/*
*--------------------------------------------------------------------------
*
* ResEachTile --
*
* For each tile, make a list of all possible current sources/
* sinks including contacts, devices, and junctions. Once this * sinks including contacts, devices, and junctions. Once this
* list is made, calculate the resistor network for the tile. * list is made, calculate the resistor network for the tile.
* *
@ -230,9 +214,10 @@ ResStartTile(tile, x, y)
#define IGNORE_BOTTOM 8 #define IGNORE_BOTTOM 8
bool bool
ResEachTile(tile, devTiles) ResEachTile(tile, startpoint)
Tile *tile; /* Tile being processed */ Tile *tile;
ResDevTile *devTiles; /* List of device tiles for reference */ Point *startpoint;
{ {
Tile *tp; Tile *tp;
resNode *resptr; resNode *resptr;
@ -241,12 +226,14 @@ ResEachTile(tile, devTiles)
int xj, yj, i; int xj, yj, i;
bool merged; bool merged;
tElement *tcell; tElement *tcell;
resInfo *tstructs = (resInfo *)TiGetClientPTR(tile); resInfo *tstructs= (resInfo *)TiGetClientPTR(tile);
ExtDevice *devptr; ExtDevice *devptr;
int sides; int sides;
ResTileCount++; ResTileCount++;
/* Process startpoint, if any. */
/* Simplification: Split tiles handle either the non-space side, /* Simplification: Split tiles handle either the non-space side,
* or if neither side is space, then handle the left side. * or if neither side is space, then handle the left side.
*/ */
@ -271,7 +258,21 @@ ResEachTile(tile, devTiles)
t1 = TiGetTypeExact(tile); t1 = TiGetTypeExact(tile);
} }
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t1)) if (startpoint != (Point *) NULL)
{
int x = startpoint->p_x;
int y = startpoint->p_y;
resptr = (resNode *) mallocMagic((unsigned)(sizeof(resNode)));
InitializeResNode(resptr, x, y, RES_NODE_ORIGIN);
resptr->rn_status = TRUE;
resptr->rn_noderes = 0;
ResAddToQueue(resptr, &ResNodeQueue);
NEWBREAK(resptr, tile, x, y, NULL);
if (resCurrentNode == NULL) resCurrentNode = resptr;
resNodeIsPort(resptr, x, y, tile);
}
if TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t1)
{ {
/* /*
* The device is put in the center of the tile. This is fine * The device is put in the center of the tile. This is fine
@ -294,7 +295,9 @@ ResEachTile(tile, devTiles)
InitializeResNode(resptr, x, y, RES_NODE_JUNCTION); InitializeResNode(resptr, x, y, RES_NODE_JUNCTION);
resptr->rn_te = tcell; resptr->rn_te = tcell;
ResAddToQueue(resptr, &ResNodeQueue); ResAddToQueue(resptr, &ResNodeQueue);
ResNewBreak(resptr, tile, resptr->rn_loc.p_x, resNodeIsPort(resptr, x, y, tile);
NEWBREAK(resptr, tile, resptr->rn_loc.p_x,
resptr->rn_loc.p_y, NULL); resptr->rn_loc.p_y, NULL);
} }
} }
@ -323,7 +326,7 @@ ResEachTile(tile, devTiles)
/* left */ /* left */
if (!(sides & IGNORE_LEFT)) if (!(sides & IGNORE_LEFT))
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp)) for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp))
{ {
t2 = TiGetRightType(tp); t2 = TiGetRightType(tp);
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2)) if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2))
@ -338,14 +341,14 @@ ResEachTile(tile, devTiles)
/* found device */ /* found device */
xj = LEFT(tile); xj = LEFT(tile);
yj = (TOP(tp) + BOTTOM(tp)) >> 1; yj = (TOP(tp) + BOTTOM(tp)) >> 1;
ResNewTermDevice(tile, tp, i, xj, yj, RIGHTEDGE, &ResNodeQueue); ResNewSDDevice(tile, tp, xj, yj, RIGHTEDGE, &ResNodeQueue);
break; break;
} }
} }
if (i < devptr->exts_deviceSDCount) break; if (i < devptr->exts_deviceSDCount) break;
} }
} }
if (TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2)) if TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2)
{ {
/* tile is junction */ /* tile is junction */
xj = LEFT(tile); xj = LEFT(tile);
@ -356,7 +359,7 @@ ResEachTile(tile, devTiles)
/* right */ /* right */
if (!(sides & IGNORE_RIGHT)) if (!(sides & IGNORE_RIGHT))
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp)) for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp=LB(tp))
{ {
t2 = TiGetLeftType(tp); t2 = TiGetLeftType(tp);
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2)) if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2))
@ -371,18 +374,18 @@ ResEachTile(tile, devTiles)
/* found device */ /* found device */
xj = RIGHT(tile); xj = RIGHT(tile);
yj = (TOP(tp) + BOTTOM(tp)) >> 1; yj = (TOP(tp) + BOTTOM(tp)) >> 1;
ResNewTermDevice(tile, tp, i, xj, yj, LEFTEDGE, &ResNodeQueue); ResNewSDDevice(tile, tp, xj, yj, LEFTEDGE, &ResNodeQueue);
break; break;
} }
} }
if (i < devptr->exts_deviceSDCount) break; if (i < devptr->exts_deviceSDCount) break;
} }
} }
if (TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1], t2)) if TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1], t2)
{ {
/* tile is junction */ /* tile is junction */
xj = RIGHT(tile); xj = RIGHT(tile);
yj = (MAX(BOTTOM(tile), BOTTOM(tp)) + MIN(TOP(tile), TOP(tp))) >> 1; yj = (MAX(BOTTOM(tile),BOTTOM(tp)) + MIN(TOP(tile), TOP(tp))) >> 1;
(void)ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue); (void)ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
} }
} }
@ -404,25 +407,25 @@ ResEachTile(tile, devTiles)
/* found device */ /* found device */
yj = TOP(tile); yj = TOP(tile);
xj = (LEFT(tp) + RIGHT(tp)) >> 1; xj = (LEFT(tp) + RIGHT(tp)) >> 1;
ResNewTermDevice(tile, tp, i, xj, yj, BOTTOMEDGE, &ResNodeQueue); ResNewSDDevice(tile, tp, xj, yj, BOTTOMEDGE, &ResNodeQueue);
break; break;
} }
} }
if (i < devptr->exts_deviceSDCount) break; if (i < devptr->exts_deviceSDCount) break;
} }
} }
if (TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1], t2)) if TTMaskHasType(&ExtCurStyle->exts_nodeConn[t1], t2)
{ {
/* tile is junction */ /* tile is junction */
yj = TOP(tile); yj = TOP(tile);
xj = (MAX(LEFT(tile), LEFT(tp)) + MIN(RIGHT(tile), RIGHT(tp))) >> 1; xj = (MAX(LEFT(tile),LEFT(tp)) + MIN(RIGHT(tile),RIGHT(tp))) >> 1;
ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue); ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
} }
} }
/* bottom */ /* bottom */
if (!(sides & IGNORE_BOTTOM)) if (!(sides & IGNORE_BOTTOM))
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp)) for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp))
{ {
t2 = TiGetTopType(tp); t2 = TiGetTopType(tp);
if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2)) if (TTMaskHasType(&(ExtCurStyle->exts_deviceMask), t2))
@ -437,59 +440,50 @@ ResEachTile(tile, devTiles)
/* found device */ /* found device */
yj = BOTTOM(tile); yj = BOTTOM(tile);
xj = (LEFT(tp) + RIGHT(tp)) >> 1; xj = (LEFT(tp) + RIGHT(tp)) >> 1;
ResNewTermDevice(tile, tp, i, xj, yj, TOPEDGE, &ResNodeQueue); ResNewSDDevice(tile, tp, xj, yj, TOPEDGE, &ResNodeQueue);
break; break;
} }
} }
if (i < devptr->exts_deviceSDCount) break; if (i < devptr->exts_deviceSDCount) break;
} }
} }
if (TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2)) if TTMaskHasType(&(ExtCurStyle->exts_nodeConn[t1]), t2)
{ {
/* tile is junction */ /* tile is junction */
yj = BOTTOM(tile); yj = BOTTOM(tile);
xj = (MAX(LEFT(tile), LEFT(tp)) + MIN(RIGHT(tile), RIGHT(tp))) >> 1; xj = (MAX(LEFT(tile),LEFT(tp)) + MIN(RIGHT(tile),RIGHT(tp))) >> 1;
ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue); ResProcessJunction(tile, tp, xj, yj, &ResNodeQueue);
} }
} }
/* Check for terminals on other planes (e.g., capacitors, bipolars, ...) */ /* Check for source/drain on other planes (e.g., capacitors, bipolars, ...) */
/* Note: Need to tag these tiles per device to avoid checking through */
/* the device list for each tile. (To be done) */
if (TTMaskHasType(&ResTermTypesBitMask, t1)) if (TTMaskHasType(&ResSDTypesBitMask, t1))
{ {
Rect r; Rect r;
int pNum; int pNum;
TileTypeBitMask devMask; TileTypeBitMask devMask;
TileAndTerm tat;
ResDevTile *devtile;
ExtDevice *devptr;
TiToRect(tile, &r); TiToRect(tile, &r);
for (devtile = devTiles; devtile; devtile = devtile->nextDev) for (pNum = 0; pNum < DBNumPlanes; pNum++)
{ {
Tile *tp; if (DBTypeOnPlane(t1, pNum)) continue;
TileType devtype = devtile->type;
devptr = devtile->devptr; /* NOTE: This is ridiculously inefficient and should be done
for (i = 0; i < devptr->exts_deviceSDCount; i++) * in a different way.
{ */
if (TTMaskHasType(&devptr->exts_deviceSDTypes[i], t1))
{ TTMaskZero(&devMask);
if (GEO_OVERLAP(&devtile->area, &r)) for (t2 = TT_TECHDEPBASE; t2 < DBNumUserLayers; t2++)
{ for (devptr = ExtCurStyle->exts_device[t2]; devptr;
Plane *plane = ResUse->cu_def->cd_planes[DBPlane(devtype)]; devptr = devptr->exts_next)
xj = (r.r_xtop + r.r_xbot) / 2; for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++)
yj = (r.r_ytop + r.r_ybot) / 2; if (TTMaskHasType(&devptr->exts_deviceSDTypes[i], t1))
tp = PlaneGetHint(plane); TTMaskSetType(&devMask, t2);
GOTOPOINT(tp, &devtile->area.r_ll);
PlaneSetHint(plane, tp); DBSrPaintArea((Tile *)NULL, ResUse->cu_def->cd_planes[pNum],
ResNewTermDevice(tile, tp, i, xj, yj, OTHERPLANE, &ResNodeQueue); &r, &devMask, ResMultiPlaneFunc, (ClientData)&tile);
}
}
}
} }
} }
@ -500,37 +494,32 @@ ResEachTile(tile, devTiles)
Rect r; Rect r;
int pNum; int pNum;
TileTypeBitMask devMask; TileTypeBitMask devMask;
ResDevTile *devtile;
ExtDevice *devptr;
TiToRect(tile, &r); TiToRect(tile, &r);
for (devtile = devTiles; devtile; devtile = devtile->nextDev) for (pNum = 0; pNum < DBNumPlanes; pNum++)
{ {
Tile *tp; if (DBTypeOnPlane(t1, pNum)) continue;
TileType devtype = devtile->type;
devptr = devtile->devptr; /* NOTE: This is ridiculously inefficient and should be done
* in a different way.
*/
if (TTMaskHasType(&devptr->exts_deviceSubstrateTypes, t1)) TTMaskZero(&devMask);
{ for (t2 = TT_TECHDEPBASE; t2 < DBNumUserLayers; t2++)
if (GEO_OVERLAP(&devtile->area, &r)) for (devptr = ExtCurStyle->exts_device[t2]; devptr;
{ devptr = devptr->exts_next)
Plane *plane = ResUse->cu_def->cd_planes[DBPlane(devtype)]; if (TTMaskHasType(&devptr->exts_deviceSubstrateTypes, t1))
xj = (r.r_xtop + r.r_xbot) / 2; TTMaskSetType(&devMask, t2);
yj = (r.r_ytop + r.r_ybot) / 2;
tp = PlaneGetHint(plane); DBSrPaintArea((Tile *)NULL, ResUse->cu_def->cd_planes[pNum],
GOTOPOINT(tp, &devtile->area.r_ll); &r, &devMask, ResSubstrateFunc, (ClientData)&tile);
PlaneSetHint(plane, tp);
ResNewSubDevice(tile, tp, xj, yj, OTHERPLANE, &ResNodeQueue);
}
}
} }
} }
tstructs->ri_status |= RES_TILE_DONE; tstructs->ri_status |= RES_TILE_DONE;
resMakePortBreakpoints(tile, &ResNodeQueue); resAllPortNodes(tile, &ResNodeQueue);
merged = ResCalcTileResistance(tile, tstructs, &ResNodeQueue, merged = ResCalcTileResistance(tile, tstructs, &ResNodeQueue,
&ResNodeList); &ResNodeList);

View File

@ -61,7 +61,7 @@ ResSanityChecks(nodename, resistorList, nodeList, devlist)
{ {
resSanityStack = StackNew(64); resSanityStack = StackNew(64);
} }
for (node = nodeList; node != NULL; node = node->rn_more) for (node = nodeList; node != NULL; node=node->rn_more)
{ {
node->rn_status &= ~RES_REACHED_NODE; node->rn_status &= ~RES_REACHED_NODE;
if (node->rn_why & RES_NODE_ORIGIN) if (node->rn_why & RES_NODE_ORIGIN)
@ -133,7 +133,7 @@ ResSanityChecks(nodename, resistorList, nodeList, devlist)
} }
} }
foundorigin = 0; foundorigin = 0;
for (node = nodeList; node != NULL; node = node->rn_more) for (node = nodeList; node != NULL; node=node->rn_more)
{ {
if ((node->rn_status & RES_REACHED_NODE) == 0) if ((node->rn_status & RES_REACHED_NODE) == 0)
{ {

View File

@ -128,11 +128,11 @@ ResPrintDeviceList(fp, list)
{ {
if (list->rd_terminals[i] == NULL) continue; if (list->rd_terminals[i] == NULL) continue;
if (fp == stdout) if (fp == stdout)
TxPrintf("%c (%d,%d) ", termtype[i], TxPrintf("%c (%d,%d) ",termtype[i],
list->rd_terminals[i]->rn_loc.p_x, list->rd_terminals[i]->rn_loc.p_x,
list->rd_terminals[i]->rn_loc.p_y); list->rd_terminals[i]->rn_loc.p_y);
else else
fprintf(fp, "%c (%d,%d) ", termtype[i], fprintf(fp, "%c (%d,%d) ",termtype[i],
list->rd_terminals[i]->rn_loc.p_x, list->rd_terminals[i]->rn_loc.p_x,
list->rd_terminals[i]->rn_loc.p_y); list->rd_terminals[i]->rn_loc.p_y);

View File

@ -106,7 +106,7 @@ enumerate:
} }
else else
{ {
resTopTile = BL(resTopTile); resTopTile=BL(resTopTile);
} }
} }
} }
@ -205,7 +205,7 @@ ResCheckConcavity(bot, top, tt)
ylen = ypos - resWalkdown(bot, tt, xpos, ypos, NULL); ylen = ypos - resWalkdown(bot, tt, xpos, ypos, NULL);
if (xlen > ylen) if (xlen > ylen)
{ {
(void) resWalkdown(bot, tt, xpos, ypos, ResSplitX); (void) resWalkdown(bot,tt,xpos,ypos,ResSplitX);
} }
} }
} }
@ -274,7 +274,7 @@ int
resWalkup(tile, tt, xpos, ypos, func) resWalkup(tile, tt, xpos, ypos, func)
Tile *tile; Tile *tile;
TileType tt; TileType tt;
int xpos, ypos; int xpos,ypos;
Tile * (*func)(); Tile * (*func)();
{ {
@ -443,7 +443,7 @@ ResSplitX(tile, x)
Tile *tp = TiSplitX(tile, x); Tile *tp = TiSplitX(tile, x);
Tile *tp2; Tile *tp2;
TiSetBody(tp, tt); TiSetBody(tp,tt);
/* check to see if we can combine with the tiles above or below us */ /* check to see if we can combine with the tiles above or below us */
tp2 = RT(tile); tp2 = RT(tile);
if (TiGetType(tp2) == tt && LEFT(tp2) == LEFT(tile) && RIGHT(tp2) == RIGHT(tile)) if (TiGetType(tp2) == tt && LEFT(tp2) == LEFT(tile) && RIGHT(tp2) == RIGHT(tile))

View File

@ -29,31 +29,26 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
/* /*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
* *
* ResNewTermDevice -- * ResNewSDDevice -- called when a device is reached via a piece of
* diffusion. (Devices reached via poly, i.e.
* gates, are handled by ResEachTile.)
* *
* Called when a device is reached via a type in the device's * Results:none
* terminal type list (e.g., diffusion, for MOSFETs). Note that
* devices reached by the device type (e.g., poly, for MOSFETs)
* are handled by ResEachTile.
* *
* Results: * Side Effects: determines to which terminal (source or drain) node
* None * is connected. Makes new node if node hasn't already been created .
* * Allocates breakpoint in current tile for device.
* Side Effects:
* Determines to which terminal (source or drain) node is connected.
* Makes new node if node hasn't already been created. Allocates
* breakpoint in current tile for device.
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
void void
ResNewTermDevice(tile, tp, n, xj, yj, direction, PendingList) ResNewSDDevice(tile, tp, xj, yj, direction, PendingList)
Tile *tile, *tp; Tile *tile, *tp;
int n, xj, yj, direction; int xj, yj, direction;
resNode **PendingList; resNode **PendingList;
{ {
resNode *resptr = NULL; resNode *resptr;
resDevice *resDev; resDevice *resDev;
tElement *tcell; tElement *tcell;
int newnode; int newnode;
@ -69,9 +64,7 @@ ResNewTermDevice(tile, tp, n, xj, yj, direction, PendingList)
ri = (resInfo *) TiGetClientPTR(tp); ri = (resInfo *) TiGetClientPTR(tp);
resDev = ri->deviceList; resDev = ri->deviceList;
if (resDev == NULL) return; /* Shouldn't happen? */ 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)
{ {
@ -80,9 +73,11 @@ ResNewTermDevice(tile, tp, n, 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 if (resDev->rd_nterms > 3) else
{ {
if (resDev->rd_fet_drain == (resNode *) NULL) if (resDev->rd_fet_drain == (resNode *) NULL)
{ {
@ -91,7 +86,9 @@ ResNewTermDevice(tile, tp, n, 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)
{ {
@ -102,8 +99,7 @@ ResNewTermDevice(tile, tp, n, xj, yj, direction, PendingList)
resptr->rn_te = tcell; resptr->rn_te = tcell;
ResAddToQueue(resptr, PendingList); ResAddToQueue(resptr, PendingList);
} }
if (resptr != NULL) NEWBREAK(resptr, tile, xj, yj, NULL);
ResNewBreak(resptr, tile, xj, yj, NULL);
} }
/* /*
@ -135,16 +131,20 @@ ResNewSubDevice(tile, tp, xj, yj, direction, PendingList)
ri = (resInfo *) TiGetClientPTR(tp); ri = (resInfo *) TiGetClientPTR(tp);
resDev = ri->deviceList; resDev = ri->deviceList;
if (resDev == NULL) return; /* Should not happen? */ /* Arrived at a device that has a terminal connected to substrate */
/* that is not a FET bulk terminal (e.g., varactor, diode). */
if (resDev->rd_nterms < 4) return;
if (resDev->rd_fet_subs == (resNode *)NULL) 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)
{ {
@ -155,7 +155,7 @@ ResNewSubDevice(tile, tp, xj, yj, direction, PendingList)
resptr->rn_te = tcell; resptr->rn_te = tcell;
ResAddToQueue(resptr, PendingList); ResAddToQueue(resptr, PendingList);
} }
ResNewBreak(resptr, tile, xj, yj, NULL); NEWBREAK(resptr, tile, xj, yj, NULL);
} }
/* /*
@ -213,10 +213,10 @@ ResProcessJunction(tile, tp, xj, yj, NodeList)
junction->rj_nextjunction[1] = ri2->junctionList; junction->rj_nextjunction[1] = ri2->junctionList;
ri2->junctionList = junction; ri2->junctionList = junction;
ResNewBreak(junction->rj_jnode, tile, junction->rj_loc.p_x, NEWBREAK(junction->rj_jnode,tile, junction->rj_loc.p_x,
junction->rj_loc.p_y, NULL); junction->rj_loc.p_y, NULL);
ResNewBreak(junction->rj_jnode, tp, junction->rj_loc.p_x, NEWBREAK(junction->rj_jnode,tp, junction->rj_loc.p_x,
junction->rj_loc.p_y, NULL); junction->rj_loc.p_y, NULL);
} }

View File

@ -40,7 +40,8 @@ resNode *resCurrentNode;
int ResTileCount = 0; /* Number of tiles rn_status */ int ResTileCount = 0; /* Number of tiles rn_status */
extern ExtRegion *ResFirst(); extern ExtRegion *ResFirst();
extern Tile *FindStartTile(); extern Tile *FindStartTile();
TileTypeBitMask ResTermTypesBitMask; extern int ResEachTile();
TileTypeBitMask ResSDTypesBitMask;
TileTypeBitMask ResSubTypesBitMask; TileTypeBitMask ResSubTypesBitMask;
extern HashTable ResNodeTable; extern HashTable ResNodeTable;
@ -99,7 +100,7 @@ ResInitializeConn()
* *
* ResGetReCell -- * ResGetReCell --
* *
* This procedure makes sure that ResUse, ResDef * This procedure makes sure that ResUse,ResDef
* have been properly initialized to refer to a cell definition * have been properly initialized to refer to a cell definition
* named "__RESIS__". * named "__RESIS__".
* *
@ -147,86 +148,51 @@ void
ResDissolveContacts(contacts) ResDissolveContacts(contacts)
ResContactPoint *contacts; ResContactPoint *contacts;
{ {
TileType t, conttype; TileType t, oldtype;
Tile *tp; Tile *tp;
TileType residue[NP][NT]; TileTypeBitMask residues;
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)
{ {
conttype = contacts->cp_type; oldtype=contacts->cp_type;
#ifdef PARANOID #ifdef PARANOID
if (conttype == TT_SPACE) if (oldtype == 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);
/* Fill in details of the residue types for each contact type. DBErase(ResUse->cu_def, &(contacts->cp_rect), oldtype);
* This is done only once per contact type. This could be refined for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
* further by temporarily changing the paint table directly or if (TTMaskHasType(&residues, t))
* creating a separate paint table which erases contact cuts and DBPaint(ResUse->cu_def, &(contacts->cp_rect), t);
* replaces them with the residues.
*/
if (residue[DBPlane(conttype)][conttype] == TT_SPACE) tp = PlaneGetHint(ResDef->cd_planes[DBPlane(contacts->cp_type)]);
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) GOTOPOINT(tp, &(contacts->cp_rect.r_ll));
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
tp = PlaneGetHint(ResDef->cd_planes[DBPlane(conttype)]); if (TiGetTypeExact(tp) == contacts->cp_type)
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
} }
} }
/* Structure used by ResMakeDriverSinkPorts() to pass information to
* ResAddPortFunc(). Contains a reference to a node, so that the
* link between the tile and the node can be maintained, and the
* driver or sink, which has the information about the position and
* tile type of the connection.
*/
typedef struct driversinkdata {
ResExtNode *dsd_node;
ResConnect *dsd_connect;
} DriverSinkData;
/* /*
*--------------------------------------------------------------------------- *---------------------------------------------------------------------------
* *
* ResMakeDriverSinkPorts -- * ResMakePortBreakpoints --
* *
* Search through the list of node drivers and sinks (connections up * Search for nodes which are ports, and force them to be breakpoints
* and down in the hierarchy), and make sure this information is * in the "resInfo" field of their respective tiles in ResUse. This
* copied to the resInfo record of the tile(s) found at the connection. * ensures that connected nodes that stretch between two ports will
* not be assumed to be "hanging" nodes.
* *
* Results: * Do the same thing for labels.
* None.
*
* Side effects:
* Adds information to the resInfo clientData of tiles in def.
* *
*---------------------------------------------------------------------------- *----------------------------------------------------------------------------
*/ */
void void
ResMakeDriverSinkPorts(def) ResMakePortBreakpoints(def)
CellDef *def; CellDef *def;
{ {
Plane *plane; Plane *plane;
@ -235,66 +201,21 @@ ResMakeDriverSinkPorts(def)
HashSearch hs; HashSearch hs;
HashEntry *entry; HashEntry *entry;
ResExtNode *node; ResExtNode *node;
ResConnect *rdriver, *rsink; int ResAddBreakpointFunc(); /* Forward Declaration */
DriverSinkData dsd;
int ResAddPortFunc(); /* Forward Declaration */
HashStartSearch(&hs); HashStartSearch(&hs);
while((entry = HashNext(&ResNodeTable, &hs)) != NULL) while((entry = HashNext(&ResNodeTable, &hs)) != NULL)
{ {
node = (ResExtNode *)HashGetValue(entry); node = (ResExtNode *)HashGetValue(entry);
if (node->status & PORTNODE)
for (rdriver = node->drivepoints; rdriver; rdriver = rdriver->rc_next)
{ {
if (rdriver->rc_type <= 0) if (node->rs_ttype <= 0)
{ {
TxError("Warning: Label \"%s\" is unconnected.\n", node->name); TxError("Warning: Label \"%s\" is unconnected.\n", node->name);
continue; continue;
} }
rect = &(rdriver->rc_rect); rect = &(node->rs_bbox);
/* If label is on a contact, the contact has been dissolved. */
/* Assume that the uppermost residue is the port. This may */
/* not necessarily be the case. Could do a boundary scan on */
/* each residue plane to see which side of the contact is */
/* the internal connection in the def. . . */
if (DBIsContact(rdriver->rc_type))
{
TileType type;
DBFullResidueMask(rdriver->rc_type, &mask);
for (type = DBNumUserLayers - 1; type >= TT_TECHDEPBASE; type--)
if (TTMaskHasType(&mask, type))
{
plane = def->cd_planes[DBPlane(type)];
break;
}
}
else
{
TTMaskSetOnlyType(&mask, rdriver->rc_type);
plane = def->cd_planes[DBPlane(rdriver->rc_type)];
}
dsd.dsd_connect = rdriver;
dsd.dsd_node = node;
(void) DBSrPaintArea((Tile *) NULL, plane, rect, &mask,
ResAddPortFunc, (ClientData)&dsd);
}
/* Process sink points in the same way */
for (rsink = node->sinkpoints; rsink; rsink = rsink->rc_next)
{
if (rsink->rc_type <= 0)
{
TxError("Warning: Label \"%s\" is unconnected.\n", node->name);
continue;
}
rect = &(rsink->rc_rect);
/* Beware of zero-area ports */ /* Beware of zero-area ports */
if (rect->r_xbot == rect->r_xtop) if (rect->r_xbot == rect->r_xtop)
@ -314,11 +235,11 @@ ResMakeDriverSinkPorts(def)
/* each residue plane to see which side of the contact is */ /* each residue plane to see which side of the contact is */
/* the internal connection in the def. . . */ /* the internal connection in the def. . . */
if (DBIsContact(rsink->rc_type)) if (DBIsContact(node->rs_ttype))
{ {
TileType type; TileType type;
DBFullResidueMask(rsink->rc_type, &mask); DBFullResidueMask(node->rs_ttype, &mask);
for (type = DBNumUserLayers - 1; type >= TT_TECHDEPBASE; type--) for (type = DBNumUserLayers - 1; type >= TT_TECHDEPBASE; type--)
if (TTMaskHasType(&mask, type)) if (TTMaskHasType(&mask, type))
{ {
@ -328,122 +249,40 @@ ResMakeDriverSinkPorts(def)
} }
else else
{ {
TTMaskSetOnlyType(&mask, rsink->rc_type); TTMaskSetOnlyType(&mask, node->rs_ttype);
plane = def->cd_planes[DBPlane(rsink->rc_type)]; plane = def->cd_planes[DBPlane(node->rs_ttype)];
} }
dsd.dsd_connect = rsink;
dsd.dsd_node = node;
(void) DBSrPaintArea((Tile *) NULL, plane, rect, &mask, (void) DBSrPaintArea((Tile *) NULL, plane, rect, &mask,
ResAddPortFunc, (ClientData)&dsd); ResAddBreakpointFunc, (ClientData)node);
} }
} }
} }
/*
*----------------------------------------------------------------------------
*
* ResAddPortFunc --
*
* Add a portList entry to the "resInfo" structure of the tile. The
* portList entry keeps a record of the area of overlap or abutment
* of the port, as well as a pointer to the resNode.
*
* Results:
* Always returns 0;
*
* Side effects:
* Adds information to a tile's "resInfo" clientData.
*
*----------------------------------------------------------------------------
*/
int
ResAddPortFunc(tile, dinfo, dsd)
Tile *tile;
TileType dinfo; /* (unused) */
DriverSinkData *dsd; /* Data for driver or sink */
{
resPort *rp;
resInfo *pX;
Rect rect;
ResConnect *connect;
ResExtNode *node;
if (TiGetClient(tile) == CLIENTDEFAULT)
return 0;
/* To simplify processing, if a split tile does not have TT_SPACE
* on either side, then only the left side is processed.
*/
if (IsSplit(tile))
if (TiGetLeftType(tile) != TT_SPACE && TiGetRightType(tile) != TT_SPACE)
if (dinfo & TT_SIDE)
return 0;
node = dsd->dsd_node;
connect = dsd->dsd_connect;
TiToRect(tile, &rect);
pX = (resInfo *)TiGetClient(tile);
rp = (resPort *) mallocMagic((unsigned)(sizeof(resPort)));
rp->rp_nextPort = pX->portList;
rp->rp_bbox = connect->rc_rect;
rp->rp_loc = connect->rc_rect.r_ll;
rp->rp_connect = connect;
rp->rp_nodename = node->name;
pX->portList = rp;
return 0;
}
/* Structure used by ResMakeLabelPorts() to pass information to
* ResAddPortFunc(). Contains a reference to a node, so that the
* link between the tile and the node can be maintained, and the
* label, which has the information about the position and tile
* type of the label.
*/
typedef struct reslabeldata {
ResExtNode *rld_node;
Label *rld_label;
ResConnect *rld_connect;
} ResLabelData;
/* /*
*--------------------------------------------------------------------------- *---------------------------------------------------------------------------
* *
* ResMakeLabelPorts -- * ResMakeLabelBreakpoints --
* *
* Search for labels that are part of a node, and add them to the * Search for labels that are part of a node, and force them to be
* portList linked list in the "resInfo" field of their respective tiles * breakpoints in the "resInfo" field of their respective tiles in
* in ResUse. This ensures (among other things) that pins of a top level * ResUse. This ensures (among other things) that pins of a top level
* cell will be retained and become the endpoint of a net. * cell will be retained and become the endpoint of a net.
* *
* Results:
* None.
*
* Side effects:
* Adds information to the resInfo clientData of tiles in def.
*
*---------------------------------------------------------------------------- *----------------------------------------------------------------------------
*/ */
void void
ResMakeLabelPorts(def, resisdata) ResMakeLabelBreakpoints(def, resisdata)
CellDef *def; CellDef *def;
ResisData *resisdata; ResisData *resisdata;
{ {
Plane *plane; Plane *plane;
Rect *rect;
TileTypeBitMask mask; TileTypeBitMask mask;
HashEntry *entry; HashEntry *entry;
ResExtNode *node; ResExtNode *node;
ResConnect *rdriver, *newsink;
Label *slab; Label *slab;
ResLabelData rld; int ResAddBreakpointFunc(); /* Forward Declaration */
int ResAddLabelFunc(); /* Forward Declaration */
for (slab = def->cd_labels; slab != NULL; slab = slab->lab_next) for (slab = def->cd_labels; slab != NULL; slab = slab->lab_next)
{ {
@ -454,26 +293,20 @@ ResMakeLabelPorts(def, resisdata)
entry = HashFind(&ResNodeTable, slab->lab_text); entry = HashFind(&ResNodeTable, slab->lab_text);
node = ResExtInitNode(entry); node = ResExtInitNode(entry);
/* If there is an existing drivepoint at this location, */ /* If the drivepoint position changes and the drivepoint is */
/* then ignore it. */ /* in the "resisdata" record, then make sure the tile type */
/* in "resisdata" gets changed to match. */
for (rdriver = node->drivepoints; rdriver; rdriver = rdriver->rc_next) if (resisdata->rg_devloc == &node->drivepoint)
{
if (GEO_TOUCH(&slab->lab_rect, &rdriver->rc_rect))
break;
}
if (rdriver != NULL) break;
/* Add a new sinkpoint to the node where the label is */
newsink = (ResConnect *)mallocMagic(sizeof(ResConnect));
newsink->rc_next = node->sinkpoints;
node->sinkpoints = newsink;
if (GEO_ENCLOSE(resisdata->rg_devloc, &slab->lab_rect))
resisdata->rg_ttype = slab->lab_type; resisdata->rg_ttype = slab->lab_type;
newsink->rc_rect = slab->lab_rect; node->drivepoint = slab->lab_rect.r_ll;
newsink->rc_type = slab->lab_type; node->rs_bbox = slab->lab_rect;
node->location = slab->lab_rect.r_ll;
node->rs_ttype = slab->lab_type;
node->type = slab->lab_type;
rect = &(node->rs_bbox);
/* If label is on a contact, the contact has been dissolved. */ /* If label is on a contact, the contact has been dissolved. */
/* Assume that the uppermost residue is the port. This may */ /* Assume that the uppermost residue is the port. This may */
@ -499,44 +332,29 @@ ResMakeLabelPorts(def, resisdata)
plane = def->cd_planes[DBPlane(slab->lab_type)]; plane = def->cd_planes[DBPlane(slab->lab_type)];
} }
rld.rld_node = node; (void) DBSrPaintArea((Tile *) NULL, plane, rect, &mask,
rld.rld_label = slab; ResAddBreakpointFunc, (ClientData)node);
rld.rld_connect = newsink;
(void) DBSrPaintArea((Tile *) NULL, plane, &newsink->rc_rect, &mask,
ResAddLabelFunc, (ClientData)&rld);
} }
} }
/* /*
*---------------------------------------------------------------------------- *----------------------------------------------------------------------------
* *
* ResAddLabelFunc -- * ResAddBreakpointFunc --
* *
* Add a portList entry to the "resInfo" structure of the tile. The * Add a breakpoint to the "resInfo" structure of the tile
* portList entry keeps a record of the area of overlap or abutment
* of the port, as well as a pointer to the resNode.
*
* Results:
* Always returns 0;
*
* Side effects:
* Adds information to a tile's "resInfo" clientData.
* *
*---------------------------------------------------------------------------- *----------------------------------------------------------------------------
*/ */
int int
ResAddLabelFunc(tile, dinfo, rld) ResAddBreakpointFunc(tile, dinfo, node)
Tile *tile; Tile *tile;
TileType dinfo; /* (unused) */ TileType dinfo; /* (unused) */
ResLabelData *rld; /* Label and node data */ ResExtNode *node;
{ {
resPort *rp; resInfo *info;
resInfo *pX;
Rect rect;
Label *label;
ResExtNode *node;
ResConnect *connect;
if (TiGetClient(tile) == CLIENTDEFAULT) if (TiGetClient(tile) == CLIENTDEFAULT)
return 0; return 0;
@ -549,38 +367,24 @@ ResAddLabelFunc(tile, dinfo, rld)
if (dinfo & TT_SIDE) if (dinfo & TT_SIDE)
return 0; return 0;
node = rld->rld_node; NEWPORT(node, tile);
label = rld->rld_label;
connect = rld->rld_connect;
TiToRect(tile, &rect);
pX = (resInfo *)TiGetClient(tile);
rp = (resPort *) mallocMagic((unsigned)(sizeof(resPort)));
rp->rp_nextPort = pX->portList;
rp->rp_bbox = label->lab_rect;
rp->rp_loc = label->lab_rect.r_ll;
rp->rp_connect = connect;
rp->rp_nodename = node->name;
pX->portList = rp;
return 0; return 0;
} }
/* /*
*--------------------------------------------------------------------------- *---------------------------------------------------------------------------
* *
* 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: modifies information in the contact records. * Side Effects: 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.
* *
*---------------------------------------------------------------------------- *----------------------------------------------------------------------------
*/ */
@ -592,40 +396,29 @@ 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)
{ {
/* Avoid re-running the following code for the same contact type */ DBFullResidueMask(contacts->cp_type, &mask);
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)
{ {
lastType = contacts->cp_type; TileTypeBitMask cMask;
DBFullResidueMask(contacts->cp_type, &mask); TTMaskAndMask3(&cMask, &DBConnectTbl[contacts->cp_type],
&DBPlaneTypes[ExtCurStyle->exts_globSubstratePlane]);
/* Watch for types that connect to the substrate plane or well; */ if (!TTMaskIsZero(&cMask))
/* e.g., psubstratepdiff connects to nwell but not through a */ TTMaskSetMask(&mask, &cMask);
/* 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)
{ {
@ -683,11 +476,10 @@ ResFindNewContactTiles(contacts)
/* /*
*-------------------------------------------------------------------------- *--------------------------------------------------------------------------
* *
* ResProcessTiles -- * ResProcessTiles--Calls ResEachTile with processed tiles belonging to
* * nodes in ResNodeQueue. When all the tiles corresponding
* Calls ResEachTile with processed tiles belonging to nodes in ResNodeQueue. * to a node have been processed, the node is moved to
* When all the tiles corresponding to a node have been processed, the node * ResNodeList.
* is moved to ResNodeList.
* *
* Results: Return 1 if any error occurred, 0 otherwise. * Results: Return 1 if any error occurred, 0 otherwise.
* *
@ -697,10 +489,10 @@ ResFindNewContactTiles(contacts)
*/ */
int int
ResProcessTiles(resisdata, origin, devices) ResProcessTiles(resisdata, origin)
ResisData *resisdata;
Point *origin; Point *origin;
ResDevTile *devices; ResisData *resisdata;
{ {
Tile *startTile; Tile *startTile;
int tilenum, merged; int tilenum, merged;
@ -717,8 +509,7 @@ ResProcessTiles(resisdata, origin, devices)
if (startTile == NULL) if (startTile == NULL)
return 1; return 1;
resCurrentNode = NULL; resCurrentNode = NULL;
ResStartTile(startTile, origin->p_x, origin->p_y); (void) ResEachTile(startTile, origin);
(void) ResEachTile(startTile, devices);
} }
#ifdef PARANOID #ifdef PARANOID
else else
@ -755,7 +546,7 @@ ResProcessTiles(resisdata, origin, devices)
if ((ri->ri_status & RES_TILE_DONE) == 0) if ((ri->ri_status & RES_TILE_DONE) == 0)
{ {
resCurrentNode = resptr2; resCurrentNode = resptr2;
merged |= ResEachTile(tile, devices); merged |= ResEachTile(tile, (Point *)NULL);
} }
} }
rj->rj_status = TRUE; rj->rj_status = TRUE;
@ -781,7 +572,7 @@ ResProcessTiles(resisdata, origin, devices)
if (cp->cp_cnode[tilenum] == resptr2) if (cp->cp_cnode[tilenum] == resptr2)
{ {
resCurrentNode = resptr2; resCurrentNode = resptr2;
merged |= ResEachTile(tile, devices); merged |= ResEachTile(tile, (Point *)NULL);
} }
else else
{ {
@ -864,7 +655,7 @@ ResCalcPerimOverlap(tile, dev)
} }
/* right */ /* right */
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp)) for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp=LB(tp))
{ {
if TTMaskHasType(omask, TiGetLeftType(tp)) if TTMaskHasType(omask, TiGetLeftType(tp))
overlap += MIN(TOP(tile), TOP(tp)) - MAX(BOTTOM(tile), BOTTOM(tp)); overlap += MIN(TOP(tile), TOP(tp)) - MAX(BOTTOM(tile), BOTTOM(tp));
@ -878,7 +669,7 @@ ResCalcPerimOverlap(tile, dev)
} }
/* bottom */ /* bottom */
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp)) for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp))
{ {
if TTMaskHasType(omask, TiGetTopType(tp)) if TTMaskHasType(omask, TiGetTopType(tp))
overlap += MIN(RIGHT(tile), RIGHT(tp)) - MAX(LEFT(tile), LEFT(tp)); overlap += MIN(RIGHT(tile), RIGHT(tp)) - MAX(LEFT(tile), LEFT(tp));
@ -1209,7 +1000,6 @@ ResExtractNet(node, resisdata, cellname)
int pNum; int pNum;
int resMakeDevFunc(); int resMakeDevFunc();
int resExpandDevFunc(); int resExpandDevFunc();
int result;
/* Make sure all global network variables are reset */ /* Make sure all global network variables are reset */
@ -1264,22 +1054,15 @@ ResExtractNet(node, resisdata, cellname)
/* Copy Paint */ /* Copy Paint */
/* If the node location is INFINITY, then use the first drivepoint */ /* If the node location is INFINITY, then use the rs_bbox */
if ((node->location.p_x == INFINITY) || (node->location.p_y == INFINITY)) if ((node->location.p_x == INFINITY) || (node->location.p_y == INFINITY))
{ {
ResConnect *rdriver = node->drivepoints; scx.scx_area.r_ll.p_x = node->rs_bbox.r_xbot;
if (rdriver) scx.scx_area.r_ll.p_y = node->rs_bbox.r_ybot;
{ scx.scx_area.r_ur.p_x = node->rs_bbox.r_xtop;
scx.scx_area.r_ll.p_x = rdriver->rc_rect.r_xbot - 2; scx.scx_area.r_ur.p_y = node->rs_bbox.r_ytop;
scx.scx_area.r_ll.p_y = rdriver->rc_rect.r_ybot - 2; startpoint = node->drivepoint;
scx.scx_area.r_ur.p_x = rdriver->rc_rect.r_xtop + 2;
scx.scx_area.r_ur.p_y = rdriver->rc_rect.r_ytop + 2;
startpoint.p_x = (rdriver->rc_rect.r_xtop + rdriver->rc_rect.r_xbot) / 2;
startpoint.p_y = (rdriver->rc_rect.r_ytop + rdriver->rc_rect.r_ybot) / 2;
}
else
TxError("Internal error: Node location is set to infinity.\n");
} }
else else
{ {
@ -1302,41 +1085,15 @@ ResExtractNet(node, resisdata, cellname)
DBTreeCopyConnect(&scx, &FirstTileMask, 0, ResCopyMask, &TiPlaneRect, DBTreeCopyConnect(&scx, &FirstTileMask, 0, ResCopyMask, &TiPlaneRect,
SEL_DO_LABELS, ResUse); SEL_DO_LABELS, ResUse);
} }
else if (node->drivepoints)
{
/* Use the first valid drivepoint */
ResConnect *drivepoint = node->drivepoints;
while (drivepoint && (drivepoint->rc_type == TT_SPACE))
drivepoint = drivepoint->rc_next;
if (drivepoint)
{
TTMaskZero(&FirstTileMask);
TTMaskSetMask(&FirstTileMask, &DBConnectTbl[drivepoint->rc_type]);
DBTreeCopyConnect(&scx, &FirstTileMask, 0, ResCopyMask, &TiPlaneRect, TTMaskZero(&ResSDTypesBitMask);
SEL_DO_LABELS, ResUse);
}
else
{
TxError("Node %s: Did not find the net layout at any drivepoint.\n",
node->name);
return TRUE;
}
}
else
{
TxError("Node %s: Did not find the net layout at node location (%d %d).\n",
node->name, node->location.p_x, node->location.p_y);
return TRUE;
}
TTMaskZero(&ResTermTypesBitMask);
TTMaskZero(&ResSubTypesBitMask); TTMaskZero(&ResSubTypesBitMask);
/* Add devices to ResUse from list in node */ /* Add devices to ResUse from list in node */
DevTiles = NULL; DevTiles = NULL;
for (tptr = node->devices; tptr; tptr = tptr->nextDev) for (tptr = node->firstDev; tptr; tptr = tptr->nextDev)
{ {
int result;
int i; int i;
ExtDevice *devptr; ExtDevice *devptr;
@ -1366,13 +1123,13 @@ ResExtractNet(node, resisdata, cellname)
TTMaskSetOnlyType(&tMask, thisDev->type); TTMaskSetOnlyType(&tMask, thisDev->type);
DBTreeSrTiles(&scx, &tMask, 0, resExpandDevFunc, (ClientData)thisDev); DBTreeSrTiles(&scx, &tMask, 0, resExpandDevFunc, (ClientData)thisDev);
/* If the device has terminal types in a different plane than */ /* If the device has source/drain types in a different plane than */
/* the device identifier type, then add the terminal types to */ /* the device identifier type, then add the source/drain types to */
/* the mask ResTermTypesBitMask. */ /* the mask ResSDTypesBitMask. */
devptr = tptr->thisDev->rs_devptr; devptr = tptr->thisDev->rs_devptr;
for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++) for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++)
TTMaskSetMask(&ResTermTypesBitMask, &devptr->exts_deviceSDTypes[i]); TTMaskSetMask(&ResSDTypesBitMask, &devptr->exts_deviceSDTypes[i]);
/* Add the substrate types to the mask ResSubTypesBitMask */ /* Add the substrate types to the mask ResSubTypesBitMask */
TTMaskSetMask(&ResSubTypesBitMask, &devptr->exts_deviceSubstrateTypes); TTMaskSetMask(&ResSubTypesBitMask, &devptr->exts_deviceSubstrateTypes);
@ -1382,6 +1139,8 @@ ResExtractNet(node, resisdata, cellname)
} }
DBReComputeBbox(ResUse->cu_def); DBReComputeBbox(ResUse->cu_def);
ExtResetTiles(scx.scx_use->cu_def, CLIENTDEFAULT);
/* To avoid issues with overlapping stacked contact types and */ /* To avoid issues with overlapping stacked contact types and */
/* double-counting contacts on multiple planes, erase the top */ /* double-counting contacts on multiple planes, erase the top */
/* contact layers of all contacts. ExtFindRegions() will still */ /* contact layers of all contacts. ExtFindRegions() will still */
@ -1417,38 +1176,27 @@ ResExtractNet(node, resisdata, cellname)
ResDissolveContacts(ResContactList); ResDissolveContacts(ResContactList);
/* Fracture the plane to change maximum horizontal stripes to a /* Add "resInfo" fields to tiles */
* format better suited to tracking the path of current through
* the wiring.
*/
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{ {
Plane *plane = ResUse->cu_def->cd_planes[pNum]; Plane *plane = ResUse->cu_def->cd_planes[pNum];
Rect *rect = &ResUse->cu_def->cd_bbox; Rect *rect = &ResUse->cu_def->cd_bbox;
ResFracture(plane, rect); ResFracture(plane, rect);
(void) DBSrPaintClient((Tile *) NULL, plane, rect,
&DBAllButSpaceAndDRCBits,
(ClientData) CLIENTDEFAULT, ResAddPlumbing,
(ClientData) &ResDevList);
} }
/* Add "resInfo" fields to device tiles. */
for (thisDev = DevTiles; thisDev; thisDev = thisDev->nextDev)
ResAddDevPlumbing(thisDev, &ResDevList);
/* Add "resInfo" fields to any untouched tiles. */
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
DBSrPaintClient((Tile *)NULL,
ResUse->cu_def->cd_planes[pNum],
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
(ClientData)CLIENTDEFAULT, ResAddPlumbing,
(ClientData)NULL);
/* If this is a top-level cell, then determine where connections /* If this is a top-level cell, then determine where connections
* are made into the cell from ports. Otherwise, determine points * are made into the cell from ports. Otherwise, determine points
* of entry by looking at how all parent cells connect to this * of entry by looking at how all parent cells connect to this
* cell. * cell.
*/ */
ResMakeDriverSinkPorts(ResUse->cu_def); ResMakePortBreakpoints(ResUse->cu_def);
ResMakeLabelPorts(ResUse->cu_def, resisdata); ResMakeLabelBreakpoints(ResUse->cu_def, resisdata);
/* Finish preprocessing. */ /* Finish preprocessing. */
@ -1456,9 +1204,7 @@ ResExtractNet(node, resisdata, cellname)
ResPreProcessDevices(DevTiles, ResDevList, ResUse->cu_def); ResPreProcessDevices(DevTiles, ResDevList, ResUse->cu_def);
/* do extraction */ /* do extraction */
result = ResProcessTiles(resisdata, &startpoint, DevTiles); if (ResProcessTiles(resisdata, &startpoint) != 0) return TRUE;
ResFreeDevTiles(DevTiles);
if (result != 0) return TRUE;
return FALSE; return FALSE;
} }
@ -1635,7 +1381,6 @@ 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;
@ -1650,13 +1395,13 @@ FindStartTile(resisdata, SourcePoint)
if (workingPoint.p_x == LEFT(tile)) if (workingPoint.p_x == LEFT(tile))
{ {
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp)) for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp=RT(tp))
if (TiGetRightType(tp) == resisdata->rg_ttype) if (TiGetRightType(tp) == resisdata->rg_ttype)
return(tp); return(tp);
} }
else if (workingPoint.p_y == BOTTOM(tile)) else if (workingPoint.p_y == BOTTOM(tile))
{ {
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp)) for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp=TR(tp))
if (TiGetTopType(tp) == resisdata->rg_ttype) if (TiGetTopType(tp) == resisdata->rg_ttype)
return(tp); return(tp);
} }
@ -1669,7 +1414,6 @@ 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))
{ {
@ -1713,7 +1457,7 @@ FindStartTile(resisdata, SourcePoint)
TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2)) TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2))
{ {
SourcePoint->p_x = LEFT(tile); SourcePoint->p_x = LEFT(tile);
SourcePoint->p_y = (MIN(TOP(tile), TOP(tp)) + SourcePoint->p_y = (MIN(TOP(tile),TOP(tp)) +
MAX(BOTTOM(tile), BOTTOM(tp))) >> 1; MAX(BOTTOM(tile), BOTTOM(tp))) >> 1;
return(tp); return(tp);
} }
@ -1756,7 +1500,7 @@ FindStartTile(resisdata, SourcePoint)
TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2)) TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2))
{ {
SourcePoint->p_y = TOP(tile); SourcePoint->p_y = TOP(tile);
SourcePoint->p_x = (MIN(RIGHT(tile), RIGHT(tp)) + SourcePoint->p_x = (MIN(RIGHT(tile),RIGHT(tp)) +
MAX(LEFT(tile), LEFT(tp))) >> 1; MAX(LEFT(tile), LEFT(tp))) >> 1;
return(tp); return(tp);
} }
@ -1812,7 +1556,7 @@ FindStartTile(resisdata, SourcePoint)
TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2)) TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2))
{ {
SourcePoint->p_x = LEFT(tile); SourcePoint->p_x = LEFT(tile);
SourcePoint->p_y = (MIN(TOP(tile), TOP(tp)) + SourcePoint->p_y = (MIN(TOP(tile),TOP(tp)) +
MAX(BOTTOM(tile), BOTTOM(tp))) >> 1; MAX(BOTTOM(tile), BOTTOM(tp))) >> 1;
while (!StackEmpty(devStack)) while (!StackEmpty(devStack))
{ {
@ -1880,7 +1624,7 @@ FindStartTile(resisdata, SourcePoint)
TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2)) TTMaskHasType(&(devptr->exts_deviceSDTypes[i]), t2))
{ {
SourcePoint->p_y = TOP(tile); SourcePoint->p_y = TOP(tile);
SourcePoint->p_x = (MIN(RIGHT(tile), RIGHT(tp)) + SourcePoint->p_x = (MIN(RIGHT(tile),RIGHT(tp)) +
MAX(LEFT(tile), LEFT(tp))) >> 1; MAX(LEFT(tile), LEFT(tp))) >> 1;
while (!StackEmpty(devStack)) while (!StackEmpty(devStack))
{ {
@ -2021,7 +1765,6 @@ 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))

View File

@ -76,9 +76,10 @@ 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 */
@ -124,7 +125,7 @@ ResCalcEastWest(tile, pendingList, doneList, resList)
resNode **pendingList, **doneList; resNode **pendingList, **doneList;
resResistor **resList; resResistor **resList;
{ {
int count, height; int height;
bool merged; bool merged;
TileType ttype; TileType ttype;
Breakpoint *p1, *p2, *p3; Breakpoint *p1, *p2, *p3;
@ -133,8 +134,6 @@ 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);
@ -164,38 +163,21 @@ 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);
/* For long lists (defined as >= 16 entries), make a hash table of ResSortBreaks(&info->breakList, TRUE);
* 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)
@ -233,38 +215,25 @@ 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)
{ {
he = HashFind(&BreakTable, (char *)currNode); if (p3->br_this == currNode)
HashSetValue(he, (char *)p2->br_this); p3->br_this = 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;
@ -307,8 +276,6 @@ 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;
@ -334,7 +301,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
resNode **pendingList, **doneList; resNode **pendingList, **doneList;
resResistor **resList; resResistor **resList;
{ {
int count, width; int width;
bool merged; bool merged;
TileType ttype; TileType ttype;
Breakpoint *p1, *p2, *p3; Breakpoint *p1, *p2, *p3;
@ -343,8 +310,6 @@ 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);
@ -364,15 +329,7 @@ ResCalcNorthSouth(tile, pendingList, doneList, resList)
} }
/* Re-sort nodes south to north. */ /* Re-sort nodes south to north. */
count = ResSortBreaks(&info->breakList, FALSE); 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))
@ -396,75 +353,51 @@ 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.
*/ */
if (count >= 16) p3 = p2->br_next;
while (p3 != NULL)
{ {
he = HashFind(&BreakTable, (char *)currNode); if (p3->br_this == currNode)
HashSetValue(he, (char *)p2->br_this); p3->br_this = 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;
}
} }
} }
@ -558,7 +491,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;
@ -592,7 +525,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)
{ {
@ -687,7 +620,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
} }
else else
{ {
deltay = 0; deltay=0;
} }
} }
else else
@ -701,15 +634,15 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
{ {
if (p2->br_crect->r_ll.p_y > p1->br_loc.p_y) if (p2->br_crect->r_ll.p_y > p1->br_loc.p_y)
{ {
deltay = MIN(deltay, p2->br_crect->r_ll.p_y - p1->br_loc.p_y); deltay = MIN(deltay,p2->br_crect->r_ll.p_y - p1->br_loc.p_y);
} }
else if (p2->br_crect->r_ur.p_y < p1->br_loc.p_y) else if (p2->br_crect->r_ur.p_y < p1->br_loc.p_y)
{ {
deltay = MIN(deltay, p1->br_loc.p_y - p2->br_crect->r_ur.p_y); deltay = MIN(deltay,p1->br_loc.p_y - p2->br_crect->r_ur.p_y);
} }
else else
{ {
deltay = 0; deltay=0;
} }
} }
else else
@ -887,7 +820,7 @@ ResDoContacts(contact, nodes, resList)
Tile *tile = contact->cp_tile[tilenum]; Tile *tile = contact->cp_tile[tilenum];
contact->cp_cnode[tilenum] = resptr; contact->cp_cnode[tilenum] = resptr;
ResNewBreak(resptr, tile, contact->cp_center.p_x, NEWBREAK(resptr, tile, contact->cp_center.p_x,
contact->cp_center.p_y, &contact->cp_rect); contact->cp_center.p_y, &contact->cp_rect);
} }
} }
@ -936,7 +869,7 @@ ResDoContacts(contact, nodes, resList)
ccell->ce_thisc = contact; ccell->ce_thisc = contact;
contact->cp_cnode[tilenum] = resptr; contact->cp_cnode[tilenum] = resptr;
ResNewBreak(resptr, tile, contact->cp_center.p_x, NEWBREAK(resptr, tile, contact->cp_center.p_x,
contact->cp_center.p_y, &contact->cp_rect); contact->cp_center.p_y, &contact->cp_rect);
/* Add resistors here */ /* Add resistors here */
@ -986,207 +919,21 @@ ResDoContacts(contact, nodes, resList)
/* /*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
* *
* BreakCompare -- * ResSortBreaks --
*
* 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)
@ -1223,6 +970,5 @@ ResSortBreaks(masterlist, xsort)
} }
} }
} }
return count;
} }

View File

@ -26,6 +26,7 @@ extern void ResEliminateResistor();
extern void ResCleanNode(); extern void ResCleanNode();
extern void ResFixBreakPoint(); extern void ResFixBreakPoint();
/* /*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
* *
@ -210,7 +211,7 @@ ResFixParallel(elimResis, newResis)
* ResSeriesCheck -- for nodes with no devices, sees if a series * ResSeriesCheck -- for nodes with no devices, sees if a series
* or loop combination is possible. * or loop combination is possible.
* *
* Results: returns SINGLE, LOOP, or SERIES if succesful. * Results: returns SINGLE,LOOP,or SERIES if succesful.
* *
* Side Effects: may delete some nodes and resistors. * Side Effects: may delete some nodes and resistors.
* *
@ -405,70 +406,13 @@ 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)
@ -503,7 +447,6 @@ ResParallelCheck(resptr)
} }
if (status == PARALLEL) break; if (status == PARALLEL) break;
} }
return status; return status;
} }
@ -530,179 +473,6 @@ 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)
@ -839,9 +609,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.
* *
@ -1010,7 +780,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.
* *
@ -1018,7 +788,7 @@ ResMergeNodes(node1, node2, pendingList, doneList)
*/ */
void void
ResDeleteResPointer(node, resistor) ResDeleteResPointer(node,resistor)
resNode *node; resNode *node;
resResistor *resistor; resResistor *resistor;
@ -1059,7 +829,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.
@ -1097,7 +867,8 @@ 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: none. * Results:
* None.
* *
* Side Effects: frees memory * Side Effects: frees memory
* *

View File

@ -52,7 +52,7 @@ ResPrintExtRes(outextfile, resistors, nodename)
char *nodename; char *nodename;
{ {
int nodenum = 0; int nodenum=0;
char newname[MAXNAME]; char newname[MAXNAME];
HashEntry *entry; HashEntry *entry;
ResExtNode *node; ResExtNode *node;
@ -261,7 +261,7 @@ ResPrintExtNode(outextfile, nodelist, node)
{ {
if (snode->rn_name == NULL) if (snode->rn_name == NULL)
{ {
(void)sprintf(tmpname, "%s", nodename); (void)sprintf(tmpname,"%s",nodename);
cp = tmpname + strlen(tmpname) - 1; cp = tmpname + strlen(tmpname) - 1;
if (*cp == '!' || *cp == '#') *cp = '\0'; if (*cp == '!' || *cp == '#') *cp = '\0';
@ -342,13 +342,13 @@ ResPrintStats(resisdata, name)
nodes = 0; nodes = 0;
resistors = 0; resistors = 0;
totalnets++; totalnets++;
for (node = ResNodeList; node != NULL; node = node->rn_more) for (node = ResNodeList; node != NULL; node=node->rn_more)
{ {
nodes++; nodes++;
totalnodes++; totalnodes++;
} }
for (res = ResResList; res != NULL; res = res->rr_nextResistor) for (res = ResResList; res != NULL; res=res->rr_nextResistor)
{ {
resistors++; resistors++;
totalresistors++; totalresistors++;

View File

@ -61,7 +61,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#define DEV_PARAM_START 7 #define DEV_PARAM_START 7
#define NODES_NODENAME 1 #define NODES_NODENAME 1
#define NODES_NODERES 2
#define NODES_NODEX 4 #define NODES_NODEX 4
#define NODES_NODEY 5 #define NODES_NODEY 5
#define NODES_NODETYPE 6 #define NODES_NODETYPE 6
@ -83,24 +82,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#define PORT_URY 6 #define PORT_URY 6
#define PORT_TYPE 7 #define PORT_TYPE 7
#define USE_DEF_NAME 1
#define USE_ID_NAME 2
#define USE_TRANSFORM_A 3
#define USE_TRANSFORM_B 4
#define USE_TRANSFORM_C 5
#define USE_TRANSFORM_D 6
#define USE_TRANSFORM_E 7
#define USE_TRANSFORM_F 8
/* Note that "connect" lines may repeat these six entries up to argc */
#define CONNECT_LLX 1
#define CONNECT_LLY 2
#define CONNECT_URX 3
#define CONNECT_URY 4
#define CONNECT_TYPE 5
#define CONNECT_UP_NAME 6
#define CONNECT_DOWN_NAME 7
#define MAXDIGIT 20 #define MAXDIGIT 20
ResExtNode *ResOriginalNodes; /*Linked List of Nodes */ ResExtNode *ResOriginalNodes; /*Linked List of Nodes */
@ -110,18 +91,11 @@ ResFixPoint *ResFixList;
/* /*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
* *
* ResReadExt -- * ResReadExt--
* *
* Read a .ext file for resistance extraction. Extresist does not use * Results: returns 0 if ext file is correct, 1 if not.
* the .ext file reader in extflat/EFread.c because it takes only a
* small amount of information from the .ext file, mainly to keep a
* list of nets and net names, devices and their terminals and
* connections, and subcell connections. However, it does make use
* of the line parser and tokenizer in extflat.
* *
* Results: Returns 0 if ext file is correct, 1 if not. * Side Effects:Reads in ExtTable and makes a hash table of nodes.
*
* Side Effects: Creates lists of nodes and devices for extresist.
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -133,11 +107,8 @@ ResReadExt(CellDef *def)
int result, locresult; int result, locresult;
int argc, n, size = 0; int argc, n, size = 0;
FILE *fp; FILE *fp;
CellDef *dbdef, *parent; CellDef *dbdef;
CellUse *use;
ResExtNode *curnode; ResExtNode *curnode;
HashTable parentHash;
HashEntry *he;
/* Search for the .ext file in the same way that efReadDef() does. */ /* Search for the .ext file in the same way that efReadDef() does. */
@ -171,10 +142,7 @@ ResReadExt(CellDef *def)
} }
/* We don't care about most tokens, only DEVICE, NODE, PORT, /* We don't care about most tokens, only DEVICE, NODE, PORT,
* and SUBSTRATE; and CONNECT is used to locate sink points. * and SUBSTRATE; and MERGE is used to locate drive points.
* Note that MERGE is not useful here, as it may implicitly
* merge nets in the cell, which is useful for netlisting but
* not for annotating the extraction file.
*/ */
switch (keyTable[n].k_key) switch (keyTable[n].k_key)
{ {
@ -193,16 +161,17 @@ ResReadExt(CellDef *def)
case FET: case FET:
locresult = ResReadFET(argc, argv); locresult = ResReadFET(argc, argv);
break; break;
case CONNECT: case MERGE:
locresult = ResReadConnectPoint(def, argc, argv); /* To be completed */
break; /* ResReadDrivePoint(argc, argv); */
case PORT:
locresult = ResReadPort(argc, argv);
break; break;
case NODE: case NODE:
case SUBSTRATE: case SUBSTRATE:
curnode = ResReadNode(argc, argv); curnode = ResReadNode(argc, argv);
break; break;
case PORT:
locresult = ResReadPort(argc, argv);
break;
case ATTR: case ATTR:
locresult = ResReadAttribute(curnode, argc, argv); locresult = ResReadAttribute(curnode, argc, argv);
break; break;
@ -215,293 +184,9 @@ ResReadExt(CellDef *def)
if (locresult == 1) result = 1; if (locresult == 1) result = 1;
} }
fclose(fp); fclose(fp);
/* Find all the parent CellDefs of "def" and read the .ext file of
* each one to find where connections are made to this cell from
* parent cells. Place drive points at each connection point.
*/
HashInit(&parentHash, 32, HT_STRINGKEYS);
for (use = def->cd_parents; use; use = use->cu_nextuse)
{
if ((parent = use->cu_parent) == NULL) continue;
if (parent->cd_flags & CDINTERNAL) continue;
he = HashFind(&parentHash, parent->cd_name);
if ((CellDef *)HashGetValue(he) == NULL)
{
/* Mark parent def as being visited */
HashSetValue(he, (char *)parent);
/* Read connection information from the parent's .ext file */
ResReadParentExt(parent, def);
}
}
HashKill(&parentHash);
return(result); return(result);
} }
/*
*-------------------------------------------------------------------------
*
* ResReadUse --
*
* Read a "use" statement from the .ext file of a parent CellDef of
* the current def being extracted. If the use is a use of the
* current def, then save the use name and its transform in the
* hash table so that later "connect" statements can be translated
* into the coordinate system of the current cell def.
*
* Results:
* 1 if something went wrong with the parsing, 0 otherwise.
*
* Side effects:
* May add to the hash table.
*
*-------------------------------------------------------------------------
*/
int
ResReadUse(CellDef *def,
int argc,
char *argv[],
HashTable *useHash)
{
char *defname, *useid;
Transform *tinv, t;
HashEntry *he;
defname = argv[USE_DEF_NAME];
if (strcmp(defname, def->cd_name)) return 0; /* Not my use */
useid = argv[USE_ID_NAME];
he = HashFind(useHash, useid);
t.t_a = atoi(argv[USE_TRANSFORM_A]);
t.t_b = atoi(argv[USE_TRANSFORM_B]);
t.t_c = atoi(argv[USE_TRANSFORM_C]);
t.t_d = atoi(argv[USE_TRANSFORM_D]);
t.t_e = atoi(argv[USE_TRANSFORM_E]);
t.t_f = atoi(argv[USE_TRANSFORM_F]);
tinv = (Transform *)mallocMagic(sizeof(Transform));
GeoInvertTrans(&t, tinv);
HashSetValue(he, (char *)tinv);
return 0;
}
/*
*-------------------------------------------------------------------------
*
* ResReadDrivePoint --
*
* Read a "connect" statement from the .ext file of a parent CellDef
* of the current def being extracted. If the connection is made to
* a use of the current def, then translate the area of the connection
* into the current def, and mark the connection as a drive point of
* def.
*
* Results:
* 1 if something went wrong with the parsing, 0 otherwise.
*
* Side effects:
* May add information to the node list of def.
*
*-------------------------------------------------------------------------
*/
int
ResReadDrivePoint(CellDef *def,
int argc,
char *argv[],
HashTable *useHash)
{
HashEntry *entry;
ResExtNode *node;
ResConnect *newdriver;
int pNum;
TileType ttype;
Transform *t;
Rect r;
char *hierptr, *useid, *qptr, *downname;
/* Only handle entries that are in the use ID hash table */
useid = argv[CONNECT_DOWN_NAME];
if (*useid == '"') useid++;
hierptr = strchr(useid, '/');
if (hierptr != NULL) *hierptr = '\0';
qptr = strrchr(useid, '"');
if (qptr != NULL) *qptr = '\0';
if (hierptr != NULL)
downname = hierptr + 1;
else
downname = useid; /* This is probably invalid */
entry = HashFind(useHash, useid);
if ((t = (Transform *)HashGetValue(entry)) == NULL) return 0;
/* Check for the given tile type */
ttype = DBTechNoisyNameType(argv[CONNECT_TYPE]);
if (ttype == -1)
{
TxError("Bad tile type name \"%s\" in .ext file for node %s\n",
argv[CONNECT_TYPE], argv[CONNECT_UP_NAME]);
return 1;
}
/* Look up the node name */
if (strcmp(downname, "None"))
{
entry = HashLookOnly(&ResNodeTable, downname);
if (entry != NULL)
node = (ResExtNode *)HashGetValue(entry);
else
{
TxError("Unknown node name \"%s\" in .ext file connect entry\n",
downname);
return 1;
}
/* Generate new drivepoint entry */
newdriver = (ResConnect *)mallocMagic(sizeof(ResConnect));
r.r_xbot = atoi(argv[CONNECT_LLX]);
r.r_ybot = atoi(argv[CONNECT_LLY]);
r.r_xtop = atoi(argv[CONNECT_URX]);
r.r_ytop = atoi(argv[CONNECT_URY]);
/* Translate the connection position from the parent to the
* current cell def.
*/
GeoTransRect(t, &r, &newdriver->rc_rect);
newdriver->rc_type = ttype;
newdriver->rc_node = (resNode *)NULL;
newdriver->rc_next = node->drivepoints;
node->drivepoints = newdriver;
node->status |= FORCE | DRIVELOC;
if (ResOptionsFlags & ResOpt_Debug)
{
/* Diagnostic */
TxPrintf("Added driver at %d %d %d %d\n",
newdriver->rc_rect.r_xbot, newdriver->rc_rect.r_ybot,
newdriver->rc_rect.r_xtop, newdriver->rc_rect.r_ytop);
}
}
return 0;
}
/*
*-------------------------------------------------------------------------
*
* ResReadParentExt --
*
* Read a .ext file for a parent cell of the cell being extracted.
* Each .ext file contains a list of connection points into its
* subcells. However, no .ext file has information about how a
* parent cell connects to it; the exact connection may depend on
* the layout, and may or may not coincide with marked ports.
* Except for the top level cell, for which only marked ports can
* be used to guess at intended points of connection, every subcell
* can query its parents to find exact points of connection.
*
* Results: Returns 0 if ext file is correct, 1 if not.
*
* Side Effects: Creates lists of connection points for extresist.
*
*-------------------------------------------------------------------------
*/
int
ResReadParentExt(CellDef *parent,
CellDef *def)
{
char *line = NULL, *argv[128];
int result, locresult;
int argc, n, size = 0;
FILE *fp;
CellDef *dbdef;
ResExtNode *curnode;
HashTable useHash;
HashEntry *he;
HashSearch hs;
/* Search for the .ext file in the same way that efReadDef() does. */
fp = ExtFileOpen(parent, (char *)NULL, "r", (char **)NULL);
if (fp == NULL)
{
TxError("Cannot open file %s%s\n", parent->cd_name, ".ext");
return 1;
}
HashInit(&useHash, 32, HT_STRINGKEYS);
/* Read in the file. Makes use of various functions
* from extflat, mostly in EFread.c.
*/
EFSaveLocs = FALSE;
efReadLineNum = 0;
result = 0;
while ((argc = efReadLine(&line, &size, fp, argv)) >= 0)
{
n = LookupStruct(argv[0], (const LookupTable *)keyTable, sizeof keyTable[0]);
if (n < 0)
{
efReadError("Unrecognized token \"%s\" (ignored)\n", argv[0]);
continue;
}
if (argc < keyTable[n].k_mintokens)
{
efReadError("Not enough tokens for %s line\n", argv[0]);
continue;
}
/* When reading a parent .ext file to find connections to
* the cell being extracted by "extresist", we only care
* about CONNECT lines, and USE lines so that we can
* translate the connection points into the current cell def.
*
* Note: This method depends on the .ext file format having
* all "use" lines before "connect" lines.
*/
switch (keyTable[n].k_key)
{
case USE:
locresult = ResReadUse(def, argc, argv, &useHash);
break;
case CONNECT:
locresult = ResReadDrivePoint(def, argc, argv, &useHash);
break;
default:
break;
}
if (locresult == 1) result = 1;
}
fclose(fp);
HashStartSearch(&hs);
while ((he = HashNext(&useHash, &hs)))
{
if (HashGetValue(he) != NULL)
{
freeMagic(HashGetValue(he)); /* Free the allocated tranform */
HashSetValue(he, (ClientData)NULL);
}
}
HashKill(&useHash);
return(result);
}
/* /*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
@ -522,18 +207,20 @@ ResReadNode(int argc, char *argv[])
{ {
HashEntry *entry; HashEntry *entry;
ResExtNode *node; ResExtNode *node;
int noderesist;
entry = HashFind(&ResNodeTable, argv[NODES_NODENAME]); entry = HashFind(&ResNodeTable, argv[NODES_NODENAME]);
node = ResExtInitNode(entry); node = ResExtInitNode(entry);
node->location.p_x = atoi(argv[NODES_NODEX]); node->location.p_x = atoi(argv[NODES_NODEX]);
node->location.p_y = atoi(argv[NODES_NODEY]); node->location.p_y = atoi(argv[NODES_NODEY]);
node->type = DBTechNameType(argv[NODES_NODETYPE]);
noderesist = atoi(argv[NODES_NODERES]); /* If this node was previously read as a port, then don't change the
if (noderesist < 0) noderesist = INFINITY; * node type, which is tracking the type at the drivepoint.
/* Make sure node resistance is in units of milliohms */ */
node->resistance = (float)noderesist * (float)ExtCurStyle->exts_resistScale; if (!(node->status & PORTNODE))
{
node->type = DBTechNameType(argv[NODES_NODETYPE]);
}
if (node->type == -1) if (node->type == -1)
{ {
@ -543,85 +230,6 @@ ResReadNode(int argc, char *argv[])
return node; return node;
} }
/*
*-------------------------------------------------------------------------
*
* ResReadConnectPoint-- Reads in a "connect" statement from the .ext file
* and sets node records accordingly to mark the node as a connection
* point. There is a use (instance) name associated with each connection,
* which is unused for finding connection points to subcells; we
* don't care what the subcell is, only that there is a connection at
* a point on a net in this cell that should be recorded and never
* optimized out.
*
* Results: 0 if successful and 1 otherwise.
*
* Side Effects: see above
*
*-------------------------------------------------------------------------
*/
int
ResReadConnectPoint(CellDef *def,
int argc,
char *argv[])
{
HashEntry *entry;
ResExtNode *node;
ResConnect *newsink;
int pNum;
TileType ttype;
/* Check for the given tile type */
ttype = DBTechNoisyNameType(argv[CONNECT_TYPE]);
if (ttype == -1)
{
TxError("Bad tile type name \"%s\" in .ext file for node %s\n",
argv[CONNECT_TYPE], argv[CONNECT_UP_NAME]);
return 1;
}
/* Look up the node name */
if (strcmp(argv[CONNECT_UP_NAME], "None"))
{
entry = HashLookOnly(&ResNodeTable, argv[CONNECT_UP_NAME]);
if (entry != NULL)
node = (ResExtNode *)HashGetValue(entry);
else
{
TxError("Unknown node name \"%s\" in .ext file connect entry\n",
argv[CONNECT_UP_NAME]);
return 1;
}
/* Generate new sinkpoint entry */
newsink = (ResConnect *)mallocMagic(sizeof(ResConnect));
newsink->rc_rect.r_xbot = atoi(argv[CONNECT_LLX]);
newsink->rc_rect.r_ybot = atoi(argv[CONNECT_LLY]);
newsink->rc_rect.r_xtop = atoi(argv[CONNECT_URX]);
newsink->rc_rect.r_ytop = atoi(argv[CONNECT_URY]);
newsink->rc_type = ttype;
newsink->rc_node = (resNode *)NULL;
newsink->rc_next = node->sinkpoints;
node->sinkpoints = newsink;
node->status |= FORCE | DRIVELOC;
if (ResOptionsFlags & ResOpt_Debug)
{
/* Diagnostic */
TxPrintf("Added sink at %d %d %d %d\n", newsink->rc_rect.r_xbot,
newsink->rc_rect.r_ybot, newsink->rc_rect.r_xtop,
newsink->rc_rect.r_ytop);
}
}
return 0;
}
/* /*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
* *
@ -632,13 +240,6 @@ ResReadConnectPoint(CellDef *def,
* *
* Side Effects: see above * Side Effects: see above
* *
* NOTE: The use of "port" to mark drive points is restricted to top
* level cells, because no other information is available about how the
* cell connects to a parent cell. For every cell other than the top
* level, the "connect" statements are used to find the actual locations
* where signals connect between cells through abutting or overlapping
* material.
*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -648,33 +249,22 @@ ResReadPort(int argc,
{ {
HashEntry *entry; HashEntry *entry;
ResExtNode *node; ResExtNode *node;
ResConnect *newdriver;
entry = HashFind(&ResNodeTable, argv[PORT_NAME]); entry = HashFind(&ResNodeTable, argv[PORT_NAME]);
node = ResExtInitNode(entry); node = ResExtInitNode(entry);
/* Generate new drivepoint entry */ node->drivepoint.p_x = atoi(argv[PORT_LLX]);
node->drivepoint.p_y = atoi(argv[PORT_LLY]);
newdriver = (ResConnect *)mallocMagic(sizeof(ResConnect)); node->status |= FORCE;
/* To do: Check for multiple ports on a net; each port needs its
newdriver->rc_rect.r_xbot = atoi(argv[PORT_LLX]); * own drivepoint.
newdriver->rc_rect.r_ybot = atoi(argv[PORT_LLY]); */
newdriver->rc_rect.r_xtop = atoi(argv[PORT_URX]); node->status |= DRIVELOC | PORTNODE;
newdriver->rc_rect.r_ytop = atoi(argv[PORT_URY]); node->rs_bbox.r_ll = node->drivepoint;
newdriver->rc_type = DBTechNoisyNameType(argv[PORT_TYPE]); node->rs_bbox.r_ur.p_x = atoi(argv[PORT_URX]);
newdriver->rc_node = (resNode *)NULL; node->rs_bbox.r_ur.p_y = atoi(argv[PORT_URY]);
node->rs_ttype = DBTechNoisyNameType(argv[PORT_TYPE]);
newdriver->rc_next = node->drivepoints; node->type = node->rs_ttype;
node->drivepoints = newdriver;
node->status |= FORCE | DRIVELOC | PORTNODE;
if (ResOptionsFlags & ResOpt_Debug)
{
/* Diagnostic */
TxPrintf("Added port at %d %d %d %d\n",
newdriver->rc_rect.r_xbot, newdriver->rc_rect.r_ybot,
newdriver->rc_rect.r_xtop, newdriver->rc_rect.r_ytop);
}
if (node->type == -1) if (node->type == -1)
{ {
@ -683,7 +273,6 @@ ResReadPort(int argc,
} }
return 0; return 0;
} }
/* /*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
* *
@ -698,7 +287,7 @@ ResReadPort(int argc,
* None. * None.
* *
* Side effects: * Side effects:
* Allocates memory for a devPtr, adds to the node's "devices" linked * Allocates memory for a devPtr, adds to the node's firstDev linked
* list. * list.
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
@ -713,8 +302,8 @@ ResNodeAddDevice(ResExtNode *node,
tptr = (devPtr *)mallocMagic((unsigned)(sizeof(devPtr))); tptr = (devPtr *)mallocMagic((unsigned)(sizeof(devPtr)));
tptr->thisDev = device; tptr->thisDev = device;
tptr->nextDev = node->devices; tptr->nextDev = node->firstDev;
node->devices = tptr; node->firstDev = tptr;
tptr->terminal = termtype; tptr->terminal = termtype;
} }
@ -737,11 +326,13 @@ ResReadDevice(int argc,
char *argv[]) char *argv[])
{ {
RDev *device; RDev *device;
int rvalue, i, j, k, w, l; int rvalue, i, j, k;
ExtDevice *devptr; ExtDevice *devptr;
TileType ttype; TileType ttype;
HashEntry *entry; HashEntry *entry;
ResExtNode *node; ResExtNode *node;
ResValue rpersquare;
float wval;
device = (RDev *)mallocMagic((unsigned)(sizeof(RDev))); device = (RDev *)mallocMagic((unsigned)(sizeof(RDev)));
@ -770,20 +361,34 @@ ResReadDevice(int argc,
device->drain = (ResExtNode *)NULL; device->drain = (ResExtNode *)NULL;
device->subs = (ResExtNode *)NULL; device->subs = (ResExtNode *)NULL;
/* Find the end of parameter arguments */ entry = HashLookOnly(&devptr->exts_deviceResist, "linear");
if (entry != NULL)
rpersquare = (ResValue)(spointertype)HashGetValue(entry);
else
rpersquare = (ResValue)10000.0; /* Default to a sane value */
/* For devices, the device width is in the parameter list */
wval = 0.0;
for (i = DEV_Y; i < argc; i++) for (i = DEV_Y; i < argc; i++)
{ {
char *eptr; char *eptr;
if ((eptr = strchr(argv[i], '=')) == NULL) if ((eptr = strchr(argv[i], '=')) != NULL)
if (!StrIsInt(argv[i])) {
break; if (*argv[i] == 'w')
sscanf(eptr + 1, "%f", &wval);
}
else if (!StrIsInt(argv[i]))
break;
} }
if (i == argc) if (i == argc)
{ {
TxError("Bad device %s: Too few arguments in .ext file\n", TxError("Bad device %s: Too few arguments in .ext file\n",
argv[DEV_NAME]); argv[DEV_NAME]);
return 1; return 1;
} }
else
device->resistance = wval * rpersquare; /* Channel resistance */
/* Find and record the device terminal nodes */ /* Find and record the device terminal nodes */
/* Note that this only records up to two terminals matching FET /* Note that this only records up to two terminals matching FET
@ -801,8 +406,6 @@ ResReadDevice(int argc,
entry = HashFind(&ResNodeTable, argv[i]); entry = HashFind(&ResNodeTable, argv[i]);
device->gate = (ResExtNode *)HashGetValue(entry); device->gate = (ResExtNode *)HashGetValue(entry);
device->rs_gattr = StrDup((char **)NULL, argv[i + 2]); device->rs_gattr = StrDup((char **)NULL, argv[i + 2]);
l = atoi(argv[i + 1]);
w = 0;
ResNodeAddDevice(device->gate, device, GATE); ResNodeAddDevice(device->gate, device, GATE);
i += 3; i += 3;
@ -811,7 +414,6 @@ ResReadDevice(int argc,
entry = HashFind(&ResNodeTable, argv[i]); entry = HashFind(&ResNodeTable, argv[i]);
device->source = (ResExtNode *)HashGetValue(entry); device->source = (ResExtNode *)HashGetValue(entry);
device->rs_sattr = StrDup((char **)NULL, argv[i + 2]); device->rs_sattr = StrDup((char **)NULL, argv[i + 2]);
w = atoi(argv[i + 1]);
ResNodeAddDevice(device->source, device, SOURCE); ResNodeAddDevice(device->source, device, SOURCE);
i += 3; i += 3;
} }
@ -821,7 +423,6 @@ ResReadDevice(int argc,
entry = HashFind(&ResNodeTable, argv[i]); entry = HashFind(&ResNodeTable, argv[i]);
device->drain = (ResExtNode *)HashGetValue(entry); device->drain = (ResExtNode *)HashGetValue(entry);
device->rs_dattr = StrDup((char **)NULL, argv[i + 2]); device->rs_dattr = StrDup((char **)NULL, argv[i + 2]);
w = MAX(w, atoi(argv[i + 1]));
ResNodeAddDevice(device->drain, device, DRAIN); ResNodeAddDevice(device->drain, device, DRAIN);
i += 3; i += 3;
} }
@ -832,7 +433,6 @@ ResReadDevice(int argc,
} }
device->rs_ttype = extGetDevType(devptr->exts_deviceName); device->rs_ttype = extGetDevType(devptr->exts_deviceName);
device->rs_wl = (l == 0) ? 0.0 : (float)w / (float)l;
ResRDevList = device; ResRDevList = device;
device->layout = NULL; device->layout = NULL;
@ -856,11 +456,13 @@ ResReadFET(int argc,
char *argv[]) char *argv[])
{ {
RDev *device; RDev *device;
int rvalue, i, j, k, w, l; int rvalue, i, j, k;
ExtDevice *devptr; ExtDevice *devptr;
TileType ttype; TileType ttype;
HashEntry *entry; HashEntry *entry;
ResExtNode *node; ResExtNode *node;
ResValue rpersquare;
float area, perim, wval, lval;
device = (RDev *)mallocMagic((unsigned)(sizeof(RDev))); device = (RDev *)mallocMagic((unsigned)(sizeof(RDev)));
@ -885,6 +487,20 @@ ResReadFET(int argc,
device->rs_dattr = RDEV_NOATTR; device->rs_dattr = RDEV_NOATTR;
device->rs_devptr = devptr; device->rs_devptr = devptr;
entry = HashLookOnly(&devptr->exts_deviceResist, "linear");
if (entry != NULL)
rpersquare = (ResValue)(spointertype)HashGetValue(entry);
else
rpersquare = (ResValue)10000.0; /* Default to a sane value */
/* For old-style FETs, the width is determined from area and perimeter */
area = MagAtof(argv[FET_AREA]);
perim = MagAtof(argv[FET_PERIM]);
lval = 0.5 * (perim + sqrt(perim * perim - 4 * area));
wval = area / lval;
device->resistance = wval * rpersquare; /* Channel resistance */
/* Find and record the FET terminal nodes */ /* Find and record the FET terminal nodes */
entry = HashFind(&ResNodeTable, argv[FET_GATE]); entry = HashFind(&ResNodeTable, argv[FET_GATE]);
@ -906,11 +522,6 @@ ResReadFET(int argc,
device->rs_sattr = StrDup((char **)NULL, argv[FET_SOURCE_ATTR]); device->rs_sattr = StrDup((char **)NULL, argv[FET_SOURCE_ATTR]);
device->rs_dattr = StrDup((char **)NULL, argv[FET_DRAIN_ATTR]); device->rs_dattr = StrDup((char **)NULL, argv[FET_DRAIN_ATTR]);
l = atoi(argv[FET_GATE_ATTR - 1]);
w = atoi(argv[FET_SOURCE_ATTR - 1]);
w = MAX(w, atoi(argv[FET_DRAIN_ATTR - 1]));
device->rs_wl = (l == 0) ? 0.0 : (float)w / (float)l;
ResRDevList = device; ResRDevList = device;
device->layout = NULL; device->layout = NULL;
return 0; return 0;
@ -1017,22 +628,10 @@ ResReadAttribute(ResExtNode *node,
else if (strncmp(avalue, "res:drive", 9) == 0 && else if (strncmp(avalue, "res:drive", 9) == 0 &&
(ResOptionsFlags & ResOpt_Signal)) (ResOptionsFlags & ResOpt_Signal))
{ {
ResConnect *newdriver; node->drivepoint.p_x = atoi(argv[RES_EXT_ATTR_X]);
node->drivepoint.p_y = atoi(argv[RES_EXT_ATTR_Y]);
/* Generate new drivepoint entry */ node->rs_ttype = DBTechNoisyNameType(argv[RES_EXT_ATTR_TYPE]);
newdriver = (ResConnect *)mallocMagic(sizeof(ResConnect));
node->status |= DRIVELOC; node->status |= DRIVELOC;
newdriver->rc_rect.r_xbot = atoi(argv[RES_EXT_ATTR_X]);
newdriver->rc_rect.r_ybot = atoi(argv[RES_EXT_ATTR_Y]);
newdriver->rc_rect.r_xtop = atoi(argv[RES_EXT_ATTR_X]);
newdriver->rc_rect.r_ytop = atoi(argv[RES_EXT_ATTR_Y]);
newdriver->rc_type = DBTechNoisyNameType(argv[RES_EXT_ATTR_TYPE]);
newdriver->rc_node = (resNode *)NULL;
newdriver->rc_next = node->drivepoints;
node->drivepoints = newdriver;
} }
return 0; return 0;
} }
@ -1069,11 +668,11 @@ ResExtInitNode(entry)
node->cap_couple = 0; node->cap_couple = 0;
node->resistance = 0; node->resistance = 0;
node->type = 0; node->type = 0;
node->devices = NULL; node->firstDev = NULL;
node->name = entry->h_key.h_name; node->name = entry->h_key.h_name;
node->oldname = NULL; node->oldname = NULL;
node->drivepoints = NULL; node->drivepoint.p_x = INFINITY;
node->sinkpoints = NULL; node->drivepoint.p_y = INFINITY;
node->location.p_x = INFINITY; node->location.p_x = INFINITY;
node->location.p_y = INFINITY; node->location.p_y = INFINITY;
} }

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,6 @@
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>
@ -178,7 +177,7 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
/* other recievers at far end? If so, reschedule other node; /* other recievers at far end? If so, reschedule other node;
* deadlock will be settled from that node. * deadlock will be settled from that node.
*/ */
if ((MarkedReceivers + UnMarkedReceivers + NumberOfDrivers == 2) || if ((MarkedReceivers+UnMarkedReceivers+NumberOfDrivers == 2) ||
(UnMarkedReceivers == 0 && MarkedReceivers > 1 && (UnMarkedReceivers == 0 && MarkedReceivers > 1 &&
resistor2 == resistor1 && PendingReceivers == 0)) resistor2 == resistor1 && PendingReceivers == 0))
{ {
@ -229,7 +228,7 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
* Two resistors in series? Combine them and move devices to * Two resistors in series? Combine them and move devices to
* appropriate end. * appropriate end.
*/ */
else if (numdrive + numreceive == 2 && (resistor1->rr_value < tolerance && else if (numdrive+numreceive == 2 && (resistor1->rr_value < tolerance &&
resistor2->rr_value < tolerance)) resistor2->rr_value < tolerance))
{ {
if ((resistor1->rr_status & RES_MARKED) == 0 && if ((resistor1->rr_status & RES_MARKED) == 0 &&
@ -362,7 +361,7 @@ ResSimplifyNet(nodelist, biglist, reslist, tolerance)
/* /*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
* *
* ResMoveDevices-- move devices from one node (node1) to anther (node2) * ResMoveDevices-- move devices from one node1 to node2
* *
* Results: none * Results: none
* *
@ -387,11 +386,11 @@ 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_fet_subs == node1) else if ((device->rd_nterms >= 4) && (device->rd_fet_subs == node1))
device->rd_fet_subs = node2; device->rd_fet_subs = node2;
else if ((device->rd_nterms > 2) && (device->rd_fet_source == node1)) else if (device->rd_fet_source == node1)
device->rd_fet_source = node2; device->rd_fet_source = node2;
else if ((device->rd_nterms > 3) && (device->rd_fet_drain == node1)) else if (device->rd_fet_drain == node1)
device->rd_fet_drain = node2; device->rd_fet_drain = node2;
else else
TxError("Missing Device connection in squish routines" TxError("Missing Device connection in squish routines"
@ -402,29 +401,6 @@ 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;
}
/* /*
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
* *
@ -448,82 +424,29 @@ ResScrunchNet(reslist, pendingList, biglist, tolerance)
float tolerance; float tolerance;
{ {
resResistor *current, *working; resResistor *locallist = NULL, *current, *working;
resNode *node1, *node2; resNode *node1, *node2;
resElement *rcell1; resElement *rcell1;
int c1, c2, count = 0; int c1, c2;
/* Method used to sort resistors by size depends on list length */
for (current = *reslist; current; current = current->rr_nextResistor)
{
count++;
if (count >= 10) break;
}
/* Sort resistors by size */ /* Sort resistors by size */
current = *reslist;
if (count >= 10) while (current != NULL)
{ {
int i; working = current;
resResistor **resSortList; current = current->rr_nextResistor;
if (working == *reslist)
*reslist = current;
else
working->rr_lastResistor->rr_nextResistor = current;
/* For long lists, sort using qsort() */ if (current != NULL)
/* NOTE: It might be better to use the same merge sort used for current->rr_lastResistor = working->rr_lastResistor;
* 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 *)); ResAddResistorToList(working, &locallist);
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;
@ -578,8 +501,8 @@ ResScrunchNet(reslist, pendingList, biglist, tolerance)
} }
} }
/* /*
* If the current resistor isn't a dead end, add its value and * If the current resistor isn't a deadend, add its value and
* area to that of the next smallest one. If it is a dead end, * area to that of the next smallest one. If it is a deadend,
* simply add its area to its node. * simply add its area to its node.
*/ */
if (c1 != 0 && c2 != 0) if (c1 != 0 && c2 != 0)
@ -644,7 +567,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)
{ {
@ -707,7 +630,7 @@ ResDistributeCapacitance(nodelist, totalcap)
for (workingNode = nodelist; workingNode != NULL; workingNode = workingNode->rn_more) for (workingNode = nodelist; workingNode != NULL; workingNode = workingNode->rn_more)
{ {
for (rptr = workingNode->rn_re; rptr != NULL; rptr = rptr->re_nextEl) for (rptr = workingNode->rn_re; rptr != NULL; rptr=rptr->re_nextEl)
if (rptr->re_thisEl->rr_float.rr_area != 0.0) if (rptr->re_thisEl->rr_float.rr_area != 0.0)
TxError("Nonnull resistor area\n"); TxError("Nonnull resistor area\n");
@ -829,11 +752,11 @@ ResCalculateTDi(node, resistor, resistorvalue)
ASSERT(rcd != NULL, "ResCalculateTdi"); ASSERT(rcd != NULL, "ResCalculateTdi");
if (resistor == NULL) if (resistor == NULL)
rcd->rc_Tdi = rcd->rc_Cdownstream * (float)resistorvalue; rcd->rc_Tdi = rcd->rc_Cdownstream*(float)resistorvalue;
else else
{ {
rcd2 = (RCDelayStuff *)resistor->rr_connection1->rn_client; rcd2 = (RCDelayStuff *)resistor->rr_connection1->rn_client;
ASSERT(rcd2 != NULL, "ResCalculateTdi"); ASSERT(rcd2 != NULL,"ResCalculateTdi");
rcd->rc_Tdi = rcd->rc_Cdownstream * (float)resistor->rr_value + rcd->rc_Tdi = rcd->rc_Cdownstream * (float)resistor->rr_value +
rcd2->rc_Tdi; rcd2->rc_Tdi;
} }
@ -920,20 +843,25 @@ ResPruneTree(node, minTdi, nodelist1, nodelist2, resistorlist)
*/ */
int int
ResDoSimplify(resisdata) ResDoSimplify(tolerance,resisdata)
float tolerance;
ResisData *resisdata; ResisData *resisdata;
{ {
resNode *node, *slownode; resNode *node, *slownode;
float bigres = 0.0; float bigres = 0;
float millitolerance;
float totalcap; float totalcap;
float rctol;
resResistor *res; resResistor *res;
rctol = resisdata->tdiTolerance;
ResSetPathRes(resisdata); ResSetPathRes(resisdata);
for (node = ResNodeList; node != NULL; node = node->rn_more) for (node = ResNodeList; node != NULL; node = node->rn_more)
bigres = MAX(bigres, node->rn_noderes); bigres = MAX(bigres, node->rn_noderes);
bigres /= OHMSTOMILLIOHMS; /* convert from milliohms to ohms */
resisdata->rg_maxres = bigres; resisdata->rg_maxres = bigres;
#ifdef PARANOID #ifdef PARANOID
@ -947,8 +875,8 @@ ResDoSimplify(resisdata)
(void) ResDistributeCapacitance(ResNodeList, resisdata->rg_nodecap); (void) ResDistributeCapacitance(ResNodeList, resisdata->rg_nodecap);
if (((ResOptionsFlags & ResOpt_Simplify) == 0) && if (((tolerance > bigres) || ((ResOptionsFlags & ResOpt_Simplify) == 0)) &&
((ResOptionsFlags & ResOpt_DoLumpFile) == 0)) ((ResOptionsFlags & ResOpt_DoLumpFile) == 0))
return 0; return 0;
res = ResResList; res = ResResList;
@ -958,6 +886,16 @@ ResDoSimplify(resisdata)
res = res->rr_nextResistor; res = res->rr_nextResistor;
oldres->rr_status &= ~RES_HEAP; oldres->rr_status &= ~RES_HEAP;
/*------ NOTE: resistors marked with RES_TDI_IGNORE are
* part of loops but should NOT be removed.
if (oldres->rr_status & RES_TDI_IGNORE)
{
ResDeleteResPointer(oldres->rr_node[0], oldres);
ResDeleteResPointer(oldres->rr_node[1], oldres);
ResEliminateResistor(oldres, &ResResList);
}
------*/
} }
if (ResNodeAtOrigin == NULL) if (ResNodeAtOrigin == NULL)
@ -965,7 +903,7 @@ ResDoSimplify(resisdata)
TxError("Error: Network simplification: Failed to to get origin node.\n"); TxError("Error: Network simplification: Failed to to get origin node.\n");
resisdata->rg_Tdi = 0; resisdata->rg_Tdi = 0;
} }
else if (resisdata->mindelay > 0) else if (ResOptionsFlags & ResOpt_Tdi)
{ {
if ((resisdata->rg_nodecap != -1) && if ((resisdata->rg_nodecap != -1) &&
(totalcap = ResCalculateChildCapacitance(ResNodeAtOrigin)) != -1) (totalcap = ResCalculateChildCapacitance(ResNodeAtOrigin)) != -1)
@ -973,7 +911,8 @@ ResDoSimplify(resisdata)
RCDelayStuff *rc = (RCDelayStuff *) ResNodeList->rn_client; RCDelayStuff *rc = (RCDelayStuff *) ResNodeList->rn_client;
resisdata->rg_nodecap = totalcap; resisdata->rg_nodecap = totalcap;
ResCalculateTDi(ResNodeAtOrigin, (resResistor *)NULL, 0); ResCalculateTDi(ResNodeAtOrigin, (resResistor *)NULL,
resisdata->rg_bigdevres);
if (rc != (RCDelayStuff *)NULL) if (rc != (RCDelayStuff *)NULL)
resisdata->rg_Tdi = rc->rc_Tdi; resisdata->rg_Tdi = rc->rc_Tdi;
else else
@ -997,10 +936,20 @@ ResDoSimplify(resisdata)
else else
resisdata->rg_Tdi = 0; resisdata->rg_Tdi = 0;
/* Simplify network */ if ((rctol+1) * resisdata->rg_bigdevres * resisdata->rg_nodecap >
rctol * resisdata->rg_Tdi &&
(ResOptionsFlags & ResOpt_Tdi) &&
resisdata->rg_Tdi != -1)
return 0;
/* Simplify network; resistors are still in milliohms, so use
* millitolerance.
*/
if (ResOptionsFlags & ResOpt_Simplify) if (ResOptionsFlags & ResOpt_Simplify)
{ {
millitolerance = tolerance * MILLIOHMSPEROHM;
/* /*
* Start simplification at driver (R=0). Remove it from the done list * Start simplification at driver (R=0). Remove it from the done list
* and add it to the pending list. Call ResSimplifyNet as long as * and add it to the pending list. Call ResSimplifyNet as long as
@ -1018,18 +967,16 @@ ResDoSimplify(resisdata)
/* if Tdi is enabled, prune all branches whose end nodes */ /* if Tdi is enabled, prune all branches whose end nodes */
/* have time constants less than the tolerance. */ /* have time constants less than the tolerance. */
if ((resisdata->rg_Tdi != -1) && (resisdata->mindelay > 0)) if ((ResOptionsFlags & ResOpt_Tdi) &&
ResPruneTree(ResNodeAtOrigin, resisdata->mindelay, resisdata->rg_Tdi != -1 &&
&ResNodeList, &ResNodeQueue, &ResResList); rctol != 0)
ResNodeAtOrigin->rn_status &= ~RES_MARKED;
if (ResNodeAtOrigin->rn_less == CLIENTDEFAULT)
{ {
TxError("ResSimplify: Bad resptr at node %s origin.\n", ResPruneTree(ResNodeAtOrigin, (rctol + 1) *
ResNodeAtOrigin->rn_name); resisdata->rg_bigdevres * resisdata->rg_nodecap / rctol,
return 0; &ResNodeList, &ResNodeQueue, &ResResList);
} }
else if (ResNodeAtOrigin->rn_less == NULL) ResNodeAtOrigin->rn_status &= ~RES_MARKED;
if (ResNodeAtOrigin->rn_less == NULL)
ResNodeList = ResNodeAtOrigin->rn_more; ResNodeList = ResNodeAtOrigin->rn_more;
else else
ResNodeAtOrigin->rn_less->rn_more = ResNodeAtOrigin->rn_more; ResNodeAtOrigin->rn_less->rn_more = ResNodeAtOrigin->rn_more;
@ -1041,14 +988,13 @@ ResDoSimplify(resisdata)
ResNodeAtOrigin->rn_less = NULL; ResNodeAtOrigin->rn_less = NULL;
ResNodeQueue = ResNodeAtOrigin; ResNodeQueue = ResNodeAtOrigin;
while (ResNodeQueue != NULL) while (ResNodeQueue != NULL)
ResSimplifyNet(&ResNodeQueue, &ResNodeList, &ResResList, ResSimplifyNet(&ResNodeQueue, &ResNodeList, &ResResList, millitolerance);
resisdata->minres);
/* /*
* Call ResScrunchNet to eliminate any remaining under-tolerance * Call ResScrunchNet to eliminate any remaining under tolerance
* resistors. * resistors.
*/ */
ResScrunchNet(&ResResList, &ResNodeQueue, &ResNodeList, resisdata->minres); ResScrunchNet(&ResResList, &ResNodeQueue, &ResNodeList, millitolerance);
} }
} }
return 0; return 0;

File diff suppressed because it is too large Load Diff

View File

@ -160,7 +160,7 @@ resCurrentPrintFunc(node, resistor, filename)
void void
ResDeviceCounts() ResDeviceCounts()
{ {
int i, j, k; int i,j,k;
resNode *n; resNode *n;
resDevice *t; resDevice *t;
resResistor *r; resResistor *r;

View File

@ -51,24 +51,16 @@ 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. Actual devices may have /* Definitions for old FET-style MOSFET devices */
* 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_SUBS 1 #define RT_SOURCE 1
#define RT_SOURCE 2 #define RT_DRAIN 2
#define RT_DRAIN 3 #define RT_SUBS 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
{ {
@ -87,19 +79,6 @@ typedef struct device
Tile *rd_tile; /* pointer to a tile in device */ Tile *rd_tile; /* pointer to a tile in device */
} resDevice; } resDevice;
/*
* A resConnect maintains a location and tile type of a connections up
* (driver) or down (sink), a tile type that makes the connection, and
* a link to the resNode that must exist at the point of connection.
*/
typedef struct resconnect
{
TileType rc_type;
Rect rc_rect;
struct resnode *rc_node;
struct resconnect *rc_next;
} ResConnect;
/* /*
* A junction is formed when two tiles that connect are next to one another. * A junction is formed when two tiles that connect are next to one another.
*/ */
@ -121,10 +100,9 @@ typedef struct junction
typedef struct resport typedef struct resport
{ {
struct resport *rp_nextPort; struct resport *rp_nextPort;
Rect rp_bbox;
Point rp_loc;
char *rp_nodename; char *rp_nodename;
ResConnect *rp_connect;
Rect rp_bbox;
Point rp_loc;
} resPort; } resPort;
/* /*
@ -274,10 +252,9 @@ typedef struct resoptions
{ {
/* Global options for extresist */ /* Global options for extresist */
float minres; /* Minimum network resistance to output */ float tdiTolerance;
float mindelay; /* Minimum network delay to output */ float frequency;
float rthresh; /* Minimum individual resistance */ float rthresh;
float frequency; /* For FastHenry geometry extraction */
struct saveList *savePlanes; struct saveList *savePlanes;
CellDef *mainDef; CellDef *mainDef;
@ -289,8 +266,9 @@ typedef struct resoptions
TileType rg_ttype; TileType rg_ttype;
float rg_maxres; float rg_maxres;
float rg_nodecap; /* Node capacitance */ float rg_nodecap;
float rg_Tdi; /* Node delay */ float rg_Tdi;
int rg_bigdevres;
int rg_tilecount; int rg_tilecount;
int rg_status; int rg_status;
Point *rg_devloc; Point *rg_devloc;
@ -311,19 +289,21 @@ typedef struct rcdelaystuff
typedef struct rdev typedef struct rdev
{ {
struct rdev *nextDev; /* Next device in linked list */ struct rdev *nextDev; /* Next device in linked list */
struct rdev *realDev; /* Single Lumped Device for */
/* devices connected in parallel */
resDevice *layout; /* pointer to resDevice that */ resDevice *layout; /* pointer to resDevice that */
/* corresponds to RDev */ /* corresponds to RDev */
int status; int status;
struct resextnode *gate; /* Terminals of transistor. */ struct resextnode *gate; /* Terminals of transistor. */
struct resextnode *source; struct resextnode *source;
struct resextnode *drain; struct resextnode *drain;
struct resextnode *subs; /* Used with subcircuit type only */ struct resextnode *subs; /* Used with subcircuit type only */
Point location; /* Location of lower left point */ Point location; /* Location of lower left point of */
/* of the device. */ /* device. */
TileType rs_ttype; /* tile type for device */ float resistance; /* "Resistance" of device. */
float rs_wl; /* device W/L, if relevant */ TileType rs_ttype; /* tile type for device */
ExtDevice *rs_devptr; /* device extraction record */ ExtDevice *rs_devptr; /* device extraction record */
char *rs_gattr; /* Gate attributes, if any */ char *rs_gattr; /* Gate attributes, if any */
char *rs_sattr; char *rs_sattr;
char *rs_dattr; char *rs_dattr;
} RDev; } RDev;
@ -340,13 +320,17 @@ typedef struct resextnode
float cap_couple; /* Coupling capacitance */ float cap_couple; /* Coupling capacitance */
float resistance; /* Lumped resistance */ float resistance; /* Lumped resistance */
float minsizeres; /* Minimum size resistor allowed */ float minsizeres; /* Minimum size resistor allowed */
ResConnect *drivepoints; /* Upward connections */ Point drivepoint; /* optional, user specified drive */
ResConnect *sinkpoints; /* Downward connections */ /* point for network. */
TileType rs_ttype; /* Tiletype of drivepoint */
Point location; /* Location of bottom of leftmost */ Point location; /* Location of bottom of leftmost */
/* tile in the lowest numbered */ /* tile in the lowest numbered */
/* plane contained in the node. */ /* plane contained in the node. */
Rect rs_bbox; /* Location of bottom of leftmost */
/* tile in the lowest numbered */
/* plane contained in the node. */
TileType type; /* Tile type of tile at location */ TileType type; /* Tile type of tile at location */
struct devptr *devices; /* Linked list of devices */ struct devptr *firstDev; /* Linked list of devices */
/* connected to node. */ /* connected to node. */
char *name; /* Pointer to name of node stored */ char *name; /* Pointer to name of node stored */
/* in hash table. */ /* in hash table. */
@ -459,7 +443,6 @@ typedef struct capval
/* Capacitance table constants */ /* Capacitance table constants */
#define OHMSTOMILLIOHMS 1000 #define OHMSTOMILLIOHMS 1000
#define MILLIOHMSTOOHMS 0.001
#define UNTOUCHED 0 #define UNTOUCHED 0
#define SERIES 1 #define SERIES 1
@ -494,12 +477,12 @@ typedef struct capval
#define ResOpt_DoExtFile 0x0004 #define ResOpt_DoExtFile 0x0004
#define ResOpt_DoLumpFile 0x0008 #define ResOpt_DoLumpFile 0x0008
#define ResOpt_RunSilent 0x0010 #define ResOpt_RunSilent 0x0010
#define ResOpt_Debug 0x0020 #define ResOpt_Stats 0x0020
#define ResOpt_Stats 0x0040 #define ResOpt_Tdi 0x0040
#define ResOpt_Signal 0x0080 #define ResOpt_Signal 0x0080
#define ResOpt_Geometry 0x0100 #define ResOpt_Geometry 0x0100
#define ResOpt_FastHenry 0x0200 #define ResOpt_FastHenry 0x0200
#define ResOpt_Blackbox 0x0400 #define ResOpt_Blackbox 0x0300
#define ResOpt_DoSubstrate 0x0800 #define ResOpt_DoSubstrate 0x0800
#define ResOpt_Box 0x1000 #define ResOpt_Box 0x1000
@ -527,7 +510,7 @@ extern ResFixPoint *ResFixList;
extern int ResTileCount; extern int ResTileCount;
extern ResExtNode **ResNodeArray; extern ResExtNode **ResNodeArray;
extern CellDef *mainDef; extern CellDef *mainDef;
extern TileTypeBitMask ResTermTypesBitMask; extern TileTypeBitMask ResSDTypesBitMask;
extern TileTypeBitMask ResSubTypesBitMask; extern TileTypeBitMask ResSubTypesBitMask;
extern HashTable ResDevTable; extern HashTable ResDevTable;
extern TileTypeBitMask ResNoMergeMask[NT]; extern TileTypeBitMask ResNoMergeMask[NT];
@ -542,14 +525,12 @@ extern int ResReadResistor();
extern int ResReadAttribute(); extern int ResReadAttribute();
extern int ResReadMerge(); extern int ResReadMerge();
extern int ResReadSubckt(); extern int ResReadSubckt();
extern int ResReadParentExt();
extern int ResProcessNode(); extern int ResProcessNode();
extern int ResExtCombineParallel(); extern int ResExtCombineParallel();
extern int dbSrConnectStartFunc(); extern int dbSrConnectStartFunc();
extern int ResEach(); extern int ResEach();
extern int ResAddPlumbing(); extern int ResAddPlumbing();
extern void ResAddDevPlumbing();
extern int ResRemovePlumbing(); extern int ResRemovePlumbing();
extern float ResCalculateChildCapacitance(); extern float ResCalculateChildCapacitance();
extern ResDevTile *DBTreeCopyConnectDCS(); extern ResDevTile *DBTreeCopyConnectDCS();
@ -562,18 +543,14 @@ extern void ResCheckExtNodes();
extern void ResSortByGate(); extern void ResSortByGate();
extern void ResFixDevName(); extern void ResFixDevName();
extern void ResWriteLumpFile(); extern void ResWriteLumpFile();
extern int ResSortBreaks(); extern void ResSortBreaks();
extern Plane *extResPrepSubstrate(); extern Plane *extResPrepSubstrate();
extern bool ResEachTile();
extern void ResStartTile();
/* C99 compat */ /* C99 compat */
extern void ExtResisForDef(CellDef *celldef, ResisData *resisdata); extern void ExtResisForDef(CellDef *celldef, ResisData *resisdata);
extern char *ResExtGetAttribute(char *sptr); extern char *ResExtGetAttribute(char *sptr);
extern int ResReadFET(int argc, char *argv[]); extern int ResReadFET(int argc, char *argv[]);
extern int ResReadConnectPoint(CellDef *def, int argc, char *argv[]);
extern int ResReadPort(int argc, char *argv[]); extern int ResReadPort(int argc, char *argv[]);
extern char *ResExtGetAttribute(char *sptr); extern char *ResExtGetAttribute(char *sptr);
@ -590,10 +567,9 @@ extern void ResEliminateResistor();
extern bool ResExtractNet(); extern bool ResExtractNet();
extern int ResFracture(); extern int ResFracture();
extern void ResMergeNodes(); extern void ResMergeNodes();
extern void ResNewTermDevice(); extern void ResNewSDDevice();
extern void ResNewSubDevice(); extern void ResNewSubDevice();
extern void ResPreProcessDevices(); extern void ResPreProcessDevices();
extern void ResFreeDevTiles();
extern void ResPrintDeviceList(); extern void ResPrintDeviceList();
extern void ResPrintExtDev(); extern void ResPrintExtDev();
extern void ResPrintReference(); extern void ResPrintReference();
@ -620,8 +596,59 @@ extern int resWalkleft();
extern int resWalkright(); extern int resWalkright();
extern int resWalkup(); extern int resWalkup();
extern void InitializeResNode(); /* Macros */
extern void ResInfoInit();
extern void ResNewBreak(); #define InitializeResNode(node,x,y,why) \
{\
(node)->rn_te = NULL;\
(node)->rn_id=0;\
(node)->rn_float.rn_area = 0.0;\
(node)->rn_name = NULL;\
(node)->rn_client = (ClientData)NULL;\
(node)->rn_noderes = RES_INFINITY;\
(node)->rn_je = NULL;\
(node)->rn_status = FALSE;\
(node)->rn_loc.p_x = (x);\
(node)->rn_loc.p_y = (y);\
(node)->rn_why = (why);\
(node)->rn_ce = (cElement *) NULL;\
(node)->rn_re = (resElement *) NULL;\
}
#define ResInfoInit(Info) \
{ \
Info->contactList = (cElement *) NULL; \
Info->deviceList = (resDevice *) NULL; \
Info->junctionList = (ResJunction *) NULL; \
Info->breakList = (Breakpoint *) NULL; \
Info->portList = (resPort *) NULL; \
Info->ri_status = FALSE; \
Info->sourceEdge = 0 ; \
}
#define NEWBREAK(node,tile,px,py,crect)\
{\
Breakpoint *bp;\
resInfo *jX_ = (resInfo *)((tile)->ti_client); \
bp = (Breakpoint *) mallocMagic((unsigned)(sizeof(Breakpoint))); \
bp->br_next= jX_->breakList; \
bp->br_this = (node); \
bp->br_loc.p_x = px; \
bp->br_loc.p_y = py; \
bp->br_crect = (Rect *) (crect); \
jX_->breakList = bp; \
}
#define NEWPORT(node,tile)\
{\
resPort *rp;\
resInfo *pX_ = (resInfo *)((tile)->ti_client); \
rp = (resPort *) mallocMagic((unsigned)(sizeof(resPort))); \
rp->rp_nextPort = pX_->portList; \
rp->rp_bbox = node->rs_bbox; \
rp->rp_loc = node->drivepoint; \
rp->rp_nodename = node->name; \
pX_->portList = rp; \
}
#endif /* _MAGIC__RESIS__RESIS_H */ #endif /* _MAGIC__RESIS__RESIS_H */

View File

@ -159,7 +159,7 @@ rtrFollowName(name, firstInNet, area)
{ {
if ( firstInNet ) if ( firstInNet )
{ {
RtrMilestonePrint(); RtrMilestonePrint("#");
(void) DBSrLabelLoc(EditCellUse, name, rtrFollowLocFunc, (ClientData) area); (void) DBSrLabelLoc(EditCellUse, name, rtrFollowLocFunc, (ClientData) area);
} }
return 0; return 0;

View File

@ -470,15 +470,13 @@ SelectArea(scx, types, xMask, globmatch)
if (TTMaskHasType(types, L_LABEL)) if (TTMaskHasType(types, L_LABEL))
{ {
TTMaskClearType(types, L_LABEL);
if (TTMaskIsZero(types)) types = &DBAllButSpaceAndDRCBits;
if (globmatch != NULL) if (globmatch != NULL)
DBCellCopyGlobLabels(scx, types, xMask, SelectUse, &labelArea, DBCellCopyGlobLabels(scx, &DBAllTypeBits, xMask, SelectUse, &labelArea,
globmatch); globmatch);
else else
DBCellCopyAllLabels(scx, types, xMask, SelectUse, &labelArea); DBCellCopyAllLabels(scx, &DBAllTypeBits, xMask, SelectUse, &labelArea);
} }
else (void) DBCellCopyAllLabels(scx, types, xMask, SelectUse, &labelArea);
/* Select cell uses. */ /* Select cell uses. */
@ -837,8 +835,6 @@ 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);
} }

View File

@ -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[MAXPATHNAME]; static char nodeName[256];
CellDef *def; CellDef *def;
TerminalPath *tpath = cx->tc_filter->tf_tpath; TerminalPath *tpath = cx->tc_filter->tf_tpath;
@ -133,8 +133,7 @@ SimConnectFunc(
char c = *n; char c = *n;
SigDisableInterrupts(); SigDisableInterrupts();
strncpy(nodeName, SimGetNodeName(cx->tc_scx, tile, dinfo, tpath->tp_first), strcpy(nodeName, SimGetNodeName(cx->tc_scx, tile, dinfo, tpath->tp_first));
MAXPATHNAME);
SigEnableInterrupts(); SigEnableInterrupts();
*n = c; *n = c;

View File

@ -640,7 +640,8 @@ SimAddLabels(
pos = SimPutLabel(rootuse, &selectBox, GEO_CENTER, pos = SimPutLabel(rootuse, &selectBox, GEO_CENTER,
current->tl_simLabel, TT_SPACE); current->tl_simLabel, TT_SPACE);
DBReComputeBbox(rootuse); DBReComputeBbox(rootuse);
DBWAreaChanged(rootuse, &selectBox, DBW_ALLWINDOWS, &DBAllButSpaceBits); DBWLabelChanged(rootuse, current->tl_simLabel, &selectBox,
pos, DBW_ALLWINDOWS);
} }
} }

View File

@ -35,10 +35,10 @@ proc magic::libcallback {command} {
switch $command { switch $command {
load {$winname load $celldef} load {$winname load $celldef}
place {$winname getcell $celldef child 0 0} place {$winname getcell $celldef}
pick { pick {
magic::tool pick magic::tool pick
$winname getcell $celldef child 0 0 $winname getcell $celldef
magic::startselect $winname pick magic::startselect $winname pick
} }
} }

70
tcltk/magicps.pro Normal file
View File

@ -0,0 +1,70 @@
%%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

View File

@ -249,9 +249,6 @@ 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

View File

@ -651,9 +651,9 @@ proc magic::startselect {window {option {}}} {
select nocycle select nocycle
} }
} }
set Opts(origin) [cursor internal] set Opts(origin) [cursor]
set Opts(motion) [bind ${window} <Motion>] set Opts(motion) [bind ${window} <Motion>]
bind ${window} <Motion> [subst {$Opts(motion); set p \[cursor internal\]; \ bind ${window} <Motion> [subst {$Opts(motion); set p \[cursor\]; \
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}}]

View File

@ -96,7 +96,6 @@ extern char TxInterruptChar; /* The current interrupt character */
/* command procedures */ /* command procedures */
extern void TxDispatch(FILE *f); extern void TxDispatch(FILE *f);
extern int TxDispatchString(const char *str, bool quiet);
/* C99 compat */ /* C99 compat */
extern void TxMore(const char *mesg); extern void TxMore(const char *mesg);

View File

@ -1751,47 +1751,6 @@ done:
DQFree(&inputCommands); DQFree(&inputCommands);
} }
int
TxDispatchString(
const char *str,
bool quiet)
{
int result = 0;
DQueue inputCommands;
DQInit(&inputCommands, 4);
TxParseString_internal(str, &inputCommands, (TxInputEvent *) NULL);
while (!DQIsEmpty(&inputCommands))
{
TxCommand *cmd;
cmd = (TxCommand *) DQPopFront(&inputCommands);
if (txHaveCurrentPoint)
{
cmd->tx_p = txCurrentPoint;
cmd->tx_wid = txCurrentWindowID;
txHaveCurrentPoint = FALSE;
}
result = WindSendCommand((MagWindow *) NULL, cmd, quiet);
TxFreeCommand(cmd);
TxCommandNumber++;
if (result != 0)
break;
}
WindUpdate();
while (!DQIsEmpty(&inputCommands))
TxFreeCommand((TxCommand *) DQPopFront(&inputCommands));
DQFree(&inputCommands);
return result;
}
#endif /* !MAGIC_WRAPPER */ #endif /* !MAGIC_WRAPPER */
/* /*

Some files were not shown because too many files have changed in this diff Show More