Compare commits
No commits in common. "master" and "8.3.640" have entirely different histories.
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 }}
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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/
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
||||||
67
cif/CIFgen.c
67
cif/CIFgen.c
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -913,18 +913,18 @@ CmdExpand(
|
||||||
DBExpandAll(rootBoxUse, &rootRect, windowMask,
|
DBExpandAll(rootBoxUse, &rootRect, windowMask,
|
||||||
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
|
||||||
{
|
{
|
||||||
DBExpandAll(rootBoxUse, &rootRect, windowMask,
|
DBExpandAll(rootBoxUse, &rootRect, windowMask,
|
||||||
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:
|
||||||
|
|
@ -933,18 +933,18 @@ CmdExpand(
|
||||||
DBExpandAll(rootBoxUse, &rootRect, windowMask,
|
DBExpandAll(rootBoxUse, &rootRect, windowMask,
|
||||||
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
|
||||||
{
|
{
|
||||||
DBExpandAll(rootBoxUse, &rootRect, windowMask,
|
DBExpandAll(rootBoxUse, &rootRect, windowMask,
|
||||||
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:
|
||||||
|
|
@ -953,18 +953,18 @@ CmdExpand(
|
||||||
DBExpandAll(rootBoxUse, &TiPlaneRect, windowMask,
|
DBExpandAll(rootBoxUse, &TiPlaneRect, windowMask,
|
||||||
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
|
||||||
{
|
{
|
||||||
DBExpandAll(rootBoxUse, &TiPlaneRect, windowMask,
|
DBExpandAll(rootBoxUse, &TiPlaneRect, windowMask,
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -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];
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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],
|
||||||
|
|
|
||||||
|
|
@ -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},
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
magic.js
|
|
||||||
magic.wasm
|
|
||||||
*.tgz
|
|
||||||
node_modules/
|
|
||||||
package-lock.json
|
|
||||||
examples/output/
|
|
||||||
10
npm/LICENSE
10
npm/LICENSE
|
|
@ -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.
|
|
||||||
153
npm/README.md
153
npm/README.md
|
|
@ -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.
|
|
||||||
132
npm/build.sh
132
npm/build.sh
|
|
@ -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
|
|
||||||
|
|
@ -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);
|
|
||||||
|
|
@ -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.');
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
# CIF export
|
|
||||||
tech load __TECH__
|
|
||||||
load /work/__CELL__
|
|
||||||
cif write /work/__CELL__
|
|
||||||
|
|
@ -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.');
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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}`);
|
|
||||||
|
|
@ -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.');
|
|
||||||
}
|
|
||||||
|
|
@ -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__
|
|
||||||
|
|
@ -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.');
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
# GDS export
|
|
||||||
tech load __TECH__
|
|
||||||
load /work/__CELL__
|
|
||||||
gds write /work/__CELL__
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
@ -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 >>
|
|
||||||
|
|
@ -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 };
|
|
||||||
15
npm/index.js
15
npm/index.js
|
|
@ -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;
|
|
||||||
23
npm/pack.sh
23
npm/pack.sh
|
|
@ -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
|
|
||||||
|
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
271
resis/ResBasic.c
271
resis/ResBasic.c
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
495
resis/ResMain.c
495
resis/ResMain.c
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
253
resis/ResMerge.c
253
resis/ResMerge.c
|
|
@ -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
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -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++;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
801
resis/ResRex.c
801
resis/ResRex.c
File diff suppressed because it is too large
Load Diff
|
|
@ -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;
|
||||||
|
|
|
||||||
1008
resis/ResUtils.c
1008
resis/ResUtils.c
File diff suppressed because it is too large
Load Diff
|
|
@ -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;
|
||||||
|
|
|
||||||
151
resis/resis.h
151
resis/resis.h
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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}}]
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
Loading…
Reference in New Issue