Compare commits
143 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
381714e2d5 | |
|
|
d44aeaa1d1 | |
|
|
a7f2a38d32 | |
|
|
a38fa29dac | |
|
|
295ec7e492 | |
|
|
f650248764 | |
|
|
8466279b6c | |
|
|
7296aca107 | |
|
|
50320a055a | |
|
|
d37793e7d0 | |
|
|
4669fa9a9f | |
|
|
4fe8f12595 | |
|
|
bc340fba16 | |
|
|
c4923d44a2 | |
|
|
1ca85fa372 | |
|
|
6efb44db0a | |
|
|
db36e896e6 | |
|
|
ed576b23c8 | |
|
|
7c71d0f3e5 | |
|
|
5801acce62 | |
|
|
4dd0cfd472 | |
|
|
d873cd7f2b | |
|
|
2f2faf68eb | |
|
|
ab2515fd8f | |
|
|
e45db485d8 | |
|
|
8d61bae1f1 | |
|
|
3934b77f64 | |
|
|
788c73b867 | |
|
|
83569da8b3 | |
|
|
65f034777e | |
|
|
3667b348e8 | |
|
|
e2673e4e36 | |
|
|
14afb4bd52 | |
|
|
1db2567841 | |
|
|
0efed5813e | |
|
|
43e4cf9b03 | |
|
|
7a0e2aa2b9 | |
|
|
a157ec9aa8 | |
|
|
1a1cee058e | |
|
|
799fd5d8f2 | |
|
|
21b8579734 | |
|
|
03610f6d40 | |
|
|
c22031724a | |
|
|
349ffd091f | |
|
|
4393d9310a | |
|
|
1bcad6a25c | |
|
|
d9e6c78adb | |
|
|
d8580be739 | |
|
|
1a16502a69 | |
|
|
5ecf10c022 | |
|
|
e366cf6a4c | |
|
|
7ecebb5dd6 | |
|
|
099d513011 | |
|
|
e45399d347 | |
|
|
7a3717b02a | |
|
|
a062fdcfe0 | |
|
|
29447a35cd | |
|
|
1dcd09e20c | |
|
|
9626b5e8c9 | |
|
|
256955f48e | |
|
|
b983e33be7 | |
|
|
db224105a7 | |
|
|
e5a6cf0df9 | |
|
|
22e182f908 | |
|
|
0013dda92d | |
|
|
85561d0503 | |
|
|
eb83075e16 | |
|
|
8fea20425e | |
|
|
ad14c26597 | |
|
|
19a2d5c57c | |
|
|
fb01f77755 | |
|
|
9d74f4f9a7 | |
|
|
9af6b329de | |
|
|
6d3494a8fe | |
|
|
068b93608a | |
|
|
e62626fc06 | |
|
|
145fba9ac0 | |
|
|
19113bec89 | |
|
|
480c40f516 | |
|
|
1fffc2b8b4 | |
|
|
392d9c4408 | |
|
|
c8b50a702d | |
|
|
354416f717 | |
|
|
f802d729af | |
|
|
1d402d2c5f | |
|
|
2d6a3a8ed6 | |
|
|
8560027569 | |
|
|
02087ea3f8 | |
|
|
8e8fada32f | |
|
|
f4c22438c6 | |
|
|
fdfb54badb | |
|
|
6fc7b30386 | |
|
|
476bb5474c | |
|
|
537d370536 | |
|
|
bdc0325901 | |
|
|
fa80458d80 | |
|
|
c3ee33e9a1 | |
|
|
900f6d7b0f | |
|
|
97fd047aab | |
|
|
df4ec3ab32 | |
|
|
d0e38df6bf | |
|
|
d157eea7f3 | |
|
|
67c6ed9395 | |
|
|
f15f0dabbb | |
|
|
ae6d26578e | |
|
|
cb1653b157 | |
|
|
a3f5e665d1 | |
|
|
2eea849c06 | |
|
|
6e295d030e | |
|
|
ceba050a21 | |
|
|
f7cceed5e3 | |
|
|
5d35ae38b5 | |
|
|
05561b90f3 | |
|
|
06eab7feb6 | |
|
|
9ade4c931e | |
|
|
1bb5316d8d | |
|
|
2f26237b8b | |
|
|
003506ba62 | |
|
|
d659b5e1df | |
|
|
a0afe242c8 | |
|
|
88ca77f6a4 | |
|
|
9d967bdf64 | |
|
|
7fd2ef8100 | |
|
|
e789f18523 | |
|
|
460a357730 | |
|
|
7ceeccef56 | |
|
|
66faf1d907 | |
|
|
37db9e453b | |
|
|
2d5c4be6dd | |
|
|
a9673e45ae | |
|
|
8f95efc257 | |
|
|
fd12c39c37 | |
|
|
7d9167257a | |
|
|
058b320c3f | |
|
|
fee4b887c0 | |
|
|
04e91d640d | |
|
|
7d9210a3f1 | |
|
|
03bbc544b2 | |
|
|
ee79bba5e4 | |
|
|
15943d0cb1 | |
|
|
7bdd9e1d4f | |
|
|
725c8e9235 | |
|
|
73ffad3802 |
|
|
@ -138,6 +138,8 @@ jobs:
|
||||||
echo "BUILD_GCC_VERSION=$BUILD_GCC_VERSION" >> $GITHUB_ENV
|
echo "BUILD_GCC_VERSION=$BUILD_GCC_VERSION" >> $GITHUB_ENV
|
||||||
echo "BUILD_CLANG_VERSION=$BUILD_CLANG_VERSION" >> $GITHUB_ENV
|
echo "BUILD_CLANG_VERSION=$BUILD_CLANG_VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
sudo apt-get update
|
||||||
|
|
||||||
if [ -n "$BUILD_GCC_VERSION" ]
|
if [ -n "$BUILD_GCC_VERSION" ]
|
||||||
then
|
then
|
||||||
GCCV=$BUILD_GCC_VERSION
|
GCCV=$BUILD_GCC_VERSION
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
# This is a basic workflow to help you get started with Actions
|
# CI for native ARM64 Linux build.
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -23,27 +21,3 @@ 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: Build
|
|
||||||
run: |
|
|
||||||
source ./emsdk/emsdk_env.sh
|
|
||||||
emconfigure ./configure --without-cairo --without-opengl --without-x --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
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,256 @@
|
||||||
|
name: CI-wasm
|
||||||
|
|
||||||
|
# Builds the Magic WebAssembly target (both the non-TCL and TCL variants)
|
||||||
|
# on every push and pull request as a CI check. **Publishing** only happens
|
||||||
|
# when a release tag of the form <x.y.z>... (optionally v-prefixed) is
|
||||||
|
# pushed — the same tag that triggers the AppImage release workflows:
|
||||||
|
#
|
||||||
|
# # bump magic/VERSION, commit, push to default branch
|
||||||
|
# git tag 8.3.638
|
||||||
|
# git push origin 8.3.638
|
||||||
|
#
|
||||||
|
# The tag name (minus any leading "v") provides the base; the workflow appends
|
||||||
|
# the commit date and short SHA: 8.3.799 → 8.3.799020261231+git01234cde.
|
||||||
|
# Forks publish under their own namespace via the @<owner>/ scope.
|
||||||
|
|
||||||
|
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'
|
||||||
|
tcl_ref:
|
||||||
|
description: 'TCL ref to build against (default: auto-resolve latest stable tag). Use a tag like core-9-0-3, a branch, or a commit SHA to bisect a regression.'
|
||||||
|
type: string
|
||||||
|
default: ''
|
||||||
|
tcl_repo_url:
|
||||||
|
description: 'TCL repository URL (default: https://github.com/tcltk/tcl.git)'
|
||||||
|
type: string
|
||||||
|
default: ''
|
||||||
|
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
|
||||||
|
|
||||||
|
# Determine which TCL ref to build against.
|
||||||
|
# Priority: workflow_dispatch input > auto-resolved latest stable tag.
|
||||||
|
# TCL stable releases follow the core-<major>-<even_minor>-<patch>
|
||||||
|
# naming convention; core-9-0-x is the current stable series.
|
||||||
|
# Falls back to main only if no release tags are found at all.
|
||||||
|
- name: Resolve TCL ref
|
||||||
|
id: resolve-tcl
|
||||||
|
env:
|
||||||
|
TCL_REPO_URL: ${{ github.event.inputs.tcl_repo_url || 'https://github.com/tcltk/tcl.git' }}
|
||||||
|
TCL_REF_INPUT: ${{ github.event.inputs.tcl_ref || '' }}
|
||||||
|
run: |
|
||||||
|
if [ -n "$TCL_REF_INPUT" ]; then
|
||||||
|
TCL_REF="$TCL_REF_INPUT"
|
||||||
|
echo "Using workflow_dispatch TCL_REF: $TCL_REF"
|
||||||
|
else
|
||||||
|
TCL_REF=$(git ls-remote --tags --sort=-version:refname "$TCL_REPO_URL" \
|
||||||
|
'refs/tags/core-9-0-*' \
|
||||||
|
| grep -v '\^{}' \
|
||||||
|
| head -1 \
|
||||||
|
| awk '{print $2}' \
|
||||||
|
| sed 's|refs/tags/||')
|
||||||
|
if [ -z "$TCL_REF" ]; then
|
||||||
|
TCL_REF=main
|
||||||
|
echo "Warning: no stable core-9-0-x tag found, falling back to main"
|
||||||
|
else
|
||||||
|
echo "Auto-resolved latest stable TCL tag: $TCL_REF"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo "tcl_ref=$TCL_REF" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "tcl_repo_url=$TCL_REPO_URL" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
# Clone tcltk/tcl into a sibling directory at the resolved ref.
|
||||||
|
# Done as an explicit step so the exact commit is visible in the job
|
||||||
|
# log. The source tree is read-only — the WASM build runs inside magic.
|
||||||
|
- name: Clone tcltk/tcl
|
||||||
|
env:
|
||||||
|
TCL_REPO_URL: ${{ steps.resolve-tcl.outputs.tcl_repo_url }}
|
||||||
|
TCL_REF: ${{ steps.resolve-tcl.outputs.tcl_ref }}
|
||||||
|
run: |
|
||||||
|
# autocrlf=false: ubuntu-latest is already LF, but make it explicit.
|
||||||
|
git -c core.autocrlf=false clone "$TCL_REPO_URL" ../tcl
|
||||||
|
cd ../tcl
|
||||||
|
git checkout --detach "$TCL_REF"
|
||||||
|
echo "=== TCL commit ==="
|
||||||
|
git log -n1 --format="commit %H%nauthor %an <%ae>%ndate %ci%nref %D%n%n %s"
|
||||||
|
|
||||||
|
- name: Build WASM — both variants (tcl + notcl)
|
||||||
|
env:
|
||||||
|
TCL_REF: ${{ steps.resolve-tcl.outputs.tcl_ref }}
|
||||||
|
TCL_REPO_URL: ${{ steps.resolve-tcl.outputs.tcl_repo_url }}
|
||||||
|
run: |
|
||||||
|
source ./emsdk/emsdk_env.sh
|
||||||
|
bash npm/build.sh --variant=both
|
||||||
|
|
||||||
|
- name: Run example tests (non-TCL variant)
|
||||||
|
run: cd npm && npm test
|
||||||
|
|
||||||
|
- name: Run full test suite (TCL variant)
|
||||||
|
run: cd npm && npm run test:tcl
|
||||||
|
|
||||||
|
# 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 dir in npm/examples/output npm/examples/output-tcl; do
|
||||||
|
[ -d "$dir" ] || continue
|
||||||
|
echo "======== $dir ========"
|
||||||
|
for f in "$dir"/*; do
|
||||||
|
name=$(basename "$f")
|
||||||
|
case "$f" in
|
||||||
|
*.gds) echo "===== $name (binary, $(wc -c < "$f") bytes — skipped) =====" ;;
|
||||||
|
*) echo "===== $name ====="; cat "$f" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
# The release gate. We publish a new npm version only when a tag of the
|
||||||
|
# shape <x.y.z>... (optionally v-prefixed) is pushed, matching the
|
||||||
|
# AppImage release workflows so one tag releases everything.
|
||||||
|
#
|
||||||
|
# Version scheme (per dmiles' recommendation):
|
||||||
|
# {MAJOR}.{MINOR}.{PATCH}0{YYYYMMDD}+git{SHORT_SHA}
|
||||||
|
# e.g. 8.3.799 pushed on 2026-12-31 → 8.3.799020261231+git01234cde
|
||||||
|
#
|
||||||
|
# The leading zero between PATCH and date keeps the number readable and
|
||||||
|
# ensures correct numeric ordering: 799020261231 < 800020261231.
|
||||||
|
# Build metadata (+git...) is ignored by npm for comparison but retained
|
||||||
|
# for traceability. Security patches for the 799 series can be inserted
|
||||||
|
# as later dates (799020270101, 799020270201, …) and are matched by the
|
||||||
|
# range <=8.3.799900000000 or <8.3.8000000000000.
|
||||||
|
- name: Determine release version (tag-driven only)
|
||||||
|
id: release
|
||||||
|
run: |
|
||||||
|
date=$(git show -s --format=%cs | tr -d '-')
|
||||||
|
hash=$(git show -s --format=%h)
|
||||||
|
if [ "${{ github.event_name }}" = "push" ] && \
|
||||||
|
echo "${{ github.ref }}" | grep -Eq '^refs/tags/v?[0-9]+\.[0-9]+\.[0-9]+'; then
|
||||||
|
tag="${GITHUB_REF#refs/tags/}"
|
||||||
|
base="${tag#v}"
|
||||||
|
echo "publish=true" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "version=${base}0${date}+git${hash}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Tag release: $tag → npm version ${base}0${date}+git${hash}"
|
||||||
|
else
|
||||||
|
base=$(cat VERSION)
|
||||||
|
echo "publish=false" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "version=${base}0${date}+git${hash}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Non-tag build: will not publish."
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Set package version and scope
|
||||||
|
env:
|
||||||
|
VERSION: ${{ steps.release.outputs.version }}
|
||||||
|
run: |
|
||||||
|
# Scope the package to the repo owner so it lands in the right
|
||||||
|
# GitHub Packages namespace regardless of who hosts the repo.
|
||||||
|
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 --allow-same-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: Publish to GitHub Packages
|
||||||
|
if: steps.release.outputs.publish == 'true' && github.event.inputs.dry_run != 'true'
|
||||||
|
run: cd npm && npm publish
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
# Write a Markdown summary visible next to the artifacts on the Actions
|
||||||
|
# page. Captures the exact versions used so a future regression can be
|
||||||
|
# bisected without scrolling through raw logs.
|
||||||
|
- name: Build summary
|
||||||
|
if: always()
|
||||||
|
env:
|
||||||
|
TCL_REF: ${{ steps.resolve-tcl.outputs.tcl_ref }}
|
||||||
|
TCL_REPO_URL: ${{ steps.resolve-tcl.outputs.tcl_repo_url }}
|
||||||
|
run: |
|
||||||
|
source ./emsdk/emsdk_env.sh 2>/dev/null || true
|
||||||
|
EMCC_VER=$(emcc --version 2>/dev/null | head -1 || echo "unavailable")
|
||||||
|
GCC_VER=$(gcc --version 2>/dev/null | head -1 || echo "unavailable")
|
||||||
|
NODE_VER=$(node --version 2>/dev/null || echo "unavailable")
|
||||||
|
MAGIC_VER=$(cat VERSION 2>/dev/null || echo "unavailable")
|
||||||
|
if [ -d ../tcl/.git ]; then
|
||||||
|
TCL_SHA=$(cd ../tcl && git rev-parse HEAD)
|
||||||
|
TCL_DATE=$(cd ../tcl && git log -1 --format="%ci")
|
||||||
|
TCL_SUBJECT=$(cd ../tcl && git log -1 --format="%s")
|
||||||
|
else
|
||||||
|
TCL_SHA="(not cloned)"; TCL_DATE=""; TCL_SUBJECT=""
|
||||||
|
fi
|
||||||
|
printf '## Build info\n\n' >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
printf '| Component | Details |\n' >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
printf '|-----------|----------|\n' >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
printf '| Magic | `%s` |\n' "$MAGIC_VER" >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
printf '| Emscripten | %s |\n' "$EMCC_VER" >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
printf '| GCC | %s |\n' "$GCC_VER" >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
printf '| Node.js | %s |\n' "$NODE_VER" >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
printf '| TCL repo | %s |\n' "$TCL_REPO_URL" >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
printf '| TCL ref | `%s` |\n' "$TCL_REF" >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
printf '| TCL commit | `%s` |\n' "$TCL_SHA" >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
printf '| TCL date | %s |\n' "$TCL_DATE" >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
printf '| TCL subject | %s |\n' "$TCL_SUBJECT" >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
|
@ -1,61 +1,21 @@
|
||||||
# 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:
|
||||||
vezzal:
|
|
||||||
# The type of runner that the job will run on
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
|
||||||
steps:
|
|
||||||
- name: Pulling the docker image
|
|
||||||
run: docker pull vezzal/vezzal:v1
|
|
||||||
|
|
||||||
- name: Start the container with the docker image
|
|
||||||
run: docker run -id --name test_magic vezzal/vezzal:v1 bash | exit
|
|
||||||
|
|
||||||
- name: Run the testing on the container and send the mail
|
|
||||||
run: docker exec test_magic /vezzal/test_magic.sh "lankasaicharan123@gmail.com,tim@opencircuitdesign.com" ${{secrets.MAILING_KEY}}
|
|
||||||
simple_build_linux:
|
simple_build_linux:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- 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: Build
|
|
||||||
run: |
|
|
||||||
source ./emsdk/emsdk_env.sh
|
|
||||||
emconfigure ./configure --without-cairo --without-opengl --without-x --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,19 +1,33 @@
|
||||||
|
# Autoconf / configure outputs
|
||||||
defs.mak
|
defs.mak
|
||||||
*/Depend
|
!toolchains/emscripten/defs.mak
|
||||||
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
|
||||||
.*.swp
|
|
||||||
*.o
|
|
||||||
*.so
|
|
||||||
*~
|
|
||||||
scmos/cif_template/objs/*
|
|
||||||
database/database.h
|
|
||||||
install.log
|
install.log
|
||||||
magic/proto.magicrc
|
|
||||||
make.log
|
make.log
|
||||||
|
reconfigure.sh
|
||||||
|
|
||||||
|
# Compiled objects / libraries
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
*/Depend
|
||||||
|
database/database.h
|
||||||
|
|
||||||
|
# Editor / OS cruft
|
||||||
|
.*.swp
|
||||||
|
.*.swo
|
||||||
|
*~
|
||||||
|
.DS_Store
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Magic runtime-generated files
|
||||||
|
magic/proto.magicrc
|
||||||
|
scmos/cif_template/objs/*
|
||||||
scmos/gdsquery.tech
|
scmos/gdsquery.tech
|
||||||
scmos/minimum.tech
|
scmos/minimum.tech
|
||||||
scmos/scmos-sub.tech
|
scmos/scmos-sub.tech
|
||||||
|
|
@ -21,14 +35,29 @@ 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
|
||||||
|
build-tcl-wasm/
|
||||||
|
net2ir/net2ir
|
||||||
|
net2ir/net2ir.js
|
||||||
|
net2ir/net2ir.wasm
|
||||||
|
|
||||||
|
# Generated test output
|
||||||
|
npm/examples/output/
|
||||||
|
|
|
||||||
|
|
@ -789,8 +789,8 @@ calmaElementSref(
|
||||||
char *filename)
|
char *filename)
|
||||||
{
|
{
|
||||||
int nbytes, rtype, cols, rows, nref, n, i, savescale;
|
int nbytes, rtype, cols, rows, nref, n, i, savescale;
|
||||||
int xlo, ylo, xhi, yhi, xsep, ysep;
|
int xlo, ylo, xhi, yhi, xsep, ysep, angle;
|
||||||
bool madeinst = FALSE;
|
bool madeinst = FALSE, rotated = FALSE;
|
||||||
char *sname = NULL;
|
char *sname = NULL;
|
||||||
bool isArray = FALSE;
|
bool isArray = FALSE;
|
||||||
bool dolookahead = FALSE;
|
bool dolookahead = FALSE;
|
||||||
|
|
@ -990,6 +990,14 @@ calmaElementSref(
|
||||||
refarray[2].p_x = refarray[2].p_y = 0;
|
refarray[2].p_x = refarray[2].p_y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the array is given an angle, then the meaning of rows and
|
||||||
|
* columns needs to be swapped for the purpose of ignoring
|
||||||
|
* X or Y values in the case of a 1-row or 1-column entry.
|
||||||
|
*/
|
||||||
|
angle = GeoTransAngle(&trans, 0);
|
||||||
|
if ((angle == 90) || (angle == 270) || (angle == -90) || (angle == -270))
|
||||||
|
rotated = TRUE;
|
||||||
|
|
||||||
/* If this is a cell reference, then we scale to magic coordinates
|
/* If this is a cell reference, then we scale to magic coordinates
|
||||||
* and place the cell in the magic database. However, if this is
|
* and place the cell in the magic database. However, if this is
|
||||||
* a cell to be flattened a la "gds flatten", then we keep the GDS
|
* a cell to be flattened a la "gds flatten", then we keep the GDS
|
||||||
|
|
@ -1000,6 +1008,7 @@ calmaElementSref(
|
||||||
* is problematic, and probably incorrect.
|
* is problematic, and probably incorrect.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
for (n = 0; n < nref; n++)
|
for (n = 0; n < nref; n++)
|
||||||
{
|
{
|
||||||
savescale = calmaReadScale1;
|
savescale = calmaReadScale1;
|
||||||
|
|
@ -1011,17 +1020,17 @@ calmaElementSref(
|
||||||
* them as needed.
|
* them as needed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((n > 0) && (rows == 1))
|
if ((n > 0) && ((!rotated && (rows == 1)) || (rotated && (cols == 1))))
|
||||||
{
|
{
|
||||||
calmaReadX(&refarray[n], 1);
|
calmaReadX(&refarray[n], 1);
|
||||||
calmaSkipBytes(4);
|
calmaSkipBytes(4);
|
||||||
refarray[n].p_y = 0;
|
refarray[n].p_y = refarray[0].p_y;
|
||||||
}
|
}
|
||||||
else if ((n > 0) && (cols == 1))
|
else if ((n > 0) && ((!rotated && (cols == 1)) || (rotated && (rows == 1))))
|
||||||
{
|
{
|
||||||
calmaSkipBytes(4);
|
calmaSkipBytes(4);
|
||||||
calmaReadY(&refarray[n], 1);
|
calmaReadY(&refarray[n], 1);
|
||||||
refarray[n].p_x = 0;
|
refarray[n].p_x = refarray[0].p_x;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
calmaReadPoint(&refarray[n], 1);
|
calmaReadPoint(&refarray[n], 1);
|
||||||
|
|
|
||||||
|
|
@ -537,7 +537,6 @@ calmaElementPath(void)
|
||||||
int layer, dt, width, pathtype, ciftype, savescale;
|
int layer, dt, width, pathtype, ciftype, savescale;
|
||||||
int xmin, ymin, xmax, ymax, temp;
|
int xmin, ymin, xmax, ymax, temp;
|
||||||
CIFPath *pathheadp, *pathp, *previousp;
|
CIFPath *pathheadp, *pathp, *previousp;
|
||||||
Rect segment;
|
|
||||||
Plane *plane;
|
Plane *plane;
|
||||||
int first,last;
|
int first,last;
|
||||||
CellUse *use;
|
CellUse *use;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
extern int calmaWriteInitFunc(CellDef *def, ClientData cdata); /* UNUSED */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scaling.
|
* Scaling.
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ typedef struct {
|
||||||
} calmaOutputStruct;
|
} calmaOutputStruct;
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
extern int calmaWriteInitFunc(CellDef *def);
|
extern int calmaWriteInitFunc(CellDef *def, ClientData cdata); /* UNUSED */
|
||||||
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,9 +822,11 @@ 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);
|
extern int calmaWriteInitFunc(CellDef *def, ClientData cdata); /* UNUSED */
|
||||||
|
|
||||||
/* Structure used by calmaWritePaintFuncZ() and others */
|
/* Structure used by calmaWritePaintFuncZ() and others */
|
||||||
|
|
||||||
|
|
|
||||||
245
cif/CIFgen.c
245
cif/CIFgen.c
|
|
@ -25,6 +25,7 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
|
||||||
#include <stdlib.h> /* for abs() */
|
#include <stdlib.h> /* for abs() */
|
||||||
#include <math.h> /* for ceil() and sqrt() */
|
#include <math.h> /* for ceil() and sqrt() */
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <string.h> /* for strcmp() */
|
||||||
|
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
|
|
@ -4116,7 +4117,7 @@ cifSrTiles(
|
||||||
* one or more times for the planes being used in processing
|
* one or more times for the planes being used in processing
|
||||||
* where the CIF search should be conducted over "area" scaled
|
* where the CIF search should be conducted over "area" scaled
|
||||||
* to CIF units, rather than the entire plane. Currently used
|
* to CIF units, rather than the entire plane. Currently used
|
||||||
* only for operator CIFOP_INTERACT.
|
* only for operators CIFOP_INTERACT and CIFOP_TAGGED.
|
||||||
*
|
*
|
||||||
* Results:
|
* Results:
|
||||||
* Returns the value returned by the function.
|
* Returns the value returned by the function.
|
||||||
|
|
@ -4170,12 +4171,21 @@ cifSrTiles2(
|
||||||
}
|
}
|
||||||
|
|
||||||
cifScale = 1;
|
cifScale = 1;
|
||||||
for (t = 0; t < TT_MAXTYPES; t++, temps++)
|
if (TTMaskIsZero(&cifOp->co_cifMask) && TTMaskIsZero(&cifOp->co_paintMask))
|
||||||
if (TTMaskHasType(&cifOp->co_cifMask, t))
|
{
|
||||||
if (DBSrPaintArea((Tile *)NULL, *temps, area,
|
/* Current CIF plane is in *temps */
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5044,6 +5054,47 @@ cifInteractingRegions(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* cifCopyPropPlaneFunc --
|
||||||
|
*
|
||||||
|
* Copy the contents of a plane saved as a plane-type property into the
|
||||||
|
* current CIF plane. The property plane is in magic internal
|
||||||
|
* coordinates, so each tile needs to be scaled and redrawn into the
|
||||||
|
* current CIF plane.
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* Zero to keep the search going
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* Copies translated geometry into the target plane.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
cifCopyPropPlaneFunc(Tile *tile,
|
||||||
|
TileType dinfo,
|
||||||
|
Plane *curPlane)
|
||||||
|
{
|
||||||
|
Rect bbox;
|
||||||
|
|
||||||
|
TiToRect(tile, &bbox);
|
||||||
|
|
||||||
|
cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
|
||||||
|
|
||||||
|
bbox.r_xbot *= cifScale;
|
||||||
|
bbox.r_ybot *= cifScale;
|
||||||
|
bbox.r_xtop *= cifScale;
|
||||||
|
bbox.r_ytop *= cifScale;
|
||||||
|
|
||||||
|
cifScale = 1;
|
||||||
|
DBNMPaintPlane(curPlane, CIF_SOLIDTYPE, &bbox,
|
||||||
|
CIFPaintTable, (PaintUndoInfo *)NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -5095,12 +5146,13 @@ CIFGenLayer(
|
||||||
CIFSquaresInfo csi;
|
CIFSquaresInfo csi;
|
||||||
SearchContext scx;
|
SearchContext scx;
|
||||||
TileType ttype;
|
TileType ttype;
|
||||||
char *netname;
|
char *netname, *text;
|
||||||
|
Label *label;
|
||||||
BloatStruct bls;
|
BloatStruct bls;
|
||||||
BridgeStruct brs;
|
BridgeStruct brs;
|
||||||
BridgeLimStruct brlims;
|
BridgeLimStruct brlims;
|
||||||
BridgeData *bridge;
|
BridgeData *bridge;
|
||||||
BloatData *bloats;
|
BloatData *bloats, locbloat;
|
||||||
bool hstop = FALSE;
|
bool hstop = FALSE;
|
||||||
PropertyRecord *proprec;
|
PropertyRecord *proprec;
|
||||||
char *propvalue;
|
char *propvalue;
|
||||||
|
|
@ -5411,7 +5463,6 @@ 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,
|
||||||
|
|
@ -5419,9 +5470,12 @@ CIFGenLayer(
|
||||||
(ClientData)NULL);
|
(ClientData)NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
TTMaskSetMask(&bls.connect, &op->co_paintMask);
|
||||||
DBSrPaintArea((Tile *)NULL, cellDef->cd_planes[bloats->bl_plane],
|
DBSrPaintArea((Tile *)NULL, cellDef->cd_planes[bloats->bl_plane],
|
||||||
&TiPlaneRect, &bls.connect, cifProcessResetFunc,
|
&TiPlaneRect, &bls.connect, cifProcessResetFunc,
|
||||||
(ClientData)NULL);
|
(ClientData)NULL);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -5560,6 +5614,149 @@ CIFGenLayer(
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CIFOP_TAGGED:
|
||||||
|
if (hier)
|
||||||
|
{
|
||||||
|
hstop = TRUE; /* Stop hierarchical processing */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find all relevant labels by text matching and then continue
|
||||||
|
* like CIFOP_BLOATALL. CIFOP_BLOATALL uses a BloatData record
|
||||||
|
* which is not part of CIFOP_TAGGED. Create a BloatData record
|
||||||
|
* on the fly for each tagged area based on type, and swap it for
|
||||||
|
* the text, so that cifBloatAllFunc believes this is actually a
|
||||||
|
* CIFOP_BLOATALL operation. Note that we don't actually care
|
||||||
|
* what layer the label is attached to (lab_type). We are looking
|
||||||
|
* for labels whose lab_rect values overlap the types that are given
|
||||||
|
* in the rule.
|
||||||
|
*/
|
||||||
|
|
||||||
|
cifPlane = curPlane;
|
||||||
|
bls.op = op;
|
||||||
|
bls.def = cellDef;
|
||||||
|
bls.temps = temps;
|
||||||
|
|
||||||
|
text = (char *)op->co_client;
|
||||||
|
|
||||||
|
bloats = &locbloat;
|
||||||
|
if (!TTMaskIsZero(&op->co_cifMask))
|
||||||
|
{
|
||||||
|
bloats->bl_plane = -1;
|
||||||
|
for (ttype = 0; ttype < TT_MAXTYPES; ttype++)
|
||||||
|
{
|
||||||
|
if (TTMaskHasType(&op->co_cifMask, ttype))
|
||||||
|
bloats->bl_distance[ttype] = 1;
|
||||||
|
else
|
||||||
|
bloats->bl_distance[ttype] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!TTMaskIsZero(&op->co_paintMask))
|
||||||
|
{
|
||||||
|
int plane, pmask;
|
||||||
|
pmask = DBTechTypesToPlanes(&op->co_paintMask);
|
||||||
|
for (plane = PL_TECHDEPBASE; plane < DBNumPlanes; plane++)
|
||||||
|
if (PlaneMaskHasPlane(pmask, plane))
|
||||||
|
break;
|
||||||
|
bloats->bl_plane = plane;
|
||||||
|
for (ttype = 0; ttype < TT_MAXTYPES; ttype++)
|
||||||
|
{
|
||||||
|
if (TTMaskHasType(&op->co_paintMask, ttype))
|
||||||
|
bloats->bl_distance[ttype] = 1;
|
||||||
|
else
|
||||||
|
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 */
|
||||||
|
op->co_client = (ClientData)bloats;
|
||||||
|
|
||||||
|
if (bloats->bl_plane < 0)
|
||||||
|
{
|
||||||
|
/* bl_plane == -1 indicates bloating into a CIF templayer, */
|
||||||
|
/* so the only connecting type should be CIF_SOLIDTYPE. */
|
||||||
|
TTMaskSetOnlyType(&bls.connect, CIF_SOLIDTYPE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
TTMaskZero(&bls.connect);
|
||||||
|
for (i = 0; i < TT_MAXTYPES; i++)
|
||||||
|
if (bloats->bl_distance[i] != 0)
|
||||||
|
TTMaskSetType(&bls.connect, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (label = cellDef->cd_labels; label; label = label->lab_next)
|
||||||
|
{
|
||||||
|
if (!strcmp(label->lab_text, text))
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset marked tiles */
|
||||||
|
|
||||||
|
if (bloats->bl_plane < 0) /* Bloat types are CIF types */
|
||||||
|
{
|
||||||
|
for (ttype = 0; ttype < TT_MAXTYPES; ttype++, bls.temps++)
|
||||||
|
if (bloats->bl_distance[ttype] > 0)
|
||||||
|
(void) DBSrPaintArea((Tile *)NULL, *bls.temps, &TiPlaneRect,
|
||||||
|
&CIFSolidBits, cifProcessResetFunc,
|
||||||
|
(ClientData)NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TTMaskSetMask(&bls.connect, &op->co_paintMask);
|
||||||
|
DBSrPaintArea((Tile *)NULL, cellDef->cd_planes[bloats->bl_plane],
|
||||||
|
&TiPlaneRect, &bls.connect, cifProcessResetFunc,
|
||||||
|
(ClientData)NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Replace the client data */
|
||||||
|
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;
|
||||||
|
|
||||||
case CIFOP_BOUNDARY:
|
case CIFOP_BOUNDARY:
|
||||||
if (hier)
|
if (hier)
|
||||||
{
|
{
|
||||||
|
|
@ -5646,6 +5843,7 @@ CIFGenLayer(
|
||||||
int n;
|
int n;
|
||||||
char propname[512];
|
char propname[512];
|
||||||
char *layername = (char *)op->co_client;
|
char *layername = (char *)op->co_client;
|
||||||
|
Tile *t;
|
||||||
|
|
||||||
snprintf(propname, 512, "MASKHINTS_%s", layername);
|
snprintf(propname, 512, "MASKHINTS_%s", layername);
|
||||||
|
|
||||||
|
|
@ -5653,30 +5851,11 @@ CIFGenLayer(
|
||||||
proprec = DBPropGet(cellDef, propname, &found);
|
proprec = DBPropGet(cellDef, propname, &found);
|
||||||
if (!found) break; /* No mask hints available */
|
if (!found) break; /* No mask hints available */
|
||||||
|
|
||||||
if (proprec->prop_type == PROPERTY_TYPE_DIMENSION)
|
ASSERT (proprec->prop_type == PROPERTY_TYPE_PLANE, "CIFGenLayer");
|
||||||
{
|
t = PlaneGetHint(proprec->prop_value.prop_plane);
|
||||||
for (n = 0; n < proprec->prop_len; n += 4)
|
DBSrPaintArea(t, proprec->prop_value.prop_plane,
|
||||||
{
|
&TiPlaneRect, &CIFSolidBits,
|
||||||
if ((n + 3) >= proprec->prop_len) break;
|
cifCopyPropPlaneFunc, (ClientData)curPlane);
|
||||||
|
|
||||||
cifPlane = curPlane;
|
|
||||||
cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
|
|
||||||
|
|
||||||
bbox.r_xbot = proprec->prop_value.prop_integer[n];
|
|
||||||
bbox.r_ybot = proprec->prop_value.prop_integer[n + 1];
|
|
||||||
bbox.r_xtop = proprec->prop_value.prop_integer[n + 2];
|
|
||||||
bbox.r_ytop = proprec->prop_value.prop_integer[n + 3];
|
|
||||||
|
|
||||||
bbox.r_xbot *= cifScale;
|
|
||||||
bbox.r_ybot *= cifScale;
|
|
||||||
bbox.r_xtop *= cifScale;
|
|
||||||
bbox.r_ytop *= cifScale;
|
|
||||||
|
|
||||||
cifScale = 1;
|
|
||||||
DBNMPaintPlane(curPlane, CIF_SOLIDTYPE, &bbox,
|
|
||||||
CIFPaintTable, (PaintUndoInfo *)NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
146
cif/CIFhier.c
146
cif/CIFhier.c
|
|
@ -209,16 +209,52 @@ typedef struct _maskHintsData
|
||||||
{
|
{
|
||||||
Transform *mh_trans;
|
Transform *mh_trans;
|
||||||
CellDef *mh_def;
|
CellDef *mh_def;
|
||||||
|
Plane *mh_plane;
|
||||||
} MaskHintsData;
|
} MaskHintsData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* cifCopyMaskHintFunc --
|
||||||
|
*
|
||||||
|
* Callback function used by cifFlatMaskHints. Transforms a tile
|
||||||
|
* from the original plane and paints it into the target plane,
|
||||||
|
* both of which are properties.
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* Zero to keep the search going.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* Paints geometry into the target plane.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
cifCopyMaskHintFunc(Tile *tile,
|
||||||
|
TileType dinfo,
|
||||||
|
ClientData cdata)
|
||||||
|
{
|
||||||
|
MaskHintsData *mhd = (MaskHintsData *)cdata;
|
||||||
|
Rect r, newr;
|
||||||
|
|
||||||
|
TiToRect(tile, &r);
|
||||||
|
|
||||||
|
/* Transform tile area to coordinates of mhd->mh_plane and paint */
|
||||||
|
GeoTransRect(mhd->mh_trans, &r, &newr);
|
||||||
|
DBPaintPlane(mhd->mh_plane, &newr, CIFPaintTable, (PaintUndoInfo *)NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* cifFlatMaskHints --
|
* cifFlatMaskHints --
|
||||||
*
|
*
|
||||||
* Copy a mask hint into a flattened cell by transforming it into the
|
* Copy a mask hint into a flattened cell by transforming it into the
|
||||||
* coordinate system of the flattened cell, and adding it to the
|
* coordinate system of the flattened cell, and painting it into the
|
||||||
* property list of the flattened cell.
|
* property plane of the flattened cell.
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* 0 to keep the search going.
|
* 0 to keep the search going.
|
||||||
|
|
@ -240,6 +276,7 @@ cifFlatMaskHints(
|
||||||
bool propfound;
|
bool propfound;
|
||||||
int i, lastlen, numvals;
|
int i, lastlen, numvals;
|
||||||
PropertyRecord *newproprec, *oldproprec;
|
PropertyRecord *newproprec, *oldproprec;
|
||||||
|
Plane *plane;
|
||||||
|
|
||||||
if (!strncmp(name, "MASKHINTS_", 10))
|
if (!strncmp(name, "MASKHINTS_", 10))
|
||||||
{
|
{
|
||||||
|
|
@ -247,53 +284,24 @@ cifFlatMaskHints(
|
||||||
oldproprec = (PropertyRecord *)DBPropGet(mhd->mh_def, name, &propfound);
|
oldproprec = (PropertyRecord *)DBPropGet(mhd->mh_def, name, &propfound);
|
||||||
if (propfound)
|
if (propfound)
|
||||||
{
|
{
|
||||||
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
ASSERT(oldproprec->prop_type == PROPERTY_TYPE_PLANE,
|
||||||
(oldproprec->prop_len + proprec->prop_len - 2) * sizeof(int));
|
"cifFlatMaskHints");
|
||||||
newproprec->prop_len = oldproprec->prop_len + proprec->prop_len;
|
plane = oldproprec->prop_value.prop_plane;
|
||||||
newproprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||||
(proprec->prop_len - 2) * sizeof(int));
|
newproprec->prop_len = 0; /* (unused) */
|
||||||
newproprec->prop_len = proprec->prop_len;
|
newproprec->prop_type = PROPERTY_TYPE_PLANE;
|
||||||
newproprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
plane = DBNewPlane((ClientData)TT_SPACE);
|
||||||
|
newproprec->prop_value.prop_plane = plane;
|
||||||
|
DBPropPut(mhd->mh_def, name, newproprec);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < proprec->prop_len; i += 4)
|
mhd->mh_plane = plane;
|
||||||
{
|
DBSrPaintArea((Tile *)NULL, proprec->prop_value.prop_plane,
|
||||||
/* There should be a multiple of 4 values but avoid an array overrun
|
&TiPlaneRect, &CIFSolidBits,
|
||||||
* if not.
|
cifCopyMaskHintFunc, (ClientData)mhd);
|
||||||
*/
|
|
||||||
if ((i + 3) >= proprec->prop_len)
|
|
||||||
{
|
|
||||||
TxError("MASKHINTS_%s: Expected 4 values, found only %d\n",
|
|
||||||
name + 10, numvals);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
r.r_xbot = proprec->prop_value.prop_integer[i];
|
|
||||||
r.r_ybot = proprec->prop_value.prop_integer[i + 1];
|
|
||||||
r.r_xtop = proprec->prop_value.prop_integer[i + 2];
|
|
||||||
r.r_ytop = proprec->prop_value.prop_integer[i + 3];
|
|
||||||
|
|
||||||
/* Transform rectangle to top level coordinates */
|
|
||||||
GeoTransRect(mhd->mh_trans, &r, &newr);
|
|
||||||
|
|
||||||
newproprec->prop_value.prop_integer[i] = newr.r_xbot;
|
|
||||||
newproprec->prop_value.prop_integer[i + 1] = newr.r_ybot;
|
|
||||||
newproprec->prop_value.prop_integer[i + 2] = newr.r_xtop;
|
|
||||||
newproprec->prop_value.prop_integer[i + 3] = newr.r_ytop;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If there were existing entries, copy them into the new property */
|
|
||||||
if (propfound)
|
|
||||||
{
|
|
||||||
for (i = 0; i < oldproprec->prop_len; i++)
|
|
||||||
newproprec->prop_value.prop_integer[i + proprec->prop_len] =
|
|
||||||
oldproprec->prop_value.prop_integer[i];
|
|
||||||
}
|
|
||||||
DBPropPut(mhd->mh_def, name, newproprec);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -304,9 +312,10 @@ cifFlatMaskHints(
|
||||||
* CIFCopyMaskHints --
|
* CIFCopyMaskHints --
|
||||||
*
|
*
|
||||||
* Callback function to copy mask hints from one cell into another.
|
* Callback function to copy mask hints from one cell into another.
|
||||||
|
* (Occasionally called as a standalone function, not as a callback.)
|
||||||
*
|
*
|
||||||
* Results:
|
* Results:
|
||||||
* None.
|
* Return 0 to keep the search going.
|
||||||
*
|
*
|
||||||
* Side effects:
|
* Side effects:
|
||||||
* May modify properties in the target cell.
|
* May modify properties in the target cell.
|
||||||
|
|
@ -314,7 +323,7 @@ cifFlatMaskHints(
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
int
|
||||||
CIFCopyMaskHints(
|
CIFCopyMaskHints(
|
||||||
SearchContext *scx,
|
SearchContext *scx,
|
||||||
CellDef *targetDef)
|
CellDef *targetDef)
|
||||||
|
|
@ -324,38 +333,9 @@ CIFCopyMaskHints(
|
||||||
CellDef *sourceDef = scx->scx_use->cu_def;
|
CellDef *sourceDef = scx->scx_use->cu_def;
|
||||||
mhd.mh_trans = &scx->scx_trans;
|
mhd.mh_trans = &scx->scx_trans;
|
||||||
mhd.mh_def = targetDef;
|
mhd.mh_def = targetDef;
|
||||||
|
mhd.mh_plane = (Plane *)NULL;
|
||||||
|
|
||||||
DBPropEnum(sourceDef, cifFlatMaskHints, &mhd);
|
DBPropEnum(sourceDef, cifFlatMaskHints, &mhd);
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ----------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* cifHierCopyMaskHints --
|
|
||||||
*
|
|
||||||
* Callback function to copy mask hints from a subcell into a flattened
|
|
||||||
* cell, which is passed in the clientData record.
|
|
||||||
*
|
|
||||||
* Results:
|
|
||||||
* Always returns 0 to keep the search alive.
|
|
||||||
*
|
|
||||||
* Side effects:
|
|
||||||
* May modify properties in the flattened cell.
|
|
||||||
*
|
|
||||||
* ----------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
|
||||||
cifHierCopyMaskHints(
|
|
||||||
SearchContext *scx,
|
|
||||||
ClientData clientData)
|
|
||||||
{
|
|
||||||
MaskHintsData mhd;
|
|
||||||
|
|
||||||
mhd.mh_trans = &scx->scx_trans;
|
|
||||||
mhd.mh_def = (CellDef *)clientData;
|
|
||||||
|
|
||||||
DBPropEnum(scx->scx_use->cu_def, cifFlatMaskHints, &mhd);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -480,7 +460,7 @@ cifHierCellFunc(
|
||||||
|
|
||||||
/* Flatten mask hints in the area of interest */
|
/* Flatten mask hints in the area of interest */
|
||||||
CIFCopyMaskHints(scx, CIFComponentDef);
|
CIFCopyMaskHints(scx, CIFComponentDef);
|
||||||
DBTreeSrCells(&newscx, 0, cifHierCopyMaskHints,
|
DBTreeSrCells(&newscx, 0, CIFCopyMaskHints,
|
||||||
(ClientData)CIFComponentDef);
|
(ClientData)CIFComponentDef);
|
||||||
|
|
||||||
/* Set CIFErrorDef to NULL to ignore errors here... these will
|
/* Set CIFErrorDef to NULL to ignore errors here... these will
|
||||||
|
|
@ -755,8 +735,10 @@ 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)
|
* with extract). Save and restore GrDisplayStatus so that
|
||||||
|
* 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;
|
||||||
|
|
@ -808,7 +790,7 @@ CIFGenSubcells(
|
||||||
cifHierCopyFunc, (ClientData) CIFTotalDef);
|
cifHierCopyFunc, (ClientData) CIFTotalDef);
|
||||||
/* Flatten mask hints in the area of interest */
|
/* Flatten mask hints in the area of interest */
|
||||||
CIFCopyMaskHints(&scx, CIFTotalDef);
|
CIFCopyMaskHints(&scx, CIFTotalDef);
|
||||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||||
(ClientData)CIFTotalDef);
|
(ClientData)CIFTotalDef);
|
||||||
|
|
||||||
CIFErrorDef = def;
|
CIFErrorDef = def;
|
||||||
|
|
@ -881,7 +863,7 @@ CIFGenSubcells(
|
||||||
|
|
||||||
CIFHierTileOps += CIFTileOps - oldTileOps;
|
CIFHierTileOps += CIFTileOps - oldTileOps;
|
||||||
|
|
||||||
GrDisplayStatus = DISPLAY_IDLE;
|
GrDisplayStatus = savedDisplayStatus;
|
||||||
SigRemoveTimer();
|
SigRemoveTimer();
|
||||||
|
|
||||||
UndoEnable();
|
UndoEnable();
|
||||||
|
|
@ -986,14 +968,14 @@ cifHierElementFunc(
|
||||||
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
|
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
|
||||||
cifHierCopyFunc, (ClientData) CIFTotalDef);
|
cifHierCopyFunc, (ClientData) CIFTotalDef);
|
||||||
CIFCopyMaskHints(&scx, CIFTotalDef);
|
CIFCopyMaskHints(&scx, CIFTotalDef);
|
||||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||||
(ClientData)CIFTotalDef);
|
(ClientData)CIFTotalDef);
|
||||||
|
|
||||||
DBCellClearDef(CIFComponentDef);
|
DBCellClearDef(CIFComponentDef);
|
||||||
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
|
(void) DBTreeSrTiles(&scx, &CIFCurStyle->cs_yankLayers, 0,
|
||||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||||
CIFCopyMaskHints(&scx, CIFComponentDef);
|
CIFCopyMaskHints(&scx, CIFComponentDef);
|
||||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||||
(ClientData)CIFComponentDef);
|
(ClientData)CIFComponentDef);
|
||||||
|
|
||||||
CIFErrorDef = (CellDef *) NULL;
|
CIFErrorDef = (CellDef *) NULL;
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,7 @@ typedef struct cifop
|
||||||
* CIFOP_BRIDGELIM - Added 27/07/20---Bridge across catecorner gaps, but with limiting layers
|
* CIFOP_BRIDGELIM - Added 27/07/20---Bridge across catecorner gaps, but with limiting layers
|
||||||
* CIFOP_MASKHINTS - Added 12/14/20---Add geometry from cell properties, if any.
|
* CIFOP_MASKHINTS - Added 12/14/20---Add geometry from cell properties, if any.
|
||||||
* CIFOP_NOTSQUARE - Added 2/26/26---Keep only geometry which is not square.
|
* CIFOP_NOTSQUARE - Added 2/26/26---Keep only geometry which is not square.
|
||||||
|
* CIFOP_TAGGED - Added 3/11/26---Find geometry attached to the given text label
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CIFOP_AND 1
|
#define CIFOP_AND 1
|
||||||
|
|
@ -174,6 +175,7 @@ typedef struct cifop
|
||||||
#define CIFOP_BRIDGELIM 24
|
#define CIFOP_BRIDGELIM 24
|
||||||
#define CIFOP_MASKHINTS 25
|
#define CIFOP_MASKHINTS 25
|
||||||
#define CIFOP_NOTSQUARE 26
|
#define CIFOP_NOTSQUARE 26
|
||||||
|
#define CIFOP_TAGGED 27
|
||||||
|
|
||||||
/* Definitions of bit fields used in the value of co_client for CIFOP_INTERACT */
|
/* Definitions of bit fields used in the value of co_client for CIFOP_INTERACT */
|
||||||
#define CIFOP_INT_NOT 0x1 /* Inverted sense (not interacting) */
|
#define CIFOP_INT_NOT 0x1 /* Inverted sense (not interacting) */
|
||||||
|
|
@ -338,9 +340,8 @@ extern Plane *CIFGenLayer(CIFOp *op, const Rect *area, CellDef *cellDef, CellDef
|
||||||
bool hier, ClientData clientdata);
|
bool hier, ClientData clientdata);
|
||||||
extern void CIFInitCells(void);
|
extern void CIFInitCells(void);
|
||||||
extern int cifHierCopyFunc(Tile *tile, TileType dinfo, TreeContext *cxp);
|
extern int cifHierCopyFunc(Tile *tile, TileType dinfo, TreeContext *cxp);
|
||||||
extern int cifHierCopyMaskHints(SearchContext *scx, ClientData clientData);
|
|
||||||
extern void CIFLoadStyle(char *stylename);
|
extern void CIFLoadStyle(char *stylename);
|
||||||
extern void CIFCopyMaskHints(SearchContext *scx, CellDef *targetDef);
|
extern int CIFCopyMaskHints(SearchContext *scx, CellDef *targetDef);
|
||||||
|
|
||||||
/* C99 compat */
|
/* C99 compat */
|
||||||
extern void CIFCoverageLayer(CellDef *rootDef, Rect *area, char *layer, bool dolist);
|
extern void CIFCoverageLayer(CellDef *rootDef, Rect *area, char *layer, bool dolist);
|
||||||
|
|
|
||||||
108
cif/CIFrdcl.c
108
cif/CIFrdcl.c
|
|
@ -613,7 +613,7 @@ CIFPaintCurrent(
|
||||||
CIFOp *op;
|
CIFOp *op;
|
||||||
|
|
||||||
plane = CIFGenLayer(cifCurReadStyle->crs_layers[i]->crl_ops,
|
plane = CIFGenLayer(cifCurReadStyle->crs_layers[i]->crl_ops,
|
||||||
&TiPlaneRect, (CellDef *)NULL, (CellDef *)NULL,
|
&TiPlaneRect, cifReadCellDef, cifReadCellDef,
|
||||||
cifCurReadPlanes, FALSE, (ClientData)NULL);
|
cifCurReadPlanes, FALSE, (ClientData)NULL);
|
||||||
|
|
||||||
/* Generate a paint/erase table, then paint from the CIF
|
/* Generate a paint/erase table, then paint from the CIF
|
||||||
|
|
@ -718,6 +718,9 @@ CIFPaintCurrent(
|
||||||
&DBAllButSpaceBits, cifCheckPaintFunc,
|
&DBAllButSpaceBits, cifCheckPaintFunc,
|
||||||
(ClientData)NULL) == 1))
|
(ClientData)NULL) == 1))
|
||||||
{
|
{
|
||||||
|
/* (To do: remove the linked Rects and paint directly
|
||||||
|
* into the plane in cifMaskHintFunc())
|
||||||
|
*/
|
||||||
DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect,
|
DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect,
|
||||||
&CIFSolidBits, cifMaskHintFunc,
|
&CIFSolidBits, cifMaskHintFunc,
|
||||||
(ClientData)&lrec);
|
(ClientData)&lrec);
|
||||||
|
|
@ -728,30 +731,29 @@ CIFPaintCurrent(
|
||||||
char *propname, *layername;
|
char *propname, *layername;
|
||||||
int proplen, i, savescale;
|
int proplen, i, savescale;
|
||||||
bool origfound = FALSE;
|
bool origfound = FALSE;
|
||||||
|
Plane *plane;
|
||||||
|
|
||||||
layername = (char *)op->co_client;
|
layername = (char *)op->co_client;
|
||||||
propname = (char *)mallocMagic(11 + strlen(layername));
|
propname = (char *)mallocMagic(11 + strlen(layername));
|
||||||
sprintf(propname, "MASKHINTS_%s", layername);
|
sprintf(propname, "MASKHINTS_%s", layername);
|
||||||
|
|
||||||
/* Turn all linked Rects into a mask-hints property in the
|
/* If there is already a mask hint plane for this layer,
|
||||||
* target cell.
|
* then add to it; otherwise, create a new plane.
|
||||||
*/
|
*/
|
||||||
proplen = 0;
|
proprec = DBPropGet(cifReadCellDef, layername, &origfound);
|
||||||
for (lsrch = lrec; lsrch; lsrch = lsrch->r_next)
|
if (origfound)
|
||||||
proplen += 4;
|
plane = proprec->prop_value.prop_plane;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
proprec = (PropertyRecord *)mallocMagic(
|
||||||
|
sizeof(PropertyRecord));
|
||||||
|
proprec->prop_type = PROPERTY_TYPE_PLANE;
|
||||||
|
proprec->prop_len = 0; /* (unused) */
|
||||||
|
plane = DBNewPlane((ClientData)TT_SPACE);
|
||||||
|
proprec->prop_value.prop_plane = plane;
|
||||||
|
DBPropPut(cifReadCellDef, propname, proprec);
|
||||||
|
}
|
||||||
|
|
||||||
/* If there is already a mask hint for this layer, then
|
|
||||||
* prepend to its data.
|
|
||||||
*/
|
|
||||||
proporig = DBPropGet(cifReadCellDef, layername, &origfound);
|
|
||||||
if (origfound) proplen += proporig->prop_len;
|
|
||||||
|
|
||||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) *
|
|
||||||
(proplen - 2) * sizeof(int));
|
|
||||||
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
|
||||||
proprec->prop_len = proplen;
|
|
||||||
|
|
||||||
proplen = 0;
|
|
||||||
while (lrec != NULL)
|
while (lrec != NULL)
|
||||||
{
|
{
|
||||||
lrec->r_r.r_xtop =
|
lrec->r_r.r_xtop =
|
||||||
|
|
@ -787,29 +789,14 @@ CIFPaintCurrent(
|
||||||
(savescale / cifCurReadStyle->crs_scaleFactor);
|
(savescale / cifCurReadStyle->crs_scaleFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
proprec->prop_value.prop_integer[proplen] =
|
DBPaintPlane(plane, &lrec->r_r, CIFPaintTable,
|
||||||
lrec->r_r.r_xbot;
|
(PaintUndoInfo *)NULL);
|
||||||
proprec->prop_value.prop_integer[proplen + 1] =
|
|
||||||
lrec->r_r.r_ybot;
|
|
||||||
proprec->prop_value.prop_integer[proplen + 2] =
|
|
||||||
lrec->r_r.r_xtop;
|
|
||||||
proprec->prop_value.prop_integer[proplen + 3] =
|
|
||||||
lrec->r_r.r_ytop;
|
|
||||||
|
|
||||||
free_magic1_t mm1 = freeMagic1_init();
|
free_magic1_t mm1 = freeMagic1_init();
|
||||||
freeMagic1(&mm1, lrec);
|
freeMagic1(&mm1, lrec);
|
||||||
lrec = lrec->r_next;
|
lrec = lrec->r_next;
|
||||||
freeMagic1_end(&mm1);
|
freeMagic1_end(&mm1);
|
||||||
|
|
||||||
proplen += 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (origfound)
|
|
||||||
for (i = 0; i < proporig->prop_len; i++)
|
|
||||||
proprec->prop_value.prop_integer[proplen++] =
|
|
||||||
proporig->prop_value.prop_integer[i];
|
|
||||||
|
|
||||||
DBPropPut(cifReadCellDef, propname, proprec);
|
|
||||||
freeMagic(propname);
|
freeMagic(propname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -926,7 +913,9 @@ CIFPaintCurrent(
|
||||||
(CellDef *)NULL, CIFPlanes, FALSE, (ClientData)NULL);
|
(CellDef *)NULL, CIFPlanes, FALSE, (ClientData)NULL);
|
||||||
|
|
||||||
/* Scan the resulting plane and generate linked Rect structures for
|
/* Scan the resulting plane and generate linked Rect structures for
|
||||||
* each shape found.
|
* each shape found. (To do: Remove the linked Rects and paint
|
||||||
|
* directly into the plane in cifMaskHintFunc(), which is more
|
||||||
|
* efficient but not hugely so.)
|
||||||
*/
|
*/
|
||||||
DBSrPaintArea((Tile *)NULL, presult, &TiPlaneRect, &CIFSolidBits,
|
DBSrPaintArea((Tile *)NULL, presult, &TiPlaneRect, &CIFSolidBits,
|
||||||
cifMaskHintFunc, (ClientData)&lrec);
|
cifMaskHintFunc, (ClientData)&lrec);
|
||||||
|
|
@ -934,44 +923,45 @@ CIFPaintCurrent(
|
||||||
if (lrec != NULL)
|
if (lrec != NULL)
|
||||||
{
|
{
|
||||||
PropertyRecord *proprec;
|
PropertyRecord *proprec;
|
||||||
|
bool propfound;
|
||||||
char *propname;
|
char *propname;
|
||||||
int proplen;
|
Plane *plane;
|
||||||
|
|
||||||
propname = (char *)mallocMagic(11 + strlen(cifReadLayers[i]));
|
propname = (char *)mallocMagic(11 + strlen(cifReadLayers[i]));
|
||||||
sprintf(propname, "MASKHINTS_%s", cifReadLayers[i]);
|
sprintf(propname, "MASKHINTS_%s", cifReadLayers[i]);
|
||||||
|
|
||||||
/* Turn all linked Rects into a mask-hints property in the
|
/* Paint all linked Rects into a mask-hints property plane
|
||||||
* target cell.
|
* in the target cell.
|
||||||
*/
|
*/
|
||||||
proplen = 0;
|
|
||||||
for (lsrch = lrec; lsrch; lsrch = lsrch->r_next)
|
|
||||||
proplen += 4;
|
|
||||||
|
|
||||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) *
|
proprec = DBPropGet(cifReadCellDef, propname, &propfound);
|
||||||
(proplen - 2) * sizeof(int));
|
if (!propfound)
|
||||||
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
{
|
||||||
proprec->prop_len = proplen;
|
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||||
|
proprec->prop_type = PROPERTY_TYPE_PLANE;
|
||||||
|
proprec->prop_len = 0; /* (unused) */
|
||||||
|
plane = DBNewPlane((ClientData)TT_SPACE);
|
||||||
|
proprec->prop_value.prop_plane = plane;
|
||||||
|
DBPropPut(cifReadCellDef, propname, proprec);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
plane = proprec->prop_value.prop_plane;
|
||||||
|
|
||||||
proplen = 0;
|
|
||||||
while (lrec != NULL)
|
while (lrec != NULL)
|
||||||
{
|
{
|
||||||
proprec->prop_value.prop_integer[proplen] =
|
lrec->r_r.r_xbot /= CIFCurStyle->cs_scaleFactor;
|
||||||
lrec->r_r.r_xbot / CIFCurStyle->cs_scaleFactor;
|
lrec->r_r.r_ybot /= CIFCurStyle->cs_scaleFactor;
|
||||||
proprec->prop_value.prop_integer[proplen + 1] =
|
lrec->r_r.r_xtop /= CIFCurStyle->cs_scaleFactor;
|
||||||
lrec->r_r.r_ybot / CIFCurStyle->cs_scaleFactor;
|
lrec->r_r.r_ytop /= CIFCurStyle->cs_scaleFactor;
|
||||||
proprec->prop_value.prop_integer[proplen + 2] =
|
|
||||||
lrec->r_r.r_xtop / CIFCurStyle->cs_scaleFactor;
|
DBPaintPlane(plane, &lrec->r_r, CIFPaintTable,
|
||||||
proprec->prop_value.prop_integer[proplen + 3] =
|
(PaintUndoInfo *)NULL);
|
||||||
lrec->r_r.r_ytop / CIFCurStyle->cs_scaleFactor;
|
|
||||||
|
|
||||||
free_magic1_t mm1 = freeMagic1_init();
|
free_magic1_t mm1 = freeMagic1_init();
|
||||||
freeMagic1(&mm1, lrec);
|
freeMagic1(&mm1, lrec);
|
||||||
lrec = lrec->r_next;
|
lrec = lrec->r_next;
|
||||||
freeMagic1_end(&mm1);
|
freeMagic1_end(&mm1);
|
||||||
|
|
||||||
proplen += 4;
|
|
||||||
}
|
}
|
||||||
DBPropPut(cifReadCellDef, propname, proprec);
|
|
||||||
freeMagic(propname);
|
freeMagic(propname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1796,8 +1786,8 @@ CIFReadCellCleanup(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do geometrical processing on the top-level cell. */
|
/* Do geometrical processing on the top-level cell. */
|
||||||
|
if (filetype == FILE_CIF) CIFPaintCurrent(filetype);
|
||||||
|
|
||||||
CIFPaintCurrent(FILE_CIF);
|
|
||||||
DBAdjustLabels(EditCellUse->cu_def, &TiPlaneRect);
|
DBAdjustLabels(EditCellUse->cu_def, &TiPlaneRect);
|
||||||
DBReComputeBbox(EditCellUse->cu_def);
|
DBReComputeBbox(EditCellUse->cu_def);
|
||||||
DBWAreaChanged(EditCellUse->cu_def, &EditCellUse->cu_def->cd_bbox,
|
DBWAreaChanged(EditCellUse->cu_def, &EditCellUse->cu_def->cd_bbox,
|
||||||
|
|
|
||||||
|
|
@ -462,9 +462,22 @@ CIFPaintWirePath(
|
||||||
/* Wire reverses direction. Break wire here, */
|
/* Wire reverses direction. Break wire here, */
|
||||||
/* draw, and start new polygon. */
|
/* draw, and start new polygon. */
|
||||||
|
|
||||||
TxError("Warning: direction reversal in path at (%d, %d).\n",
|
/* Check first if last point and current point */
|
||||||
pathp->cifp_x, pathp->cifp_y);
|
/* are the same, in which case a different */
|
||||||
|
/* message should be issued (and possibly */
|
||||||
|
/* should be handled differently?) */
|
||||||
|
|
||||||
|
if (previousp && previousp->cifp_x == pathp->cifp_x
|
||||||
|
&& previousp->cifp_y == pathp->cifp_y)
|
||||||
|
{
|
||||||
|
TxError("Warning: duplicate point in path at (%d, %d).\n",
|
||||||
|
pathp->cifp_x / 2, pathp->cifp_y / 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TxError("Warning: direction reversal in path at (%d, %d).\n",
|
||||||
|
pathp->cifp_x / 2, pathp->cifp_y / 2);
|
||||||
|
}
|
||||||
phi = theta;
|
phi = theta;
|
||||||
if (endcap)
|
if (endcap)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -332,7 +332,8 @@ cifNewReadStyle(void)
|
||||||
free_magic1_t mm1 = freeMagic1_init();
|
free_magic1_t mm1 = freeMagic1_init();
|
||||||
for (op = layer->crl_ops; op != NULL; op = op->co_next)
|
for (op = layer->crl_ops; op != NULL; op = op->co_next)
|
||||||
{
|
{
|
||||||
if (op->co_opcode == CIFOP_MASKHINTS)
|
if (op->co_opcode == CIFOP_MASKHINTS ||
|
||||||
|
op->co_opcode == CIFOP_TAGGED)
|
||||||
freeMagic((char *)op->co_client);
|
freeMagic((char *)op->co_client);
|
||||||
freeMagic1(&mm1, (char *)op);
|
freeMagic1(&mm1, (char *)op);
|
||||||
}
|
}
|
||||||
|
|
@ -998,6 +999,8 @@ CIFReadTechLine(
|
||||||
newOp->co_opcode = CIFOP_NOTSQUARE;
|
newOp->co_opcode = CIFOP_NOTSQUARE;
|
||||||
else if (strcmp(argv[0], "mask-hints") == 0)
|
else if (strcmp(argv[0], "mask-hints") == 0)
|
||||||
newOp->co_opcode = CIFOP_MASKHINTS;
|
newOp->co_opcode = CIFOP_MASKHINTS;
|
||||||
|
else if (strcmp(argv[0], "tagged") == 0)
|
||||||
|
newOp->co_opcode = CIFOP_TAGGED;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TechError("Unknown statement \"%s\".\n", argv[0]);
|
TechError("Unknown statement \"%s\".\n", argv[0]);
|
||||||
|
|
@ -1028,6 +1031,12 @@ CIFReadTechLine(
|
||||||
if (argc != 2) goto wrongNumArgs;
|
if (argc != 2) goto wrongNumArgs;
|
||||||
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
|
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
|
||||||
break;
|
break;
|
||||||
|
case CIFOP_TAGGED:
|
||||||
|
if ((argc != 2) && (argc != 3)) goto wrongNumArgs;
|
||||||
|
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
|
||||||
|
if (argc == 3)
|
||||||
|
CIFParseReadLayers(argv[2], &newOp->co_cifMask, TRUE);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Link the new CIFOp onto the list. */
|
/* Link the new CIFOp onto the list. */
|
||||||
|
|
|
||||||
12
cif/CIFsee.c
12
cif/CIFsee.c
|
|
@ -166,9 +166,9 @@ CIFPaintLayer(
|
||||||
scx.scx_use = CIFDummyUse;
|
scx.scx_use = CIFDummyUse;
|
||||||
scx.scx_trans = GeoIdentityTransform;
|
scx.scx_trans = GeoIdentityTransform;
|
||||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||||
CIFCopyMaskHints(&scx, CIFComponentDef);
|
CIFCopyMaskHints(&scx, CIFComponentDef);
|
||||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||||
(ClientData)CIFComponentDef);
|
(ClientData)CIFComponentDef);
|
||||||
|
|
||||||
oldCount = DBWFeedbackCount;
|
oldCount = DBWFeedbackCount;
|
||||||
|
|
@ -287,9 +287,9 @@ CIFSeeLayer(
|
||||||
scx.scx_use = CIFDummyUse;
|
scx.scx_use = CIFDummyUse;
|
||||||
scx.scx_trans = GeoIdentityTransform;
|
scx.scx_trans = GeoIdentityTransform;
|
||||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||||
CIFCopyMaskHints(&scx, CIFComponentDef);
|
CIFCopyMaskHints(&scx, CIFComponentDef);
|
||||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||||
(ClientData)CIFComponentDef);
|
(ClientData)CIFComponentDef);
|
||||||
|
|
||||||
oldCount = DBWFeedbackCount;
|
oldCount = DBWFeedbackCount;
|
||||||
|
|
@ -459,9 +459,9 @@ CIFCoverageLayer(
|
||||||
scx.scx_use = CIFDummyUse;
|
scx.scx_use = CIFDummyUse;
|
||||||
scx.scx_trans = GeoIdentityTransform;
|
scx.scx_trans = GeoIdentityTransform;
|
||||||
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
(void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0,
|
||||||
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
cifHierCopyFunc, (ClientData) CIFComponentDef);
|
||||||
CIFCopyMaskHints(&scx, CIFComponentDef);
|
CIFCopyMaskHints(&scx, CIFComponentDef);
|
||||||
DBTreeSrCells(&scx, 0, cifHierCopyMaskHints,
|
DBTreeSrCells(&scx, 0, CIFCopyMaskHints,
|
||||||
(ClientData)CIFComponentDef);
|
(ClientData)CIFComponentDef);
|
||||||
|
|
||||||
CIFGen(CIFComponentDef, rootDef, area, CIFPlanes, &depend, TRUE, TRUE,
|
CIFGen(CIFComponentDef, rootDef, area, CIFPlanes, &depend, TRUE, TRUE,
|
||||||
|
|
|
||||||
|
|
@ -1107,6 +1107,8 @@ CIFTechLine(
|
||||||
newOp->co_opcode = CIFOP_BBOX;
|
newOp->co_opcode = CIFOP_BBOX;
|
||||||
else if (strcmp(argv[0], "net") == 0)
|
else if (strcmp(argv[0], "net") == 0)
|
||||||
newOp->co_opcode = CIFOP_NET;
|
newOp->co_opcode = CIFOP_NET;
|
||||||
|
else if (strcmp(argv[0], "tagged") == 0)
|
||||||
|
newOp->co_opcode = CIFOP_TAGGED;
|
||||||
else if (strcmp(argv[0], "maxrect") == 0)
|
else if (strcmp(argv[0], "maxrect") == 0)
|
||||||
newOp->co_opcode = CIFOP_MAXRECT;
|
newOp->co_opcode = CIFOP_MAXRECT;
|
||||||
else if (strcmp(argv[0], "boundary") == 0)
|
else if (strcmp(argv[0], "boundary") == 0)
|
||||||
|
|
@ -1357,10 +1359,12 @@ bloatCheck:
|
||||||
bloatDone: break;
|
bloatDone: break;
|
||||||
|
|
||||||
case CIFOP_NET:
|
case CIFOP_NET:
|
||||||
if (argc != 3) goto wrongNumArgs;
|
case CIFOP_TAGGED:
|
||||||
|
if ((argc != 2) && (argc != 3)) goto wrongNumArgs;
|
||||||
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
|
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
|
||||||
cifParseLayers(argv[2], CIFCurStyle, &newOp->co_paintMask,
|
if (argc == 3)
|
||||||
&newOp->co_cifMask, FALSE);
|
cifParseLayers(argv[2], CIFCurStyle, &newOp->co_paintMask,
|
||||||
|
&newOp->co_cifMask, FALSE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CIFOP_MASKHINTS:
|
case CIFOP_MASKHINTS:
|
||||||
|
|
@ -1671,12 +1675,12 @@ cifComputeRadii(
|
||||||
|
|
||||||
for (op = layer->cl_ops; op != NULL; op = op->co_next)
|
for (op = layer->cl_ops; op != NULL; op = op->co_next)
|
||||||
{
|
{
|
||||||
/* BBOX, NET, and MASKHINTS operators should never be used */
|
/* BBOX, NET, TAGGED, and MASKHINTS operators should never be */
|
||||||
/* hierarchically so ignore any grow/shrink operators that */
|
/* used hierarchically so ignore any grow/shrink operators that */
|
||||||
/* come after them. */
|
/* come after them. */
|
||||||
|
|
||||||
if (op->co_opcode == CIFOP_BBOX || op->co_opcode == CIFOP_NET ||
|
if (op->co_opcode == CIFOP_BBOX || op->co_opcode == CIFOP_NET ||
|
||||||
op->co_opcode == CIFOP_MASKHINTS)
|
op->co_opcode == CIFOP_TAGGED || op->co_opcode == CIFOP_MASKHINTS)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* If CIF layers are used, switch to the max of current
|
/* If CIF layers are used, switch to the max of current
|
||||||
|
|
@ -1988,8 +1992,8 @@ CIFTechFinal(void)
|
||||||
/* Presence of op->co_opcode in CIFOP_OR indicates a copy */
|
/* Presence of op->co_opcode in CIFOP_OR indicates a copy */
|
||||||
/* of the SquaresData pointer from a following operator. */
|
/* of the SquaresData pointer from a following operator. */
|
||||||
/* CIFOP_BBOX and CIFOP_MAXRECT uses the co_client field */
|
/* CIFOP_BBOX and CIFOP_MAXRECT uses the co_client field */
|
||||||
/* as a flag field, while CIFOP_NET and CIFOP_MASKHINTS */
|
/* as a flag field, while CIFOP_NET, CIFOP_MASKHINTS, and */
|
||||||
/* uses it for a string. */
|
/* CIFOP_TAGGED use it for a string. */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch (op->co_opcode)
|
switch (op->co_opcode)
|
||||||
|
|
@ -2001,6 +2005,7 @@ CIFTechFinal(void)
|
||||||
case CIFOP_MAXRECT:
|
case CIFOP_MAXRECT:
|
||||||
case CIFOP_MANHATTAN:
|
case CIFOP_MANHATTAN:
|
||||||
case CIFOP_NET:
|
case CIFOP_NET:
|
||||||
|
case CIFOP_TAGGED:
|
||||||
break;
|
break;
|
||||||
case CIFOP_BRIDGELIM:
|
case CIFOP_BRIDGELIM:
|
||||||
case CIFOP_BRIDGE:
|
case CIFOP_BRIDGE:
|
||||||
|
|
@ -2536,6 +2541,7 @@ CIFTechOutputScale(
|
||||||
case CIFOP_MAXRECT:
|
case CIFOP_MAXRECT:
|
||||||
case CIFOP_MANHATTAN:
|
case CIFOP_MANHATTAN:
|
||||||
case CIFOP_NET:
|
case CIFOP_NET:
|
||||||
|
case CIFOP_TAGGED:
|
||||||
case CIFOP_INTERACT:
|
case CIFOP_INTERACT:
|
||||||
break;
|
break;
|
||||||
case CIFOP_BRIDGELIM:
|
case CIFOP_BRIDGELIM:
|
||||||
|
|
@ -2651,8 +2657,8 @@ CIFTechOutputScale(
|
||||||
default:
|
default:
|
||||||
/* op->co_opcode in CIFOP_OR is a pointer copy, */
|
/* op->co_opcode in CIFOP_OR is a pointer copy, */
|
||||||
/* in CIFOP_BBOX and CIFOP_MAXRECT is a flag, */
|
/* in CIFOP_BBOX and CIFOP_MAXRECT is a flag, */
|
||||||
/* and in CIFOP_NET and CIFOP_MASKHINTS is a */
|
/* and in CIFOP_NET, CIFOP_MASKHINTS, and */
|
||||||
/* string. */
|
/* CIFOP_TAGGED is a string. */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
extern int cifWriteInitFunc(CellDef *def, ClientData cdata); /* UNUSED */
|
||||||
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,9 +204,11 @@ 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,10 +217,11 @@ CMWdelete(
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*ARGSUSED*/
|
||||||
void
|
void
|
||||||
CMWreposition(
|
CMWreposition(
|
||||||
MagWindow *window,
|
MagWindow *window,
|
||||||
Rect *newScreenArea,
|
Rect *newScreenArea, /* UNUSED */
|
||||||
bool final)
|
bool final)
|
||||||
{
|
{
|
||||||
if (final)
|
if (final)
|
||||||
|
|
|
||||||
164
commands/CmdE.c
164
commands/CmdE.c
|
|
@ -781,39 +781,82 @@ cmdEraseCellsFunc(
|
||||||
* Implement the "expand" command.
|
* Implement the "expand" command.
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* expand
|
* expand [selection|surround|overlap|all] [toggle]
|
||||||
* expand toggle
|
*
|
||||||
|
* "selection" expands cells in the selection. All other options
|
||||||
|
* expand cells in the layout. "all" expands all cells in the
|
||||||
|
* layout. "surround" expands cells which the cursor box
|
||||||
|
* surrounds completely, and "overlap" expands cells which the
|
||||||
|
* cursor box overlaps.
|
||||||
|
*
|
||||||
|
* If "toggle" is specified, flips the expanded/unexpanded status.
|
||||||
|
* Cells which were expanded are unexpanded, and cells which were
|
||||||
|
* unexpanded are expanded.
|
||||||
|
*
|
||||||
|
* For backwards compatibility:
|
||||||
|
* "expand" alone implements "expand overlap".
|
||||||
|
* "expand toggle" implements "expand selection toggle".
|
||||||
|
*
|
||||||
|
* Also see: CmdUnexpand
|
||||||
*
|
*
|
||||||
* Results:
|
* Results:
|
||||||
* None.
|
* None.
|
||||||
*
|
*
|
||||||
* Side effects:
|
* Side effects:
|
||||||
* If "toggle" is specified, flips the expanded/unexpanded status
|
* Expansion state of cells is changed. May read cells in from
|
||||||
* of all selected cells. Otherwise, aren't any unexpanded cells
|
* disk, and update bounding boxes that have changed.
|
||||||
* left under the box. May read cells in from disk, and updates
|
|
||||||
* bounding boxes that have changed.
|
|
||||||
*
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define EXPAND_SELECTION 0
|
||||||
|
#define EXPAND_SURROUND 1
|
||||||
|
#define EXPAND_OVERLAP 2
|
||||||
|
#define EXPAND_ALL 3
|
||||||
|
#define EXPAND_HELP 4
|
||||||
|
|
||||||
void
|
void
|
||||||
CmdExpand(
|
CmdExpand(
|
||||||
MagWindow *w,
|
MagWindow *w,
|
||||||
TxCommand *cmd)
|
TxCommand *cmd)
|
||||||
{
|
{
|
||||||
int windowMask, boxMask, d;
|
int windowMask, boxMask, d, option;
|
||||||
|
bool doToggle = FALSE;
|
||||||
|
const char * const *msg;
|
||||||
Rect rootRect;
|
Rect rootRect;
|
||||||
CellUse *rootBoxUse;
|
CellUse *rootBoxUse;
|
||||||
CellDef *rootBoxDef;
|
CellDef *rootBoxDef;
|
||||||
|
|
||||||
int cmdExpandFunc(CellUse *use, int windowMask); /* Forward reference. */
|
int cmdExpandFunc(CellUse *use, int windowMask); /* Forward reference. */
|
||||||
|
|
||||||
if (cmd->tx_argc > 2 || (cmd->tx_argc == 2
|
static const char * const cmdExpandOption[] = {
|
||||||
&& (strncmp(cmd->tx_argv[1], "toggle", strlen(cmd->tx_argv[1])) != 0)))
|
"selection expand cell instances in the selection",
|
||||||
|
"surround expand cell instances which the cursor box surrounds",
|
||||||
|
"overlap expand cell instances which the cursor box overlaps",
|
||||||
|
"all expand all cell instances",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
if (cmd->tx_argc > 1)
|
||||||
{
|
{
|
||||||
TxError("Usage: %s or %s toggle\n", cmd->tx_argv[0], cmd->tx_argv[0]);
|
if (!strncmp(cmd->tx_argv[cmd->tx_argc - 1], "toggle",
|
||||||
return;
|
strlen(cmd->tx_argv[cmd->tx_argc - 1])))
|
||||||
|
{
|
||||||
|
doToggle = TRUE;
|
||||||
|
cmd->tx_argc--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cmd->tx_argc > 1)
|
||||||
|
{
|
||||||
|
option = Lookup(cmd->tx_argv[1], cmdExpandOption);
|
||||||
|
if (option < 0) option = EXPAND_HELP;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
option = EXPAND_OVERLAP;
|
||||||
|
|
||||||
|
if (option == EXPAND_HELP) goto badusage;
|
||||||
|
|
||||||
windCheckOnlyWindow(&w, DBWclientID);
|
windCheckOnlyWindow(&w, DBWclientID);
|
||||||
if (w == (MagWindow *) NULL)
|
if (w == (MagWindow *) NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -844,23 +887,95 @@ CmdExpand(
|
||||||
WindScale(d, 1);
|
WindScale(d, 1);
|
||||||
TxPrintf("expand: rescaled by %d\n", d);
|
TxPrintf("expand: rescaled by %d\n", d);
|
||||||
d = DBLambda[1];
|
d = DBLambda[1];
|
||||||
if (cmd->tx_argc == 2) break; /* Don't toggle twice */
|
if (doToggle) break; /* Don't toggle twice */
|
||||||
}
|
}
|
||||||
(void) ToolGetBoxWindow(&rootRect, &boxMask);
|
(void) ToolGetBoxWindow(&rootRect, &boxMask);
|
||||||
|
|
||||||
if (cmd->tx_argc == 2)
|
if (option != EXPAND_SELECTION)
|
||||||
SelectExpand(windowMask);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if ((boxMask & windowMask) != windowMask)
|
if ((boxMask & windowMask) != windowMask)
|
||||||
{
|
{
|
||||||
TxError("The box isn't in the same window as the cursor.\n");
|
TxError("The box isn't in the same window as the cursor.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DBExpandAll(rootBoxUse, &rootRect, windowMask,
|
}
|
||||||
TRUE, cmdExpandFunc, (ClientData)(pointertype) windowMask);
|
|
||||||
|
switch (option)
|
||||||
|
{
|
||||||
|
case EXPAND_SELECTION:
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
(doToggle) ? DB_EXPAND_TOGGLE : DB_EXPAND,
|
||||||
|
(Rect *)NULL);
|
||||||
|
break;
|
||||||
|
case EXPAND_OVERLAP:
|
||||||
|
if (doToggle)
|
||||||
|
{
|
||||||
|
DBExpandAll(rootBoxUse, &rootRect, windowMask,
|
||||||
|
DB_EXPAND_TOGGLE | DB_EXPAND_OVERLAP,
|
||||||
|
cmdExpandFunc, (ClientData)(pointertype)windowMask);
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
DB_EXPAND_TOGGLE | DB_EXPAND_OVERLAP,
|
||||||
|
&rootRect);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBExpandAll(rootBoxUse, &rootRect, windowMask,
|
||||||
|
DB_EXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
cmdExpandFunc, (ClientData)(pointertype)windowMask);
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
DB_EXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
&rootRect);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EXPAND_SURROUND:
|
||||||
|
if (doToggle)
|
||||||
|
{
|
||||||
|
DBExpandAll(rootBoxUse, &rootRect, windowMask,
|
||||||
|
DB_EXPAND_TOGGLE | DB_EXPAND_SURROUND,
|
||||||
|
cmdExpandFunc, (ClientData)(pointertype)windowMask);
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
DB_EXPAND_TOGGLE | DB_EXPAND_SURROUND,
|
||||||
|
&rootRect);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBExpandAll(rootBoxUse, &rootRect, windowMask,
|
||||||
|
DB_EXPAND | DB_EXPAND_SURROUND,
|
||||||
|
cmdExpandFunc, (ClientData)(pointertype)windowMask);
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
DB_EXPAND | DB_EXPAND_SURROUND,
|
||||||
|
&rootRect);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EXPAND_ALL:
|
||||||
|
if (doToggle)
|
||||||
|
{
|
||||||
|
DBExpandAll(rootBoxUse, &TiPlaneRect, windowMask,
|
||||||
|
DB_EXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
cmdExpandFunc, (ClientData)(pointertype)windowMask);
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
DB_EXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
(Rect *)NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBExpandAll(rootBoxUse, &TiPlaneRect, windowMask,
|
||||||
|
DB_EXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
cmdExpandFunc, (ClientData)(pointertype)windowMask);
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
DB_EXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
(Rect *)NULL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} while (d != DBLambda[1]);
|
} while (d != DBLambda[1]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
badusage:
|
||||||
|
for (msg = &(cmdExpandOption[0]); *msg != NULL; msg++)
|
||||||
|
TxPrintf(" %s\n", *msg);
|
||||||
|
TxPrintf(" toggle Toggle the visibility of cell instances.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is called for each cell whose expansion status changed.
|
/* This function is called for each cell whose expansion status changed.
|
||||||
|
|
@ -981,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 ensure unique node names during extraction",
|
"unique [notopports] ensure unique node names during extraction",
|
||||||
"resistance extract resistance (same as \"do extresist\")",
|
"resistance extract resistance (same as \"do extresist\")",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
@ -1288,6 +1403,7 @@ 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
|
||||||
|
|
@ -1318,9 +1434,19 @@ 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
|
||||||
|
|
|
||||||
202
commands/CmdLQ.c
202
commands/CmdLQ.c
|
|
@ -45,9 +45,8 @@ static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magi
|
||||||
#include "utils/undo.h"
|
#include "utils/undo.h"
|
||||||
#include "select/select.h"
|
#include "select/select.h"
|
||||||
#include "netmenu/netmenu.h"
|
#include "netmenu/netmenu.h"
|
||||||
|
|
||||||
/* C99 compat */
|
|
||||||
#include "cif/cif.h"
|
#include "cif/cif.h"
|
||||||
|
#include "cif/CIFint.h"
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
|
|
||||||
|
|
@ -518,14 +517,14 @@ CmdLoad(
|
||||||
|
|
||||||
DBExpandAll(topuse, &(topuse->cu_bbox),
|
DBExpandAll(topuse, &(topuse->cu_bbox),
|
||||||
((DBWclientRec *)w->w_clientData)->dbw_bitmask,
|
((DBWclientRec *)w->w_clientData)->dbw_bitmask,
|
||||||
TRUE, keepGoing, NULL);
|
DB_EXPAND, keepGoing, NULL);
|
||||||
|
|
||||||
DBExpandAll(topuse, &(topuse->cu_bbox),
|
DBExpandAll(topuse, &(topuse->cu_bbox),
|
||||||
((DBWclientRec *)w->w_clientData)->dbw_bitmask,
|
((DBWclientRec *)w->w_clientData)->dbw_bitmask,
|
||||||
FALSE, keepGoing, NULL);
|
DB_UNEXPAND, keepGoing, NULL);
|
||||||
DBExpand(topuse,
|
DBExpand(topuse,
|
||||||
((DBWclientRec *)w->w_clientData)->dbw_bitmask,
|
((DBWclientRec *)w->w_clientData)->dbw_bitmask,
|
||||||
TRUE);
|
DB_EXPAND);
|
||||||
|
|
||||||
/* We don't want to save and restore DBLambda, because */
|
/* We don't want to save and restore DBLambda, because */
|
||||||
/* loading the file may change their values. Instead, we */
|
/* loading the file may change their values. Instead, we */
|
||||||
|
|
@ -2325,9 +2324,9 @@ CmdDoProperty(
|
||||||
TxCommand *cmd,
|
TxCommand *cmd,
|
||||||
int argstart)
|
int argstart)
|
||||||
{
|
{
|
||||||
PropertyRecord *proprec;
|
PropertyRecord *proprec = NULL;
|
||||||
char *value;
|
char *value;
|
||||||
bool propfound;
|
bool propfound, dolist;
|
||||||
int proptype, proplen, propvalue, i;
|
int proptype, proplen, propvalue, i;
|
||||||
dlong dvalue;
|
dlong dvalue;
|
||||||
int locargc = cmd->tx_argc - argstart + 1;
|
int locargc = cmd->tx_argc - argstart + 1;
|
||||||
|
|
@ -2335,15 +2334,31 @@ CmdDoProperty(
|
||||||
Tcl_Obj *tobj;
|
Tcl_Obj *tobj;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int printPropertiesFunc(); /* Forward declaration */
|
/* Forward declarations */
|
||||||
|
int printPropertiesFunc();
|
||||||
|
int printPlanePropFunc();
|
||||||
|
|
||||||
/* These should match the property codes in database.h.in, except
|
/* These should match the property codes in database.h.in, except
|
||||||
* for "compat" which must come at the end.
|
* for "compat" which must come at the end.
|
||||||
*/
|
*/
|
||||||
static const char * const cmdPropertyType[] = {
|
static const char * const cmdPropertyType[] = {
|
||||||
"string", "integer", "dimension", "double", "compat", NULL
|
"string", "integer", "dimension", "double", "plane", "compat", NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* If the first keyword is "list", then set dolist and increment
|
||||||
|
* the starting argument position.
|
||||||
|
*/
|
||||||
|
dolist = FALSE;
|
||||||
|
if (locargc > 1)
|
||||||
|
{
|
||||||
|
if (!strcmp(cmd->tx_argv[argstart], "list"))
|
||||||
|
{
|
||||||
|
dolist = TRUE;
|
||||||
|
locargc--;
|
||||||
|
argstart++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If a property type is given, parse it and then strip it from
|
/* If a property type is given, parse it and then strip it from
|
||||||
* the arguments list.
|
* the arguments list.
|
||||||
*/
|
*/
|
||||||
|
|
@ -2393,7 +2408,7 @@ CmdDoProperty(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* print the value of the indicated property */
|
/* Print the value of the indicated property */
|
||||||
proprec = (PropertyRecord *)DBPropGet(def, cmd->tx_argv[argstart], &propfound);
|
proprec = (PropertyRecord *)DBPropGet(def, cmd->tx_argv[argstart], &propfound);
|
||||||
if (propfound)
|
if (propfound)
|
||||||
{
|
{
|
||||||
|
|
@ -2434,6 +2449,14 @@ CmdDoProperty(
|
||||||
Tcl_SetObjResult(magicinterp, tobj);
|
Tcl_SetObjResult(magicinterp, tobj);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case PROPERTY_TYPE_PLANE:
|
||||||
|
tobj = Tcl_NewListObj(0, NULL);
|
||||||
|
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||||
|
proprec->prop_value.prop_plane,
|
||||||
|
&TiPlaneRect, &CIFSolidBits, printPlanePropFunc,
|
||||||
|
(ClientData)tobj);
|
||||||
|
Tcl_SetObjResult(magicinterp, tobj);
|
||||||
|
break;
|
||||||
case PROPERTY_TYPE_DOUBLE:
|
case PROPERTY_TYPE_DOUBLE:
|
||||||
if (proprec->prop_len == 1)
|
if (proprec->prop_len == 1)
|
||||||
Tcl_SetObjResult(magicinterp,
|
Tcl_SetObjResult(magicinterp,
|
||||||
|
|
@ -2465,10 +2488,17 @@ CmdDoProperty(
|
||||||
for (i = 0; i < proprec->prop_len; i++)
|
for (i = 0; i < proprec->prop_len; i++)
|
||||||
TxPrintf("%s ", DBWPrintValue(
|
TxPrintf("%s ", DBWPrintValue(
|
||||||
proprec->prop_value.prop_integer[i], w,
|
proprec->prop_value.prop_integer[i], w,
|
||||||
((i % 2) == 0) ? TRUE : FALSE);
|
((i % 2) == 0) ? TRUE : FALSE));
|
||||||
|
|
||||||
TxPrintf("\n");
|
TxPrintf("\n");
|
||||||
break;
|
break;
|
||||||
|
case PROPERTY_TYPE_PLANE:
|
||||||
|
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||||
|
proprec->prop_value.prop_plane,
|
||||||
|
&TiPlaneRect, &CIFSolidBits, printPlanePropFunc,
|
||||||
|
(ClientData)NULL);
|
||||||
|
TxPrintf("\n");
|
||||||
|
break;
|
||||||
case PROPERTY_TYPE_DOUBLE:
|
case PROPERTY_TYPE_DOUBLE:
|
||||||
for (i = 0; i < proprec->prop_len; i++)
|
for (i = 0; i < proprec->prop_len; i++)
|
||||||
TxPrintf( "%"DLONG_PREFIX"d",
|
TxPrintf( "%"DLONG_PREFIX"d",
|
||||||
|
|
@ -2482,9 +2512,9 @@ CmdDoProperty(
|
||||||
#ifdef MAGIC_WRAPPER
|
#ifdef MAGIC_WRAPPER
|
||||||
/* If the command was "cellname list property ...", then */
|
/* If the command was "cellname list property ...", then */
|
||||||
/* just return NULL if the property was not found. */
|
/* just return NULL if the property was not found. */
|
||||||
if (strcmp(cmd->tx_argv[1], "list"))
|
if (!dolist)
|
||||||
#endif
|
#endif
|
||||||
TxError("Property name \"%s\" is not defined\n", cmd->tx_argv[1]);
|
TxError("Property name \"%s\" is not defined\n", cmd->tx_argv[argstart]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (locargc >= 3)
|
else if (locargc >= 3)
|
||||||
|
|
@ -2514,7 +2544,7 @@ CmdDoProperty(
|
||||||
* keyword functions work correctly.
|
* keyword functions work correctly.
|
||||||
*
|
*
|
||||||
* GDS_START, GDS_END: PROPERTY_TYPE_DOUBLE
|
* GDS_START, GDS_END: PROPERTY_TYPE_DOUBLE
|
||||||
* MASKHINTS_*: PROPERTY_TYPE_DIMENSION
|
* MASKHINTS_*: PROPERTY_TYPE_PLANE
|
||||||
* FIXED_BBOX: PROPERTY_TYPE_DIMENSION
|
* FIXED_BBOX: PROPERTY_TYPE_DIMENSION
|
||||||
*/
|
*/
|
||||||
if (!strcmp(cmd->tx_argv[argstart], "GDS_START"))
|
if (!strcmp(cmd->tx_argv[argstart], "GDS_START"))
|
||||||
|
|
@ -2528,7 +2558,7 @@ CmdDoProperty(
|
||||||
else if (!strcmp(cmd->tx_argv[argstart], "OBS_BBOX"))
|
else if (!strcmp(cmd->tx_argv[argstart], "OBS_BBOX"))
|
||||||
proptype = PROPERTY_TYPE_DIMENSION;
|
proptype = PROPERTY_TYPE_DIMENSION;
|
||||||
else if (!strncmp(cmd->tx_argv[argstart], "MASKHINTS_", 10))
|
else if (!strncmp(cmd->tx_argv[argstart], "MASKHINTS_", 10))
|
||||||
proptype = PROPERTY_TYPE_DIMENSION;
|
proptype = PROPERTY_TYPE_PLANE;
|
||||||
|
|
||||||
if (strlen(cmd->tx_argv[argstart + 1]) == 0)
|
if (strlen(cmd->tx_argv[argstart + 1]) == 0)
|
||||||
DBPropPut(def, cmd->tx_argv[argstart], NULL);
|
DBPropPut(def, cmd->tx_argv[argstart], NULL);
|
||||||
|
|
@ -2543,8 +2573,11 @@ CmdDoProperty(
|
||||||
proprec->prop_len = proplen;
|
proprec->prop_len = proplen;
|
||||||
strcpy(proprec->prop_value.prop_string, cmd->tx_argv[argstart + 1]);
|
strcpy(proprec->prop_value.prop_string, cmd->tx_argv[argstart + 1]);
|
||||||
}
|
}
|
||||||
else /* PROPERTY_TYPE_INTEGER or PROPERTY_TYPE_DIMENSION */
|
else /* All non-string properties */
|
||||||
{
|
{
|
||||||
|
Plane *plane;
|
||||||
|
Rect r;
|
||||||
|
|
||||||
/* Two choices: If locargc == 3 then all values are in one
|
/* Two choices: If locargc == 3 then all values are in one
|
||||||
* argument. If locargc > 3, then parse each argument as a
|
* argument. If locargc > 3, then parse each argument as a
|
||||||
* separate value.
|
* separate value.
|
||||||
|
|
@ -2555,6 +2588,12 @@ CmdDoProperty(
|
||||||
if (proptype == PROPERTY_TYPE_DOUBLE)
|
if (proptype == PROPERTY_TYPE_DOUBLE)
|
||||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||||
(proplen - 1)*sizeof(dlong));
|
(proplen - 1)*sizeof(dlong));
|
||||||
|
else if (proptype == PROPERTY_TYPE_PLANE)
|
||||||
|
{
|
||||||
|
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||||
|
plane = DBNewPlane((ClientData)TT_SPACE);
|
||||||
|
proprec->prop_value.prop_plane = plane;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
||||||
(proplen - 2)*sizeof(int));
|
(proplen - 2)*sizeof(int));
|
||||||
|
|
@ -2587,6 +2626,28 @@ CmdDoProperty(
|
||||||
proprec->prop_value.prop_double[i - 1] = 0;
|
proprec->prop_value.prop_double[i - 1] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (proptype == PROPERTY_TYPE_PLANE)
|
||||||
|
{
|
||||||
|
propvalue = cmdParseCoord(w, cmd->tx_argv[argstart + i],
|
||||||
|
FALSE, ((i % 2) == 0) ? FALSE : TRUE);
|
||||||
|
switch ((i - 1) % 4)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
r.r_xbot = propvalue;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
r.r_ybot = propvalue;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
r.r_xtop = propvalue;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
r.r_ytop = propvalue;
|
||||||
|
DBPaintPlane(plane, &r, CIFPaintTable,
|
||||||
|
(PaintUndoInfo *)NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
else /* PROPERTY_TYPE_DIMENSION */
|
else /* PROPERTY_TYPE_DIMENSION */
|
||||||
{
|
{
|
||||||
propvalue = cmdParseCoord(w, cmd->tx_argv[argstart + i],
|
propvalue = cmdParseCoord(w, cmd->tx_argv[argstart + i],
|
||||||
|
|
@ -2613,11 +2674,20 @@ CmdDoProperty(
|
||||||
}
|
}
|
||||||
if (proplen > 0)
|
if (proplen > 0)
|
||||||
{
|
{
|
||||||
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
if (proptype == PROPERTY_TYPE_PLANE)
|
||||||
(proplen - 2)*sizeof(int));
|
{
|
||||||
|
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||||
|
plane = DBNewPlane((ClientData)TT_SPACE);
|
||||||
|
proprec->prop_value.prop_plane = plane;
|
||||||
|
} else {
|
||||||
|
proprec = (PropertyRecord *)mallocMagic(
|
||||||
|
sizeof(PropertyRecord) +
|
||||||
|
(proplen - 2) * sizeof(int));
|
||||||
|
}
|
||||||
proprec->prop_type = proptype;
|
proprec->prop_type = proptype;
|
||||||
proprec->prop_len = proplen;
|
proprec->prop_len = proplen;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Second pass */
|
/* Second pass */
|
||||||
value = cmd->tx_argv[argstart + 1];
|
value = cmd->tx_argv[argstart + 1];
|
||||||
for (proplen = 0; proplen < proprec->prop_len; proplen++)
|
for (proplen = 0; proplen < proprec->prop_len; proplen++)
|
||||||
|
|
@ -2657,6 +2727,28 @@ CmdDoProperty(
|
||||||
}
|
}
|
||||||
proprec->prop_value.prop_double[proplen] = dvalue;
|
proprec->prop_value.prop_double[proplen] = dvalue;
|
||||||
}
|
}
|
||||||
|
else if (proptype == PROPERTY_TYPE_PLANE)
|
||||||
|
{
|
||||||
|
propvalue = cmdParseCoord(w, value, FALSE,
|
||||||
|
((proplen % 2) == 0) ? TRUE : FALSE);
|
||||||
|
switch (proplen % 4)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
r.r_xbot = propvalue;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
r.r_ybot = propvalue;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
r.r_xtop = propvalue;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
r.r_ytop = propvalue;
|
||||||
|
DBPaintPlane(plane, &r, CIFPaintTable,
|
||||||
|
(PaintUndoInfo *)NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
else /* PROPERTY_TYPE_DIMENSION */
|
else /* PROPERTY_TYPE_DIMENSION */
|
||||||
{
|
{
|
||||||
propvalue = cmdParseCoord(w, value, FALSE,
|
propvalue = cmdParseCoord(w, value, FALSE,
|
||||||
|
|
@ -2727,6 +2819,59 @@ CmdProperty(
|
||||||
CmdDoProperty(def, w, cmd, 1);
|
CmdDoProperty(def, w, cmd, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* Callback function for printing values from a Plane property
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef MAGIC_WRAPPER
|
||||||
|
int
|
||||||
|
printPlanePropFunc(
|
||||||
|
Tile *tile,
|
||||||
|
TileType dinfo,
|
||||||
|
Tcl_Obj *lobj)
|
||||||
|
{
|
||||||
|
Rect r;
|
||||||
|
MagWindow *w;
|
||||||
|
|
||||||
|
TiToRect(tile, &r);
|
||||||
|
windCheckOnlyWindow(&w, DBWclientID);
|
||||||
|
|
||||||
|
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||||
|
Tcl_NewStringObj(DBWPrintValue(r.r_xbot, w, TRUE), -1));
|
||||||
|
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||||
|
Tcl_NewStringObj(DBWPrintValue(r.r_ybot, w, FALSE), -1));
|
||||||
|
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||||
|
Tcl_NewStringObj(DBWPrintValue(r.r_xtop, w, TRUE), -1));
|
||||||
|
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||||
|
Tcl_NewStringObj(DBWPrintValue(r.r_ytop, w, FALSE), -1));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
int
|
||||||
|
printPlanePropFunc(
|
||||||
|
Tile *tile,
|
||||||
|
TileType dinfo,
|
||||||
|
ClientData cdata) /* (unused) */
|
||||||
|
{
|
||||||
|
Rect r;
|
||||||
|
MagWindow *w;
|
||||||
|
|
||||||
|
TiToRect(tile, &r);
|
||||||
|
windCheckOnlyWindow(&w, DBWclientID);
|
||||||
|
|
||||||
|
TxPrintf("%s ", DBWPrintValue(r.r_xbot, w, TRUE));
|
||||||
|
TxPrintf("%s ", DBWPrintValue(r.r_ybot, w, FALSE));
|
||||||
|
TxPrintf("%s ", DBWPrintValue(r.r_xtop, w, TRUE));
|
||||||
|
TxPrintf("%s ", DBWPrintValue(r.r_ytop, w, FALSE));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
* Callback function for printing a single property key:value pair
|
* Callback function for printing a single property key:value pair
|
||||||
|
|
@ -2766,6 +2911,12 @@ printPropertiesFunc(
|
||||||
DBWPrintValue(proprec->prop_value.prop_integer[i],
|
DBWPrintValue(proprec->prop_value.prop_integer[i],
|
||||||
w, ((i % 2) == 0) ? TRUE : FALSE), -1));
|
w, ((i % 2) == 0) ? TRUE : FALSE), -1));
|
||||||
break;
|
break;
|
||||||
|
case PROPERTY_TYPE_PLANE:
|
||||||
|
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||||
|
proprec->prop_value.prop_plane,
|
||||||
|
&TiPlaneRect, &CIFSolidBits, printPlanePropFunc,
|
||||||
|
(ClientData)lobj);
|
||||||
|
break;
|
||||||
case PROPERTY_TYPE_DOUBLE:
|
case PROPERTY_TYPE_DOUBLE:
|
||||||
for (i = 0; i < proprec->prop_len; i++)
|
for (i = 0; i < proprec->prop_len; i++)
|
||||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
Tcl_ListObjAppendElement(magicinterp, lobj,
|
||||||
|
|
@ -2779,25 +2930,32 @@ printPropertiesFunc(
|
||||||
switch (proprec->prop_type)
|
switch (proprec->prop_type)
|
||||||
{
|
{
|
||||||
case PROPERTY_TYPE_STRING:
|
case PROPERTY_TYPE_STRING:
|
||||||
TxPrintf("%s = %s\n", name, (const char *)proprec->prop_string);
|
TxPrintf("%s = %s\n", name, (const char *)proprec->prop_value.prop_string);
|
||||||
break;
|
break;
|
||||||
case PROPERTY_TYPE_INTEGER:
|
case PROPERTY_TYPE_INTEGER:
|
||||||
TxPrintf("%s = ", name);
|
TxPrintf("%s = ", name);
|
||||||
for (i = 0; i < proprec->prop_len; i++)
|
for (i = 0; i < proprec->prop_len; i++)
|
||||||
TxPrintf("%d ", proprec->prop_integer[i]);
|
TxPrintf("%d ", proprec->prop_value.prop_integer[i]);
|
||||||
TxPrintf("\n");
|
TxPrintf("\n");
|
||||||
break;
|
break;
|
||||||
case PROPERTY_TYPE_DIMENSION:
|
case PROPERTY_TYPE_DIMENSION:
|
||||||
TxPrintf("%s = ", name);
|
TxPrintf("%s = ", name);
|
||||||
for (i = 0; i < proprec->prop_len; i++)
|
for (i = 0; i < proprec->prop_len; i++)
|
||||||
TxPrintf("%s ", DBWPrintValue(proprec->prop_value.prop_integer[i],
|
TxPrintf("%s ", DBWPrintValue(proprec->prop_value.prop_integer[i],
|
||||||
w, ((i % 2) == 0) ? TRUE : FALSE);
|
w, ((i % 2) == 0) ? TRUE : FALSE));
|
||||||
TxPrintf("\n");
|
TxPrintf("\n");
|
||||||
break;
|
break;
|
||||||
|
case PROPERTY_TYPE_PLANE:
|
||||||
|
TxPrintf("%s = ", name);
|
||||||
|
DBSrPaintArea((Tile *)NULL, proprec->prop_value.prop_plane,
|
||||||
|
&TiPlaneRect, &CIFSolidBits, printPlanePropFunc,
|
||||||
|
(ClientData)NULL);
|
||||||
|
TxPrintf("\n");
|
||||||
|
break;
|
||||||
case PROPERTY_TYPE_DOUBLE:
|
case PROPERTY_TYPE_DOUBLE:
|
||||||
TxPrintf("%s = ", name);
|
TxPrintf("%s = ", name);
|
||||||
for (i = 0; i < proprec->prop_len; i++)
|
for (i = 0; i < proprec->prop_len; i++)
|
||||||
TxPrintf("%"DLONG_PREFIX"d ", proprec->prop_double[i]);
|
TxPrintf("%"DLONG_PREFIX"d ", proprec->prop_value.prop_double[i]);
|
||||||
TxPrintf("\n");
|
TxPrintf("\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
125
commands/CmdRS.c
125
commands/CmdRS.c
|
|
@ -635,10 +635,21 @@ cmdSelectArea(
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < DBNumUserLayers; i++)
|
for (i = 0; i < DBNumUserLayers; i++)
|
||||||
{
|
{
|
||||||
if((TTMaskHasType(&mask, i)) && !(TTMaskHasType(&crec->dbw_visibleLayers, i)))
|
if ((TTMaskHasType(&mask, i)) &&
|
||||||
|
!(TTMaskHasType(&crec->dbw_visibleLayers, i)))
|
||||||
TTMaskClearType(&mask, i);
|
TTMaskClearType(&mask, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Remove L_CELL and L_LABEL if crec->dbw_flags indicates that
|
||||||
|
* they are not visible in the layout window.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!(crec->dbw_flags & DBW_SEELABELS)) TTMaskClearType(&mask, L_LABEL);
|
||||||
|
if (!(crec->dbw_flags & DBW_SEECELLS)) TTMaskClearType(&mask, L_CELL);
|
||||||
}
|
}
|
||||||
|
else if (option == SEL_AREA)
|
||||||
|
TTMaskSetType(&mask, L_LABEL);
|
||||||
|
|
||||||
SelectArea(&scx, &mask, crec->dbw_bitmask, globmatch);
|
SelectArea(&scx, &mask, crec->dbw_bitmask, globmatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1027,7 +1038,7 @@ CmdSelect(
|
||||||
|
|
||||||
/*--------------------------------------------------------------------
|
/*--------------------------------------------------------------------
|
||||||
* Select everything under the box, perhaps looking only at
|
* Select everything under the box, perhaps looking only at
|
||||||
* particular layers, but only if its visible.
|
* particular layers, but only if it's visible.
|
||||||
*--------------------------------------------------------------------
|
*--------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -1801,13 +1812,18 @@ cmdLabelSizeFunc(
|
||||||
|
|
||||||
if (value == NULL)
|
if (value == NULL)
|
||||||
{
|
{
|
||||||
|
char *labsize;
|
||||||
|
MagWindow *w;
|
||||||
|
|
||||||
|
windCheckOnlyWindow(&w, DBWclientID);
|
||||||
|
labsize = DBWPrintValue(label->lab_size / 8, w, FALSE);
|
||||||
|
|
||||||
#ifdef MAGIC_WRAPPER
|
#ifdef MAGIC_WRAPPER
|
||||||
lobj = Tcl_GetObjResult(magicinterp);
|
lobj = Tcl_GetObjResult(magicinterp);
|
||||||
Tcl_ListObjAppendElement(magicinterp, lobj,
|
Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_NewStringObj(labsize, -1));
|
||||||
Tcl_NewDoubleObj((double)label->lab_size / 8.0));
|
|
||||||
Tcl_SetObjResult(magicinterp, lobj);
|
Tcl_SetObjResult(magicinterp, lobj);
|
||||||
#else
|
#else
|
||||||
TxPrintf("%g\n", (double)label->lab_size / 8.0);
|
TxPrintf("%s\n", labsize);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (label->lab_size != *value)
|
else if (label->lab_size != *value)
|
||||||
|
|
@ -1952,18 +1968,22 @@ cmdLabelOffsetFunc(
|
||||||
|
|
||||||
if (point == NULL)
|
if (point == NULL)
|
||||||
{
|
{
|
||||||
|
char *laboffx, *laboffy;
|
||||||
|
MagWindow *w;
|
||||||
|
|
||||||
|
windCheckOnlyWindow(&w, DBWclientID);
|
||||||
|
laboffx = DBWPrintValue(label->lab_offset.p_x / 8, w, TRUE);
|
||||||
|
laboffy = DBWPrintValue(label->lab_offset.p_x / 8, w, FALSE);
|
||||||
|
|
||||||
#ifdef MAGIC_WRAPPER
|
#ifdef MAGIC_WRAPPER
|
||||||
lobj = Tcl_GetObjResult(magicinterp);
|
lobj = Tcl_GetObjResult(magicinterp);
|
||||||
pobj = Tcl_NewListObj(0, NULL);
|
pobj = Tcl_NewListObj(0, NULL);
|
||||||
Tcl_ListObjAppendElement(magicinterp, lobj, pobj);
|
Tcl_ListObjAppendElement(magicinterp, lobj, pobj);
|
||||||
Tcl_ListObjAppendElement(magicinterp, pobj,
|
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(laboffx, -1));
|
||||||
Tcl_NewDoubleObj((double)label->lab_offset.p_x / 8.0));
|
Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewStringObj(laboffy, -1));
|
||||||
Tcl_ListObjAppendElement(magicinterp, pobj,
|
|
||||||
Tcl_NewDoubleObj((double)label->lab_offset.p_y / 8.0));
|
|
||||||
Tcl_SetObjResult(magicinterp, lobj);
|
Tcl_SetObjResult(magicinterp, lobj);
|
||||||
#else
|
#else
|
||||||
TxPrintf("%g %g\n", (double)(label->lab_offset.p_x) / 8.0,
|
TxPrintf("%s %s\n", laboffx, laboffy);
|
||||||
(double)(label->lab_offset.p_y) / 8.0);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (!GEO_SAMEPOINT(label->lab_offset, *point))
|
else if (!GEO_SAMEPOINT(label->lab_offset, *point))
|
||||||
|
|
@ -2212,9 +2232,13 @@ CmdSetLabel(
|
||||||
}
|
}
|
||||||
else if (EditCellUse)
|
else if (EditCellUse)
|
||||||
{
|
{
|
||||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
if (locargc == 2)
|
||||||
cmdLabelTextFunc, (locargc == 3) ?
|
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
(ClientData)cmd->tx_argv[argstart + 1] : (ClientData)NULL);
|
cmdLabelTextFunc, (ClientData)NULL);
|
||||||
|
else
|
||||||
|
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
|
cmdLabelTextFunc,
|
||||||
|
(ClientData)cmd->tx_argv[argstart + 1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -2280,9 +2304,12 @@ CmdSetLabel(
|
||||||
}
|
}
|
||||||
else if (EditCellUse)
|
else if (EditCellUse)
|
||||||
{
|
{
|
||||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
if (locargc == 2)
|
||||||
cmdLabelFontFunc, (locargc == 3) ?
|
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
(ClientData)&font : (ClientData)NULL);
|
cmdLabelFontFunc, (ClientData)NULL);
|
||||||
|
else
|
||||||
|
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
|
cmdLabelFontFunc, (ClientData)&font);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -2310,9 +2337,12 @@ CmdSetLabel(
|
||||||
}
|
}
|
||||||
else if (EditCellUse)
|
else if (EditCellUse)
|
||||||
{
|
{
|
||||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
if (locargc == 2)
|
||||||
cmdLabelJustFunc, (locargc == 3) ?
|
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
(ClientData)&pos : (ClientData)NULL);
|
cmdLabelJustFunc, (ClientData)NULL);
|
||||||
|
else
|
||||||
|
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
|
cmdLabelJustFunc, (ClientData)&pos);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -2341,9 +2371,12 @@ CmdSetLabel(
|
||||||
}
|
}
|
||||||
else if (EditCellUse)
|
else if (EditCellUse)
|
||||||
{
|
{
|
||||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
if (locargc == 2)
|
||||||
cmdLabelSizeFunc, (locargc == 3) ?
|
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
(ClientData)&size : (ClientData)NULL);
|
cmdLabelSizeFunc, (ClientData)NULL);
|
||||||
|
else
|
||||||
|
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
|
cmdLabelSizeFunc, (ClientData)&size);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -2393,9 +2426,12 @@ CmdSetLabel(
|
||||||
}
|
}
|
||||||
else if (EditCellUse)
|
else if (EditCellUse)
|
||||||
{
|
{
|
||||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
if (locargc == 2)
|
||||||
cmdLabelOffsetFunc, (locargc != 2) ?
|
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
(ClientData)&offset : (ClientData)NULL);
|
cmdLabelOffsetFunc, (ClientData)NULL);
|
||||||
|
else
|
||||||
|
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
|
cmdLabelOffsetFunc, (ClientData)&offset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -2459,10 +2495,12 @@ CmdSetLabel(
|
||||||
rect.r_ytop = cmdScaleCoord(w, cmd->tx_argv[argstart + 4],
|
rect.r_ytop = cmdScaleCoord(w, cmd->tx_argv[argstart + 4],
|
||||||
TRUE, FALSE, 1);
|
TRUE, FALSE, 1);
|
||||||
}
|
}
|
||||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
if ((locargc == 3) || (locargc == 6))
|
||||||
cmdLabelRectFunc,
|
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
((locargc == 6) || (locargc == 3)) ?
|
cmdLabelRectFunc, (ClientData)&rect);
|
||||||
(ClientData)&rect : (ClientData)NULL);
|
else
|
||||||
|
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
|
cmdLabelRectFunc, (ClientData)NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -2488,9 +2526,12 @@ CmdSetLabel(
|
||||||
}
|
}
|
||||||
else if (EditCellUse)
|
else if (EditCellUse)
|
||||||
{
|
{
|
||||||
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
if (locargc == 2)
|
||||||
cmdLabelRotateFunc, (locargc == 3) ?
|
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
(ClientData)&rotate : (ClientData)NULL);
|
cmdLabelRotateFunc, (ClientData)NULL);
|
||||||
|
else
|
||||||
|
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
|
cmdLabelRotateFunc, (ClientData)&rotate);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -2522,9 +2563,12 @@ CmdSetLabel(
|
||||||
}
|
}
|
||||||
else if (EditCellUse)
|
else if (EditCellUse)
|
||||||
{
|
{
|
||||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
if (locargc == 2)
|
||||||
cmdLabelStickyFunc, (locargc == 3) ?
|
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
(ClientData)&flags : (ClientData)NULL);
|
cmdLabelStickyFunc, (ClientData)NULL);
|
||||||
|
else
|
||||||
|
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
|
cmdLabelStickyFunc, (ClientData)&flags);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -2563,9 +2607,12 @@ CmdSetLabel(
|
||||||
}
|
}
|
||||||
else if (EditCellUse)
|
else if (EditCellUse)
|
||||||
{
|
{
|
||||||
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
if (locargc == 2)
|
||||||
cmdLabelLayerFunc, (locargc == 3) ?
|
SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
(ClientData)&ttype : (ClientData)NULL);
|
cmdLabelLayerFunc, (ClientData)NULL);
|
||||||
|
else
|
||||||
|
SelEnumLabelsMirror(&DBAllTypeBits, TRUE, (bool *)NULL,
|
||||||
|
cmdLabelLayerFunc, (ClientData)&ttype);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1019,7 +1019,7 @@ CmdSetWindCaption(
|
||||||
* edit cell was selected.
|
* edit cell was selected.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
int cmdWindSet(MagWindow *window);
|
int cmdWindSet(MagWindow *window, ClientData clientData); /* UNUSED */
|
||||||
|
|
||||||
newEditDef = (newEditUse) ? newEditUse->cu_def : NULL;
|
newEditDef = (newEditUse) ? newEditUse->cu_def : NULL;
|
||||||
newRootDef = rootDef;
|
newRootDef = rootDef;
|
||||||
|
|
@ -1053,9 +1053,11 @@ CmdSetWindCaption(
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*ARGSUSED*/
|
||||||
int
|
int
|
||||||
cmdWindSet(
|
cmdWindSet(
|
||||||
MagWindow *window)
|
MagWindow *window,
|
||||||
|
ClientData clientData) /* UNUSED */
|
||||||
{
|
{
|
||||||
char caption[200];
|
char caption[200];
|
||||||
CellDef *wDef;
|
CellDef *wDef;
|
||||||
|
|
@ -1239,7 +1241,7 @@ cmdExpandOneLevel(
|
||||||
extern int cmdExpand1func(CellUse *cu, ClientData bitmask);
|
extern int cmdExpand1func(CellUse *cu, ClientData bitmask);
|
||||||
|
|
||||||
/* first, expand this cell use */
|
/* first, expand this cell use */
|
||||||
DBExpand(cu, bitmask, expand);
|
DBExpand(cu, bitmask, expand ? DB_EXPAND : DB_UNEXPAND);
|
||||||
|
|
||||||
/* now, unexpand its direct children (ONE LEVEL ONLY) */
|
/* now, unexpand its direct children (ONE LEVEL ONLY) */
|
||||||
if (expand)
|
if (expand)
|
||||||
|
|
@ -1251,7 +1253,7 @@ cmdExpand1func(
|
||||||
CellUse *cu,
|
CellUse *cu,
|
||||||
ClientData bitmask)
|
ClientData bitmask)
|
||||||
{
|
{
|
||||||
DBExpand(cu, (int)CD2INT(bitmask), FALSE);
|
DBExpand(cu, (int)CD2INT(bitmask), DB_UNEXPAND);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -702,32 +702,62 @@ CmdTool(
|
||||||
* Implement the "unexpand" command.
|
* Implement the "unexpand" command.
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* unexpand
|
* unexpand [selection|surround|overlap|all]
|
||||||
|
*
|
||||||
|
* "selection" unexpands (hides) cells in the selection. All
|
||||||
|
* other options unexpand cells in the layout. "all" unexpands
|
||||||
|
* all cells in the layout. "surround" unexpannds cells which
|
||||||
|
* the cursor box surrounds completely, and "overlap" unexpands
|
||||||
|
* cells which the cursor box overlaps.
|
||||||
|
*
|
||||||
|
* For backwards compatibility:
|
||||||
|
* "unexpand" alone implements "unexpand surround".
|
||||||
|
*
|
||||||
|
* Also see: CmdExpand
|
||||||
*
|
*
|
||||||
* Results:
|
* Results:
|
||||||
* None.
|
* None.
|
||||||
*
|
*
|
||||||
* Side effects:
|
* Side effects:
|
||||||
* Unexpands all cells under the box that don't completely
|
* Changes the expansion state of cells.
|
||||||
* contain the box.
|
|
||||||
*
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define UNEXPAND_SELECTION 0
|
||||||
|
#define UNEXPAND_SURROUND 1
|
||||||
|
#define UNEXPAND_OVERLAP 2
|
||||||
|
#define UNEXPAND_ALL 3
|
||||||
|
#define UNEXPAND_HELP 4
|
||||||
|
|
||||||
void
|
void
|
||||||
CmdUnexpand(
|
CmdUnexpand(
|
||||||
MagWindow *w,
|
MagWindow *w,
|
||||||
TxCommand *cmd)
|
TxCommand *cmd)
|
||||||
{
|
{
|
||||||
int windowMask, boxMask;
|
int windowMask, boxMask, option;
|
||||||
|
const char * const *msg;
|
||||||
Rect rootRect;
|
Rect rootRect;
|
||||||
|
|
||||||
int cmdUnexpandFunc(CellUse *use, int windowMask); /* Forward reference. */
|
int cmdUnexpandFunc(CellUse *use, int windowMask); /* Forward reference. */
|
||||||
|
|
||||||
if (cmd->tx_argc != 1)
|
static const char * const cmdUnexpandOption[] = {
|
||||||
|
"selection expand cell instances in the selection",
|
||||||
|
"surround expand cell instances which the cursor box surrounds",
|
||||||
|
"overlap expand cell instances which the cursor box overlaps",
|
||||||
|
"all expand all cell instances",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
if (cmd->tx_argc > 1)
|
||||||
{
|
{
|
||||||
TxError("Usage: %s\n", cmd->tx_argv[0]);
|
option = Lookup(cmd->tx_argv[1], cmdUnexpandOption);
|
||||||
return;
|
if (option < 0) option = UNEXPAND_HELP;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
option = UNEXPAND_SURROUND;
|
||||||
|
|
||||||
|
if (option == UNEXPAND_HELP) goto badusage;
|
||||||
|
|
||||||
windCheckOnlyWindow(&w, DBWclientID);
|
windCheckOnlyWindow(&w, DBWclientID);
|
||||||
if (w == (MagWindow *) NULL)
|
if (w == (MagWindow *) NULL)
|
||||||
|
|
@ -743,8 +773,42 @@ CmdUnexpand(
|
||||||
TxError("The box isn't in the same window as the cursor.\n");
|
TxError("The box isn't in the same window as the cursor.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DBExpandAll(((CellUse *) w->w_surfaceID), &rootRect, windowMask,
|
|
||||||
FALSE, cmdUnexpandFunc, (ClientData)(pointertype) windowMask);
|
switch (option)
|
||||||
|
{
|
||||||
|
case UNEXPAND_SELECTION:
|
||||||
|
SelectExpand(windowMask, DB_UNEXPAND, (Rect *)NULL);
|
||||||
|
break;
|
||||||
|
case UNEXPAND_OVERLAP:
|
||||||
|
DBExpandAll(((CellUse *)w->w_surfaceID), &rootRect, windowMask,
|
||||||
|
DB_UNEXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
cmdUnexpandFunc, (ClientData)(pointertype)windowMask);
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
DB_UNEXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
&rootRect);
|
||||||
|
break;
|
||||||
|
case UNEXPAND_SURROUND:
|
||||||
|
DBExpandAll(((CellUse *)w->w_surfaceID), &rootRect, windowMask,
|
||||||
|
DB_UNEXPAND | DB_EXPAND_SURROUND,
|
||||||
|
cmdUnexpandFunc, (ClientData)(pointertype)windowMask);
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
DB_UNEXPAND | DB_EXPAND_SURROUND,
|
||||||
|
&rootRect);
|
||||||
|
break;
|
||||||
|
case UNEXPAND_ALL:
|
||||||
|
DBExpandAll(((CellUse *)w->w_surfaceID), &TiPlaneRect, windowMask,
|
||||||
|
DB_UNEXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
cmdUnexpandFunc, (ClientData)(pointertype)windowMask);
|
||||||
|
SelectExpand(windowMask,
|
||||||
|
DB_UNEXPAND | DB_EXPAND_OVERLAP,
|
||||||
|
(Rect *)NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
badusage:
|
||||||
|
for (msg = &(cmdUnexpandOption[0]); *msg != NULL; msg++)
|
||||||
|
TxPrintf(" %s\n", *msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is called for each cell whose expansion status changed.
|
/* This function is called for each cell whose expansion status changed.
|
||||||
|
|
|
||||||
|
|
@ -53,10 +53,10 @@ typedef struct dbcellboundstruct
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
DBBoundCellPlane(def, extended, rect)
|
DBBoundCellPlane(
|
||||||
CellDef *def;
|
CellDef *def,
|
||||||
Rect *extended;
|
Rect *extended,
|
||||||
Rect *rect;
|
Rect *rect)
|
||||||
{
|
{
|
||||||
TreeFilter filter;
|
TreeFilter filter;
|
||||||
DBCellBoundStruct cbs;
|
DBCellBoundStruct cbs;
|
||||||
|
|
@ -79,9 +79,9 @@ DBBoundCellPlane(def, extended, rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
dbCellBoundFunc(use, fp)
|
dbCellBoundFunc(
|
||||||
CellUse *use;
|
CellUse *use,
|
||||||
TreeFilter *fp;
|
TreeFilter *fp)
|
||||||
{
|
{
|
||||||
DBCellBoundStruct *cbs;
|
DBCellBoundStruct *cbs;
|
||||||
|
|
||||||
|
|
@ -124,9 +124,9 @@ dbCellBoundFunc(use, fp)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
DBBoundPlane(plane, rect)
|
DBBoundPlane(
|
||||||
Plane *plane;
|
Plane *plane,
|
||||||
Rect *rect;
|
Rect *rect)
|
||||||
{
|
{
|
||||||
Tile *left, *right, *top, *bottom, *tp;
|
Tile *left, *right, *top, *bottom, *tp;
|
||||||
|
|
||||||
|
|
@ -205,9 +205,9 @@ DBBoundPlane(plane, rect)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
DBBoundPlaneVert(plane, rect)
|
DBBoundPlaneVert(
|
||||||
Plane *plane;
|
Plane *plane,
|
||||||
Rect *rect;
|
Rect *rect)
|
||||||
{
|
{
|
||||||
Tile *left, *right, *top, *bottom, *tp;
|
Tile *left, *right, *top, *bottom, *tp;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
||||||
#include "windows/windows.h"
|
#include "windows/windows.h"
|
||||||
#include "dbwind/dbwind.h"
|
#include "dbwind/dbwind.h"
|
||||||
#include "commands/commands.h"
|
#include "commands/commands.h"
|
||||||
|
|
||||||
/* C99 compat */
|
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
|
#include "cif/CIFint.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following variable points to the tables currently used for
|
* The following variable points to the tables currently used for
|
||||||
|
|
@ -357,9 +356,43 @@ DBCellCheckCopyAllPaint(scx, mask, xMask, targetUse, func)
|
||||||
struct propUseDefStruct {
|
struct propUseDefStruct {
|
||||||
CellDef *puds_source;
|
CellDef *puds_source;
|
||||||
CellDef *puds_dest;
|
CellDef *puds_dest;
|
||||||
|
Plane *puds_plane; /* Mask hint plane in dest */
|
||||||
Transform *puds_trans; /* Transform from source use to dest */
|
Transform *puds_trans; /* Transform from source use to dest */
|
||||||
|
Rect *puds_area; /* Clip area in source coordinates */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
*-----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* dbCopyMaskHintPlaneFunc --
|
||||||
|
*
|
||||||
|
* Translate tiles from a child mask-hint property plane into the
|
||||||
|
* coordinate system of the parent, and paint the mask-hint area
|
||||||
|
* into the mask-hint property plane of the parent.
|
||||||
|
*
|
||||||
|
*-----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
dbCopyMaskHintPlaneFunc(Tile *tile,
|
||||||
|
TileType dinfo,
|
||||||
|
struct propUseDefStruct *puds)
|
||||||
|
{
|
||||||
|
Transform *trans = puds->puds_trans;
|
||||||
|
Rect *clip = puds->puds_area;
|
||||||
|
Rect r, rnew;
|
||||||
|
Plane *plane = puds->puds_plane;
|
||||||
|
|
||||||
|
TiToRect(tile, &r);
|
||||||
|
GeoClip(&r, clip);
|
||||||
|
if (!GEO_RECTNULL(&r))
|
||||||
|
{
|
||||||
|
GeoTransRect(trans, &r, &rnew);
|
||||||
|
DBPaintPlane(plane, &rnew, CIFPaintTable, (PaintUndoInfo *)NULL);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*-----------------------------------------------------------------------------
|
*-----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -387,62 +420,45 @@ dbCopyMaskHintsFunc(key, proprec, puds)
|
||||||
{
|
{
|
||||||
CellDef *dest = puds->puds_dest;
|
CellDef *dest = puds->puds_dest;
|
||||||
Transform *trans = puds->puds_trans;
|
Transform *trans = puds->puds_trans;
|
||||||
|
Rect *clip = puds->puds_area;
|
||||||
PropertyRecord *parentproprec, *newproprec;
|
PropertyRecord *parentproprec, *newproprec;
|
||||||
char *parentprop, *newvalue, *vptr;
|
char *parentprop, *newvalue, *vptr;
|
||||||
Rect r, rnew;
|
Rect r, rnew;
|
||||||
bool propfound;
|
bool propfound;
|
||||||
int i;
|
int i, j;
|
||||||
|
|
||||||
if (!strncmp(key, "MASKHINTS_", 10))
|
if (!strncmp(key, "MASKHINTS_", 10))
|
||||||
{
|
{
|
||||||
char *vptr, *lastval;
|
char *vptr, *lastval;
|
||||||
int lastlen;
|
int lastlen;
|
||||||
|
Plane *plane;
|
||||||
|
|
||||||
/* Append to existing mask hint (if any) */
|
ASSERT(proprec->prop_type == PROPERTY_TYPE_PLANE, "dbCopyMaskHintsFunc");
|
||||||
|
|
||||||
|
/* Get the existing mask hint plane in the parent cell, and
|
||||||
|
* create it if it does not already exist.
|
||||||
|
*/
|
||||||
parentproprec = (PropertyRecord *)DBPropGet(dest, key, &propfound);
|
parentproprec = (PropertyRecord *)DBPropGet(dest, key, &propfound);
|
||||||
|
|
||||||
if (propfound)
|
if (propfound)
|
||||||
{
|
plane = parentproprec->prop_value.prop_plane;
|
||||||
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
|
||||||
(proprec->prop_len + parentproprec->prop_len - 2) *
|
|
||||||
sizeof(int));
|
|
||||||
newproprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
|
||||||
newproprec->prop_len = proprec->prop_len + parentproprec->prop_len;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
|
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||||
(proprec->prop_len - 2) * sizeof(int));
|
newproprec->prop_type = PROPERTY_TYPE_PLANE;
|
||||||
newproprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
newproprec->prop_len = 0;
|
||||||
newproprec->prop_len = proprec->prop_len;
|
plane = DBNewPlane((ClientData)TT_SPACE);
|
||||||
|
newproprec->prop_value.prop_plane = plane;
|
||||||
|
DBPropPut(dest, key, newproprec);
|
||||||
}
|
}
|
||||||
|
puds->puds_plane = plane;
|
||||||
|
|
||||||
for (i = 0; i < proprec->prop_len; i += 4)
|
/* Copy the properties from child to parent */
|
||||||
{
|
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||||
r.r_xbot = proprec->prop_value.prop_integer[i];
|
proprec->prop_value.prop_plane,
|
||||||
r.r_ybot = proprec->prop_value.prop_integer[i + 1];
|
clip, &CIFSolidBits, dbCopyMaskHintPlaneFunc,
|
||||||
r.r_xtop = proprec->prop_value.prop_integer[i + 2];
|
(ClientData)puds);
|
||||||
r.r_ytop = proprec->prop_value.prop_integer[i + 3];
|
|
||||||
|
|
||||||
GeoTransRect(trans, &r, &rnew);
|
|
||||||
|
|
||||||
newproprec->prop_value.prop_integer[i] = rnew.r_xbot;
|
|
||||||
newproprec->prop_value.prop_integer[i + 1] = rnew.r_ybot;
|
|
||||||
newproprec->prop_value.prop_integer[i + 2] = rnew.r_xtop;
|
|
||||||
newproprec->prop_value.prop_integer[i + 3] = rnew.r_ytop;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (propfound)
|
|
||||||
{
|
|
||||||
/* Append the original values to the end of the list */
|
|
||||||
for (i = 0; i < parentproprec->prop_len; i++)
|
|
||||||
newproprec->prop_value.prop_integer[i + proprec->prop_len] =
|
|
||||||
parentproprec->prop_value.prop_integer[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
DBPropPut(dest, key, newproprec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -474,6 +490,7 @@ DBCellCopyMaskHints(child, parent, transform)
|
||||||
puds.puds_source = child->cu_def;
|
puds.puds_source = child->cu_def;
|
||||||
puds.puds_dest = parent;
|
puds.puds_dest = parent;
|
||||||
puds.puds_trans = transform;
|
puds.puds_trans = transform;
|
||||||
|
puds.puds_area = (Rect *)&TiPlaneRect;
|
||||||
DBPropEnum(child->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);
|
DBPropEnum(child->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -507,6 +524,7 @@ dbFlatCopyMaskHintsFunc(scx, def)
|
||||||
puds.puds_source = scx->scx_use->cu_def;
|
puds.puds_source = scx->scx_use->cu_def;
|
||||||
puds.puds_dest = def;
|
puds.puds_dest = def;
|
||||||
puds.puds_trans = &scx->scx_trans;
|
puds.puds_trans = &scx->scx_trans;
|
||||||
|
puds.puds_area = &scx->scx_area;
|
||||||
|
|
||||||
DBPropEnum(use->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);
|
DBPropEnum(use->cu_def, dbCopyMaskHintsFunc, (ClientData)&puds);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -588,6 +588,25 @@ DBTreeSrLabels(scx, mask, xMask, tpath, flags, func, cdarg)
|
||||||
if (!DBCellRead(def, TRUE, TRUE, NULL))
|
if (!DBCellRead(def, TRUE, TRUE, NULL))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (flags & TF_LABEL_REVERSE_SEARCH)
|
||||||
|
{
|
||||||
|
/* Search children first */
|
||||||
|
filter.tf_func = func;
|
||||||
|
filter.tf_arg = cdarg;
|
||||||
|
filter.tf_mask = mask;
|
||||||
|
filter.tf_xmask = xMask;
|
||||||
|
filter.tf_tpath = tpath;
|
||||||
|
filter.tf_flags = flags;
|
||||||
|
|
||||||
|
scx2 = *scx;
|
||||||
|
if (scx2.scx_area.r_xbot > TiPlaneRect.r_xbot) scx2.scx_area.r_xbot -= 1;
|
||||||
|
if (scx2.scx_area.r_ybot > TiPlaneRect.r_ybot) scx2.scx_area.r_ybot -= 1;
|
||||||
|
if (scx2.scx_area.r_xtop < TiPlaneRect.r_xtop) scx2.scx_area.r_xtop += 1;
|
||||||
|
if (scx2.scx_area.r_ytop < TiPlaneRect.r_ytop) scx2.scx_area.r_ytop += 1;
|
||||||
|
if (DBCellSrArea(&scx2, dbCellLabelSrFunc, (ClientData) &filter))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
for (lab = def->cd_labels; lab; lab = lab->lab_next)
|
||||||
{
|
{
|
||||||
if (SigInterruptPending) break;
|
if (SigInterruptPending) break;
|
||||||
|
|
@ -640,6 +659,8 @@ DBTreeSrLabels(scx, mask, xMask, tpath, flags, func, cdarg)
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & TF_LABEL_REVERSE_SEARCH) return 0; /* children already searched */
|
||||||
|
|
||||||
filter.tf_func = func;
|
filter.tf_func = func;
|
||||||
filter.tf_arg = cdarg;
|
filter.tf_arg = cdarg;
|
||||||
filter.tf_mask = mask;
|
filter.tf_mask = mask;
|
||||||
|
|
@ -711,6 +732,16 @@ dbCellLabelSrFunc(scx, fp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If fp->tf_flags has TF_LABEL_REVERSE_SEARCH, then search child
|
||||||
|
* uses first, then the parent. This is for display, so that if
|
||||||
|
* a child cell and parent cell have overlapping labels, the parent
|
||||||
|
* label is the one on top.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (fp->tf_flags & TF_LABEL_REVERSE_SEARCH)
|
||||||
|
if (DBCellSrArea(scx, dbCellLabelSrFunc, (ClientData) fp))
|
||||||
|
result = 1;
|
||||||
|
|
||||||
/* Apply the function first to any of the labels in this def. */
|
/* Apply the function first to any of the labels in this def. */
|
||||||
|
|
||||||
result = 0;
|
result = 0;
|
||||||
|
|
@ -732,9 +763,11 @@ dbCellLabelSrFunc(scx, fp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now visit each child use recursively */
|
/* Now visit each child use recursively, if not doing a reverse search */
|
||||||
if (DBCellSrArea(scx, dbCellLabelSrFunc, (ClientData) fp))
|
|
||||||
result = 1;
|
if (!(fp->tf_flags & TF_LABEL_REVERSE_SEARCH))
|
||||||
|
if (DBCellSrArea(scx, dbCellLabelSrFunc, (ClientData) fp))
|
||||||
|
result = 1;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
/* Remove the trailing pathname component from the TerminalPath */
|
/* Remove the trailing pathname component from the TerminalPath */
|
||||||
|
|
@ -1713,7 +1746,7 @@ dbTileMoveFunc(tile, dinfo, mvvals)
|
||||||
if (IsSplit(tile))
|
if (IsSplit(tile))
|
||||||
type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
|
type = (dinfo & TT_SIDE) ? SplitRightType(tile) : SplitLeftType(tile);
|
||||||
DBNMPaintPlane(mvvals->ptarget, exact, &targetRect,
|
DBNMPaintPlane(mvvals->ptarget, exact, &targetRect,
|
||||||
DBStdPaintTbl(type, mvvals->pnum),
|
(mvvals->pnum < 0) ? CIFPaintTable : DBStdPaintTbl(type, mvvals->pnum),
|
||||||
(PaintUndoInfo *)NULL);
|
(PaintUndoInfo *)NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1814,7 +1847,22 @@ int dbScaleProp(name, proprec, cps)
|
||||||
int i, scalen, scaled;
|
int i, scalen, scaled;
|
||||||
Point p;
|
Point p;
|
||||||
|
|
||||||
/* Only "dimension" type properties get scaled */
|
/* Only "dimension" and "plane" type properties get scaled */
|
||||||
|
|
||||||
|
if (proprec->prop_type == PROPERTY_TYPE_PLANE)
|
||||||
|
{
|
||||||
|
Plane *newplane;
|
||||||
|
newplane = DBNewPlane((ClientData)TT_SPACE);
|
||||||
|
DBClearPaintPlane(newplane);
|
||||||
|
/* Plane index is unused; arbitrarily substitute -1 */
|
||||||
|
dbScalePlane(proprec->prop_value.prop_plane, newplane, -1,
|
||||||
|
scalen, scaled, TRUE);
|
||||||
|
DBFreePaintPlane(proprec->prop_value.prop_plane);
|
||||||
|
TiFreePlane(proprec->prop_value.prop_plane);
|
||||||
|
proprec->prop_value.prop_plane = newplane;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
|
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
|
||||||
|
|
||||||
/* Scale numerator held in point X value, */
|
/* Scale numerator held in point X value, */
|
||||||
|
|
@ -1857,7 +1905,22 @@ int dbMoveProp(name, proprec, cps)
|
||||||
char *newvalue;
|
char *newvalue;
|
||||||
Point p;
|
Point p;
|
||||||
|
|
||||||
/* Only "dimension" type properties get scaled */
|
/* Only "dimension" and "plane" type properties get scaled */
|
||||||
|
|
||||||
|
if (proprec->prop_type == PROPERTY_TYPE_PLANE)
|
||||||
|
{
|
||||||
|
Plane *newplane;
|
||||||
|
|
||||||
|
newplane = DBNewPlane((ClientData) TT_SPACE);
|
||||||
|
DBClearPaintPlane(newplane);
|
||||||
|
/* Use plane index -1 to indicate use of CIFPaintTable */
|
||||||
|
dbMovePlane(proprec->prop_value.prop_plane, newplane, -1, origx, origy);
|
||||||
|
DBFreePaintPlane(proprec->prop_value.prop_plane);
|
||||||
|
TiFreePlane(proprec->prop_value.prop_plane);
|
||||||
|
proprec->prop_value.prop_plane = newplane;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
|
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
|
||||||
|
|
||||||
origx = cps->cps_point.p_x;
|
origx = cps->cps_point.p_x;
|
||||||
|
|
|
||||||
|
|
@ -1037,7 +1037,13 @@ 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. */
|
/* start a new one. NOTE: Setting lasttop to -1 means */
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
|
@ -1045,6 +1051,7 @@ 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;
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ struct expandArg
|
||||||
{
|
{
|
||||||
bool ea_deref; /* TRUE if root def dereference flag is set */
|
bool ea_deref; /* TRUE if root def dereference flag is set */
|
||||||
int ea_xmask; /* Expand mask. */
|
int ea_xmask; /* Expand mask. */
|
||||||
|
int ea_type; /* Expand, unexpand, or toggle */
|
||||||
int (*ea_func)(); /* Function to call for each cell whose
|
int (*ea_func)(); /* Function to call for each cell whose
|
||||||
* status is changed.
|
* status is changed.
|
||||||
*/
|
*/
|
||||||
|
|
@ -67,15 +68,22 @@ struct expandArg
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
DBExpand(cellUse, expandMask, expandFlag)
|
DBExpand(cellUse, expandMask, expandType)
|
||||||
CellUse *cellUse;
|
CellUse *cellUse;
|
||||||
int expandMask;
|
int expandMask;
|
||||||
bool expandFlag;
|
int expandType;
|
||||||
{
|
{
|
||||||
CellDef *def;
|
CellDef *def;
|
||||||
|
bool expandFlag, expandTest;
|
||||||
|
|
||||||
if (DBDescendSubcell(cellUse, expandMask) == expandFlag)
|
expandTest = DBDescendSubcell(cellUse, expandMask);
|
||||||
return;
|
if ((expandType & DB_EXPAND_MASK) == DB_EXPAND_TOGGLE)
|
||||||
|
expandFlag = expandTest;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
expandFlag = ((expandType & DB_EXPAND_MASK) == DB_EXPAND) ? TRUE : FALSE;
|
||||||
|
if (expandFlag == expandTest) return;
|
||||||
|
}
|
||||||
|
|
||||||
if (expandFlag)
|
if (expandFlag)
|
||||||
{
|
{
|
||||||
|
|
@ -130,17 +138,17 @@ DBExpand(cellUse, expandMask, expandFlag)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
DBExpandAll(rootUse, rootRect, expandMask, expandFlag, func, cdarg)
|
DBExpandAll(rootUse, rootRect, expandMask, expandType, func, cdarg)
|
||||||
CellUse *rootUse; /* Root cell use from which search begins */
|
CellUse *rootUse; /* Root cell use from which search begins */
|
||||||
Rect *rootRect; /* Area to be expanded, in root coordinates */
|
Rect *rootRect; /* Area to be expanded, in root coordinates */
|
||||||
int expandMask; /* Window mask in which cell is to be expanded */
|
int expandMask; /* Window mask in which cell is to be expanded */
|
||||||
bool expandFlag; /* TRUE => expand, FALSE => unexpand */
|
int expandType; /* DB_EXPAND, DB_UNEXPAND, DB_EXPAND_TOGGLE */
|
||||||
int (*func)(); /* Function to call for each cell whose expansion
|
int (*func)(); /* Function to call for each cell whose expansion
|
||||||
* status is modified. NULL means don't call anyone.
|
* status is modified. NULL means don't call anyone.
|
||||||
*/
|
*/
|
||||||
ClientData cdarg; /* Argument to pass to func. */
|
ClientData cdarg; /* Argument to pass to func. */
|
||||||
{
|
{
|
||||||
int dbExpandFunc(), dbUnexpandFunc();
|
int dbExpandFunc();
|
||||||
SearchContext scontext;
|
SearchContext scontext;
|
||||||
struct expandArg arg;
|
struct expandArg arg;
|
||||||
|
|
||||||
|
|
@ -148,29 +156,26 @@ DBExpandAll(rootUse, rootRect, expandMask, expandFlag, func, cdarg)
|
||||||
(void) DBCellRead(rootUse->cu_def, TRUE, TRUE, NULL);
|
(void) DBCellRead(rootUse->cu_def, TRUE, TRUE, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Walk through the area and set the expansion state
|
* Walk through the area and set the expansion state appropriately.
|
||||||
* appropriately.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
arg.ea_xmask = expandMask;
|
arg.ea_xmask = expandMask;
|
||||||
arg.ea_func = func;
|
arg.ea_func = func;
|
||||||
arg.ea_arg = cdarg;
|
arg.ea_arg = cdarg;
|
||||||
|
arg.ea_type = expandType;
|
||||||
arg.ea_deref = (rootUse->cu_def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
arg.ea_deref = (rootUse->cu_def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
|
||||||
|
|
||||||
scontext.scx_use = rootUse;
|
scontext.scx_use = rootUse;
|
||||||
scontext.scx_trans = GeoIdentityTransform;
|
scontext.scx_trans = GeoIdentityTransform;
|
||||||
scontext.scx_area = *rootRect;
|
scontext.scx_area = *rootRect;
|
||||||
if (expandFlag)
|
DBCellSrArea(&scontext, dbExpandFunc, (ClientData) &arg);
|
||||||
DBCellSrArea(&scontext, dbExpandFunc, (ClientData) &arg);
|
|
||||||
else
|
|
||||||
DBCellSrArea(&scontext, dbUnexpandFunc, (ClientData) &arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dbExpandFunc --
|
* dbExpandFunc --
|
||||||
*
|
*
|
||||||
* Filter function called by DBCellSrArea on behalf of DBExpandAll above
|
* Filter function called by DBCellSrArea on behalf of DBExpandAll above
|
||||||
* when cells are being expanded.
|
* when cells are being expanded, unexpanded, or toggled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
@ -184,68 +189,55 @@ dbExpandFunc(scx, arg)
|
||||||
{
|
{
|
||||||
CellUse *childUse = scx->scx_use;
|
CellUse *childUse = scx->scx_use;
|
||||||
int n = DBLambda[1];
|
int n = DBLambda[1];
|
||||||
|
int expandTest;
|
||||||
|
int expandType = (arg->ea_type & DB_EXPAND_MASK);
|
||||||
|
int expandSurround = (arg->ea_type & DB_EXPAND_SURROUND_MASK);
|
||||||
|
bool surround;
|
||||||
|
|
||||||
|
expandTest = DBDescendSubcell(childUse, arg->ea_xmask);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Change the expansion status of this cell if necessary. Call the
|
* Change the expansion status of this cell if necessary. Call the
|
||||||
* client's function if the expansion status has changed.
|
* client's function if the expansion status has changed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!DBDescendSubcell(childUse, arg->ea_xmask))
|
if (!expandTest && ((expandType == DB_EXPAND) || (expandType == DB_EXPAND_TOGGLE)))
|
||||||
{
|
{
|
||||||
/* If the cell is unavailable, then don't expand it.
|
surround = (!GEO_SURROUND(&childUse->cu_def->cd_bbox, &scx->scx_area)
|
||||||
*/
|
|| GEO_SURROUND(&scx->scx_area, &childUse->cu_def->cd_bbox));
|
||||||
if ((childUse->cu_def->cd_flags & CDAVAILABLE) == 0)
|
if (surround || (expandSurround == DB_EXPAND_OVERLAP))
|
||||||
{
|
{
|
||||||
/* If the parent is dereferenced, then the child should be, too */
|
/* If the cell is unavailable, then don't expand it.
|
||||||
if (arg->ea_deref) childUse->cu_def->cd_flags |= CDDEREFERENCE;
|
*/
|
||||||
if(!DBCellRead(childUse->cu_def, TRUE, TRUE, NULL))
|
if ((childUse->cu_def->cd_flags & CDAVAILABLE) == 0)
|
||||||
{
|
{
|
||||||
TxError("Cell %s is unavailable. It could not be expanded.\n",
|
/* If the parent is dereferenced, then the child should be, too */
|
||||||
childUse->cu_def->cd_name);
|
if (arg->ea_deref) childUse->cu_def->cd_flags |= CDDEREFERENCE;
|
||||||
return 2;
|
if (!DBCellRead(childUse->cu_def, TRUE, TRUE, NULL))
|
||||||
|
{
|
||||||
|
TxError("Cell %s is unavailable. It could not be expanded.\n",
|
||||||
|
childUse->cu_def->cd_name);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
childUse->cu_expandMask |= arg->ea_xmask;
|
||||||
|
expandTest = TRUE;
|
||||||
|
if (arg->ea_func != NULL)
|
||||||
|
{
|
||||||
|
if ((*arg->ea_func)(childUse, arg->ea_arg) != 0) return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
childUse->cu_expandMask |= arg->ea_xmask;
|
|
||||||
if (arg->ea_func != NULL)
|
|
||||||
{
|
|
||||||
if ((*arg->ea_func)(childUse, arg->ea_arg) != 0) return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if (expandTest && ((expandType == DB_UNEXPAND) ||
|
||||||
if (DBCellSrArea(scx, dbExpandFunc, (ClientData) arg))
|
(expandType == DB_EXPAND_TOGGLE)))
|
||||||
return 1;
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* dbUnexpandFunc --
|
|
||||||
*
|
|
||||||
* Filter function called by DBCellSrArea on behalf of DBExpandAll above
|
|
||||||
* when cells are being unexpanded.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
|
||||||
dbUnexpandFunc(scx, arg)
|
|
||||||
SearchContext *scx; /* Pointer to search context containing
|
|
||||||
* child use, search area in coor-
|
|
||||||
* dinates of the child use, and
|
|
||||||
* transform back to "root".
|
|
||||||
*/
|
|
||||||
struct expandArg *arg; /* Client data from caller */
|
|
||||||
{
|
|
||||||
CellUse *childUse = scx->scx_use;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Change the expansion status of this cell if necessary.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (DBDescendSubcell(childUse, arg->ea_xmask))
|
|
||||||
{
|
{
|
||||||
if (!GEO_SURROUND(&childUse->cu_def->cd_bbox, &scx->scx_area)
|
surround = (!GEO_SURROUND(&childUse->cu_def->cd_bbox, &scx->scx_area)
|
||||||
|| GEO_SURROUND(&scx->scx_area, &childUse->cu_def->cd_bbox))
|
|| GEO_SURROUND(&scx->scx_area, &childUse->cu_def->cd_bbox));
|
||||||
|
if (surround || (expandSurround == DB_EXPAND_OVERLAP))
|
||||||
{
|
{
|
||||||
childUse->cu_expandMask &= ~arg->ea_xmask;
|
childUse->cu_expandMask &= ~arg->ea_xmask;
|
||||||
|
expandTest = FALSE;
|
||||||
|
|
||||||
/* Call the client's function, if there is one. */
|
/* Call the client's function, if there is one. */
|
||||||
|
|
||||||
|
|
@ -256,11 +248,7 @@ dbUnexpandFunc(scx, arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't recursively search things that aren't already expanded. */
|
if (DBCellSrArea(scx, dbExpandFunc, (ClientData) arg))
|
||||||
|
|
||||||
else return 2;
|
|
||||||
|
|
||||||
if (DBCellSrArea(scx, dbUnexpandFunc, (ClientData) arg))
|
|
||||||
return 1;
|
return 1;
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
366
database/DBio.c
366
database/DBio.c
|
|
@ -73,10 +73,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
||||||
#include "utils/undo.h"
|
#include "utils/undo.h"
|
||||||
#include "utils/malloc.h"
|
#include "utils/malloc.h"
|
||||||
#include "utils/signals.h"
|
#include "utils/signals.h"
|
||||||
|
|
||||||
/* C99 compat */
|
|
||||||
#include "dbwind/dbwtech.h"
|
#include "dbwind/dbwtech.h"
|
||||||
#include "cif/cif.h"
|
#include "cif/cif.h"
|
||||||
|
#include "cif/CIFint.h"
|
||||||
#include "lef/lef.h"
|
#include "lef/lef.h"
|
||||||
#include "commands/commands.h"
|
#include "commands/commands.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
|
|
@ -2017,8 +2016,8 @@ badTransform:
|
||||||
if ((cellDef->cd_file != NULL) && (cellDef->cd_file[0] == '/'))
|
if ((cellDef->cd_file != NULL) && (cellDef->cd_file[0] == '/'))
|
||||||
{
|
{
|
||||||
char *homedir = getenv("HOME");
|
char *homedir = getenv("HOME");
|
||||||
if (strncmp(cellDef->cd_file, homedir, strlen(homedir)) ||
|
if (homedir && (strncmp(cellDef->cd_file, homedir, strlen(homedir)) ||
|
||||||
*(cellDef->cd_file + strlen(homedir)) != '/')
|
*(cellDef->cd_file + strlen(homedir)) != '/'))
|
||||||
{
|
{
|
||||||
char *homeroot = strrchr(homedir, '/');
|
char *homeroot = strrchr(homedir, '/');
|
||||||
int rootlen = (int)(homeroot - homedir) + 1;
|
int rootlen = (int)(homeroot - homedir) + 1;
|
||||||
|
|
@ -2061,9 +2060,10 @@ badTransform:
|
||||||
if (*pathptr == '~')
|
if (*pathptr == '~')
|
||||||
{
|
{
|
||||||
char *homedir = getenv("HOME");
|
char *homedir = getenv("HOME");
|
||||||
if (!strncmp(subCellDef->cd_file, homedir, strlen(homedir))
|
if (homedir && (!strncmp(subCellDef->cd_file, homedir,
|
||||||
&& (!strcmp(subCellDef->cd_file + strlen(homedir),
|
strlen(homedir)) &&
|
||||||
pathptr + 1)))
|
(!strcmp(subCellDef->cd_file + strlen(homedir),
|
||||||
|
pathptr + 1))))
|
||||||
pathOK = TRUE;
|
pathOK = TRUE;
|
||||||
}
|
}
|
||||||
else if (!strcmp(cwddir, pathptr)) pathOK = TRUE;
|
else if (!strcmp(cwddir, pathptr)) pathOK = TRUE;
|
||||||
|
|
@ -2255,9 +2255,9 @@ badTransform:
|
||||||
/* Check if the path is the same as the current directory */
|
/* Check if the path is the same as the current directory */
|
||||||
|
|
||||||
char *homedir = getenv("HOME");
|
char *homedir = getenv("HOME");
|
||||||
if (!strncmp(cwddir, homedir, strlen(homedir))
|
if (homedir && (!strncmp(cwddir, homedir, strlen(homedir))
|
||||||
&& (!strcmp(cwddir + strlen(homedir),
|
&& (!strcmp(cwddir + strlen(homedir),
|
||||||
pathptr + 1)))
|
pathptr + 1))))
|
||||||
pathOK = TRUE;
|
pathOK = TRUE;
|
||||||
}
|
}
|
||||||
else if (!strcmp(cwddir, pathptr)) pathOK = TRUE;
|
else if (!strcmp(cwddir, pathptr)) pathOK = TRUE;
|
||||||
|
|
@ -2492,10 +2492,24 @@ dbReadProperties(cellDef, line, len, f, scalen, scaled)
|
||||||
* (2) "integer" (a fixed integer or list of integers)
|
* (2) "integer" (a fixed integer or list of integers)
|
||||||
* (3) "dimension" (an integer that scales with internal units)
|
* (3) "dimension" (an integer that scales with internal units)
|
||||||
* (4) "double" (a fixed double-wide integer or list thereof)
|
* (4) "double" (a fixed double-wide integer or list thereof)
|
||||||
|
* (5) "plane" (a tile plane structure)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
switch (option)
|
switch (option)
|
||||||
{
|
{
|
||||||
|
case PROPERTY_TYPE_PLANE:
|
||||||
|
/* Treat this like "string" but make sure property is a
|
||||||
|
* mask hint. There is currently no method to specify
|
||||||
|
* a plane property other than to write out the bounding
|
||||||
|
* box coordinates of all the tiles in a list.
|
||||||
|
*/
|
||||||
|
if (strncmp(propertyname, "MASKHINTS_", 10))
|
||||||
|
{
|
||||||
|
TxError("Plane type specified for property \"%s\" but "
|
||||||
|
"property is not a mask hint!\n", propertyname);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Else drop through */
|
||||||
case PROPERTY_TYPE_STRING:
|
case PROPERTY_TYPE_STRING:
|
||||||
/* Go ahead and process the vendor GDS property */
|
/* Go ahead and process the vendor GDS property */
|
||||||
if (!strcmp(propertyname, "GDS_FILE"))
|
if (!strcmp(propertyname, "GDS_FILE"))
|
||||||
|
|
@ -2565,70 +2579,65 @@ dbReadProperties(cellDef, line, len, f, scalen, scaled)
|
||||||
else if (!strncmp(propertyname, "MASKHINTS_", 10))
|
else if (!strncmp(propertyname, "MASKHINTS_", 10))
|
||||||
{
|
{
|
||||||
pptr = pvalueptr;
|
pptr = pvalueptr;
|
||||||
|
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
|
||||||
|
proprec->prop_type = PROPERTY_TYPE_PLANE;
|
||||||
|
proprec->prop_len = 0;
|
||||||
|
|
||||||
/* Do one pass through the string to count the number of
|
proprec->prop_value.prop_plane = DBNewPlane((ClientData)TT_SPACE);
|
||||||
* values and make sure they all parse as integers.
|
|
||||||
|
/* Parse the string and convert sets of four values
|
||||||
|
* to coordinates and paint into the plane.
|
||||||
*/
|
*/
|
||||||
numvals = 0;
|
numvals = 0;
|
||||||
while (*pptr != '\0')
|
while (*pptr != '\0')
|
||||||
{
|
{
|
||||||
|
Rect r;
|
||||||
while (isspace(*pptr) && (*pptr != '\0')) pptr++;
|
while (isspace(*pptr) && (*pptr != '\0')) pptr++;
|
||||||
if (!isspace(*pptr))
|
if (!isspace(*pptr))
|
||||||
{
|
{
|
||||||
char *endptr;
|
if (sscanf(pptr, "%d", &ival) != 1)
|
||||||
long result;
|
|
||||||
|
|
||||||
/* Check that the value is an integer */
|
|
||||||
result = strtol(pptr, &endptr, 0);
|
|
||||||
if (endptr == pptr)
|
|
||||||
{
|
{
|
||||||
/* Unable to parse correctly. Save as a string value */
|
TxError("Mask-hint \"%s\" has non-integer values!",
|
||||||
proplen = strlen(pvalueptr);
|
pptr);
|
||||||
proprec = (PropertyRecord *)mallocMagic(
|
DBFreePaintPlane(proprec->prop_value.prop_plane);
|
||||||
sizeof(PropertyRecord) - 7 + proplen);
|
TiFreePlane(proprec->prop_value.prop_plane);
|
||||||
proprec->prop_type = PROPERTY_TYPE_STRING;
|
freeMagic((char *)proprec);
|
||||||
proprec->prop_len = proplen;
|
proprec = (PropertyRecord *)NULL;
|
||||||
strcpy(proprec->prop_value.prop_string, pvalueptr);
|
|
||||||
(void) DBPropPut(cellDef, propertyname, proprec);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
while (!isspace(*pptr) && (*pptr != '\0')) pptr++;
|
|
||||||
numvals++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (numvals % 4 != 0)
|
|
||||||
{
|
|
||||||
TxError("Cannot read bounding box values in %s property",
|
|
||||||
propertyname);
|
|
||||||
/* This does not need to be a fatal error. Extra
|
|
||||||
* values will be unused.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
pptr = pvalueptr;
|
|
||||||
proprec = (PropertyRecord *)mallocMagic(
|
|
||||||
sizeof(PropertyRecord) + ((numvals - 2) * sizeof(int)));
|
|
||||||
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
|
|
||||||
proprec->prop_len = numvals;
|
|
||||||
|
|
||||||
/* Do a second pass through the string to convert the values
|
|
||||||
* to dimensions and save as an integer array.
|
|
||||||
*/
|
|
||||||
numvals = 0;
|
|
||||||
while (*pptr != '\0')
|
|
||||||
{
|
|
||||||
while (isspace(*pptr) && (*pptr != '\0')) pptr++;
|
|
||||||
if (!isspace(*pptr))
|
|
||||||
{
|
|
||||||
sscanf(pptr, "%d", &ival);
|
|
||||||
if (scalen > 1) ival *= scalen;
|
if (scalen > 1) ival *= scalen;
|
||||||
if (scaled > 1) ival /= scaled;
|
if (scaled > 1) ival /= scaled;
|
||||||
proprec->prop_value.prop_integer[numvals] = ival;
|
switch (numvals)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
r.r_xbot = ival;
|
||||||
|
numvals++;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
r.r_ybot = ival;
|
||||||
|
numvals++;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
r.r_xtop = ival;
|
||||||
|
numvals++;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
r.r_ytop = ival;
|
||||||
|
numvals = 0;
|
||||||
|
/* Paint this into the plane */
|
||||||
|
DBPaintPlane(proprec->prop_value.prop_plane,
|
||||||
|
&r, CIFPaintTable,
|
||||||
|
(PaintUndoInfo *)NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
while (!isspace(*pptr) && (*pptr != '\0')) pptr++;
|
while (!isspace(*pptr) && (*pptr != '\0')) pptr++;
|
||||||
numvals++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (numvals != 0)
|
||||||
|
{
|
||||||
|
TxError("Mask-hint property number of values is not"
|
||||||
|
" divisible by four. Truncated.\n");
|
||||||
|
}
|
||||||
(void) DBPropPut(cellDef, propertyname, proprec);
|
(void) DBPropPut(cellDef, propertyname, proprec);
|
||||||
}
|
}
|
||||||
else if ((!strncmp(propertyname, "GDS_START", 9)) ||
|
else if ((!strncmp(propertyname, "GDS_START", 9)) ||
|
||||||
|
|
@ -3481,6 +3490,23 @@ DBCellFindScale(cellDef)
|
||||||
return ggcf;
|
return ggcf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* dbFindGCFFunc ---
|
||||||
|
*
|
||||||
|
* Find the greatest common factor between the current GCF and each point
|
||||||
|
* in a tile.
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* 0 to keep the search going.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* May modify the GCF passed as client data to the function.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
dbFindGCFFunc(tile, dinfo, ggcf)
|
dbFindGCFFunc(tile, dinfo, ggcf)
|
||||||
Tile *tile;
|
Tile *tile;
|
||||||
|
|
@ -3503,6 +3529,24 @@ dbFindGCFFunc(tile, dinfo, ggcf)
|
||||||
return (*ggcf == 1) ? 1 : 0;
|
return (*ggcf == 1) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* dbFindCellGCFFunc ---
|
||||||
|
*
|
||||||
|
* Find the greatest common factor between the current GCF and each point
|
||||||
|
* of a uses bounding box, each component of the use's transform , and
|
||||||
|
* for arrays, the array pitch.
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* 0 to keep the search going.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* May modify the GCF passed as client data to the function.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
dbFindCellGCFFunc(cellUse, ggcf)
|
dbFindCellGCFFunc(cellUse, ggcf)
|
||||||
CellUse *cellUse; /* Cell use whose "call" is to be written to a file */
|
CellUse *cellUse; /* Cell use whose "call" is to be written to a file */
|
||||||
|
|
@ -3543,6 +3587,23 @@ dbFindCellGCFFunc(cellUse, ggcf)
|
||||||
return (*ggcf == 1) ? 1 : 0;
|
return (*ggcf == 1) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* dbFindPropGCFFunc ---
|
||||||
|
*
|
||||||
|
* Find the greatest common factor between the current GCF and each point
|
||||||
|
* of a dimension property, or each point of each tile in a plane property.
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* 0 to keep the search going.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* May modify the GCF passed as client data to the function.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
dbFindPropGCFFunc(key, proprec, ggcf)
|
dbFindPropGCFFunc(key, proprec, ggcf)
|
||||||
char *key;
|
char *key;
|
||||||
|
|
@ -3551,20 +3612,28 @@ dbFindPropGCFFunc(key, proprec, ggcf)
|
||||||
{
|
{
|
||||||
int value, n;
|
int value, n;
|
||||||
|
|
||||||
/* Only PROPERTY_TYPE_DIMENSION properties get handled */
|
if (proprec->prop_type == PROPERTY_TYPE_PLANE)
|
||||||
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
|
|
||||||
|
|
||||||
for (n = 0; n < proprec->prop_len; n++)
|
|
||||||
{
|
{
|
||||||
value = proprec->prop_value.prop_integer[n];
|
if (DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||||
if (value % (*ggcf) != 0)
|
proprec->prop_value.prop_plane,
|
||||||
*ggcf = FindGCF(value, *ggcf);
|
&TiPlaneRect, &CIFSolidBits, dbFindGCFFunc, (ClientData)ggcf))
|
||||||
|
return (*ggcf == 1) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
else if (proprec->prop_type == PROPERTY_TYPE_DIMENSION)
|
||||||
return (*ggcf == 1) ? 1 : 0;
|
{
|
||||||
|
for (n = 0; n < proprec->prop_len; n++)
|
||||||
|
{
|
||||||
|
value = proprec->prop_value.prop_integer[n];
|
||||||
|
if (value % (*ggcf) != 0)
|
||||||
|
*ggcf = FindGCF(value, *ggcf);
|
||||||
|
}
|
||||||
|
return (*ggcf == 1) ? 1 : 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* Only PROPERTY_TYPE_PLANE and PROPERTY_TYPE_DIMENSION get handled */
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -3573,6 +3642,12 @@ dbFindPropGCFFunc(key, proprec, ggcf)
|
||||||
* String comparison of two instance names, for the purpose of sorting
|
* String comparison of two instance names, for the purpose of sorting
|
||||||
* the instances in a .mag file output in a repeatable way.
|
* the instances in a .mag file output in a repeatable way.
|
||||||
*
|
*
|
||||||
|
* Results:
|
||||||
|
* The string comparison, equivalent to the return value of strcmp().
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* None.
|
||||||
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -3610,6 +3685,9 @@ struct cellUseList {
|
||||||
* Return value:
|
* Return value:
|
||||||
* Return 0 to keep the search going.
|
* Return 0 to keep the search going.
|
||||||
*
|
*
|
||||||
|
* Side effects:
|
||||||
|
* Adds to the list of cell uses passed as client data.
|
||||||
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -3635,6 +3713,9 @@ dbGetUseFunc(cellUse, useRec)
|
||||||
* Return value:
|
* Return value:
|
||||||
* Return 0 to keep the search going.
|
* Return 0 to keep the search going.
|
||||||
*
|
*
|
||||||
|
* Side effects:
|
||||||
|
* Increments the count passed as client data.
|
||||||
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -3663,6 +3744,12 @@ struct keyValuePair {
|
||||||
* String comparison of two property keys, for the purpose of sorting
|
* String comparison of two property keys, for the purpose of sorting
|
||||||
* the properties in a .mag file output in a repeatable way.
|
* the properties in a .mag file output in a repeatable way.
|
||||||
*
|
*
|
||||||
|
* Results:
|
||||||
|
* The string comparison, equivalent to the result of strcmp().
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* None.
|
||||||
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -3698,6 +3785,9 @@ struct cellPropList {
|
||||||
* Return value:
|
* Return value:
|
||||||
* Return 0 to keep the search going.
|
* Return 0 to keep the search going.
|
||||||
*
|
*
|
||||||
|
* Side Effects:
|
||||||
|
* Adds to the list of property records passed as client data.
|
||||||
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -3727,6 +3817,9 @@ dbGetPropFunc(key, proprec, propRec)
|
||||||
* Return value:
|
* Return value:
|
||||||
* Return 0 to keep the search going.
|
* Return 0 to keep the search going.
|
||||||
*
|
*
|
||||||
|
* Side Effects:
|
||||||
|
* Increments the count passed as client data.
|
||||||
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -4064,6 +4157,52 @@ ioerror:
|
||||||
return (TRUE);
|
return (TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* dbWritePropPaintFunc --
|
||||||
|
*
|
||||||
|
* Transform tiles in a plane into a set of four coordinate values and output
|
||||||
|
* them to the file. This turns plane data into a PROP_TYPE_DIMENSION array,
|
||||||
|
* which is not a very efficient form and may be revisited. For relatively
|
||||||
|
* simple plane data, it suffices. The property planes are single-bit types.
|
||||||
|
* Note that there is no support for non-Manhattan geometry in the property
|
||||||
|
* plane at this time.
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* 0 to keep the search going.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* Writes output to a file.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
dbWritePropPaintFunc(Tile *tile,
|
||||||
|
TileType dinfo,
|
||||||
|
ClientData cdata)
|
||||||
|
{
|
||||||
|
pwfrec *pwf = (pwfrec *)cdata;
|
||||||
|
FILE *f = pwf->pwf_file;
|
||||||
|
int reducer = pwf->pwf_reducer;
|
||||||
|
Rect r;
|
||||||
|
char newvalue[20];
|
||||||
|
|
||||||
|
TiToRect(tile, &r);
|
||||||
|
|
||||||
|
snprintf(newvalue, 20, " %d", r.r_xbot / reducer);
|
||||||
|
FPUTSR(f, newvalue);
|
||||||
|
snprintf(newvalue, 20, " %d", r.r_ybot / reducer);
|
||||||
|
FPUTSR(f, newvalue);
|
||||||
|
snprintf(newvalue, 20, " %d", r.r_xtop / reducer);
|
||||||
|
FPUTSR(f, newvalue);
|
||||||
|
snprintf(newvalue, 20, " %d", r.r_ytop / reducer);
|
||||||
|
FPUTSR(f, newvalue);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -4111,6 +4250,12 @@ dbWritePropFunc(key, proprec, cdata)
|
||||||
case PROPERTY_TYPE_INTEGER:
|
case PROPERTY_TYPE_INTEGER:
|
||||||
FPUTSR(f, "integer ");
|
FPUTSR(f, "integer ");
|
||||||
break;
|
break;
|
||||||
|
case PROPERTY_TYPE_PLANE:
|
||||||
|
/* A mask hint is a plane type property; declare it
|
||||||
|
* as a dimension, but it's arbitrary anyway since
|
||||||
|
* the prefix "MASKHINTS_" is detected on read-in and
|
||||||
|
* the property is parsed as plane data.
|
||||||
|
*/
|
||||||
case PROPERTY_TYPE_DIMENSION:
|
case PROPERTY_TYPE_DIMENSION:
|
||||||
FPUTSR(f, "dimension ");
|
FPUTSR(f, "dimension ");
|
||||||
break;
|
break;
|
||||||
|
|
@ -4143,6 +4288,13 @@ dbWritePropFunc(key, proprec, cdata)
|
||||||
FPUTSR(f, newvalue);
|
FPUTSR(f, newvalue);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case PROPERTY_TYPE_PLANE:
|
||||||
|
/* Scan the plane and output each non-space tile as four values */
|
||||||
|
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||||
|
proprec->prop_value.prop_plane,
|
||||||
|
&TiPlaneRect, &CIFSolidBits, dbWritePropPaintFunc,
|
||||||
|
(ClientData)cdata);
|
||||||
|
break;
|
||||||
case PROPERTY_TYPE_DOUBLE:
|
case PROPERTY_TYPE_DOUBLE:
|
||||||
for (i = 0; i < proprec->prop_len; i++)
|
for (i = 0; i < proprec->prop_len; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -4267,7 +4419,7 @@ DBCellWriteCommandFile(cellDef, f)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(f, "label %s %s %d %d %d %d %s %s\n",
|
fprintf(f, "label %s %s %d %d %d %d %s %s%s\n",
|
||||||
lab->lab_text,
|
lab->lab_text,
|
||||||
DBFontList[lab->lab_font]->mf_name,
|
DBFontList[lab->lab_font]->mf_name,
|
||||||
lab->lab_size >> 3,
|
lab->lab_size >> 3,
|
||||||
|
|
@ -4275,15 +4427,10 @@ DBCellWriteCommandFile(cellDef, f)
|
||||||
lab->lab_offset.p_x,
|
lab->lab_offset.p_x,
|
||||||
lab->lab_offset.p_y,
|
lab->lab_offset.p_y,
|
||||||
directionNames[lab->lab_just],
|
directionNames[lab->lab_just],
|
||||||
|
(lab->lab_flags & LABEL_STICKY) ? "-" : "",
|
||||||
DBTypeLongName(lab->lab_type));
|
DBTypeLongName(lab->lab_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lab->lab_flags & LABEL_STICKY)
|
|
||||||
{
|
|
||||||
fprintf(f, "select area label\n");
|
|
||||||
fprintf(f, "setlabel sticky true\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lab->lab_flags & PORT_DIR_MASK)
|
if (lab->lab_flags & PORT_DIR_MASK)
|
||||||
{
|
{
|
||||||
if (!(lab->lab_flags & LABEL_STICKY))
|
if (!(lab->lab_flags & LABEL_STICKY))
|
||||||
|
|
@ -4395,6 +4542,12 @@ ioerror:
|
||||||
* Callback function used by DBCellWriteCommandFile() to output
|
* Callback function used by DBCellWriteCommandFile() to output
|
||||||
* commands corresponding to cell layout geometry.
|
* commands corresponding to cell layout geometry.
|
||||||
*
|
*
|
||||||
|
* Results:
|
||||||
|
* 0 to keep the search going.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* Writes output to a file.
|
||||||
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -4460,6 +4613,12 @@ dbWritePaintCommandsFunc(tile, dinfo, cdarg)
|
||||||
* Callback function used by DBCellWriteCommandFile() to output
|
* Callback function used by DBCellWriteCommandFile() to output
|
||||||
* commands corresponding to cell uses in the layout.
|
* commands corresponding to cell uses in the layout.
|
||||||
*
|
*
|
||||||
|
* Results:
|
||||||
|
* 0 to keep the search going.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* Writes output to a file.
|
||||||
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -4479,6 +4638,45 @@ dbWriteUseCommandsFunc(cellUse, cdarg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* dbWritePropCommandPaintFunc --
|
||||||
|
*
|
||||||
|
* Transform tiles in a plane into a set of four coordinate values and output
|
||||||
|
* them to the file. This turns plane data into a PROP_TYPE_DIMENSION array,
|
||||||
|
* which is not a very efficient form and may be revisited. For relatively
|
||||||
|
* simple plane data, it suffices. The property planes are single-bit types.
|
||||||
|
* Note that there is no support for non-Manhattan geometry in the property
|
||||||
|
* plane at this time.
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* 0 to keep the search going.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* Writes output to a file.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
dbWritePropCommandPaintFunc(Tile *tile,
|
||||||
|
TileType dinfo,
|
||||||
|
FILE *f)
|
||||||
|
{
|
||||||
|
Rect r;
|
||||||
|
MagWindow *w;
|
||||||
|
|
||||||
|
TiToRect(tile, &r);
|
||||||
|
windCheckOnlyWindow(&w, DBWclientID);
|
||||||
|
fprintf(f, "%s ", DBWPrintValue(r.r_xbot, w, TRUE));
|
||||||
|
fprintf(f, "%s ", DBWPrintValue(r.r_ybot, w, FALSE));
|
||||||
|
fprintf(f, "%s ", DBWPrintValue(r.r_xtop, w, TRUE));
|
||||||
|
fprintf(f, "%s ", DBWPrintValue(r.r_ytop, w, FALSE));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -4487,6 +4685,12 @@ dbWriteUseCommandsFunc(cellUse, cdarg)
|
||||||
* Callback function used by DBCellWriteCommandFile() to output
|
* Callback function used by DBCellWriteCommandFile() to output
|
||||||
* commands corresponding to properties in the layout.
|
* commands corresponding to properties in the layout.
|
||||||
*
|
*
|
||||||
|
* Results:
|
||||||
|
* 0 to keep the search going.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* Writes output to a file.
|
||||||
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -4540,6 +4744,19 @@ dbWritePropCommandsFunc(key, proprec, cdarg)
|
||||||
fprintf(f, "\n");
|
fprintf(f, "\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PROPERTY_TYPE_PLANE:
|
||||||
|
/* Plane properties are automatically handled as plane data,
|
||||||
|
* so the property type does not need to be declared.
|
||||||
|
* Only mask hints can be plane properties.
|
||||||
|
*/
|
||||||
|
fprintf(f, "property %s ", key);
|
||||||
|
DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||||
|
proprec->prop_value.prop_plane,
|
||||||
|
&TiPlaneRect, &CIFSolidBits, dbWritePropCommandPaintFunc,
|
||||||
|
(ClientData)f);
|
||||||
|
fprintf(f, "\n");
|
||||||
|
break;
|
||||||
|
|
||||||
case PROPERTY_TYPE_DOUBLE:
|
case PROPERTY_TYPE_DOUBLE:
|
||||||
fprintf(f, "property double %s ", key);
|
fprintf(f, "property double %s ", key);
|
||||||
for (i = 0; i < proprec->prop_len; i++)
|
for (i = 0; i < proprec->prop_len; i++)
|
||||||
|
|
@ -4573,7 +4790,6 @@ dbWritePropCommandsFunc(key, proprec, cdarg)
|
||||||
* the file. If successful, rewind the now-expanded file and
|
* the file. If successful, rewind the now-expanded file and
|
||||||
* overwrite the beginning of the file, then truncate it.
|
* overwrite the beginning of the file, then truncate it.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* Results:
|
* Results:
|
||||||
* TRUE if the cell could be written successfully, FALSE otherwise.
|
* TRUE if the cell could be written successfully, FALSE otherwise.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -574,7 +574,8 @@ 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
|
* that is *not* the label type, and return the label area adjusted to leave
|
||||||
|
* 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.
|
||||||
|
|
@ -604,6 +605,26 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -661,28 +682,37 @@ 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);
|
|
||||||
|
|
||||||
r = lab->lab_rect;
|
/* If there is no material left inside the label area, then
|
||||||
DBSrPaintArea((Tile *) NULL, def->cd_planes[DBPlane(lab->lab_type)],
|
* the label gets reassigned to space.
|
||||||
&lab->lab_rect, &lmask, dbGetLabelArea, (ClientData) &r);
|
*/
|
||||||
|
if (DBSrPaintArea((Tile *) NULL, def->cd_planes[DBPlane(lab->lab_type)],
|
||||||
if (!GEO_RECTNULL(&r))
|
&lab->lab_rect, &lmask, dbLabelNotEmpty, (ClientData)NULL) == 1)
|
||||||
{
|
{
|
||||||
if ((DBVerbose >= DB_VERBOSE_ALL) && ((def->cd_flags & CDINTERNAL) == 0))
|
TTMaskCom(&lmask);
|
||||||
{
|
|
||||||
TxPrintf("Adjusting size of label \"%s\" in cell %s.\n",
|
|
||||||
lab->lab_text, def->cd_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
DBUndoEraseLabel(def, lab);
|
r = lab->lab_rect;
|
||||||
DBWLabelChanged(def, lab, DBW_ALLWINDOWS);
|
DBSrPaintArea((Tile *) NULL, def->cd_planes[DBPlane(lab->lab_type)],
|
||||||
lab->lab_rect = r;
|
&lab->lab_rect, &lmask, dbGetLabelArea, (ClientData) &r);
|
||||||
DBFontLabelSetBBox(lab);
|
|
||||||
DBUndoPutLabel(def, lab);
|
if (!GEO_RECTNULL(&r))
|
||||||
DBWLabelChanged(def, lab, DBW_ALLWINDOWS);
|
{
|
||||||
modified = TRUE;
|
if ((DBVerbose >= DB_VERBOSE_ALL) &&
|
||||||
adjusted = TRUE;
|
((def->cd_flags & CDINTERNAL) == 0))
|
||||||
|
{
|
||||||
|
TxPrintf("Adjusting size of label \"%s\" in cell %s.\n",
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,18 @@ DBPropPut(cellDef, name, value)
|
||||||
|
|
||||||
entry = HashFind(htab, name);
|
entry = HashFind(htab, name);
|
||||||
oldvalue = (PropertyRecord *)HashGetValue(entry);
|
oldvalue = (PropertyRecord *)HashGetValue(entry);
|
||||||
if (oldvalue != NULL) freeMagic((char *)oldvalue);
|
/* All properties are allocated as a single block and can just be freed,
|
||||||
|
* except for plane properties, which require freeing the plane.
|
||||||
|
*/
|
||||||
|
if (oldvalue != NULL)
|
||||||
|
{
|
||||||
|
if (oldvalue->prop_type == PROPERTY_TYPE_PLANE)
|
||||||
|
{
|
||||||
|
DBFreePaintPlane(oldvalue->prop_value.prop_plane);
|
||||||
|
TiFreePlane(oldvalue->prop_value.prop_plane);
|
||||||
|
}
|
||||||
|
freeMagic((char *)oldvalue);
|
||||||
|
}
|
||||||
if (value == (PropertyRecord *)NULL)
|
if (value == (PropertyRecord *)NULL)
|
||||||
HashRemove(htab, name);
|
HashRemove(htab, name);
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -238,9 +238,11 @@ DBUpdateStamps(def)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*ARGSUSED*/
|
||||||
int
|
int
|
||||||
dbStampFunc(cellDef)
|
dbStampFunc(cellDef, cdata)
|
||||||
CellDef *cellDef;
|
CellDef *cellDef;
|
||||||
|
ClientData cdata; /* UNUSED */
|
||||||
{
|
{
|
||||||
CellUse *cu;
|
CellUse *cu;
|
||||||
CellDef *cd;
|
CellDef *cd;
|
||||||
|
|
|
||||||
|
|
@ -578,6 +578,20 @@ 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 */
|
||||||
|
|
@ -651,6 +665,7 @@ typedef struct treeFilter
|
||||||
#define TF_LABEL_ATTACH_NOT_SE 0x10 /* Same as above, ignore tile SE corner */
|
#define TF_LABEL_ATTACH_NOT_SE 0x10 /* Same as above, ignore tile SE corner */
|
||||||
#define TF_LABEL_ATTACH_NOT_SW 0x20 /* Same as above, ignore tile SW corner */
|
#define TF_LABEL_ATTACH_NOT_SW 0x20 /* Same as above, ignore tile SW corner */
|
||||||
#define TF_LABEL_ATTACH_CORNER 0x3C /* Mask of the four types above */
|
#define TF_LABEL_ATTACH_CORNER 0x3C /* Mask of the four types above */
|
||||||
|
#define TF_LABEL_REVERSE_SEARCH 0x40 /* Search children before parent */
|
||||||
|
|
||||||
/* To do: Make the tpath entries dynamically allocated */
|
/* To do: Make the tpath entries dynamically allocated */
|
||||||
#define FLATTERMSIZE 4096 /* Used for generating flattened labels */
|
#define FLATTERMSIZE 4096 /* Used for generating flattened labels */
|
||||||
|
|
@ -719,6 +734,7 @@ typedef struct
|
||||||
char prop_string[8]; /* For PROPERTY_TYPE_STRING */
|
char prop_string[8]; /* For PROPERTY_TYPE_STRING */
|
||||||
int prop_integer[2]; /* For PROPERTY_TYPE_INTEGER or _DIMENSION */
|
int prop_integer[2]; /* For PROPERTY_TYPE_INTEGER or _DIMENSION */
|
||||||
dlong prop_double[1]; /* For PROPERTY_TYPE_DOUBLE */
|
dlong prop_double[1]; /* For PROPERTY_TYPE_DOUBLE */
|
||||||
|
Plane *prop_plane; /* For PROPERTY_TYPE_PLANE */
|
||||||
} prop_value;
|
} prop_value;
|
||||||
} PropertyRecord;
|
} PropertyRecord;
|
||||||
|
|
||||||
|
|
@ -760,6 +776,7 @@ typedef struct
|
||||||
#define PROPERTY_TYPE_INTEGER 1 /* Fixed integer property */
|
#define PROPERTY_TYPE_INTEGER 1 /* Fixed integer property */
|
||||||
#define PROPERTY_TYPE_DIMENSION 2 /* Integer property that scales with units */
|
#define PROPERTY_TYPE_DIMENSION 2 /* Integer property that scales with units */
|
||||||
#define PROPERTY_TYPE_DOUBLE 3 /* Double-long integer (for file positions) */
|
#define PROPERTY_TYPE_DOUBLE 3 /* Double-long integer (for file positions) */
|
||||||
|
#define PROPERTY_TYPE_PLANE 4 /* A tile plane structure */
|
||||||
|
|
||||||
/* -------------------- Exported procedure headers -------------------- */
|
/* -------------------- Exported procedure headers -------------------- */
|
||||||
|
|
||||||
|
|
@ -1059,6 +1076,19 @@ extern unsigned char DBVerbose; /* If 0, don't print any messages */
|
||||||
#define DB_VERBOSE_WARN 2
|
#define DB_VERBOSE_WARN 2
|
||||||
#define DB_VERBOSE_ALL 3
|
#define DB_VERBOSE_ALL 3
|
||||||
|
|
||||||
|
/* ---------- Definitions for expanding/unexpanding cells --------------*/
|
||||||
|
|
||||||
|
/* Selection expansion flags */
|
||||||
|
#define DB_EXPAND_MASK 3 /* 1 = expand, 0 = unexpand, 2 = toggle */
|
||||||
|
#define DB_EXPAND_SURROUND_MASK 4 /* 1 = surround, 0 = touch */
|
||||||
|
|
||||||
|
/* Selection expansion values */
|
||||||
|
#define DB_EXPAND 0
|
||||||
|
#define DB_UNEXPAND 1
|
||||||
|
#define DB_EXPAND_TOGGLE 2
|
||||||
|
#define DB_EXPAND_SURROUND 4
|
||||||
|
#define DB_EXPAND_OVERLAP 0
|
||||||
|
|
||||||
/* ------------------ Exported technology variables ------------------- */
|
/* ------------------ Exported technology variables ------------------- */
|
||||||
|
|
||||||
/***
|
/***
|
||||||
|
|
|
||||||
|
|
@ -131,8 +131,11 @@ DBWAddButtonHandler(
|
||||||
for (i = 0; i < MAXBUTTONHANDLERS; i++)
|
for (i = 0; i < MAXBUTTONHANDLERS; i++)
|
||||||
{
|
{
|
||||||
if (dbwButtonHandlers[i] != NULL) continue;
|
if (dbwButtonHandlers[i] != NULL) continue;
|
||||||
(void) StrDup(&dbwButtonHandlers[i], name);
|
StrDup(&dbwButtonHandlers[i], name);
|
||||||
(void) StrDup(&dbwButtonDoc[i], doc);
|
if (doc != NULL)
|
||||||
|
StrDup(&dbwButtonDoc[i], doc);
|
||||||
|
else
|
||||||
|
dbwButtonDoc[i] = (char *)NULL;
|
||||||
dbwButtonProcs[i] = proc;
|
dbwButtonProcs[i] = proc;
|
||||||
dbwButtonCursors[i] = cursor;
|
dbwButtonCursors[i] = cursor;
|
||||||
return;
|
return;
|
||||||
|
|
@ -273,6 +276,37 @@ DBWGetButtonHandler()
|
||||||
return dbwButtonHandlers[dbwButtonCurrentIndex];
|
return dbwButtonHandlers[dbwButtonCurrentIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* DBWButtonHandlerIndex()
|
||||||
|
*
|
||||||
|
* Given a string, return the index of the button handler. If the
|
||||||
|
* string does not correspond to any button handler name, then
|
||||||
|
* return -1.
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* Index of button handler, if it exists; -1 otherwise.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* None.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
DBWButtonHandlerIndex(char *toolName)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAXBUTTONHANDLERS; i++)
|
||||||
|
{
|
||||||
|
if (dbwButtonHandlers[i] == NULL) return -1;
|
||||||
|
else if (!strcmp(toolName, dbwButtonHandlers[i])) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -294,7 +328,10 @@ DBWGetButtonHandler()
|
||||||
void
|
void
|
||||||
DBWPrintButtonDoc()
|
DBWPrintButtonDoc()
|
||||||
{
|
{
|
||||||
TxPrintf("%s", dbwButtonDoc[dbwButtonCurrentIndex]);
|
if (dbwButtonDoc[dbwButtonCurrentIndex])
|
||||||
|
TxPrintf("%s", dbwButtonDoc[dbwButtonCurrentIndex]);
|
||||||
|
else
|
||||||
|
TxPrintf("(no usage information)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,9 @@ extern void CmdAutoExtToSpice();
|
||||||
#else
|
#else
|
||||||
extern void CmdExtToSpice();
|
extern void CmdExtToSpice();
|
||||||
#endif
|
#endif
|
||||||
|
#else /* !MAGIC_WRAPPER */
|
||||||
|
extern void CmdExtToSim();
|
||||||
|
extern void CmdExtToSpice();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -568,8 +571,26 @@ 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 */
|
||||||
#endif /* MAGIC_WRAPPER */
|
#else /* !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
|
||||||
|
|
|
||||||
|
|
@ -421,7 +421,8 @@ DBWredisplay(w, rootArea, clipArea)
|
||||||
/* Set style information beforehand */
|
/* Set style information beforehand */
|
||||||
GrSetStuff(STYLE_LABEL);
|
GrSetStuff(STYLE_LABEL);
|
||||||
(void) DBTreeSrLabels(&scontext, &DBAllTypeBits, bitMask,
|
(void) DBTreeSrLabels(&scontext, &DBAllTypeBits, bitMask,
|
||||||
(TerminalPath *) NULL, TF_LABEL_DISPLAY | TF_LABEL_ATTACH,
|
(TerminalPath *) NULL,
|
||||||
|
TF_LABEL_DISPLAY | TF_LABEL_ATTACH | TF_LABEL_REVERSE_SEARCH,
|
||||||
dbwLabelFunc, (ClientData)(&crec->dbw_visibleLayers));
|
dbwLabelFunc, (ClientData)(&crec->dbw_visibleLayers));
|
||||||
GrClipTo(&rootClip);
|
GrClipTo(&rootClip);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -867,8 +867,11 @@ dbwelemGetTransform(use, transform, cdarg)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*ARGSUSED*/
|
||||||
int
|
int
|
||||||
dbwElementAlways1()
|
dbwElementAlways1(w, clientData)
|
||||||
|
MagWindow *w; /* UNUSED */
|
||||||
|
ClientData clientData; /* UNUSED */
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -531,8 +531,11 @@ dbwfbGetTransform(use, transform, cdarg)
|
||||||
* cell.
|
* cell.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*ARGSUSED*/
|
||||||
int
|
int
|
||||||
dbwfbWindFunc()
|
dbwfbWindFunc(w, clientData)
|
||||||
|
MagWindow *w; /* UNUSED */
|
||||||
|
ClientData clientData; /* UNUSED */
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -357,9 +357,11 @@ DBWHLRedrawPrepWindow(MagWindow *window, Rect *area)
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*ARGSUSED*/
|
||||||
int
|
int
|
||||||
DBWHLRedrawWind(window)
|
DBWHLRedrawWind(window, clientData)
|
||||||
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;
|
||||||
|
|
|
||||||
|
|
@ -546,12 +546,12 @@ DBWloadWindow(window, name, flags)
|
||||||
newEditUse = DBCellNewUse(newEditDef, (char *) NULL);
|
newEditUse = DBCellNewUse(newEditDef, (char *) NULL);
|
||||||
(void) StrDup(&(newEditUse->cu_id), "Topmost cell in the window");
|
(void) StrDup(&(newEditUse->cu_id), "Topmost cell in the window");
|
||||||
DBExpand(newEditUse,
|
DBExpand(newEditUse,
|
||||||
((DBWclientRec *)window->w_clientData)->dbw_bitmask, TRUE);
|
((DBWclientRec *)window->w_clientData)->dbw_bitmask, DB_EXPAND);
|
||||||
|
|
||||||
if (expand)
|
if (expand)
|
||||||
DBExpandAll(newEditUse, &(newEditUse->cu_bbox),
|
DBExpandAll(newEditUse, &(newEditUse->cu_bbox),
|
||||||
((DBWclientRec *)window->w_clientData)->dbw_bitmask,
|
((DBWclientRec *)window->w_clientData)->dbw_bitmask,
|
||||||
FALSE, UnexpandFunc,
|
DB_UNEXPAND, UnexpandFunc,
|
||||||
INT2CD(((DBWclientRec *)window->w_clientData)->dbw_bitmask));
|
INT2CD(((DBWclientRec *)window->w_clientData)->dbw_bitmask));
|
||||||
|
|
||||||
if (newEdit)
|
if (newEdit)
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,7 @@ extern void DBWAddButtonHandler(const char *name, const cb_database_buttonhandle
|
||||||
int cursor, const char *doc);
|
int cursor, const char *doc);
|
||||||
extern char *DBWGetButtonHandler();
|
extern char *DBWGetButtonHandler();
|
||||||
extern char *DBWChangeButtonHandler();
|
extern char *DBWChangeButtonHandler();
|
||||||
|
extern int DBWButtonHandlerIndex();
|
||||||
extern void DBWPrintButtonDoc();
|
extern void DBWPrintButtonDoc();
|
||||||
extern void DBWBoxHandler();
|
extern void DBWBoxHandler();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,12 +71,15 @@ Operations on cell definitions.
|
||||||
<DT> <B>rename</B> <I>name newname</I>
|
<DT> <B>rename</B> <I>name newname</I>
|
||||||
<DD> Change the name of the cell definition <I>name</I> to
|
<DD> Change the name of the cell definition <I>name</I> to
|
||||||
<I>newname</I>.
|
<I>newname</I>.
|
||||||
<DT> <B>delete</B> <I>name</I>
|
<DT> <B>delete</B> <I>name</I> [<B>-noprompt</B>]
|
||||||
<DD> Delete the cell definition with name <I>name</I>. If cell
|
<DD> Delete the cell definition with name <I>name</I>. If cell
|
||||||
<I>name</I> is a descendent of another cell, the command
|
<I>name</I> is a descendent of another cell, the command
|
||||||
will be prohibited. If the cell <I>name</I> is currently
|
will be prohibited. If the cell <I>name</I> is currently
|
||||||
the topmost cell in the window, the window will be loaded
|
the topmost cell in the window, the window will be loaded
|
||||||
with default cell "(UNNAMED)".
|
with default cell "(UNNAMED)". If option <B>-noprompt</B>
|
||||||
|
is specified, then the actions specified above happen
|
||||||
|
immediately. Otherwise, a dialog box will be raised
|
||||||
|
asking for confirmation to delete the cell.
|
||||||
<DT> <B>dereference</B> <I>name</I>
|
<DT> <B>dereference</B> <I>name</I>
|
||||||
<DD> Perform a flush of the cell (per the "<B>flush</B>" command),
|
<DD> Perform a flush of the cell (per the "<B>flush</B>" command),
|
||||||
first removing any file path associated with the cell, so
|
first removing any file path associated with the cell, so
|
||||||
|
|
|
||||||
|
|
@ -334,23 +334,23 @@
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
<TD> <A HREF=undo.html> <B>undo</B></A> </TD>
|
<TD> <A HREF=undo.html> <B>undo</B></A> </TD>
|
||||||
<TD> <A HREF=units.html> <B>units</B></A> </TD>
|
|
||||||
<TD> <A HREF=updatedisplay.html> <B>updatedisplay</B></A> </TD>
|
<TD> <A HREF=updatedisplay.html> <B>updatedisplay</B></A> </TD>
|
||||||
|
<TD> <A HREF=version.html> <B>version</B></A> </TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
<TD> <A HREF=version.html> <B>version</B></A> </TD>
|
|
||||||
<TD> <A HREF=view.html> <B>view</B></A> </TD>
|
<TD> <A HREF=view.html> <B>view</B></A> </TD>
|
||||||
<TD> <A HREF=windowborder.html> <B>windowborder</B></A> </TD>
|
<TD> <A HREF=windowborder.html> <B>windowborder</B></A> </TD>
|
||||||
|
<TD> <A HREF=windowcaption.html> <B>windowcaption</B></A> </TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
<TD> <A HREF=windowcaption.html> <B>windowcaption</B></A> </TD>
|
|
||||||
<TD> <A HREF=windownames.html> <B>windownames</B></A> </TD>
|
<TD> <A HREF=windownames.html> <B>windownames</B></A> </TD>
|
||||||
<TD> <A HREF=windowscrollbars.html> <B>windowscrollbars</B></A> </TD>
|
<TD> <A HREF=windowscrollbars.html> <B>windowscrollbars</B></A> </TD>
|
||||||
|
<TD> <A HREF=xview.html> <B>xview</B></A> </TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
<TD> <A HREF=xview.html> <B>xview</B></A> </TD>
|
|
||||||
<TD> <A HREF=zoom.html> <B>zoom</B></A> </TD>
|
<TD> <A HREF=zoom.html> <B>zoom</B></A> </TD>
|
||||||
<TD> <A HREF=tk_path_name.html> <I>tk_path_name</I></A> </TD>
|
<TD> <A HREF=tk_path_name.html> <I>tk_path_name</I></A> </TD>
|
||||||
|
<TD> </TD>
|
||||||
</TR>
|
</TR>
|
||||||
</TBODY>
|
</TBODY>
|
||||||
</TABLE>
|
</TABLE>
|
||||||
|
|
@ -367,7 +367,7 @@
|
||||||
<TD> <A HREF=antennacheck.html> <B>antennacheck</B></A></TD>
|
<TD> <A HREF=antennacheck.html> <B>antennacheck</B></A></TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
<TD> <A HREF=archive.html> <B>array</B></A></TD>
|
<TD> <A HREF=archive.html> <B>archive</B></A></TD>
|
||||||
<TD> <A HREF=array.html> <B>array</B></A></TD>
|
<TD> <A HREF=array.html> <B>array</B></A></TD>
|
||||||
<TD> <A HREF=box.html> <B>box</B></A></TD>
|
<TD> <A HREF=box.html> <B>box</B></A></TD>
|
||||||
</TR>
|
</TR>
|
||||||
|
|
@ -402,28 +402,28 @@
|
||||||
<TD> <A HREF=deletecommandentry.html> <B>deletecommandentry</B></A></TD>
|
<TD> <A HREF=deletecommandentry.html> <B>deletecommandentry</B></A></TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
|
<TD> <A HREF=display.html> <B>display</B></A></TD>
|
||||||
<TD> <A HREF=down.html> <B>down</B></A></TD>
|
<TD> <A HREF=down.html> <B>down</B></A></TD>
|
||||||
<TD> <A HREF=drc.html> <B>drc</B></A></TD>
|
<TD> <A HREF=drc.html> <B>drc</B></A></TD>
|
||||||
<TD> <A HREF=dump.html> <B>dump</B></A></TD>
|
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
|
<TD> <A HREF=drop.html> <B>drop</B></A></TD>
|
||||||
|
<TD> <A HREF=dump.html> <B>dump</B></A></TD>
|
||||||
<TD> <A HREF=edit.html> <B>edit</B></A></TD>
|
<TD> <A HREF=edit.html> <B>edit</B></A></TD>
|
||||||
|
</TR>
|
||||||
|
<TR>
|
||||||
<TD> <A HREF=element.html> <B>element</B></A></TD>
|
<TD> <A HREF=element.html> <B>element</B></A></TD>
|
||||||
<TD> <A HREF=erase.html> <B>erase</B></A></TD>
|
<TD> <A HREF=erase.html> <B>erase</B></A></TD>
|
||||||
|
<TD> <A HREF=expand.html> <B>expand</B></A></TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
<TD> <A HREF=expand.html> <B>expand</B></A></TD>
|
|
||||||
<TD> <A HREF=ext.html> <B>ext</B></A></TD>
|
<TD> <A HREF=ext.html> <B>ext</B></A></TD>
|
||||||
<TD> <A HREF=ext2sim.html> <B>ext2sim</B></A></TD>
|
<TD> <A HREF=ext2sim.html> <B>ext2sim</B></A></TD>
|
||||||
|
<TD> <A HREF=ext2spice.html> <B>ext2spice</B></A></TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
<TD> <A HREF=ext2spice.html> <B>ext2spice</B></A></TD>
|
|
||||||
<TD> <A HREF=extract.html> <B>extract</B></A></TD>
|
<TD> <A HREF=extract.html> <B>extract</B></A></TD>
|
||||||
<TD> <A HREF=extresist.html> <B>extresist</B></A></TD>
|
<TD> <A HREF=extresist.html> <B>extresist</B></A></TD>
|
||||||
</TR>
|
|
||||||
<TR>
|
|
||||||
<TD> <A HREF=ext2sim.html> <B>exttosim</B></A></TD>
|
|
||||||
<TD> <A HREF=ext2spice.html> <B>exttospice</B></A></TD>
|
|
||||||
<TD> <A HREF=feedback.html> <B>feedback</B></A></TD>
|
<TD> <A HREF=feedback.html> <B>feedback</B></A></TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
|
|
@ -462,77 +462,82 @@
|
||||||
<TD> <A HREF=load.html> <B>load</B></A></TD>
|
<TD> <A HREF=load.html> <B>load</B></A></TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
|
<TD> <A HREF=locking.html> <B>locking</B></A></TD>
|
||||||
<TD> <A HREF=maketoolbar.html> <B>maketoolbar</B></A></TD>
|
<TD> <A HREF=maketoolbar.html> <B>maketoolbar</B></A></TD>
|
||||||
<TD> <A HREF=move.html> <B>move</B></A></TD>
|
|
||||||
<TD> <A HREF=measure.html> <B>measure</B></A></TD>
|
<TD> <A HREF=measure.html> <B>measure</B></A></TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
|
<TD> <A HREF=move.html> <B>move</B></A></TD>
|
||||||
<TD> <A HREF=openwrapper.html> <B>openwrapper</B></A></TD>
|
<TD> <A HREF=openwrapper.html> <B>openwrapper</B></A></TD>
|
||||||
<TD> <A HREF=paint.html> <B>paint</B></A></TD>
|
<TD> <A HREF=paint.html> <B>paint</B></A></TD>
|
||||||
<TD> <A HREF=path.html> <B>path</B></A></TD>
|
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
|
<TD> <A HREF=path.html> <B>path</B></A></TD>
|
||||||
<TD> <A HREF=peekbox.html> <B>peekbox</B></A></TD>
|
<TD> <A HREF=peekbox.html> <B>peekbox</B></A></TD>
|
||||||
<TD> <A HREF=plot.html> <B>plot</B></A></TD>
|
<TD> <A HREF=plot.html> <B>plot</B></A></TD>
|
||||||
<TD> <A HREF=plow.html> <B>plow</B></A></TD>
|
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
|
<TD> <A HREF=plow.html> <B>plow</B></A></TD>
|
||||||
<TD> <A HREF=polygon.html> <B>polygon</B></A></TD>
|
<TD> <A HREF=polygon.html> <B>polygon</B></A></TD>
|
||||||
<TD> <A HREF=popbox.html> <B>popbox</B></A></TD>
|
<TD> <A HREF=popbox.html> <B>popbox</B></A></TD>
|
||||||
<TD> <A HREF=popstack.html> <B>popstack</B></A></TD>
|
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
|
<TD> <A HREF=popstack.html> <B>popstack</B></A></TD>
|
||||||
<TD> <A HREF=port.html> <B>port</B></A></TD>
|
<TD> <A HREF=port.html> <B>port</B></A></TD>
|
||||||
<TD> <A HREF=promptload.html> <B>promptload</B></A></TD>
|
<TD> <A HREF=promptload.html> <B>promptload</B></A></TD>
|
||||||
<TD> <A HREF=promptsave.html> <B>promptsave</B></A></TD>
|
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
|
<TD> <A HREF=promptsave.html> <B>promptsave</B></A></TD>
|
||||||
<TD> <A HREF=property.html> <B>property</B></A></TD>
|
<TD> <A HREF=property.html> <B>property</B></A></TD>
|
||||||
<TD> <A HREF=pushbox.html> <B>pushbox</B></A></TD>
|
<TD> <A HREF=pushbox.html> <B>pushbox</B></A></TD>
|
||||||
<TD> <A HREF=pushstack.html> <B>pushstack</B></A></TD>
|
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
|
<TD> <A HREF=pushstack.html> <B>pushstack</B></A></TD>
|
||||||
|
<TD> <A HREF=readspice.html> <B>readspice</B></A></TD>
|
||||||
<TD> <A HREF=render3d.html> <B>render3d</B></A></TD>
|
<TD> <A HREF=render3d.html> <B>render3d</B></A></TD>
|
||||||
|
</TR>
|
||||||
|
<TR>
|
||||||
<TD> <A HREF=resumeall.html> <B>resumeall</B></A></TD>
|
<TD> <A HREF=resumeall.html> <B>resumeall</B></A></TD>
|
||||||
<TD> <A HREF=rotate.html> <B>rotate</B></A></TD>
|
<TD> <A HREF=rotate.html> <B>rotate</B></A></TD>
|
||||||
|
<TD> <A HREF=route.html> <B>route</B></A></TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
<TD> <A HREF=route.html> <B>route</B></A></TD>
|
|
||||||
<TD> <A HREF=save.html> <B>save</B></A></TD>
|
<TD> <A HREF=save.html> <B>save</B></A></TD>
|
||||||
<TD> <A HREF=scalegrid.html> <B>scalegrid</B></A></TD>
|
<TD> <A HREF=scalegrid.html> <B>scalegrid</B></A></TD>
|
||||||
|
<TD> <A HREF=search.html> <B>search</B></A></TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
<TD> <A HREF=search.html> <B>search</B></A></TD>
|
|
||||||
<TD> <A HREF=see.html> <B>see</B></A></TD>
|
<TD> <A HREF=see.html> <B>see</B></A></TD>
|
||||||
<TD> <A HREF=select.html> <B>select</B></A></TD>
|
<TD> <A HREF=select.html> <B>select</B></A></TD>
|
||||||
|
<TD> <A HREF=setlabel.html> <B>setlabel</B> <I>(version 8.0)</I></A></TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
<TD> <A HREF=setlabel.html> <B>setlabel</B> <I>(version 8.0)</I></A></TD>
|
|
||||||
<TD> <A HREF=shell.html> <B>shell</B></A></TD>
|
<TD> <A HREF=shell.html> <B>shell</B></A></TD>
|
||||||
<TD> <A HREF=sideways.html> <B>sideways</B></A></TD>
|
<TD> <A HREF=sideways.html> <B>sideways</B></A></TD>
|
||||||
|
<TD> <A HREF=snap.html> <B>snap</B></A></TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
<TD> <A HREF=snap.html> <B>snap</B></A></TD>
|
|
||||||
<TD> <A HREF=spliterase.html> <B>spliterase</B></A></TD>
|
<TD> <A HREF=spliterase.html> <B>spliterase</B></A></TD>
|
||||||
<TD> <A HREF=splitpaint.html> <B>splitpaint</B></A></TD>
|
<TD> <A HREF=splitpaint.html> <B>splitpaint</B></A></TD>
|
||||||
|
<TD> <A HREF=startup.html> <B>startup</B></A></TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
<TD> <A HREF=startup.html> <B>startup</B></A></TD>
|
|
||||||
<TD> <A HREF=straighten.html> <B>straighten</B></A></TD>
|
<TD> <A HREF=straighten.html> <B>straighten</B></A></TD>
|
||||||
<TD> <A HREF=stretch.html> <B>stretch</B></A></TD>
|
<TD> <A HREF=stretch.html> <B>stretch</B></A></TD>
|
||||||
|
<TD> <A HREF=suspendall.html> <B>suspendall</B></A></TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
<TD> <A HREF=suspendall.html> <B>suspendall</B></A></TD>
|
|
||||||
<TD> <A HREF=tag.html> <B>tag</B></A></TD>
|
<TD> <A HREF=tag.html> <B>tag</B></A></TD>
|
||||||
<TD> <A HREF=tech.html> <B>tech</B></A></TD>
|
<TD> <A HREF=tech.html> <B>tech</B></A></TD>
|
||||||
|
<TD> <A HREF=techmanager.html> <B>techmanager</B></A></TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
<TD> <A HREF=techmanager.html> <B>techmanager</B></A></TD>
|
|
||||||
<TD> <A HREF=tool.html> <B>tool</B> <I>(non-Tcl version)</I></A></TD>
|
<TD> <A HREF=tool.html> <B>tool</B> <I>(non-Tcl version)</I></A></TD>
|
||||||
<TD> <A HREF=changetool.html> <B>tool</B> <I>(Tcl version)</I></A></TD>
|
<TD> <A HREF=changetool.html> <B>tool</B> <I>(Tcl version)</I></A></TD>
|
||||||
|
<TD> <A HREF=unexpand.html> <B>unexpand</B></A></TD>
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
<TD> <A HREF=unexpand.html> <B>unexpand</B></A></TD>
|
<TD> <A HREF=units.html> <B>units</B></A> </TD>
|
||||||
<TD> <A HREF=unmeasure.html> <B>unmeasure</B></A></TD>
|
<TD> <A HREF=unmeasure.html> <B>unmeasure</B></A></TD>
|
||||||
<TD> <A HREF=upsidedown.html> <B>upsidedown</B></A></TD>
|
<TD> <A HREF=upsidedown.html> <B>upsidedown</B></A></TD>
|
||||||
</TR>
|
</TR>
|
||||||
|
|
@ -543,7 +548,7 @@
|
||||||
</TR>
|
</TR>
|
||||||
<TR>
|
<TR>
|
||||||
<TD> <A HREF=xload.html> <B>xload</B></A></TD>
|
<TD> <A HREF=xload.html> <B>xload</B></A></TD>
|
||||||
<TD> </TD>
|
<TD> <A HREF=xor.html> <B>xor</B></A></TD>
|
||||||
<TD> </TD>
|
<TD> </TD>
|
||||||
</TR>
|
</TR>
|
||||||
</TBODY>
|
</TBODY>
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,8 @@ expanded/unexpanded cells in the current selection.
|
||||||
|
|
||||||
<H3>Usage:</H3>
|
<H3>Usage:</H3>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<B>expand</B> [<B>toggle</B>] <BR><BR>
|
<B>expand</B> [<B>selection</B>|<B>surround</B>|<B>overlap</B>|<B>all</B>]
|
||||||
|
[<B>toggle</B>] <BR><BR>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H3>Shortcuts:</H3>
|
<H3>Shortcuts:</H3>
|
||||||
|
|
@ -38,14 +39,32 @@ expanded/unexpanded cells in the current selection.
|
||||||
<H3>Summary:</H3>
|
<H3>Summary:</H3>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
The <B>expand</B> command expands the view of subcells to
|
The <B>expand</B> command expands the view of subcells to
|
||||||
display the contents of the subcells. Without arguments,
|
display the contents of the subcells.
|
||||||
the <B>expand</B> command expands all unexpanded subcells that
|
|
||||||
touch or intersect the cursor box in the layout window. <P>
|
Option <B>overlap</B> expands all unexpanded subcells that
|
||||||
|
overlap with the cursor box in the layout window. <P>
|
||||||
|
|
||||||
|
Option <B>surround</B> expands all unexpanded subcells that
|
||||||
|
are completely surrounded by the cursor box in the layout window. <P>
|
||||||
|
|
||||||
|
Option <B>all</B> expands all subcells in the layout window. <P>
|
||||||
|
|
||||||
|
Option <B>selection</B> operates on the current selection, not
|
||||||
|
relative to the cursor box, expanding all selected cells. <P>
|
||||||
|
|
||||||
|
Option <B>toggle</B> will expand a selected cell that is
|
||||||
|
unexpanded, or unexpand a cell that is already expanded.
|
||||||
|
<B>toggle</B> may be given as an additional option to any
|
||||||
|
of the other options above; however, the <B>toggle</B> option
|
||||||
|
must be the last option given to the command.<P>
|
||||||
|
|
||||||
|
With no arguments, the <B>expand</B> command behaves like
|
||||||
|
<B>expand overlap</B>, and the <B>expand toggle</B> command
|
||||||
|
with no additonal arguments behaves like
|
||||||
|
<B>expand selection toggle</B>, for backwards-compatible
|
||||||
|
behavior with earlier versions of magic which offered only
|
||||||
|
the <B>toggle</B> option.
|
||||||
|
|
||||||
Option <B>expand toggle</B> operates on the current selection,
|
|
||||||
not relative to the cursor box, and will expand a selected
|
|
||||||
cell that is unexpanded, or unexpand a cell that is already
|
|
||||||
expanded.
|
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H3>Implementation Notes:</H3>
|
<H3>Implementation Notes:</H3>
|
||||||
|
|
|
||||||
|
|
@ -102,16 +102,17 @@ 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>
|
<DT> <B>unique</B> [<B>notopports</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". Instead
|
the use of the command option "extract unique" (and
|
||||||
of changing labels in the design, unique labels are
|
"extract unique notopports"). Instead of changing labels
|
||||||
generated for the duration of the extraction, and then
|
in the design, unique labels are generated for the duration
|
||||||
reverted back to the original text. The "extract unique"
|
of the extraction, and then reverted back to the original
|
||||||
command option is maintained for backwards compatibility.
|
text. The "extract unique" command option is maintained
|
||||||
Note the difference: "extract unique" is a command that
|
for backwards compatibility. Note the difference:
|
||||||
runs immediately, and cannot be undone;
|
"extract unique" is a command that runs immediately, and
|
||||||
"extract do unique" is an option setting for "extract".
|
cannot be undone; "extract do unique" is an option setting
|
||||||
|
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,11 +30,30 @@ 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>]
|
||||||
|
|
@ -42,7 +61,9 @@ 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 net statistics.
|
<DD> Turn off/on printing of nets being processed.
|
||||||
|
<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>]
|
||||||
|
|
@ -69,6 +90,8 @@ 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>
|
||||||
|
|
@ -79,9 +102,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. Extraction for digital simulation
|
impedence through the wires. Standard extraction generates "lumped
|
||||||
using <B>irsim</B> generates "lumped resistances", a single
|
resistance" values, a single resistance per network node that, along
|
||||||
resistance per network node that, along with the node capacitance
|
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)
|
||||||
|
|
@ -96,10 +119,9 @@ 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.
|
the initial netlist. After a <TT>.ext</TT> file has been generated,
|
||||||
After a <TT>.ext</TT> file has been generated, the
|
the <B>extresist</B> command may be run. The output is a file
|
||||||
<B>extresist</B> command may be run. The output is
|
<TT>.res.ext</TT> for each cell in the hierarchy.
|
||||||
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>
|
||||||
|
|
||||||
|
|
@ -110,7 +132,42 @@ 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.
|
files. When <B>extract do resistance</B> is used, there is no need
|
||||||
|
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.
|
||||||
|
|
@ -134,6 +191,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> October 4, 2021 at 3:32pm <P>
|
<P><I>Last updated:</I> May 29, 2026 at 11:33am <P>
|
||||||
</BODY>
|
</BODY>
|
||||||
</HTML>
|
</HTML>
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,50 @@ Place a label in the layout
|
||||||
to another layer. <P>
|
to another layer. <P>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<B>Attribute labels:</B> <P>
|
||||||
|
A handful of labels are referred to as "attribute" labels. These
|
||||||
|
label types are placed on devices and affect how the device is
|
||||||
|
extracted. <P>
|
||||||
|
|
||||||
|
A label that is placed inside a device (e.g., a MOSFET gate) which
|
||||||
|
ends with the character "<B>^</B>" is a <I>gate attribute</I>. A
|
||||||
|
gate attribute in the form of "<I>name</I><B>=</B><I>value</I><B>^</B>"
|
||||||
|
specifies an extra parameter to be passed to the device in addition
|
||||||
|
to the standard parameters calculated for that device. This is used
|
||||||
|
to capture parameters which cannot easily be inferred from the layout.
|
||||||
|
For example, an RF device model might be distinguished from a non-RF
|
||||||
|
device model by a parameter such as <B>rfmode=1</B>. Whether or not
|
||||||
|
a device is intended for RF use is not easily guessed from the layout,
|
||||||
|
and so "tagging" the gate with the parameter allows the correct model
|
||||||
|
parameters to be used for the device. <P>
|
||||||
|
|
||||||
|
A gate attribute that is not in the form of a parameter will be used
|
||||||
|
as the device's instance index in the netlist; e.g., a label of
|
||||||
|
"<B>1^</B>" on a MOSFET gate extracted as a MOSFET device would be an
|
||||||
|
entry "<B>M1</B>" in the netlist. This can be used to better track
|
||||||
|
device indexes between a schematic and layout. <P>
|
||||||
|
|
||||||
|
A label that is placed on the <I>edge</I> a device, specificlly a
|
||||||
|
MOSFET gate, and which ends with the character "<B>$</B>", is a
|
||||||
|
<I>terminal attribute</I>. The only terminal attributes recognized
|
||||||
|
by magic are <B>S$</B> and <B>D$</B>, which specify which side of the
|
||||||
|
gate is to be considered the source and which is to be considered the
|
||||||
|
drain. Generally, MOSFET devices are symmetric, and their use in a
|
||||||
|
simulation does not depend on which side is in the position of the
|
||||||
|
"source" and which is in the position of the "drain". To the extent
|
||||||
|
that it matters, the terminal attributes can be used to ensure that
|
||||||
|
the source and drain connections appear in the netlist in their
|
||||||
|
intended orientation. <P>
|
||||||
|
|
||||||
|
Labels ending with "<B>@</B>" are <I>node attributes</I>. There is
|
||||||
|
currently no functional application for node attributes. When one
|
||||||
|
is applied, it will appear in the output netlist in a SPICE comment
|
||||||
|
line indicating the node and attribute. This could be used, say,
|
||||||
|
by a post-processing script, but as it is in a comment line, it has
|
||||||
|
no impact on simulation or LVS.
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H3>Implementation Notes:</H3>
|
<H3>Implementation Notes:</H3>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<B>label</B> is implemented as a built-in command in <B>magic</B>.
|
<B>label</B> is implemented as a built-in command in <B>magic</B>.
|
||||||
|
|
|
||||||
|
|
@ -20,22 +20,64 @@
|
||||||
|
|
||||||
<H2>macro</H2>
|
<H2>macro</H2>
|
||||||
<HR>
|
<HR>
|
||||||
Define or print a macro called char
|
Define or print a key or button macro binding.
|
||||||
<HR>
|
<HR>
|
||||||
|
|
||||||
<H3>Usage:</H3>
|
<H3>Usage:</H3>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<B>macro</B> [<I>window_type</I>] [<I>key</I> [<I>value</I>]] <BR><BR>
|
<B>macro</B> [<I>window_type</I>] [<I>option</I>] [<I>key</I> [<I>value</I>]]
|
||||||
|
<BR><BR>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
where <I>key</I> is the name of a valid key (see below), and
|
where <I>key</I> is the name of a valid key (see below), and
|
||||||
<I>value</I> is a <B>magic</B> command-line command. If
|
<I>value</I> is a <B>magic</B> command-line command. If
|
||||||
present, <I>window_type</I> must be one of the four window
|
present, <I>window_type</I> must be one of the known valid window
|
||||||
types accepted by the <B>specialopen</B> command: <B>layout</B>,
|
types accepted by the <B>specialopen</B> command (<B>color</B>,
|
||||||
<B>color</B>, <B>netlist</B>, and <B>wind3d</B>. If omitted,
|
<B>netlist</B>, and <B>wind3d</B>), or a known layout tool
|
||||||
the layout window is assumed by default, unless the command has
|
(<B>box</B>, <B>wiring</B>, <B>nettool</B>, or <B>pick</B>). If
|
||||||
been called from inside a window (using the colon or semicolon
|
omitted, the layout window is assumed by default, unless the command
|
||||||
|
has been called from inside a window (using the colon or semicolon
|
||||||
escape to the command-line), in which case that window type is
|
escape to the command-line), in which case that window type is
|
||||||
assumed.
|
assumed. <P>
|
||||||
|
|
||||||
|
In the non-Tcl version of magic, the <I>window_type</I> must be
|
||||||
|
one of the three valid window types listed above, or <B>layout</B>.
|
||||||
|
Tool button bindings are hard-coded, fixed, and unknown to the
|
||||||
|
macro handler. <P>
|
||||||
|
|
||||||
|
In the Tcl version of magic, tool types are generated by
|
||||||
|
procedure and can be modified or overridden. The four tools
|
||||||
|
listed above are the default tools known to magic. If no window
|
||||||
|
or tool type is given, then the current tool in the current
|
||||||
|
active layout window is assumed.<P>
|
||||||
|
|
||||||
|
<I>option</I> may be one of the following:
|
||||||
|
<DL>
|
||||||
|
<DT> <B>list</B> [<B>-reverse</B>]
|
||||||
|
<DD> The key bindings are returned in the form of a Tcl list
|
||||||
|
(Tcl version of magic only). The returned value is a
|
||||||
|
single list with alternating entries of the macro key and
|
||||||
|
the macro binding. In Tcl, this list can be treated as a
|
||||||
|
dictionary type of key:value pairs. With the <B>-reverse</B>
|
||||||
|
option, the keys and values are reversed, resulting in a
|
||||||
|
dictionary that can be searched or listed by function.
|
||||||
|
<DT> <B>help</B>
|
||||||
|
<DD> Curently, <B>macro help</B> is equivalent to <B>macro</B>
|
||||||
|
without arguments, and returns a full list of macro names
|
||||||
|
and their bindings.
|
||||||
|
<DT> <B>search</B> <I>text</I>
|
||||||
|
<DD> Return only results which match (all or in part) the string
|
||||||
|
<I>text</I>. For example, <B>macro search grid</B> will
|
||||||
|
return all key bindings that include the command <B>grid</B>.
|
||||||
|
<DT> <B>copy</B> <I>tool_name</I>
|
||||||
|
<DD> This is a method introduced to allow the interactive creation
|
||||||
|
of new tools, in the Tcl version of magic. Each tool is defined
|
||||||
|
specifically by its unique button and key bindings. Because
|
||||||
|
tools generally keep most of the same default bindings, the
|
||||||
|
<B>copy</B> option will copy all the existing bindings to the
|
||||||
|
new tool from the current tool. This can be followed by
|
||||||
|
switching to the new tool and replacing macros with ones
|
||||||
|
unique to the tool.
|
||||||
|
</DL>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
@ -72,7 +114,6 @@ Define or print a macro called char
|
||||||
etc., the <B>macro</B> command accepts the abbreviated
|
etc., the <B>macro</B> command accepts the abbreviated
|
||||||
forms <B>Button1</B>, and so forth. <P>
|
forms <B>Button1</B>, and so forth. <P>
|
||||||
|
|
||||||
|
|
||||||
Finally, key modifiers may be prepended to the key name.
|
Finally, key modifiers may be prepended to the key name.
|
||||||
Valid key modifiers are <B>Shift_</B>, <B>Control_</B>,
|
Valid key modifiers are <B>Shift_</B>, <B>Control_</B>,
|
||||||
<B>Alt_</B>, and <B>Meta_</B>, and may be coupled in any
|
<B>Alt_</B>, and <B>Meta_</B>, and may be coupled in any
|
||||||
|
|
@ -89,6 +130,7 @@ Define or print a macro called char
|
||||||
<H3>See Also:</H3>
|
<H3>See Also:</H3>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<A HREF=imacro.html><B>imacro</B></A> <BR>
|
<A HREF=imacro.html><B>imacro</B></A> <BR>
|
||||||
|
<A HREF=toolchange.html><B>tool</B></A> (Tcl version) <BR>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<P><IMG SRC=graphics/line1.gif><P>
|
<P><IMG SRC=graphics/line1.gif><P>
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ Attach a "property" (string key and value pair) to the edit cell
|
||||||
|
|
||||||
<H3>Usage:</H3>
|
<H3>Usage:</H3>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<B>property</B> [<I>type</I>] [<I>key</I> [<I>value</I>]] <BR>
|
<B>property</B> [<I>list</I>] [<I>type</I>] [<I>key</I> [<I>value</I>]] <BR>
|
||||||
or
|
or
|
||||||
<B>property</B> [<B>compat</B>] [<B>true</B>|<B>false</B>] <BR><BR>
|
<B>property</B> [<B>compat</B>] [<B>true</B>|<B>false</B>] <BR><BR>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
|
|
@ -64,6 +64,13 @@ Attach a "property" (string key and value pair) to the edit cell
|
||||||
.mag file. However, if the user wants to create a property that
|
.mag file. However, if the user wants to create a property that
|
||||||
is handled differently than a string (namely, to be a dimensional
|
is handled differently than a string (namely, to be a dimensional
|
||||||
value that scales), then comptability mode should be turned off. <P>
|
value that scales), then comptability mode should be turned off. <P>
|
||||||
|
|
||||||
|
If the argument <I>list</I> is given as the first argument, and
|
||||||
|
<I>value</I> is not present, then if the property <I>key</I>
|
||||||
|
does not exist, then the command will return a NULL object to the
|
||||||
|
interpreter instead of printing an error message. This is the
|
||||||
|
"quiet" version of the command preferred for scripts that want to
|
||||||
|
query whether or not a specific property exists.
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,8 @@ Unexpand everything inside or touching the cursor box.
|
||||||
|
|
||||||
<H3>Usage:</H3>
|
<H3>Usage:</H3>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<B>unexpand</B> <BR><BR>
|
<B>unexpand</B> [<B>selection</B>|<B>surround</B>|<B>overlap</B>|<B>all</B>]
|
||||||
|
<BR><BR>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H3>Shortcuts:</H3>
|
<H3>Shortcuts:</H3>
|
||||||
|
|
@ -37,8 +38,23 @@ Unexpand everything inside or touching the cursor box.
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
The <B>unexpand</B> command unexpands the view of subcells to
|
The <B>unexpand</B> command unexpands the view of subcells to
|
||||||
hide the contents of the subcells and show the bounding box
|
hide the contents of the subcells and show the bounding box
|
||||||
outline only. The <B>unexpand</B> command unexpands all subcells
|
outline only.
|
||||||
that touch or intersect the cursor box in the layout window. <P>
|
|
||||||
|
Option <B>overlap</B> unexpands all expanded subcells that
|
||||||
|
overlap with the cursor box in the layout window. <P>
|
||||||
|
|
||||||
|
Option <B>surround</B> unexpands all expanded subcells that
|
||||||
|
are completely surrounded by the cursor box in the layout window. <P>
|
||||||
|
|
||||||
|
Option <B>all</B> unexpands all subcells in the layout window. <P>
|
||||||
|
|
||||||
|
Option <B>selection</B> operates on the current selection, not
|
||||||
|
relative to the cursor box, unexpanding all selected cells. <P>
|
||||||
|
|
||||||
|
With no arguments, the <B>unexpand</B> command behaves like
|
||||||
|
<B>unexpand surround</B>, for backwards-compatible behavior with
|
||||||
|
earlier versions of magic which did not offer the options.
|
||||||
|
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H3>Implementation Notes:</H3>
|
<H3>Implementation Notes:</H3>
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ extern int drcArrayYankFunc(), drcArrayOverlapFunc();
|
||||||
static DRCCookie drcArrayCookie = {
|
static DRCCookie drcArrayCookie = {
|
||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
{ {0} }, { {0} },
|
{ {0} }, { {0} },
|
||||||
0, 0, 0,
|
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||||
DRC_ARRAY_OVERLAP_TAG,
|
DRC_ARRAY_OVERLAP_TAG,
|
||||||
(DRCCookie *) NULL
|
(DRCCookie *) NULL
|
||||||
};
|
};
|
||||||
|
|
|
||||||
192
drc/DRCbasic.c
192
drc/DRCbasic.c
|
|
@ -27,6 +27,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h> // for memcpy()
|
#include <string.h> // for memcpy()
|
||||||
#include <math.h> // for sqrt() for diagonal check
|
#include <math.h> // for sqrt() for diagonal check
|
||||||
|
|
||||||
|
#include "tcltk/tclmagic.h"
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "tiles/tile.h"
|
#include "tiles/tile.h"
|
||||||
|
|
@ -36,7 +38,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
||||||
#include "utils/signals.h"
|
#include "utils/signals.h"
|
||||||
#include "utils/maxrect.h"
|
#include "utils/maxrect.h"
|
||||||
#include "utils/malloc.h"
|
#include "utils/malloc.h"
|
||||||
|
#include "utils/undo.h"
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
|
#include "cif/CIFint.h"
|
||||||
|
|
||||||
int dbDRCDebug = 0;
|
int dbDRCDebug = 0;
|
||||||
|
|
||||||
|
|
@ -48,7 +52,7 @@ int dbDRCDebug = 0;
|
||||||
static DRCCookie drcOverlapCookie = {
|
static DRCCookie drcOverlapCookie = {
|
||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
{ {0} }, { {0} },
|
{ {0} }, { {0} },
|
||||||
0, 0, 0,
|
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||||
DRC_OVERLAP_TAG,
|
DRC_OVERLAP_TAG,
|
||||||
(DRCCookie *) NULL
|
(DRCCookie *) NULL
|
||||||
};
|
};
|
||||||
|
|
@ -62,7 +66,33 @@ extern MaxRectsData *drcCanonicalMaxwidth();
|
||||||
/*
|
/*
|
||||||
*-----------------------------------------------------------------------
|
*-----------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* drcCifPointToSegment
|
* drcFoundOneFunc --
|
||||||
|
*
|
||||||
|
* Simple callback for a plane search on a mask-hint plane inside
|
||||||
|
* a DRC check area.
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* Return 1 always, indicating that a tile has been found in the
|
||||||
|
* DRC search area, and the search can end.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* None.
|
||||||
|
*
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
drcFoundOneFunc(Tile *tile,
|
||||||
|
TileType dinfo,
|
||||||
|
ClientData cdata)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* drcCifPointToSegment --
|
||||||
*
|
*
|
||||||
* Euclidean-distance point-to-segment distance (squared)
|
* Euclidean-distance point-to-segment distance (squared)
|
||||||
* calculation (borrowed from XCircuit)
|
* calculation (borrowed from XCircuit)
|
||||||
|
|
@ -468,12 +498,39 @@ DRCBasicCheck (celldef, checkRect, clipRect, function, cdata)
|
||||||
DBResetTilePlane(celldef->cd_planes[planeNum], DRC_UNPROCESSED);
|
DBResetTilePlane(celldef->cd_planes[planeNum], DRC_UNPROCESSED);
|
||||||
(void) DBSrPaintArea ((Tile *) NULL, celldef->cd_planes[planeNum],
|
(void) DBSrPaintArea ((Tile *) NULL, celldef->cd_planes[planeNum],
|
||||||
checkRect, &DBAllTypeBits, drcTile, (ClientData) &arg);
|
checkRect, &DBAllTypeBits, drcTile, (ClientData) &arg);
|
||||||
|
|
||||||
|
#ifdef MAGIC_WRAPPER
|
||||||
|
/* Execute pending Tcl events, so the DRC process doesn't block. */
|
||||||
|
|
||||||
|
/* WARNING: This code cannot be enabled until some method is
|
||||||
|
* worked out to determine if any event resulted in a change
|
||||||
|
* to the DRC check plane which would invalidate the current
|
||||||
|
* search. If so, the search must end immediately and the
|
||||||
|
* area being checked must be reinstated. The code was added
|
||||||
|
* to see how it speeds up the response time of magic when
|
||||||
|
* some of the DRC rules are compute-intensive. It speeds up
|
||||||
|
* performance enough that it is worthwhile to implement the
|
||||||
|
* method just mentioned.
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
UndoEnable();
|
||||||
|
while (Tcl_DoOneEvent(TCL_DONT_WAIT));
|
||||||
|
UndoDisable();
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
drcCifCheck(&arg);
|
drcCifCheck(&arg);
|
||||||
if (arg.dCD_rlist != NULL) freeMagic(arg.dCD_rlist);
|
if (arg.dCD_rlist != NULL) freeMagic(arg.dCD_rlist);
|
||||||
return (errors);
|
return (errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Expect that keeping around 3 MaxRectsData records should be sufficient
|
||||||
|
* to avoid recomputing drcCanonicalMaxwidth() multiple times. Note that
|
||||||
|
* if a PDK sets up multiple rules on an edge which all require running
|
||||||
|
* drcCanonicalMaxwidth(), then this cache size may need to be revisited.
|
||||||
|
*/
|
||||||
|
#define MAXRECTSCACHE 3
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -511,6 +568,19 @@ drcTile (tile, dinfo, arg)
|
||||||
int triggered;
|
int triggered;
|
||||||
int cdist, dist, ccdist, result;
|
int cdist, dist, ccdist, result;
|
||||||
|
|
||||||
|
/* Keep up to three MaxRectsData records to avoid doing the same
|
||||||
|
* expensive computation more than once.
|
||||||
|
*
|
||||||
|
* mrdcache[0] will be used for the tpleft tile, since it will never
|
||||||
|
* be reused. mrdcache[1] and mrdcache[2] will be used for the tile
|
||||||
|
* itself. Note that if more than 2 DRCCookie entries for the same
|
||||||
|
* edge require drcCanonicalMaxwidth(), then mrdcache[2] will be
|
||||||
|
* re-used so that at least mrdcache[1] is always a cache hit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static MaxRectsData *mrdcache[MAXRECTSCACHE] = {NULL, NULL, NULL};
|
||||||
|
DRCCookie *cptrcache;
|
||||||
|
|
||||||
arg->dCD_constraint = &errRect;
|
arg->dCD_constraint = &errRect;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -652,6 +722,8 @@ drcTile (tile, dinfo, arg)
|
||||||
DRCstatEdges++;
|
DRCstatEdges++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cptrcache = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check design rules along a vertical boundary between two tiles.
|
* Check design rules along a vertical boundary between two tiles.
|
||||||
*
|
*
|
||||||
|
|
@ -696,7 +768,6 @@ drcTile (tile, dinfo, arg)
|
||||||
int edgeX = LEFT(tile);
|
int edgeX = LEFT(tile);
|
||||||
|
|
||||||
firsttile = TRUE;
|
firsttile = TRUE;
|
||||||
mrd = NULL;
|
|
||||||
for (tpleft = BL(tile); BOTTOM(tpleft) < top; tpleft = RT(tpleft))
|
for (tpleft = BL(tile); BOTTOM(tpleft) < top; tpleft = RT(tpleft))
|
||||||
{
|
{
|
||||||
/* Get the tile types to the left and right of the edge */
|
/* Get the tile types to the left and right of the edge */
|
||||||
|
|
@ -727,6 +798,44 @@ drcTile (tile, dinfo, arg)
|
||||||
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
|
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
|
||||||
cptr = cptr->drcc_next)
|
cptr = cptr->drcc_next)
|
||||||
{
|
{
|
||||||
|
/* Handle rule exceptions and exemptions */
|
||||||
|
if (cptr->drcc_exception != DRC_EXCEPTION_NONE)
|
||||||
|
{
|
||||||
|
PropertyRecord *proprec;
|
||||||
|
bool propfound, isinside = FALSE;
|
||||||
|
char *name;
|
||||||
|
int idx = cptr->drcc_exception & ~DRC_EXCEPTION_MASK;
|
||||||
|
name = DRCCurStyle->DRCExceptionList[idx];
|
||||||
|
|
||||||
|
/* Is there any exception area defined? */
|
||||||
|
proprec = DBPropGet(arg->dCD_celldef, name, &propfound);
|
||||||
|
|
||||||
|
/* If an exception area exists, is the error edge inside? */
|
||||||
|
if (propfound)
|
||||||
|
{
|
||||||
|
Rect redge;
|
||||||
|
|
||||||
|
redge.r_xbot = redge.r_xtop = edgeX;
|
||||||
|
redge.r_ybot = edgeBot;
|
||||||
|
redge.r_ytop = edgeTop;
|
||||||
|
|
||||||
|
if (DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||||
|
proprec->prop_value.prop_plane,
|
||||||
|
&redge, &CIFSolidBits, drcFoundOneFunc,
|
||||||
|
(ClientData)NULL) == 1)
|
||||||
|
isinside = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exemption rules are ignored if the edge is inside
|
||||||
|
* an exception area. Exception rules are ignored if
|
||||||
|
* the edge is outside an exception area.
|
||||||
|
*/
|
||||||
|
if (!isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) == 0))
|
||||||
|
continue;
|
||||||
|
if (isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) != 0))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
|
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
|
||||||
/* the code above for non-Manhattan shapes and do not */
|
/* the code above for non-Manhattan shapes and do not */
|
||||||
/* need to be processed again. */
|
/* need to be processed again. */
|
||||||
|
|
@ -748,6 +857,7 @@ drcTile (tile, dinfo, arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
DRCstatRules++;
|
DRCstatRules++;
|
||||||
|
if (!triggered) mrd = NULL;
|
||||||
|
|
||||||
if (cptr->drcc_flags & DRC_AREA)
|
if (cptr->drcc_flags & DRC_AREA)
|
||||||
{
|
{
|
||||||
|
|
@ -769,12 +879,23 @@ drcTile (tile, dinfo, arg)
|
||||||
|
|
||||||
if (cptr->drcc_flags & DRC_REVERSE)
|
if (cptr->drcc_flags & DRC_REVERSE)
|
||||||
{
|
{
|
||||||
mrd = drcCanonicalMaxwidth(tpleft, GEO_WEST, arg, cptr);
|
mrd = drcCanonicalMaxwidth(tpleft, GEO_WEST, arg, cptr,
|
||||||
|
&mrdcache[0]);
|
||||||
triggered = 0;
|
triggered = 0;
|
||||||
}
|
}
|
||||||
else if (firsttile)
|
else
|
||||||
{
|
{
|
||||||
mrd = drcCanonicalMaxwidth(tile, GEO_EAST, arg, cptr);
|
if (cptrcache == NULL)
|
||||||
|
{
|
||||||
|
mrd = drcCanonicalMaxwidth(tile, GEO_EAST, arg, cptr,
|
||||||
|
&mrdcache[1]);
|
||||||
|
cptrcache = cptr;
|
||||||
|
}
|
||||||
|
else if (cptrcache != cptr)
|
||||||
|
mrd = drcCanonicalMaxwidth(tile, GEO_EAST, arg, cptr,
|
||||||
|
&mrdcache[2]);
|
||||||
|
else
|
||||||
|
mrd = (mrdcache[1]->entries == 0) ? NULL : mrdcache[1];
|
||||||
triggered = 0;
|
triggered = 0;
|
||||||
}
|
}
|
||||||
if (!trigpending || (DRCCurStyle->DRCFlags
|
if (!trigpending || (DRCCurStyle->DRCFlags
|
||||||
|
|
@ -1065,6 +1186,8 @@ drcTile (tile, dinfo, arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cptrcache = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check design rules along a horizontal boundary between two tiles.
|
* Check design rules along a horizontal boundary between two tiles.
|
||||||
*
|
*
|
||||||
|
|
@ -1104,7 +1227,6 @@ drcTile (tile, dinfo, arg)
|
||||||
|
|
||||||
/* Go right across bottom of tile */
|
/* Go right across bottom of tile */
|
||||||
firsttile = TRUE;
|
firsttile = TRUE;
|
||||||
mrd = NULL;
|
|
||||||
for (tpbot = LB(tile); LEFT(tpbot) < right; tpbot = TR(tpbot))
|
for (tpbot = LB(tile); LEFT(tpbot) < right; tpbot = TR(tpbot))
|
||||||
{
|
{
|
||||||
/* Get the tile types to the top and bottom of the edge */
|
/* Get the tile types to the top and bottom of the edge */
|
||||||
|
|
@ -1136,6 +1258,44 @@ drcTile (tile, dinfo, arg)
|
||||||
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
|
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
|
||||||
cptr = cptr->drcc_next)
|
cptr = cptr->drcc_next)
|
||||||
{
|
{
|
||||||
|
/* Handle rule exceptions and exemptions */
|
||||||
|
if (cptr->drcc_exception != DRC_EXCEPTION_NONE)
|
||||||
|
{
|
||||||
|
PropertyRecord *proprec;
|
||||||
|
bool propfound, isinside = FALSE;
|
||||||
|
char *name;
|
||||||
|
int idx = cptr->drcc_exception & ~DRC_EXCEPTION_MASK;
|
||||||
|
name = DRCCurStyle->DRCExceptionList[idx];
|
||||||
|
|
||||||
|
/* Is there any exception area defined? */
|
||||||
|
proprec = DBPropGet(arg->dCD_celldef, name, &propfound);
|
||||||
|
|
||||||
|
/* If an exception area exists, is the error edge inside? */
|
||||||
|
if (propfound)
|
||||||
|
{
|
||||||
|
Rect redge;
|
||||||
|
|
||||||
|
redge.r_ybot = redge.r_ytop = edgeY;
|
||||||
|
redge.r_xbot = edgeLeft;
|
||||||
|
redge.r_xtop = edgeRight;
|
||||||
|
|
||||||
|
if (DBSrPaintArea(PlaneGetHint(proprec->prop_value.prop_plane),
|
||||||
|
proprec->prop_value.prop_plane,
|
||||||
|
&redge, &CIFSolidBits, drcFoundOneFunc,
|
||||||
|
(ClientData)NULL) == 1)
|
||||||
|
isinside = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exemption rules are ignored if the edge is inside
|
||||||
|
* an exception area. Exception rules are ignored if
|
||||||
|
* the edge is outside an exception area.
|
||||||
|
*/
|
||||||
|
if (!isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) == 0))
|
||||||
|
continue;
|
||||||
|
if (isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) != 0))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
|
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
|
||||||
/* the code above for non-Manhattan shapes and do not */
|
/* the code above for non-Manhattan shapes and do not */
|
||||||
/* need to be processed again. */
|
/* need to be processed again. */
|
||||||
|
|
@ -1157,6 +1317,7 @@ drcTile (tile, dinfo, arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
DRCstatRules++;
|
DRCstatRules++;
|
||||||
|
if (!triggered) mrd = NULL;
|
||||||
|
|
||||||
/* top to bottom */
|
/* top to bottom */
|
||||||
|
|
||||||
|
|
@ -1173,12 +1334,23 @@ drcTile (tile, dinfo, arg)
|
||||||
|
|
||||||
if (cptr->drcc_flags & DRC_REVERSE)
|
if (cptr->drcc_flags & DRC_REVERSE)
|
||||||
{
|
{
|
||||||
mrd = drcCanonicalMaxwidth(tpbot, GEO_SOUTH, arg, cptr);
|
mrd = drcCanonicalMaxwidth(tpbot, GEO_SOUTH, arg, cptr,
|
||||||
|
&mrdcache[0]);
|
||||||
triggered = 0;
|
triggered = 0;
|
||||||
}
|
}
|
||||||
else if (firsttile)
|
else
|
||||||
{
|
{
|
||||||
mrd = drcCanonicalMaxwidth(tile, GEO_NORTH, arg, cptr);
|
if (cptrcache == NULL)
|
||||||
|
{
|
||||||
|
mrd = drcCanonicalMaxwidth(tile, GEO_NORTH, arg, cptr,
|
||||||
|
&mrdcache[1]);
|
||||||
|
cptrcache = cptr;
|
||||||
|
}
|
||||||
|
else if (cptrcache != cptr)
|
||||||
|
mrd = drcCanonicalMaxwidth(tile, GEO_NORTH, arg, cptr,
|
||||||
|
&mrdcache[2]);
|
||||||
|
else
|
||||||
|
mrd = (mrdcache[1]->entries == 0) ? NULL : mrdcache[1];
|
||||||
triggered = 0;
|
triggered = 0;
|
||||||
}
|
}
|
||||||
if (!trigpending || (DRCCurStyle->DRCFlags
|
if (!trigpending || (DRCCurStyle->DRCFlags
|
||||||
|
|
|
||||||
|
|
@ -510,16 +510,17 @@ MaxRectsExclude(
|
||||||
*/
|
*/
|
||||||
|
|
||||||
MaxRectsData *
|
MaxRectsData *
|
||||||
drcCanonicalMaxwidth(starttile, dir, arg, cptr)
|
drcCanonicalMaxwidth(starttile, dir, arg, cptr, mrdptr)
|
||||||
Tile *starttile;
|
Tile *starttile;
|
||||||
int dir; /* direction of rule */
|
int dir; /* direction of rule */
|
||||||
struct drcClientData *arg;
|
struct drcClientData *arg;
|
||||||
DRCCookie *cptr;
|
DRCCookie *cptr;
|
||||||
|
MaxRectsData **mrdptr;
|
||||||
{
|
{
|
||||||
int s, edgelimit;
|
int s, edgelimit;
|
||||||
Tile *tile,*tp;
|
Tile *tile,*tp;
|
||||||
TileTypeBitMask wrongtypes;
|
TileTypeBitMask wrongtypes;
|
||||||
static MaxRectsData *mrd = (MaxRectsData *)NULL;
|
MaxRectsData *mrd = *mrdptr;
|
||||||
Rect *boundrect, boundorig;
|
Rect *boundrect, boundorig;
|
||||||
|
|
||||||
/* Generate an initial array size of 8 for rlist and swap. */
|
/* Generate an initial array size of 8 for rlist and swap. */
|
||||||
|
|
@ -529,6 +530,7 @@ drcCanonicalMaxwidth(starttile, dir, arg, cptr)
|
||||||
mrd->rlist = (Rect *)mallocMagic(8 * sizeof(Rect));
|
mrd->rlist = (Rect *)mallocMagic(8 * sizeof(Rect));
|
||||||
mrd->swap = (Rect *)mallocMagic(8 * sizeof(Rect));
|
mrd->swap = (Rect *)mallocMagic(8 * sizeof(Rect));
|
||||||
mrd->listdepth = 8;
|
mrd->listdepth = 8;
|
||||||
|
*mrdptr = mrd;
|
||||||
}
|
}
|
||||||
if (starttile == NULL) return mrd;
|
if (starttile == NULL) return mrd;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ static ClientData drcSubClientData; /* To be passed to error function. */
|
||||||
static DRCCookie drcSubcellCookie = {
|
static DRCCookie drcSubcellCookie = {
|
||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
{ {0} }, { {0} },
|
{ {0} }, { {0} },
|
||||||
0, 0, 0,
|
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||||
DRC_SUBCELL_OVERLAP_TAG,
|
DRC_SUBCELL_OVERLAP_TAG,
|
||||||
(DRCCookie *) NULL
|
(DRCCookie *) NULL
|
||||||
};
|
};
|
||||||
|
|
@ -65,7 +65,7 @@ static DRCCookie drcSubcellCookie = {
|
||||||
static DRCCookie drcInSubCookie = {
|
static DRCCookie drcInSubCookie = {
|
||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
{ {0} }, { {0} },
|
{ {0} }, { {0} },
|
||||||
0, 0, 0,
|
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||||
DRC_IN_SUBCELL_TAG,
|
DRC_IN_SUBCELL_TAG,
|
||||||
(DRCCookie *) NULL
|
(DRCCookie *) NULL
|
||||||
};
|
};
|
||||||
|
|
@ -79,7 +79,7 @@ static DRCCookie drcInSubCookie = {
|
||||||
static DRCCookie drcOffGridCookie = {
|
static DRCCookie drcOffGridCookie = {
|
||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
{ {0} }, { {0} },
|
{ {0} }, { {0} },
|
||||||
0, 0, 0,
|
0, DRC_EXCEPTION_NONE, 0, 0,
|
||||||
DRC_OFFGRID_TAG,
|
DRC_OFFGRID_TAG,
|
||||||
(DRCCookie *) NULL
|
(DRCCookie *) NULL
|
||||||
};
|
};
|
||||||
|
|
|
||||||
202
drc/DRCtech.c
202
drc/DRCtech.c
|
|
@ -72,6 +72,12 @@ static int drcRulesOptimized = 0;
|
||||||
|
|
||||||
static int DRCtag = 0;
|
static int DRCtag = 0;
|
||||||
|
|
||||||
|
/* Keep track of what rule exemption or exception is in effect
|
||||||
|
* while reading the DRC tech file section.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static unsigned char drcCurException = DRC_EXCEPTION_NONE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Forward declarations.
|
* Forward declarations.
|
||||||
*/
|
*/
|
||||||
|
|
@ -79,6 +85,7 @@ int drcWidth(), drcSpacing(), drcEdge(), drcNoOverlap();
|
||||||
int drcExactOverlap(), drcExtend();
|
int drcExactOverlap(), drcExtend();
|
||||||
int drcSurround(), drcRectOnly(), drcOverhang();
|
int drcSurround(), drcRectOnly(), drcOverhang();
|
||||||
int drcStepSize(), drcOption(), drcOffGrid();
|
int drcStepSize(), drcOption(), drcOffGrid();
|
||||||
|
int drcException(), drcExemption();
|
||||||
int drcMaxwidth(), drcArea(), drcRectangle(), drcAngles();
|
int drcMaxwidth(), drcArea(), drcRectangle(), drcAngles();
|
||||||
int drcCifSetStyle(), drcCifWidth(), drcCifSpacing();
|
int drcCifSetStyle(), drcCifWidth(), drcCifSpacing();
|
||||||
int drcCifMaxwidth(), drcCifArea();
|
int drcCifMaxwidth(), drcCifArea();
|
||||||
|
|
@ -301,6 +308,12 @@ drcTechFreeStyle()
|
||||||
/* Clear the Why string list */
|
/* Clear the Why string list */
|
||||||
freeMagic(DRCCurStyle->DRCWhyList);
|
freeMagic(DRCCurStyle->DRCWhyList);
|
||||||
|
|
||||||
|
/* Clear the exception list */
|
||||||
|
for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++)
|
||||||
|
freeMagic(DRCCurStyle->DRCExceptionList[i]);
|
||||||
|
if (DRCCurStyle->DRCExceptionList != (char **)NULL)
|
||||||
|
freeMagic(DRCCurStyle->DRCExceptionList);
|
||||||
|
|
||||||
freeMagic(DRCCurStyle);
|
freeMagic(DRCCurStyle);
|
||||||
DRCCurStyle = NULL;
|
DRCCurStyle = NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -384,6 +397,63 @@ drcWhyCreate(whystring)
|
||||||
return DRCCurStyle->DRCWhySize;
|
return DRCCurStyle->DRCWhySize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* drcExceptionCreate --
|
||||||
|
*
|
||||||
|
* Create an entry for a DRC rule exception/exemption type, if it does
|
||||||
|
* not already exist.
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* The index of the exception (which is an unsigned character containing
|
||||||
|
* the index in the lower 7 bits and a high bit indicating if the rule
|
||||||
|
* is an exception (0) or an exemption (1)).
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* Adds to the DRCExceptionList if "name" has not been used before.
|
||||||
|
* Calls StrDup() and increments DRCExceptionSize.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned char
|
||||||
|
drcExceptionCreate(name)
|
||||||
|
char *name;
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char **newlist;
|
||||||
|
|
||||||
|
/* NOTE: DRCExceptionList has "MASKHINTS_" prepended to the names */
|
||||||
|
for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++)
|
||||||
|
if (!strcmp(name, DRCCurStyle->DRCExceptionList[i] + 10))
|
||||||
|
return (unsigned char)i;
|
||||||
|
|
||||||
|
/* Note that i cannot be 127 as this is reserved for DRC_EXCEPTION_NONE */
|
||||||
|
if (i > 126)
|
||||||
|
{
|
||||||
|
/* I would be shocked if this code ever got executed. */
|
||||||
|
TxError("Error: Too many rule exceptions! Limit is 126.\n");
|
||||||
|
return DRC_EXCEPTION_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a new list that is one entry longer than the old list.
|
||||||
|
* This is not elegant but there will never be more than a handful
|
||||||
|
* of exceptions in a rule deck.
|
||||||
|
*/
|
||||||
|
newlist = (char **)mallocMagic((i + 1) * sizeof(char *));
|
||||||
|
for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++)
|
||||||
|
newlist[i] = DRCCurStyle->DRCExceptionList[i];
|
||||||
|
|
||||||
|
/* The rule deck does not have the "MASKHINTS_" prefix on the name */
|
||||||
|
newlist[i] = (char *)mallocMagic(strlen(name) + 11);
|
||||||
|
sprintf(newlist[i], "MASKHINTS_%s", name);
|
||||||
|
DRCCurStyle->DRCExceptionSize++;
|
||||||
|
if (DRCCurStyle->DRCExceptionList != (char **)NULL)
|
||||||
|
freeMagic(DRCCurStyle->DRCExceptionList);
|
||||||
|
DRCCurStyle->DRCExceptionList = newlist;
|
||||||
|
return (unsigned char)i;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -571,6 +641,8 @@ DRCTechStyleInit()
|
||||||
DRCCurStyle->DRCStepSize = 0;
|
DRCCurStyle->DRCStepSize = 0;
|
||||||
DRCCurStyle->DRCFlags = (char)0;
|
DRCCurStyle->DRCFlags = (char)0;
|
||||||
DRCCurStyle->DRCWhySize = 0;
|
DRCCurStyle->DRCWhySize = 0;
|
||||||
|
DRCCurStyle->DRCExceptionList = (char **)NULL;
|
||||||
|
DRCCurStyle->DRCExceptionSize = 0;
|
||||||
|
|
||||||
HashInit(&DRCWhyErrorTable, 16, HT_STRINGKEYS);
|
HashInit(&DRCWhyErrorTable, 16, HT_STRINGKEYS);
|
||||||
|
|
||||||
|
|
@ -663,6 +735,7 @@ DRCTechStyleInit()
|
||||||
}
|
}
|
||||||
|
|
||||||
drcCifInit();
|
drcCifInit();
|
||||||
|
drcCurException = DRC_EXCEPTION_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -955,6 +1028,7 @@ drcCifAssign(cookie, dist, next, mask, corner, tag, cdist, flags, planeto, plane
|
||||||
(cookie)->drcc_plane = planeto;
|
(cookie)->drcc_plane = planeto;
|
||||||
(cookie)->drcc_mod = 0;
|
(cookie)->drcc_mod = 0;
|
||||||
(cookie)->drcc_cmod = 0;
|
(cookie)->drcc_cmod = 0;
|
||||||
|
(cookie)->drcc_exception = drcCurException;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is like drcCifAssign, but checks for bad plane numbers in planeto and
|
// This is like drcCifAssign, but checks for bad plane numbers in planeto and
|
||||||
|
|
@ -1031,50 +1105,37 @@ DRCTechAddRule(sectionName, argc, argv)
|
||||||
int (*rk_proc)(); /* Procedure implementing this keyword */
|
int (*rk_proc)(); /* Procedure implementing this keyword */
|
||||||
const char *rk_err; /* Error message */
|
const char *rk_err; /* Error message */
|
||||||
} ruleKeys[] = {
|
} ruleKeys[] = {
|
||||||
{"angles", 4, 4, drcAngles,
|
{"angles", 4, 4, drcAngles, "layers 45|90 why"},
|
||||||
"layers 45|90 why"},
|
|
||||||
{"edge", 8, 10, drcEdge,
|
{"edge", 8, 10, drcEdge,
|
||||||
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
|
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
|
||||||
{"edge4way", 8, 10, drcEdge,
|
{"edge4way", 8, 10, drcEdge,
|
||||||
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
|
"layers1 layers2 distance okTypes cornerTypes cornerDistance [option] why [plane]"},
|
||||||
{"exact_overlap", 2, 2, drcExactOverlap,
|
{"exact_overlap", 2, 2, drcExactOverlap, "layers"},
|
||||||
"layers"},
|
{"exception", 2, 2, drcException, "name"},
|
||||||
|
{"exemption", 2, 2, drcExemption, "name"},
|
||||||
{"extend", 5, 6, drcExtend,
|
{"extend", 5, 6, drcExtend,
|
||||||
"layers1 layers2 distance [option] why"},
|
"layers1 layers2 distance [option] why"},
|
||||||
{"no_overlap", 3, 3, drcNoOverlap,
|
{"no_overlap", 3, 3, drcNoOverlap, "layers1 layers2"},
|
||||||
"layers1 layers2"},
|
{"option", 2, 2, drcOption, "option_name option_value"},
|
||||||
{"option", 2, 2, drcOption,
|
{"overhang", 5, 5, drcOverhang, "layers1 layers2 distance why"},
|
||||||
"option_name option_value"},
|
{"rect_only", 3, 3, drcRectOnly, "layers why"},
|
||||||
{"overhang", 5, 5, drcOverhang,
|
|
||||||
"layers1 layers2 distance why"},
|
|
||||||
{"rect_only", 3, 3, drcRectOnly,
|
|
||||||
"layers why"},
|
|
||||||
{"spacing", 6, 7, drcSpacing,
|
{"spacing", 6, 7, drcSpacing,
|
||||||
"layers1 layers2 separation [layers3] adjacency why"},
|
"layers1 layers2 separation [layers3] adjacency why"},
|
||||||
{"stepsize", 2, 2, drcStepSize,
|
{"stepsize", 2, 2, drcStepSize, "step_size"},
|
||||||
"step_size"},
|
|
||||||
{"surround", 6, 7, drcSurround,
|
{"surround", 6, 7, drcSurround,
|
||||||
"layers1 layers2 distance presence why"},
|
"layers1 layers2 distance presence why"},
|
||||||
{"width", 4, 5, drcWidth,
|
{"width", 4, 5, drcWidth, "layers width why"},
|
||||||
"layers width why"},
|
|
||||||
{"widespacing", 7, 8, drcSpacing,
|
{"widespacing", 7, 8, drcSpacing,
|
||||||
"layers1 width layers2 separation adjacency why"},
|
"layers1 width layers2 separation adjacency why"},
|
||||||
{"area", 5, 5, drcArea,
|
{"area", 5, 5, drcArea, "layers area horizon why"},
|
||||||
"layers area horizon why"},
|
{"off_grid", 4, 4, drcOffGrid, "layers pitch why"},
|
||||||
{"off_grid", 4, 4, drcOffGrid,
|
{"maxwidth", 4, 6, drcMaxwidth, "layers maxwidth bends why"},
|
||||||
"layers pitch why"},
|
{"cifstyle", 2, 2, drcCifSetStyle, "cif_style"},
|
||||||
{"maxwidth", 4, 6, drcMaxwidth,
|
{"cifwidth", 4, 4, drcCifWidth, "layers width why"},
|
||||||
"layers maxwidth bends why"},
|
|
||||||
{"cifstyle", 2, 2, drcCifSetStyle,
|
|
||||||
"cif_style"},
|
|
||||||
{"cifwidth", 4, 4, drcCifWidth,
|
|
||||||
"layers width why"},
|
|
||||||
{"cifspacing", 6, 6, drcCifSpacing,
|
{"cifspacing", 6, 6, drcCifSpacing,
|
||||||
"layers1 layers2 separation adjacency why"},
|
"layers1 layers2 separation adjacency why"},
|
||||||
{"cifarea", 5, 5, drcCifArea,
|
{"cifarea", 5, 5, drcCifArea, "layers area horizon why"},
|
||||||
"layers area horizon why"},
|
{"cifmaxwidth", 5, 5, drcCifMaxwidth, "layers maxwidth bends why"},
|
||||||
{"cifmaxwidth", 5, 5, drcCifMaxwidth,
|
|
||||||
"layers maxwidth bends why"},
|
|
||||||
{"rectangle", 5, 5, drcRectangle,
|
{"rectangle", 5, 5, drcRectangle,
|
||||||
"layers maxwidth [even|odd|any] why"},
|
"layers maxwidth [even|odd|any] why"},
|
||||||
{0}
|
{0}
|
||||||
|
|
@ -1695,7 +1756,7 @@ drcMaxwidth(argc, argv)
|
||||||
if (PlaneMaskHasPlane(pmask2, plane2))
|
if (PlaneMaskHasPlane(pmask2, plane2))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (plane2 == plane)
|
if (PlaneMaskHasPlane(pmask, plane2))
|
||||||
TechError("Warning: Exclude types for \"maxwidth\" are on the "
|
TechError("Warning: Exclude types for \"maxwidth\" are on the "
|
||||||
"same plane and so cannot be checked.\n");
|
"same plane and so cannot be checked.\n");
|
||||||
}
|
}
|
||||||
|
|
@ -3634,6 +3695,84 @@ drcRectangle(argc, argv)
|
||||||
return maxwidth;
|
return maxwidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* drcException, drcExemption --
|
||||||
|
*
|
||||||
|
* Process a DRC exception declaration
|
||||||
|
* This is of the form:
|
||||||
|
*
|
||||||
|
* exception exception_name|none
|
||||||
|
* or
|
||||||
|
* exemption exemption_name|none
|
||||||
|
*
|
||||||
|
* e.g,
|
||||||
|
*
|
||||||
|
* exception SRAM
|
||||||
|
* exemption SRAM
|
||||||
|
*
|
||||||
|
* The exception_name or exemption_name is the suffix part of a MASKHINTS_*
|
||||||
|
* property name; e.g., the name SRAM corresponds to a property called
|
||||||
|
* MASKHINTS_SRAM. This declaration is followed by a block of DRC rules
|
||||||
|
* that are subject to the exception or the exemption. An exception is the
|
||||||
|
* opposite of an exemption: If a rule is excepted, then the rule applies
|
||||||
|
* within areas delineated by bounding boxes defined by the
|
||||||
|
* MASKHINTS_<exception_name> property. If a rule is exempted, then the
|
||||||
|
* rule applies only outside of areas delineated by bounding boxes defined
|
||||||
|
* by the MASKHINTS_<exemption_name> property. The block of rules subject
|
||||||
|
* to the exemption or exception ends with another exception or exemption
|
||||||
|
* declaration. If the following rules are not to be excepted or exempted
|
||||||
|
* at all, then use "exception none" or "exemption none".
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* Returns 0.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* Updates drcCurException. drcCurException contains the index in
|
||||||
|
* the lower 7 bits, and a flag in the upper bit (0 = exception rule,
|
||||||
|
* 1 = exemption rule). The index can be recovered by masking off
|
||||||
|
* the upper bit.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
drcException(argc, argv)
|
||||||
|
int argc;
|
||||||
|
char *argv[];
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (DRCCurStyle == NULL) return 0;
|
||||||
|
|
||||||
|
/* Assume that argc must be 2 because the parser insists upon it */
|
||||||
|
|
||||||
|
if (!strcmp(argv[1], "none"))
|
||||||
|
drcCurException = DRC_EXCEPTION_NONE;
|
||||||
|
else
|
||||||
|
drcCurException = drcExceptionCreate(argv[1]);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
drcExemption(argc, argv)
|
||||||
|
int argc;
|
||||||
|
char *argv[];
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (DRCCurStyle == NULL) return 0;
|
||||||
|
|
||||||
|
/* Assume that argc must be 2 because the parser insists upon it */
|
||||||
|
|
||||||
|
if (!strcmp(argv[1], "none"))
|
||||||
|
drcCurException = DRC_EXCEPTION_NONE;
|
||||||
|
else
|
||||||
|
drcCurException = drcExceptionCreate(argv[1]) | DRC_EXCEPTION_MASK;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -4119,6 +4258,7 @@ drcTechFinalStyle(style)
|
||||||
if (dp->drcc_dist > next->drcc_dist) continue;
|
if (dp->drcc_dist > next->drcc_dist) continue;
|
||||||
if (dp->drcc_cdist > next->drcc_cdist) continue;
|
if (dp->drcc_cdist > next->drcc_cdist) continue;
|
||||||
if (dp->drcc_plane != next->drcc_plane) continue;
|
if (dp->drcc_plane != next->drcc_plane) continue;
|
||||||
|
if (dp->drcc_exception != next->drcc_exception) continue;
|
||||||
if (dp->drcc_flags & DRC_REVERSE)
|
if (dp->drcc_flags & DRC_REVERSE)
|
||||||
{
|
{
|
||||||
if (!(next->drcc_flags & DRC_REVERSE)) continue;
|
if (!(next->drcc_flags & DRC_REVERSE)) continue;
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ typedef struct drccookie
|
||||||
TileTypeBitMask drcc_mask; /* Legal types on RHS */
|
TileTypeBitMask drcc_mask; /* Legal types on RHS */
|
||||||
TileTypeBitMask drcc_corner; /* Types that trigger corner check */
|
TileTypeBitMask drcc_corner; /* Types that trigger corner check */
|
||||||
unsigned short drcc_flags; /* Miscellaneous flags, see below. */
|
unsigned short drcc_flags; /* Miscellaneous flags, see below. */
|
||||||
|
unsigned char drcc_exception; /* Index to list of exceptions */
|
||||||
int drcc_edgeplane; /* Plane of edge */
|
int drcc_edgeplane; /* Plane of edge */
|
||||||
int drcc_plane; /* Index of plane on which to check
|
int drcc_plane; /* Index of plane on which to check
|
||||||
* legal types. */
|
* legal types. */
|
||||||
|
|
@ -91,6 +92,11 @@ typedef struct drccookie
|
||||||
#define DRC_UNPROCESSED CLIENTDEFAULT
|
#define DRC_UNPROCESSED CLIENTDEFAULT
|
||||||
#define DRC_PROCESSED 1
|
#define DRC_PROCESSED 1
|
||||||
|
|
||||||
|
/* drcc_exception defaults to 255 meaning no exceptions/exemptions */
|
||||||
|
#define DRC_EXCEPTION_NONE ((unsigned char)0xff)
|
||||||
|
/* The high bit of the value determines if this is an exception or an exemption. */
|
||||||
|
#define DRC_EXCEPTION_MASK ((unsigned char)0x80)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Background DRC (DRC Idle proc) for Tcl-based Magic
|
* Background DRC (DRC Idle proc) for Tcl-based Magic
|
||||||
*/
|
*/
|
||||||
|
|
@ -177,6 +183,8 @@ typedef struct drcstyle
|
||||||
unsigned short DRCFlags; /* Option flags */
|
unsigned short DRCFlags; /* Option flags */
|
||||||
char **DRCWhyList; /* Indexed list of "why" text strings */
|
char **DRCWhyList; /* Indexed list of "why" text strings */
|
||||||
int DRCWhySize; /* Length of DRCWhyList */
|
int DRCWhySize; /* Length of DRCWhyList */
|
||||||
|
char **DRCExceptionList; /* Indexed list of DRC exceptions */
|
||||||
|
int DRCExceptionSize; /* Length of DRCExceptionList */
|
||||||
PaintResultType DRCPaintTable[NP][NT][NT];
|
PaintResultType DRCPaintTable[NP][NT][NT];
|
||||||
} DRCStyle;
|
} DRCStyle;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -844,6 +844,8 @@ spcdevHierVisit(
|
||||||
case DEV_DSUBCKT:
|
case DEV_DSUBCKT:
|
||||||
case DEV_MSUBCKT:
|
case DEV_MSUBCKT:
|
||||||
fprintf(esSpiceF, "%d", esSbckNum++);
|
fprintf(esSpiceF, "%d", esSbckNum++);
|
||||||
|
if ((dev->dev_class == DEV_RSUBCKT) && esDoResistorTee)
|
||||||
|
fprintf(esSpiceF, "A");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(esSpiceF, "%d", esDevNum++);
|
fprintf(esSpiceF, "%d", esDevNum++);
|
||||||
|
|
@ -920,16 +922,27 @@ spcdevHierVisit(
|
||||||
else if (dev->dev_class != DEV_MSUBCKT)
|
else if (dev->dev_class != DEV_MSUBCKT)
|
||||||
{
|
{
|
||||||
if (dev->dev_nterm > 1)
|
if (dev->dev_nterm > 1)
|
||||||
spcdevOutNode(hc->hc_hierName, source->dterm_node->efnode_name->efnn_hier,
|
spcdevOutNode(hc->hc_hierName,
|
||||||
|
source->dterm_node->efnode_name->efnn_hier,
|
||||||
"subckt", esSpiceF);
|
"subckt", esSpiceF);
|
||||||
if (dev->dev_nterm > 2)
|
if ((dev->dev_class == DEV_RSUBCKT) && esDoResistorTee)
|
||||||
spcdevOutNode(hc->hc_hierName, drain->dterm_node->efnode_name->efnn_hier,
|
{
|
||||||
|
/* Handle resistor "tee" model */
|
||||||
|
spcdevOutNode(hc->hc_hierName,
|
||||||
|
gate->dterm_node->efnode_name->efnn_hier,
|
||||||
|
"subckt", esSpiceF);
|
||||||
|
l /= 2; /* Halve the resistor length for each side */
|
||||||
|
}
|
||||||
|
else if (dev->dev_nterm > 2)
|
||||||
|
spcdevOutNode(hc->hc_hierName,
|
||||||
|
drain->dterm_node->efnode_name->efnn_hier,
|
||||||
"subckt", esSpiceF);
|
"subckt", esSpiceF);
|
||||||
}
|
}
|
||||||
else /* class DEV_MSUBCKT */
|
else /* class DEV_MSUBCKT */
|
||||||
{
|
{
|
||||||
if (dev->dev_nterm > 2)
|
if (dev->dev_nterm > 2)
|
||||||
spcdevOutNode(hc->hc_hierName, source->dterm_node->efnode_name->efnn_hier,
|
spcdevOutNode(hc->hc_hierName,
|
||||||
|
source->dterm_node->efnode_name->efnn_hier,
|
||||||
"subckt", esSpiceF);
|
"subckt", esSpiceF);
|
||||||
}
|
}
|
||||||
/* The following only applies to DEV_SUBCKT and DEV_VERILOGA, which */
|
/* The following only applies to DEV_SUBCKT and DEV_VERILOGA, which */
|
||||||
|
|
@ -967,6 +980,54 @@ spcdevHierVisit(
|
||||||
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
|
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
|
||||||
if (sdM != 1.0)
|
if (sdM != 1.0)
|
||||||
fprintf(esSpiceF, " M=%g", sdM);
|
fprintf(esSpiceF, " M=%g", sdM);
|
||||||
|
|
||||||
|
if ((dev->dev_class == DEV_RSUBCKT) && esDoResistorTee)
|
||||||
|
{
|
||||||
|
/* Repeat everything above for the second half of the "tee" resistor */
|
||||||
|
fprintf(esSpiceF, "\n%c%dB", devchar, esSbckNum - 1);
|
||||||
|
|
||||||
|
spcdevOutNode(hc->hc_hierName,
|
||||||
|
gate->dterm_node->efnode_name->efnn_hier,
|
||||||
|
"subckt", esSpiceF);
|
||||||
|
spcdevOutNode(hc->hc_hierName,
|
||||||
|
drain->dterm_node->efnode_name->efnn_hier,
|
||||||
|
"subckt", esSpiceF);
|
||||||
|
|
||||||
|
/* Get the device parameters now, and check if the substrate is */
|
||||||
|
/* passed as a parameter rather than as a node. */
|
||||||
|
|
||||||
|
plist = efGetDeviceParams(EFDevTypes[dev->dev_type]);
|
||||||
|
for (pptr = plist; pptr != NULL; pptr = pptr->parm_next)
|
||||||
|
if (pptr->parm_type[0] == 's')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ((pptr == NULL) && subnode)
|
||||||
|
{
|
||||||
|
EFNode *dnode;
|
||||||
|
|
||||||
|
fprintf(esSpiceF, " ");
|
||||||
|
subnodeFlat = spcdevSubstrate(hc->hc_hierName,
|
||||||
|
subnode->efnode_name->efnn_hier,
|
||||||
|
dev->dev_type, esSpiceF);
|
||||||
|
|
||||||
|
/* If a tee resistor subcircuit has a substrate pin, then the
|
||||||
|
* parasitic capacitance to substrate should be assumed to be
|
||||||
|
* part of the resistor subcircuit model, and so the parasitic
|
||||||
|
* to substrate on the "gate" node should be forced to zero.
|
||||||
|
*/
|
||||||
|
dnode = GetHierNode(hc, gate->dterm_node->efnode_name->efnn_hier);
|
||||||
|
dnode->efnode_cap = 0;
|
||||||
|
}
|
||||||
|
/* Support for CDL format */
|
||||||
|
if (esFormat == CDL) fprintf(esSpiceF, " /");
|
||||||
|
fprintf(esSpiceF, " %s", EFDevTypes[dev->dev_type]);
|
||||||
|
|
||||||
|
/* Write all requested parameters to the subcircuit call. */
|
||||||
|
sdM = getCurDevMult();
|
||||||
|
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
|
||||||
|
if (sdM != 1.0)
|
||||||
|
fprintf(esSpiceF, " M=%g", sdM);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DEV_RES:
|
case DEV_RES:
|
||||||
|
|
@ -1088,6 +1149,7 @@ spcdevHierVisit(
|
||||||
|
|
||||||
if (!has_model)
|
if (!has_model)
|
||||||
{
|
{
|
||||||
|
fprintf(esSpiceF, " ");
|
||||||
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
||||||
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
|
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
|
||||||
}
|
}
|
||||||
|
|
@ -1138,6 +1200,7 @@ spcdevHierVisit(
|
||||||
|
|
||||||
if (!has_model)
|
if (!has_model)
|
||||||
{
|
{
|
||||||
|
fprintf(esSpiceF, " ");
|
||||||
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
||||||
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
|
spcHierWriteParams(hc, dev, scale, l, w, sdM, FALSE);
|
||||||
}
|
}
|
||||||
|
|
@ -1561,12 +1624,14 @@ 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;
|
||||||
|
|
@ -1593,7 +1658,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;
|
||||||
|
|
@ -1603,14 +1668,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;
|
||||||
|
|
@ -2901,13 +2901,17 @@ spcdevVisit(
|
||||||
case DEV_VOLT:
|
case DEV_VOLT:
|
||||||
fprintf(esSpiceF, "%d", esVoltNum++);
|
fprintf(esSpiceF, "%d", esVoltNum++);
|
||||||
break;
|
break;
|
||||||
|
case DEV_RSUBCKT:
|
||||||
case DEV_SUBCKT:
|
case DEV_SUBCKT:
|
||||||
case DEV_VERILOGA:
|
case DEV_VERILOGA:
|
||||||
case DEV_RSUBCKT:
|
|
||||||
case DEV_CSUBCKT:
|
case DEV_CSUBCKT:
|
||||||
case DEV_DSUBCKT:
|
case DEV_DSUBCKT:
|
||||||
case DEV_MSUBCKT:
|
case DEV_MSUBCKT:
|
||||||
fprintf(esSpiceF, "%d", esSbckNum++);
|
fprintf(esSpiceF, "%d", esSbckNum++);
|
||||||
|
if ((dev->dev_class == DEV_RSUBCKT) && esDoResistorTee)
|
||||||
|
/* For resistor tee networks, use, e.g., */
|
||||||
|
/* "X1A" and "X1B", for clarity */
|
||||||
|
fprintf(esSpiceF, "A");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(esSpiceF, "%d", esDevNum++);
|
fprintf(esSpiceF, "%d", esDevNum++);
|
||||||
|
|
@ -2982,7 +2986,15 @@ spcdevVisit(
|
||||||
if (dev->dev_nterm > 1)
|
if (dev->dev_nterm > 1)
|
||||||
spcdevOutNode(hierName, source->dterm_node->efnode_name->efnn_hier,
|
spcdevOutNode(hierName, source->dterm_node->efnode_name->efnn_hier,
|
||||||
name, esSpiceF);
|
name, esSpiceF);
|
||||||
if (dev->dev_nterm > 2)
|
if ((dev->dev_class == DEV_RSUBCKT) && esDoResistorTee)
|
||||||
|
{
|
||||||
|
l /= 2; /* Halve the resistor. Note that this may introduce
|
||||||
|
* error if l is an odd value.
|
||||||
|
*/
|
||||||
|
spcdevOutNode(hierName, gate->dterm_node->efnode_name->efnn_hier,
|
||||||
|
name, esSpiceF);
|
||||||
|
}
|
||||||
|
else if (dev->dev_nterm > 2)
|
||||||
spcdevOutNode(hierName, drain->dterm_node->efnode_name->efnn_hier,
|
spcdevOutNode(hierName, drain->dterm_node->efnode_name->efnn_hier,
|
||||||
name, esSpiceF);
|
name, esSpiceF);
|
||||||
}
|
}
|
||||||
|
|
@ -3031,6 +3043,53 @@ spcdevVisit(
|
||||||
fprintf(esSpiceF, " M=%g", sdM);
|
fprintf(esSpiceF, " M=%g", sdM);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (dev->dev_class == DEV_RSUBCKT && esDoResistorTee)
|
||||||
|
{
|
||||||
|
/* Write the second half of the "Tee" resistor when
|
||||||
|
* the resistor is type DEV_RSUBCKT and not DEV_RES.
|
||||||
|
*/
|
||||||
|
fprintf(esSpiceF, "\n%c%dB", devchar, esSbckNum - 1);
|
||||||
|
|
||||||
|
spcdevOutNode(hierName, gate->dterm_node->efnode_name->efnn_hier,
|
||||||
|
name, esSpiceF);
|
||||||
|
spcdevOutNode(hierName, drain->dterm_node->efnode_name->efnn_hier,
|
||||||
|
name, esSpiceF);
|
||||||
|
|
||||||
|
/* Get the device parameters now, and check if the substrate is */
|
||||||
|
/* passed as a parameter rather than as a node. */
|
||||||
|
|
||||||
|
plist = efGetDeviceParams(EFDevTypes[dev->dev_type]);
|
||||||
|
for (pptr = plist; pptr != NULL; pptr = pptr->parm_next)
|
||||||
|
if (pptr->parm_type[0] == 's')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ((pptr == NULL) && subnode)
|
||||||
|
{
|
||||||
|
fprintf(esSpiceF, " ");
|
||||||
|
subnodeFlat = spcdevSubstrate(hierName,
|
||||||
|
subnode->efnode_name->efnn_hier,
|
||||||
|
dev->dev_type, esSpiceF);
|
||||||
|
|
||||||
|
/* There is a substrate pin on the resistor subcircuit, so assume
|
||||||
|
* that the substrate cap is part of the subcircuit model, and
|
||||||
|
* zero it.
|
||||||
|
*/
|
||||||
|
gate->dterm_node->efnode_cap = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CDL format support: Output a slash followed by a space. */
|
||||||
|
if (esFormat == CDL) fprintf(esSpiceF, " /");
|
||||||
|
fprintf(esSpiceF, " %s", EFDevTypes[dev->dev_type]);
|
||||||
|
|
||||||
|
/* Write all requested parameters to the subcircuit call. */
|
||||||
|
|
||||||
|
sdM = getCurDevMult();
|
||||||
|
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
|
||||||
|
if (sdM != 1.0)
|
||||||
|
fprintf(esSpiceF, " M=%g", sdM);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case DEV_RES:
|
case DEV_RES:
|
||||||
if (esDoResistorTee)
|
if (esDoResistorTee)
|
||||||
{
|
{
|
||||||
|
|
@ -3140,6 +3199,7 @@ spcdevVisit(
|
||||||
|
|
||||||
if (!has_model)
|
if (!has_model)
|
||||||
{
|
{
|
||||||
|
fprintf(esSpiceF, " ");
|
||||||
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
||||||
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
|
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
|
||||||
}
|
}
|
||||||
|
|
@ -3186,6 +3246,7 @@ spcdevVisit(
|
||||||
|
|
||||||
if (!has_model)
|
if (!has_model)
|
||||||
{
|
{
|
||||||
|
fprintf(esSpiceF, " ");
|
||||||
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
esSIvalue(esSpiceF, 1.0E-15 * (double)sdM * (double)dev->dev_cap);
|
||||||
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
|
spcWriteParams(dev, hierName, scale, l, w, sdM, FALSE);
|
||||||
}
|
}
|
||||||
|
|
@ -4050,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;
|
||||||
|
|
@ -4060,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,6 +307,12 @@ 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
|
||||||
|
|
@ -367,7 +373,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)
|
||||||
*path = ".";
|
StrDup(path, ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
||||||
|
|
@ -706,6 +706,11 @@ 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 */
|
||||||
|
|
@ -1618,12 +1623,128 @@ 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'.
|
||||||
*
|
*
|
||||||
|
|
@ -1638,7 +1759,7 @@ efConnectionFreeLinkedList(Connection *conn)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
efBuildConnect(def, nodeName1, nodeName2, deltaC, av, ac)
|
efBuildMerge(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,6 +122,7 @@ 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)
|
||||||
|
|
@ -248,6 +249,7 @@ 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,6 +32,7 @@ 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"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
|
|
@ -491,7 +492,13 @@ 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,6 +145,8 @@ 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 */
|
||||||
|
|
@ -162,6 +164,7 @@ 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
|
||||||
|
|
@ -206,6 +209,17 @@ 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 */
|
||||||
|
|
@ -307,7 +321,9 @@ 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,15 +275,11 @@ readfile:
|
||||||
efBuildCap(def, argv[1], argv[2], (double) cap);
|
efBuildCap(def, argv[1], argv[2], (double) cap);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* subcap node capacitance */
|
/* connect useid llx lly urx ury type "node" ... */
|
||||||
case SUBCAP:
|
case CONNECT:
|
||||||
cap = cscale*atoCap(argv[2]);
|
efBuildConnect(def, atoi(argv[1]), atoi(argv[2]),
|
||||||
efAdjustSubCap(def, argv[1], cap);
|
atoi(argv[3]), atoi(argv[4]), argv[5],
|
||||||
break;
|
argv[6], argv[7]);
|
||||||
|
|
||||||
/* equiv node1 node2 */
|
|
||||||
case EQUIV:
|
|
||||||
efBuildEquiv(def, argv[1], argv[2], resist, isspice);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* replaces "fet" (below) */
|
/* replaces "fet" (below) */
|
||||||
|
|
@ -337,6 +333,41 @@ 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 "resist" 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++;
|
||||||
|
|
||||||
|
/* Tricky---Since "Short" devices are treated like "equiv"
|
||||||
|
* statements, then when doing full R-C extraction, it's
|
||||||
|
* important *not* to merge the nodes when reading the
|
||||||
|
* .ext file, but only when reading the .res.ext file.
|
||||||
|
* Otherwise the wrong nodes may get merged. "resist" is
|
||||||
|
* TRUE when "ext2spice extresist on" is selected, and
|
||||||
|
* DoResist is set to FALSE when the .res.ext file is
|
||||||
|
* opened for reading.
|
||||||
|
*/
|
||||||
|
if (argstart + 4 >= argc)
|
||||||
|
efReadError("Bad terminal description for Short device\n");
|
||||||
|
else if ((!resist) || (resist && (!(DoResist))))
|
||||||
|
{
|
||||||
|
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");
|
||||||
|
|
@ -344,6 +375,11 @@ 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:
|
||||||
|
|
@ -373,7 +409,7 @@ readfile:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
cap = (argc > 3) ? atoCap(argv[3]) * cscale : 0;
|
cap = (argc > 3) ? atoCap(argv[3]) * cscale : 0;
|
||||||
efBuildConnect(def, argv[1], argv[2], (double)cap, &argv[4], argc - 4);
|
efBuildMerge(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 ] */
|
||||||
|
|
@ -449,6 +485,12 @@ 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, DEVICE, DIST, EQUIV, FET, KILLNODE, MERGE,
|
ABSTRACT, ADJUST, ATTR, CAP, CONNECT, DEVICE, DIST, EQUIV, FET, KILLNODE,
|
||||||
NODE, PARAMETERS, PORT, PRIMITIVE, RESISTOR, RESISTCLASS, RNODE, SCALE,
|
MERGE, NODE, PARAMETERS, PORT, PRIMITIVE, RESISTOR, RESISTCLASS, RNODE,
|
||||||
SUBCAP, SUBSTRATE, TECH, TIMESTAMP, USE, VERSION, EXT_STYLE
|
SCALE, SUBCAP, SUBSTRATE, TECH, TIMESTAMP, USE, VERSION, EXT_STYLE
|
||||||
} Key;
|
} Key;
|
||||||
|
|
||||||
static const struct
|
static const struct
|
||||||
|
|
@ -42,6 +42,7 @@ 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();
|
int extTransPerimFunc(Boundary *, ClientData); /* UNUSED */
|
||||||
int extTransFindSubs();
|
int extTransFindSubs();
|
||||||
int extTransFindId();
|
int extTransFindId();
|
||||||
void extTermAPFunc();
|
void extTermAPFunc();
|
||||||
|
|
||||||
int extAnnularTileFunc();
|
int extAnnularTileFunc(Tile *, TileType, int, FindRegion *); /* UNUSED */
|
||||||
int extResistorTileFunc();
|
int extResistorTileFunc(Tile *, TileType, int, FindRegion *); /* UNUSED */
|
||||||
int extSpecialPerimFunc();
|
int extSpecialPerimFunc();
|
||||||
|
|
||||||
void extFindDuplicateLabels();
|
void extFindDuplicateLabels();
|
||||||
|
|
@ -629,6 +629,8 @@ 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)
|
||||||
|
|
@ -639,8 +641,15 @@ 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;
|
||||||
reg->nreg_resist += (fperim + s) / (fperim - s)
|
resnew = (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 */
|
||||||
|
|
@ -722,7 +731,8 @@ 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)
|
||||||
{
|
{
|
||||||
fprintf(outFile, "substrate \"%s\" 0 0", text);
|
intR = (reg->nreg_resist + rround) / ExtCurStyle->exts_resistScale;
|
||||||
|
fprintf(outFile, "substrate \"%s\" %d 0", text, intR);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -811,8 +821,14 @@ extOutputNodes(nodeList, outFile)
|
||||||
* For a net to be shorted to itself is not an error.
|
* For a net to be shorted to itself is not an error.
|
||||||
* NOTE: Potentially the unique name could be removed
|
* NOTE: Potentially the unique name could be removed
|
||||||
* here and save ext2spice the trouble.
|
* here and save ext2spice the trouble.
|
||||||
|
*
|
||||||
|
* Also: If "extresist" is being run in the same
|
||||||
|
* pass, then don't print an error, because
|
||||||
|
* electrical shorts are meaningless in an R-C
|
||||||
|
* extraction.
|
||||||
*/
|
*/
|
||||||
if ((portname != NULL) &&
|
if ((portname != NULL) &&
|
||||||
|
(!(ExtOptions & EXT_DORESISTANCE)) &&
|
||||||
(ll->ll_attr == LL_PORTATTR) &&
|
(ll->ll_attr == LL_PORTATTR) &&
|
||||||
(strcmp(ll->ll_label->lab_text, portname)))
|
(strcmp(ll->ll_label->lab_text, portname)))
|
||||||
{
|
{
|
||||||
|
|
@ -1110,7 +1126,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]);
|
||||||
|
|
@ -1155,14 +1171,17 @@ 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 ) lp->ll_attr = LL_SORTATTR ;
|
if (lp->ll_attr == nsd)
|
||||||
else if ( lp->ll_attr == nsd+1 ) lp->ll_attr = nsd ;
|
lp->ll_attr = LL_SORTATTR;
|
||||||
for ( lp = ll ; lp ; lp = lp->ll_next )
|
else if (lp->ll_attr == nsd + 1)
|
||||||
if ( lp->ll_attr == LL_SORTATTR ) lp->ll_attr = nsd+1;
|
lp->ll_attr = nsd;
|
||||||
|
for (lp = ll; lp; lp = lp->ll_next)
|
||||||
|
if (lp->ll_attr == LL_SORTATTR)
|
||||||
|
lp->ll_attr = nsd + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while( changed );
|
while (changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1835,6 +1854,8 @@ extOutputDevParams(reg, devptr, outFile, length, width, areavec, perimvec)
|
||||||
ParamList *chkParam;
|
ParamList *chkParam;
|
||||||
HashEntry *he;
|
HashEntry *he;
|
||||||
ResValue resvalue;
|
ResValue resvalue;
|
||||||
|
LabRegion *node; /* Node connected to gate terminal */
|
||||||
|
LabelList *ll; /* Gate's label list */
|
||||||
|
|
||||||
for (chkParam = devptr->exts_deviceParams; chkParam
|
for (chkParam = devptr->exts_deviceParams; chkParam
|
||||||
!= NULL; chkParam = chkParam->pl_next)
|
!= NULL; chkParam = chkParam->pl_next)
|
||||||
|
|
@ -1966,6 +1987,34 @@ extOutputDevParams(reg, devptr, outFile, length, width, areavec, perimvec)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If there are device attribute labels (labels attached to the device
|
||||||
|
* type ending with "^") with "=" in them, then treat them as extra
|
||||||
|
* parameters. Output each one and remove the gate attribute property
|
||||||
|
* from the label.
|
||||||
|
*/
|
||||||
|
|
||||||
|
node = (LabRegion *)ExtGetRegion(reg->treg_tile, reg->treg_dinfo);
|
||||||
|
for (ll = node->lreg_labels; ll; ll = ll->ll_next)
|
||||||
|
{
|
||||||
|
if (ll->ll_attr == LL_GATEATTR)
|
||||||
|
{
|
||||||
|
char cs, *ct, *cp = ll->ll_label->lab_text;
|
||||||
|
if (strchr(cp, '=') != NULL)
|
||||||
|
{
|
||||||
|
/* Since this is an attribute label, it has a special character
|
||||||
|
* at the end, which needs to be stripped off while printing
|
||||||
|
* and then put back again.
|
||||||
|
*/
|
||||||
|
ct = ll->ll_label->lab_text + strlen(ll->ll_label->lab_text) - 1;
|
||||||
|
cs = *ct;
|
||||||
|
*ct = '\0';
|
||||||
|
fprintf(outFile, " %s", ll->ll_label->lab_text);
|
||||||
|
ll->ll_attr = LL_NOATTR;
|
||||||
|
*ct = cs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Structures used by extTermAPFunc() for storing area and perimeter data */
|
/* Structures used by extTermAPFunc() for storing area and perimeter data */
|
||||||
|
|
@ -2155,11 +2204,13 @@ extDevFindParamMatch(devptr, length, width)
|
||||||
*
|
*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
/*ARGSUSED*/
|
||||||
int
|
int
|
||||||
extSDTileFunc(tile, dinfo, pNum)
|
extSDTileFunc(tile, dinfo, pNum, arg)
|
||||||
Tile *tile;
|
Tile *tile;
|
||||||
TileType dinfo; /* (unused) */
|
TileType dinfo; /* UNUSED */
|
||||||
int pNum;
|
int pNum;
|
||||||
|
FindRegion *arg; /* UNUSED */
|
||||||
{
|
{
|
||||||
LinkedTile *newdevtile;
|
LinkedTile *newdevtile;
|
||||||
|
|
||||||
|
|
@ -2620,30 +2671,6 @@ 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 ");
|
||||||
|
|
@ -2725,6 +2752,56 @@ extOutputDevices(def, transList, outFile)
|
||||||
/* get corrected by extComputeEffectiveLW(). */
|
/* get corrected by extComputeEffectiveLW(). */
|
||||||
length = (extTransRec.tr_gatelen - width) / 2;
|
length = (extTransRec.tr_gatelen - width) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((n == 1) && (length == 0) && (extTransRec.tr_gatelen == 0))
|
||||||
|
{
|
||||||
|
/* If a one-terminal device has not recorded any
|
||||||
|
* gate length, then get W and L from the bounding
|
||||||
|
* box of the device. This routine could be much
|
||||||
|
* better optimized but it is probably not worth
|
||||||
|
* the effort. Just reusing the code from above
|
||||||
|
* for creating extSpecialDevice, a list of device
|
||||||
|
* tiles. Note that W and L are not distinguishable
|
||||||
|
* and hopefully the PDK defines the device by area
|
||||||
|
* and perimeter.
|
||||||
|
*/
|
||||||
|
LinkedTile *lt;
|
||||||
|
Rect devbbox, ltbox;
|
||||||
|
|
||||||
|
extSpecialDevice = (LinkedTile *)NULL;
|
||||||
|
|
||||||
|
arg.fra_uninit = (ClientData)extTransRec.tr_gatenode;
|
||||||
|
arg.fra_region = (ExtRegion *)reg;
|
||||||
|
arg.fra_each = extSDTileFunc;
|
||||||
|
ExtFindNeighbors(reg->treg_tile, reg->treg_dinfo,
|
||||||
|
arg.fra_pNum, &arg);
|
||||||
|
|
||||||
|
arg.fra_uninit = (ClientData) reg;
|
||||||
|
arg.fra_region = (ExtRegion *) extTransRec.tr_gatenode;
|
||||||
|
arg.fra_each = (int (*)()) NULL;
|
||||||
|
ExtFindNeighbors(reg->treg_tile, reg->treg_dinfo,
|
||||||
|
arg.fra_pNum, &arg);
|
||||||
|
|
||||||
|
lt = extSpecialDevice;
|
||||||
|
if (lt)
|
||||||
|
{
|
||||||
|
TiToRect(lt->t, &devbbox);
|
||||||
|
for (; lt; lt = lt->t_next)
|
||||||
|
{
|
||||||
|
TiToRect(lt->t, <box);
|
||||||
|
GeoInclude(<box, &devbbox);
|
||||||
|
}
|
||||||
|
free_magic1_t mm1 = freeMagic1_init();
|
||||||
|
for (lt = extSpecialDevice; lt; lt = lt->t_next)
|
||||||
|
freeMagic1(&mm1, (char *)lt);
|
||||||
|
freeMagic1_end(&mm1);
|
||||||
|
}
|
||||||
|
length = devbbox.r_xtop - devbbox.r_xbot;
|
||||||
|
/* Width was likely a perimeter value and will
|
||||||
|
* be recalculated as the actual device width.
|
||||||
|
*/
|
||||||
|
width = devbbox.r_ytop - devbbox.r_ybot;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------*/
|
/*------------------------------------------------------*/
|
||||||
|
|
@ -3867,9 +3944,11 @@ extTermAPFunc(tile, dinfo, eapd)
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*ARGSUSED*/
|
||||||
int
|
int
|
||||||
extTransPerimFunc(bp)
|
extTransPerimFunc(bp, cdata)
|
||||||
Boundary *bp;
|
Boundary *bp;
|
||||||
|
ClientData cdata; /* UNUSED */
|
||||||
{
|
{
|
||||||
TileType tinside, toutside, dinfo;
|
TileType tinside, toutside, dinfo;
|
||||||
Tile *tile;
|
Tile *tile;
|
||||||
|
|
@ -4145,11 +4224,13 @@ extTransPerimFunc(bp)
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*ARGSUSED*/
|
||||||
int
|
int
|
||||||
extAnnularTileFunc(tile, dinfo, pNum)
|
extAnnularTileFunc(tile, dinfo, pNum, arg)
|
||||||
Tile *tile;
|
Tile *tile;
|
||||||
TileType dinfo;
|
TileType dinfo;
|
||||||
int pNum;
|
int pNum;
|
||||||
|
FindRegion *arg; /* UNUSED */
|
||||||
{
|
{
|
||||||
TileTypeBitMask mask;
|
TileTypeBitMask mask;
|
||||||
TileType loctype;
|
TileType loctype;
|
||||||
|
|
@ -4195,11 +4276,13 @@ extAnnularTileFunc(tile, dinfo, pNum)
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*ARGSUSED*/
|
||||||
int
|
int
|
||||||
extResistorTileFunc(tile, dinfo, pNum)
|
extResistorTileFunc(tile, dinfo, pNum, arg)
|
||||||
Tile *tile;
|
Tile *tile;
|
||||||
TileType dinfo;
|
TileType dinfo;
|
||||||
int pNum;
|
int pNum;
|
||||||
|
FindRegion *arg; /* UNUSED */
|
||||||
{
|
{
|
||||||
TileTypeBitMask mask;
|
TileTypeBitMask mask;
|
||||||
TileType loctype;
|
TileType loctype;
|
||||||
|
|
@ -5047,7 +5130,7 @@ extFindNodes(def, clipArea, subonly)
|
||||||
|
|
||||||
pNum = ExtCurStyle->exts_globSubstratePlane;
|
pNum = ExtCurStyle->exts_globSubstratePlane;
|
||||||
/* Does the type set of this plane intersect the substrate types? */
|
/* Does the type set of this plane intersect the substrate types? */
|
||||||
if (TTMaskIntersect(&DBPlaneTypes[pNum], &subsTypesNonSpace))
|
if ((pNum != -1) && TTMaskIntersect(&DBPlaneTypes[pNum], &subsTypesNonSpace))
|
||||||
{
|
{
|
||||||
arg.fra_pNum = pNum;
|
arg.fra_pNum = pNum;
|
||||||
DBSrPaintClient((Tile *) NULL, def->cd_planes[pNum],
|
DBSrPaintClient((Tile *) NULL, def->cd_planes[pNum],
|
||||||
|
|
|
||||||
|
|
@ -76,18 +76,19 @@ void extHeader();
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Plane *
|
Plane *
|
||||||
ExtCell(def, outName, doLength)
|
ExtCell(def, outName, isTop)
|
||||||
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 doLength; /* If TRUE, extract pathlengths from drivers to
|
bool isTop; /* If TRUE, cell is the top level cell */
|
||||||
* 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.
|
||||||
|
|
@ -111,7 +112,7 @@ ExtCell(def, outName, doLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
extNumErrors = extNumWarnings = 0;
|
extNumErrors = extNumWarnings = 0;
|
||||||
savePlane = extCellFile(def, f, doLength);
|
savePlane = extCellFile(def, f, isTop);
|
||||||
if (f != NULL) fclose(f);
|
if (f != NULL) fclose(f);
|
||||||
|
|
||||||
if (extNumErrors > 0 || extNumWarnings > 0)
|
if (extNumErrors > 0 || extNumWarnings > 0)
|
||||||
|
|
@ -471,13 +472,10 @@ ExtRevertSubstrate(def, savePlane)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Plane *
|
Plane *
|
||||||
extCellFile(def, f, doLength)
|
extCellFile(def, f, isTop)
|
||||||
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 doLength; /* TRUE if we should extract driver-receiver path
|
bool isTop; /* TRUE if the cell is the top level cell */
|
||||||
* length information for this cell (see ExtCell
|
|
||||||
* for more details).
|
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
NodeRegion *reg;
|
NodeRegion *reg;
|
||||||
Plane *saveSub;
|
Plane *saveSub;
|
||||||
|
|
@ -488,8 +486,19 @@ extCellFile(def, f, doLength)
|
||||||
/* 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)
|
||||||
|
|
@ -519,7 +528,7 @@ extCellFile(def, f, doLength)
|
||||||
ExtResetTiles(def, CLIENTDEFAULT);
|
ExtResetTiles(def, CLIENTDEFAULT);
|
||||||
|
|
||||||
/* Final pass: extract length information if desired */
|
/* Final pass: extract length information if desired */
|
||||||
if (!SigInterruptPending && doLength && (ExtOptions & EXT_DOLENGTH))
|
if (!SigInterruptPending && isTop && (ExtOptions & EXT_DOLENGTH))
|
||||||
extLength(extParentUse, f);
|
extLength(extParentUse, f);
|
||||||
|
|
||||||
UndoEnable();
|
UndoEnable();
|
||||||
|
|
|
||||||
|
|
@ -115,23 +115,91 @@ bool extTestNMInteract(Tile *t1, TileType di1, Tile *t2, TileType di2)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*----------------------------------------------------------------------
|
*----------------------------------------------------------------------
|
||||||
* extHierSubShieldFunc --
|
* extHierSubInteractFunc --
|
||||||
*
|
*
|
||||||
* Simple callback function for extHierSubstrate() that halts the
|
* Simple callback function for extHierSubShielfFunc() that halts
|
||||||
* search if any substrate shield type is found in the search area
|
* the search if any type connecting to substrate is found in
|
||||||
|
* the area.
|
||||||
|
*
|
||||||
|
* Results: 1 to stop the search.
|
||||||
|
*
|
||||||
|
* Side effects: None.
|
||||||
*
|
*
|
||||||
*----------------------------------------------------------------------
|
*----------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
extHierSubShieldFunc(tile, dinfo, clientdata)
|
extHierSubInteractFunc(tile, dinfo, clientdata)
|
||||||
Tile *tile; /* (unused) */
|
Tile *tile; /* unused */
|
||||||
TileType dinfo; /* (unused) */
|
TileType dinfo; /* unused */
|
||||||
ClientData clientdata; /* (unused) */
|
ClientData clientdata; /* unused */
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*----------------------------------------------------------------------
|
||||||
|
* extHierSubShieldFunc --
|
||||||
|
*
|
||||||
|
* Callback function for extHierSubstrate() that halts the search
|
||||||
|
* if any substrate shield type is found in the search area. To
|
||||||
|
* avoid flagging substrate shields that overlap the search area
|
||||||
|
* but do not interact with the cell, check the area of the
|
||||||
|
* substrate shield for device types that connect to substrate
|
||||||
|
* (ExtCurStyle->exts_subsDevTypes). If something is found, then
|
||||||
|
* return 1 immediately to stop the search.
|
||||||
|
*
|
||||||
|
* Results: 1 if an interacting substrate shield is found, 0 otherwise.
|
||||||
|
*
|
||||||
|
* Side effects: None.
|
||||||
|
*
|
||||||
|
*----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
extHierSubShieldFunc(tile, dinfo, use)
|
||||||
|
Tile *tile;
|
||||||
|
TileType dinfo;
|
||||||
|
CellUse *use;
|
||||||
|
{
|
||||||
|
Rect r, rsub;
|
||||||
|
int pNum;
|
||||||
|
TileType ttype;
|
||||||
|
CellDef *subdef;
|
||||||
|
Transform t;
|
||||||
|
|
||||||
|
if (IsSplit(tile))
|
||||||
|
{
|
||||||
|
ttype = TiGetLeftType(tile);
|
||||||
|
if (!TTMaskHasType(&ExtCurStyle->exts_globSubstrateShieldTypes, ttype))
|
||||||
|
ttype = TiGetRightType(tile);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ttype = TiGetTypeExact(tile);
|
||||||
|
|
||||||
|
TiToRect(tile, &r);
|
||||||
|
|
||||||
|
/* Convert area of tile to the coordinates of the cell "subdef", which is
|
||||||
|
* a child of the cell containing "tile".
|
||||||
|
*/
|
||||||
|
subdef = use->cu_def;
|
||||||
|
GeoInvertTrans(&use->cu_transform, &t);
|
||||||
|
GeoTransRect(&t, &r, &rsub);
|
||||||
|
|
||||||
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||||
|
{
|
||||||
|
if (TTMaskIntersect(&DBPlaneTypes[pNum], &ExtCurStyle->exts_subsDevTypes))
|
||||||
|
{
|
||||||
|
if (DBSrPaintNMArea((Tile *)NULL,
|
||||||
|
subdef->cd_planes[pNum], dinfo, &rsub,
|
||||||
|
&ExtCurStyle->exts_subsDevTypes,
|
||||||
|
extHierSubInteractFunc, (ClientData)NULL) == 1)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*----------------------------------------------------------------------
|
*----------------------------------------------------------------------
|
||||||
* extHierSubstrate --
|
* extHierSubstrate --
|
||||||
|
|
@ -229,7 +297,7 @@ extHierSubstrate(ha, use, x, y)
|
||||||
if (DBSrPaintArea((Tile *) NULL,
|
if (DBSrPaintArea((Tile *) NULL,
|
||||||
def->cd_planes[pNum], &subArea,
|
def->cd_planes[pNum], &subArea,
|
||||||
&ExtCurStyle->exts_globSubstrateShieldTypes,
|
&ExtCurStyle->exts_globSubstrateShieldTypes,
|
||||||
extHierSubShieldFunc, (ClientData)NULL) != 0)
|
extHierSubShieldFunc, PTR2CD(use)) != 0)
|
||||||
{
|
{
|
||||||
freeMagic(nodeList);
|
freeMagic(nodeList);
|
||||||
ExtResetTiles(use->cu_def, CLIENTDEFAULT);
|
ExtResetTiles(use->cu_def, CLIENTDEFAULT);
|
||||||
|
|
@ -281,6 +349,13 @@ 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
|
||||||
|
|
@ -294,6 +369,13 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -354,8 +436,8 @@ extHierConnections(ha, cumFlat, oneFlat)
|
||||||
if (!(lab->lab_flags & LABEL_STICKY)) continue;
|
if (!(lab->lab_flags & LABEL_STICKY)) continue;
|
||||||
|
|
||||||
r = lab->lab_rect;
|
r = lab->lab_rect;
|
||||||
|
if (!GEO_TOUCH(&r, &ha->ha_subArea)) continue;
|
||||||
GEOCLIP(&r, &ha->ha_subArea);
|
GEOCLIP(&r, &ha->ha_subArea);
|
||||||
if (GEO_RECTNULL(&r)) continue;
|
|
||||||
|
|
||||||
cumDef = cumFlat->et_use->cu_def;
|
cumDef = cumFlat->et_use->cu_def;
|
||||||
connected = &DBConnectTbl[lab->lab_type];
|
connected = &DBConnectTbl[lab->lab_type];
|
||||||
|
|
@ -499,6 +581,13 @@ 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
|
||||||
|
|
@ -514,6 +603,13 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -523,6 +619,48 @@ 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
|
||||||
|
|
@ -538,6 +676,8 @@ extHierConnectFunc1(oneTile, dinfo, ha)
|
||||||
* 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
|
||||||
|
|
@ -608,6 +748,53 @@ 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)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
|
@ -622,6 +809,12 @@ 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
|
||||||
{
|
{
|
||||||
|
|
@ -637,6 +830,12 @@ 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -733,6 +932,13 @@ 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
|
||||||
|
|
@ -748,6 +954,13 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -916,6 +1129,7 @@ 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)))
|
||||||
|
|
@ -948,7 +1162,6 @@ 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 */
|
||||||
|
|
@ -960,6 +1173,23 @@ 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);
|
||||||
|
|
@ -1005,6 +1235,7 @@ 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;
|
TileType dinfo; /* (unused) */
|
||||||
TreeContext *cxp;
|
TreeContext *cxp;
|
||||||
{
|
{
|
||||||
SearchContext newscx;
|
SearchContext newscx;
|
||||||
|
|
@ -343,8 +343,9 @@ extInterOverlapSubtree(scx)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
extInterOverlapTile(tile, cxp)
|
extInterOverlapTile(tile, dinfo, 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();
|
int extDefInitFunc(CellDef *, ClientData); /* UNUSED */
|
||||||
void extDefPush();
|
void extDefPush();
|
||||||
void extDefIncremental();
|
void extDefIncremental();
|
||||||
void extParents();
|
void extParents();
|
||||||
|
|
@ -395,9 +395,11 @@ 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)
|
extDefInitFunc(def, cdata)
|
||||||
CellDef *def;
|
CellDef *def;
|
||||||
|
ClientData cdata; /* UNUSED */
|
||||||
{
|
{
|
||||||
def->cd_client = (ClientData) 0;
|
def->cd_client = (ClientData) 0;
|
||||||
return (0);
|
return (0);
|
||||||
|
|
@ -471,6 +473,19 @@ 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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -614,6 +614,7 @@ termtop:
|
||||||
|
|
||||||
termdone:
|
termdone:
|
||||||
/* (continue) */
|
/* (continue) */
|
||||||
|
(void)0; /* older compilers need a statement after the label to prevent a compile error */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clean up---Put the ClientData entries in the tiles back to
|
/* Clean up---Put the ClientData entries in the tiles back to
|
||||||
|
|
|
||||||
|
|
@ -54,12 +54,14 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
||||||
/* C99 compat */
|
/* C99 compat */
|
||||||
#include "drc/drc.h"
|
#include "drc/drc.h"
|
||||||
|
|
||||||
#ifdef exactinteractions
|
|
||||||
/*
|
/*
|
||||||
* If "exactinteractions" is defined, we use an experimental algorithm
|
* If "exactinteractions" is defined, use an experimental algorithm
|
||||||
* for finding exact interaction areas. Currently it doesn't work too
|
* for finding exact interaction areas. Currently it doesn't work
|
||||||
* well, so we leave it turned off.
|
* too well, so it is disabled.
|
||||||
*/
|
*/
|
||||||
|
/* #define exactinteractions */
|
||||||
|
|
||||||
|
#ifdef exactinteractions
|
||||||
int ExtInterBloat = 10;
|
int ExtInterBloat = 10;
|
||||||
#endif /* exactinteractions */
|
#endif /* exactinteractions */
|
||||||
|
|
||||||
|
|
@ -174,8 +176,10 @@ 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 */
|
||||||
|
|
||||||
|
|
@ -251,6 +255,17 @@ extSubtree(parentUse, reg, f)
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
/* If result == FALSE then ha.ha_interArea is invalid. */
|
/* If result == FALSE then ha.ha_interArea is invalid. */
|
||||||
ha.ha_interArea = rlab;
|
ha.ha_interArea = rlab;
|
||||||
|
/* Ensure that the interaction area is not zero */
|
||||||
|
if (ha.ha_interArea.r_xtop - ha.ha_interArea.r_xbot == 0)
|
||||||
|
{
|
||||||
|
ha.ha_interArea.r_xtop++;
|
||||||
|
ha.ha_interArea.r_xbot--;
|
||||||
|
}
|
||||||
|
if (ha.ha_interArea.r_ytop - ha.ha_interArea.r_ybot == 0)
|
||||||
|
{
|
||||||
|
ha.ha_interArea.r_ytop++;
|
||||||
|
ha.ha_interArea.r_ybot--;
|
||||||
|
}
|
||||||
result = 1;
|
result = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -337,7 +352,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 = DISPLAY_IDLE;
|
GrDisplayStatus = savedDisplayStatus;
|
||||||
SigRemoveTimer();
|
SigRemoveTimer();
|
||||||
|
|
||||||
/* Clear the CU_SUB_EXTRACTED flag from all children instances */
|
/* Clear the CU_SUB_EXTRACTED flag from all children instances */
|
||||||
|
|
@ -779,6 +794,7 @@ extSubtreeFunc(scx, ha)
|
||||||
*/
|
*/
|
||||||
ha->ha_subArea = use->cu_bbox;
|
ha->ha_subArea = use->cu_bbox;
|
||||||
GEOCLIP(&ha->ha_subArea, &ha->ha_interArea);
|
GEOCLIP(&ha->ha_subArea, &ha->ha_interArea);
|
||||||
|
|
||||||
hy.hy_area = &ha->ha_subArea;
|
hy.hy_area = &ha->ha_subArea;
|
||||||
hy.hy_target = oneFlat->et_use;
|
hy.hy_target = oneFlat->et_use;
|
||||||
hy.hy_prefix = TRUE;
|
hy.hy_prefix = TRUE;
|
||||||
|
|
|
||||||
|
|
@ -836,6 +836,7 @@ extTechStyleInit(style)
|
||||||
|
|
||||||
style->exts_sidePlanes = style->exts_overlapPlanes = 0;
|
style->exts_sidePlanes = style->exts_overlapPlanes = 0;
|
||||||
TTMaskZero(&style->exts_deviceMask);
|
TTMaskZero(&style->exts_deviceMask);
|
||||||
|
TTMaskZero(&style->exts_subsDevTypes);
|
||||||
style->exts_activeTypes = DBAllButSpaceAndDRCBits;
|
style->exts_activeTypes = DBAllButSpaceAndDRCBits;
|
||||||
|
|
||||||
for (r = 0; r < NP; r++)
|
for (r = 0; r < NP; r++)
|
||||||
|
|
@ -2355,6 +2356,9 @@ ExtTechLine(sectionName, argc, argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
TTMaskSetMask(&ExtCurStyle->exts_deviceMask, &types1);
|
TTMaskSetMask(&ExtCurStyle->exts_deviceMask, &types1);
|
||||||
|
if (!TTMaskIsZero(&subsTypes))
|
||||||
|
TTMaskSetMask(&ExtCurStyle->exts_subsDevTypes, &types1);
|
||||||
|
|
||||||
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
|
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
|
||||||
if (TTMaskHasType(&types1, t))
|
if (TTMaskHasType(&types1, t))
|
||||||
{
|
{
|
||||||
|
|
@ -2380,6 +2384,7 @@ ExtTechLine(sectionName, argc, argv)
|
||||||
|
|
||||||
devptr->exts_next = ExtCurStyle->exts_device[t];
|
devptr->exts_next = ExtCurStyle->exts_device[t];
|
||||||
ExtCurStyle->exts_device[t] = devptr;
|
ExtCurStyle->exts_device[t] = devptr;
|
||||||
|
|
||||||
#ifdef ARIEL
|
#ifdef ARIEL
|
||||||
{
|
{
|
||||||
int z;
|
int z;
|
||||||
|
|
@ -2867,6 +2872,8 @@ ExtTechLine(sectionName, argc, argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
TTMaskSetMask(&ExtCurStyle->exts_deviceMask, &types1);
|
TTMaskSetMask(&ExtCurStyle->exts_deviceMask, &types1);
|
||||||
|
if (!TTMaskIsZero(&subsTypes))
|
||||||
|
TTMaskSetMask(&ExtCurStyle->exts_subsDevTypes, &types1);
|
||||||
|
|
||||||
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
|
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -288,9 +288,11 @@ ExtTimes(rootUse, f)
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*ARGSUSED*/
|
||||||
int
|
int
|
||||||
extTimesInitFunc(use)
|
extTimesInitFunc(use, cdata)
|
||||||
CellUse *use;
|
CellUse *use;
|
||||||
|
ClientData cdata; /* UNUSED */
|
||||||
{
|
{
|
||||||
CellDef *def = use->cu_def;
|
CellDef *def = use->cu_def;
|
||||||
struct cellStats *cs;
|
struct cellStats *cs;
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,8 @@ 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.
|
||||||
|
|
@ -226,8 +228,9 @@ 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 ||
|
||||||
&& !(ll->ll_label->lab_flags & PORT_DIR_MASK))
|
option == EXT_UNIQ_TEMP_NOPORTS) &&
|
||||||
|
!(ll->ll_label->lab_flags & PORT_DIR_MASK))
|
||||||
goto makeUnique;
|
goto makeUnique;
|
||||||
|
|
||||||
cpend = strchr(text, '\0');
|
cpend = strchr(text, '\0');
|
||||||
|
|
@ -326,7 +329,8 @@ makeUnique:
|
||||||
saveLab = *lab;
|
saveLab = *lab;
|
||||||
|
|
||||||
/* Flag this label as having been modified */
|
/* Flag this label as having been modified */
|
||||||
if (option == EXT_UNIQ_TEMP) flags |= LABEL_UNIQUE;
|
if ((option == EXT_UNIQ_TEMP) || (option == EXT_UNIQ_TEMP_NOPORTS))
|
||||||
|
flags |= LABEL_UNIQUE;
|
||||||
|
|
||||||
DBRemoveLabel(def, lab);
|
DBRemoveLabel(def, lab);
|
||||||
DBPutFontLabel(def, &saveLab.lab_rect,
|
DBPutFontLabel(def, &saveLab.lab_rect,
|
||||||
|
|
|
||||||
|
|
@ -71,11 +71,12 @@ extern const char * const extDevTable[];
|
||||||
#define EXT_DORESISTANCE 0x008 /* Extract lumped resistance */
|
#define EXT_DORESISTANCE 0x008 /* Extract lumped resistance */
|
||||||
#define EXT_DOLENGTH 0x010 /* Extract pathlengths */
|
#define EXT_DOLENGTH 0x010 /* Extract pathlengths */
|
||||||
#define EXT_DOFRINGEHALO 0x020 /* Distributed fringe capacitance */
|
#define EXT_DOFRINGEHALO 0x020 /* Distributed fringe capacitance */
|
||||||
#define EXT_DOALL 0x03f /* ALL OF THE ABOVE */
|
#define EXT_DOUNIQUE 0x100 /* Force unique nodes during extraction */
|
||||||
|
#define EXT_DOALL 0x13f /* ALL OF THE ABOVE */
|
||||||
#define EXT_DOLABELCHECK 0x040 /* Check for connections by label */
|
#define EXT_DOLABELCHECK 0x040 /* Check for connections by label */
|
||||||
#define EXT_DOALIASES 0x080 /* Output all node aliases */
|
#define EXT_DOALIASES 0x080 /* Output all node aliases */
|
||||||
#define EXT_DOUNIQUE 0x100 /* Force unique nodes during extraction */
|
|
||||||
#define EXT_DOEXTRESIST 0x200 /* Do full R-C extraction */
|
#define EXT_DOEXTRESIST 0x200 /* Do full R-C extraction */
|
||||||
|
#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 */
|
||||||
|
|
@ -86,6 +87,7 @@ 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();
|
||||||
|
|
|
||||||
|
|
@ -626,6 +626,13 @@ typedef struct extstyle
|
||||||
*/
|
*/
|
||||||
TileTypeBitMask exts_deviceConn[NT];
|
TileTypeBitMask exts_deviceConn[NT];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List of device types which connect to a substrate type. This
|
||||||
|
* distinguishes between devices that make a connection to substrate
|
||||||
|
* (e.g., FETs) and those that don't (e.g., MiM caps, metal resistors).
|
||||||
|
*/
|
||||||
|
TileTypeBitMask exts_subsDevTypes;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set of types to be considered for extraction. Types not in
|
* Set of types to be considered for extraction. Types not in
|
||||||
* this list cannot be nodes (e.g., implant layers)
|
* this list cannot be nodes (e.g., implant layers)
|
||||||
|
|
@ -981,6 +988,7 @@ 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
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "utils/hash.h"
|
#include "utils/hash.h"
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "windows/windows.h"
|
#include "windows/windows.h"
|
||||||
|
|
@ -62,6 +61,74 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*---------------------------------------------------------
|
*---------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
|
@ -247,8 +314,10 @@ 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. */
|
||||||
|
|
||||||
|
|
@ -260,25 +329,49 @@ nullSetDisplay(dispType, outFileName, mouseFileName)
|
||||||
|
|
||||||
GrEnableTabletPtr = nullDoNothing;
|
GrEnableTabletPtr = nullDoNothing;
|
||||||
GrDisableTabletPtr = nullDoNothing;
|
GrDisableTabletPtr = nullDoNothing;
|
||||||
GrSetCursorPtr = nullDoNothing;
|
GrSetCursorPtr = (void (*)()) nullDoNothingI;
|
||||||
GrTextSizePtr = NullTextSize;
|
GrTextSizePtr = NullTextSize;
|
||||||
GrDrawGlyphPtr = nullDoNothing;
|
GrDrawGlyphPtr = (void (*)()) nullDoNothingII;
|
||||||
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 = nullDoNothing;
|
grSetSPatternPtr = (void (*)()) nullDoNothingII;
|
||||||
grPutTextPtr = nullDoNothing;
|
grPutTextPtr = (void (*)()) nullDoNothingIIII;
|
||||||
grFontTextPtr = nullDoNothing;
|
grFontTextPtr = (void (*)()) nullDoNothingIIIIIII;
|
||||||
grDefineCursorPtr = nullDoNothing;
|
grDefineCursorPtr = (void (*)()) nullDoNothingI;
|
||||||
grDrawGridPtr = nullReturnFalse;
|
grFreeCursorPtr = (void (*)()) nullDoNothingI;
|
||||||
grDrawLinePtr = nullDoNothing;
|
grDrawGridPtr = (bool (*)()) nullReturnFalseIII;
|
||||||
grSetWMandCPtr = nullDoNothing;
|
grDrawLinePtr = (void (*)()) nullDoNothingIIII;
|
||||||
grFillRectPtr = nullDoNothing;
|
grSetWMandCPtr = (void (*)()) nullDoNothingII;
|
||||||
grSetStipplePtr = nullDoNothing;
|
grFillRectPtr = (void (*)()) nullDoNothingI;
|
||||||
grSetLineStylePtr = nullDoNothing;
|
grFillPolygonPtr = (void (*)()) nullDoNothingII;
|
||||||
grSetCharSizePtr = nullDoNothing;
|
grSetStipplePtr = (void (*)()) nullDoNothingI;
|
||||||
|
grSetLineStylePtr = (void (*)()) nullDoNothingI;
|
||||||
|
grSetCharSizePtr = (void (*)()) nullDoNothingI;
|
||||||
|
|
||||||
GrScreenRect.r_xtop = 511;
|
GrScreenRect.r_xtop = 511;
|
||||||
GrScreenRect.r_ytop = 483;
|
GrScreenRect.r_ytop = 483;
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
#include "windows/windows.h"
|
#include "windows/windows.h"
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@
|
||||||
#include "utils/main.h"
|
#include "utils/main.h"
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/malloc.h"
|
#include "utils/malloc.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "windows/windows.h"
|
#include "windows/windows.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@
|
||||||
|
|
||||||
#include "tcltk/tclmagic.h"
|
#include "tcltk/tclmagic.h"
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "windows/windows.h"
|
#include "windows/windows.h"
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@
|
||||||
#include "utils/main.h"
|
#include "utils/main.h"
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/malloc.h"
|
#include "utils/malloc.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "windows/windows.h"
|
#include "windows/windows.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@
|
||||||
|
|
||||||
#include "tcltk/tclmagic.h"
|
#include "tcltk/tclmagic.h"
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "windows/windows.h"
|
#include "windows/windows.h"
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@
|
||||||
#include "utils/main.h"
|
#include "utils/main.h"
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/malloc.h"
|
#include "utils/malloc.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "windows/windows.h"
|
#include "windows/windows.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@
|
||||||
|
|
||||||
#include "tcltk/tclmagic.h"
|
#include "tcltk/tclmagic.h"
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "windows/windows.h"
|
#include "windows/windows.h"
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
|
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "textio/txcommands.h"
|
#include "textio/txcommands.h"
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
#include "utils/magic.h"
|
#include "utils/magic.h"
|
||||||
#include "utils/magsgtty.h"
|
|
||||||
#include "textio/textio.h"
|
#include "textio/textio.h"
|
||||||
#include "utils/geometry.h"
|
#include "utils/geometry.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,14 @@
|
||||||
|
|
||||||
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 \
|
||||||
|
|
@ -37,7 +41,35 @@ 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)
|
||||||
|
# magicWasm.c bootstraps the embedded Tcl interp by calling Tcl_CreateInterp /
|
||||||
|
# Tcl_Init before tclStubsPtr is initialised. With -DUSE_TCL_STUBS those calls
|
||||||
|
# expand to (*tclStubsPtr->...)() and dereference a NULL stubs pointer; so
|
||||||
|
# this one file must be compiled with DFLAGS_NOSTUB (= DFLAGS without
|
||||||
|
# -DUSE_TCL_STUBS). All other files keep using stubs.
|
||||||
|
magicWasm.o: magicWasm.c
|
||||||
|
@echo --- compiling magic/magicWasm.o '(no Tcl stubs)'
|
||||||
|
${RM} magicWasm.o
|
||||||
|
${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS_NOSTUB} -c magicWasm.c
|
||||||
|
|
||||||
|
magic.js: lib${MODULE}.o ${EXTRA_LIBS}
|
||||||
|
@echo --- building main magic WASM
|
||||||
|
${RM} magic.js magic.wasm
|
||||||
|
ifneq (${TCL_LIB_DIR},)
|
||||||
|
# TCL variant: pull in the main TCL archive (LIB_SPECS_NOSTUB → -ltcl9.x) and
|
||||||
|
# the stub-bootstrap archive (-ltclstub). Both are required: magic's objects
|
||||||
|
# use USE_TCL_STUBS macros (resolved by tclStubsPtr from libtclstub.a), and
|
||||||
|
# tclStubsPtr itself must point into the real TCL implementation (libtcl9.x.a).
|
||||||
|
${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} lib${MODULE}.o ${EXTRA_LIBS} -o magic.js ${LIBS} ${LIB_SPECS_NOSTUB} -L${TCL_LIB_DIR} -ltclstub
|
||||||
|
else
|
||||||
|
${CC} ${CFLAGS} ${CPPFLAGS} ${DFLAGS} lib${MODULE}.o ${EXTRA_LIBS} -o magic.js ${LIBS}
|
||||||
|
endif
|
||||||
|
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
|
||||||
|
|
||||||
|
|
@ -78,3 +110,14 @@ $(DESTDIR)${INSTALL_SYSDIR}/magicps.pro: magicps.pro
|
||||||
${CP} magicps.pro $(DESTDIR)${INSTALL_SYSDIR}/magicps.pro
|
${CP} magicps.pro $(DESTDIR)${INSTALL_SYSDIR}/magicps.pro
|
||||||
|
|
||||||
include ${MAGICDIR}/rules.mak
|
include ${MAGICDIR}/rules.mak
|
||||||
|
|
||||||
|
ifeq (${MAKE_WASM},1)
|
||||||
|
# rules.mak defines `${MODULE}` (= `magic`) with a recipe that links a native
|
||||||
|
# executable without the TCL libraries. For the WASM build the real artifact
|
||||||
|
# is `magic.js` (+ `magic.wasm`), so override the target to be a phony alias
|
||||||
|
# that just rebuilds magic.js. Must come after the include so make uses this
|
||||||
|
# recipe instead of rules.mak's.
|
||||||
|
.PHONY: magic
|
||||||
|
magic: magic.js
|
||||||
|
@:
|
||||||
|
endif
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,14 @@ main(int argc, char *argv[])
|
||||||
* here, nor its format. It is updated by the Makefile in this directory.
|
* here, nor its format. It is updated by the Makefile in this directory.
|
||||||
*
|
*
|
||||||
* The version string originates at the top of scripts/config.
|
* The version string originates at the top of scripts/config.
|
||||||
|
*
|
||||||
|
* Under MAGIC_WRAPPER (Tcl-embedded builds), tclmagic.c owns these globals;
|
||||||
|
* defining them here as well would produce duplicate-symbol errors when both
|
||||||
|
* objects end up in the same binary (as in the WASM build).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef MAGIC_WRAPPER
|
||||||
char *MagicVersion = MAGIC_VERSION;
|
char *MagicVersion = MAGIC_VERSION;
|
||||||
char *MagicRevision = MAGIC_REVISION;
|
char *MagicRevision = MAGIC_REVISION;
|
||||||
char *MagicCompileTime = MAGIC_BUILDDATE;
|
char *MagicCompileTime = MAGIC_BUILDDATE;
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,194 @@
|
||||||
|
/*
|
||||||
|
* magicWasm.c --
|
||||||
|
*
|
||||||
|
* Headless Emscripten entry points for running Magic without a
|
||||||
|
* terminal-driven event loop.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef MAGIC_WRAPPER
|
||||||
|
#include "tcltk/tclmagic.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MAGIC_WRAPPER
|
||||||
|
/* Forward decl — Tclmagic_Init bootstraps the Tcl interpreter (registers
|
||||||
|
* the magic::initialize command and calls Tcl_InitStubs(), which sets
|
||||||
|
* tclStubsPtr). Without this, any Tcl_X macro dereferences a NULL stubs
|
||||||
|
* pointer at runtime (crashes the wasm). The actual magic:: commands
|
||||||
|
* (magic::load, magic::gds, etc.) are registered separately by
|
||||||
|
* TclmagicRegisterCommands() after magicMainInit() populates the clients. */
|
||||||
|
extern int Tclmagic_Init(Tcl_Interp *interp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE int
|
||||||
|
magic_wasm_init(void)
|
||||||
|
{
|
||||||
|
static char *argv[] = {
|
||||||
|
"magic",
|
||||||
|
"-d",
|
||||||
|
"null",
|
||||||
|
"-T",
|
||||||
|
"minimum",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
if (magicWasmEnsureCadRoot() != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#ifdef MAGIC_WRAPPER
|
||||||
|
/* In wrapper mode, magic's code (and our PaExpand path expansion) reaches
|
||||||
|
* for `magicinterp` to resolve $env vars via Tcl_GetVar. In the normal
|
||||||
|
* Linux flow Tclmagic_Init() is called by tclsh after dlopen(); here we
|
||||||
|
* embed the interp directly, so we have to bootstrap it before
|
||||||
|
* magicMainInit() runs anything that might touch Tcl.
|
||||||
|
*
|
||||||
|
* Note: we deliberately avoid TxError here — in MAGIC_WRAPPER mode
|
||||||
|
* TxError flushes via Tcl_EvalEx through tclStubsPtr, which only becomes
|
||||||
|
* non-NULL after Tclmagic_Init -> Tcl_InitStubs. So early errors go
|
||||||
|
* straight to stderr. */
|
||||||
|
if (magicinterp == NULL)
|
||||||
|
{
|
||||||
|
Tcl_Interp *interp = Tcl_CreateInterp();
|
||||||
|
if (interp == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "magic_wasm_init: Tcl_CreateInterp returned NULL\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Tcl_Init loads /init.tcl from the Tcl library directory; in our
|
||||||
|
* embedded VFS that script isn't shipped, so failure here is expected
|
||||||
|
* and non-fatal — the interpreter itself is still usable for embedded
|
||||||
|
* evaluation, which is all we need. */
|
||||||
|
(void)Tcl_Init(interp);
|
||||||
|
consoleinterp = interp;
|
||||||
|
if (Tclmagic_Init(interp) != TCL_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "magic_wasm_init: Tclmagic_Init failed: %s\n",
|
||||||
|
Tcl_GetStringResult(interp));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{
|
||||||
|
static int commandsRegistered = FALSE;
|
||||||
|
int rc = magicMainInit(5, argv);
|
||||||
|
#ifdef MAGIC_WRAPPER
|
||||||
|
if (rc == 0 && !commandsRegistered)
|
||||||
|
{
|
||||||
|
TclmagicRegisterCommands(magicinterp);
|
||||||
|
commandsRegistered = TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
#ifdef MAGIC_WRAPPER
|
||||||
|
/* In wrapper mode the command is Tcl. Evaluate it via the magic interp;
|
||||||
|
* the magic backend is reachable through ::magic:: ensemble commands. */
|
||||||
|
if (magicinterp == NULL)
|
||||||
|
return -1;
|
||||||
|
return Tcl_EvalEx(magicinterp, command, -1, 0);
|
||||||
|
#else
|
||||||
|
return TxDispatchString(command, FALSE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE int
|
||||||
|
magic_wasm_source_file(const char *path)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
|
||||||
|
status = magic_wasm_init();
|
||||||
|
if (status != 0)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
if ((path == NULL) || (*path == '\0'))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#ifdef MAGIC_WRAPPER
|
||||||
|
/* In wrapper mode the file contains Tcl; evaluate it through the
|
||||||
|
* Tcl interpreter so that magic:: commands are dispatched via
|
||||||
|
* _tcl_dispatch just like magic_wasm_run_command does for strings. */
|
||||||
|
if (magicinterp == NULL)
|
||||||
|
return -1;
|
||||||
|
return Tcl_EvalFile(magicinterp, path);
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
FILE *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 center of the screen so that
|
||||||
|
* WindSendCommand routes all commands from the file to the layout
|
||||||
|
* window client. Without this, commands arrive with point (0,0)
|
||||||
|
* and end up in the border/windClient context where most are unknown. */
|
||||||
|
TxSetPoint(GrScreenRect.r_xtop / 2, GrScreenRect.r_ytop / 2,
|
||||||
|
WIND_UNKNOWN_WINDOW);
|
||||||
|
TxDispatch(f);
|
||||||
|
fclose(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void
|
||||||
|
magic_wasm_update(void)
|
||||||
|
{
|
||||||
|
if (magic_wasm_init() == 0)
|
||||||
|
WindUpdate();
|
||||||
|
}
|
||||||
|
|
@ -26,17 +26,19 @@ StipplePattern begin
|
||||||
/FontMatrix [1 0 0 1 0 0] def
|
/FontMatrix [1 0 0 1 0 0] def
|
||||||
/FontBBox [0 0 1 1] def
|
/FontBBox [0 0 1 1] def
|
||||||
/Encoding 256 array def
|
/Encoding 256 array def
|
||||||
/PattName (P0) def
|
/PattName (P000) def
|
||||||
/tmpStr 1 string def
|
/tmpStr 3 string def
|
||||||
/NoPatt {<00>} def
|
/NoPatt {<00>} def
|
||||||
0 1 255 { Encoding exch /NoPatt put } for
|
0 1 255 { Encoding exch /NoPatt put } for
|
||||||
/BuildChar {
|
/BuildChar {
|
||||||
1 0 0 0 1 1 setcachedevice exch begin Encoding exch get load
|
1 0 0 0 1 1 setcachedevice exch begin Encoding exch get load
|
||||||
64 64 true [64 0 0 64 0 0] 5 -1 roll imagemask end } def
|
64 64 true [64 0 0 64 0 0] 5 -1 roll imagemask end } def
|
||||||
end
|
end
|
||||||
/dp { StipplePattern begin dup 30 tmpStr cvrs PattName exch 1 exch
|
/dp { StipplePattern begin
|
||||||
putinterval PattName cvn dup Encoding exch 4 -1 roll exch put exch
|
dup 10 tmpStr cvrs /num exch def
|
||||||
store end } def
|
PattName 1 num putinterval
|
||||||
|
PattName 0 num length 1 add getinterval cvn
|
||||||
|
dup Encoding exch 4 -1 roll exch put exch store end } def
|
||||||
/sf { findfont exch scalefont setfont } bind def
|
/sf { findfont exch scalefont setfont } bind def
|
||||||
/sp { patterns setfont 2 setlinewidth } def
|
/sp { patterns setfont 2 setlinewidth } def
|
||||||
/lb { gsave translate 0 0 moveto /just exch def gsave dup true charpath
|
/lb { gsave translate 0 0 moveto /just exch def gsave dup true charpath
|
||||||
|
|
@ -68,4 +70,3 @@ end
|
||||||
x y moveto w y lineto w h lineto x h lineto closepath clip bx } def
|
x y moveto w y lineto w h lineto x h lineto closepath clip bx } def
|
||||||
/tb {1 sub 3 1 roll gsave newpath moveto {lineto} repeat closepath clip pathbbox
|
/tb {1 sub 3 1 roll gsave newpath moveto {lineto} repeat closepath clip pathbbox
|
||||||
/h exch def /w exch def /y exch def /x exch def bx } def
|
/h exch def /w exch def /y exch def /x exch def bx } def
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Variant build outputs (regenerable via npm/build.sh).
|
||||||
|
tcl/magic.js
|
||||||
|
tcl/magic.wasm
|
||||||
|
notcl/magic.js
|
||||||
|
notcl/magic.wasm
|
||||||
|
|
||||||
|
# Pre-restructure artifacts (just in case anyone still has them locally).
|
||||||
|
magic.js
|
||||||
|
magic.wasm
|
||||||
|
|
||||||
|
*.tgz
|
||||||
|
node_modules/
|
||||||
|
package-lock.json
|
||||||
|
examples/output/
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
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.
|
||||||
|
|
@ -0,0 +1,235 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
The package ships two variants:
|
||||||
|
|
||||||
|
| Variant | Entry point | Description |
|
||||||
|
|---------|-------------|-------------|
|
||||||
|
| **notcl** (default) | `magic-vlsi-wasm` | Standalone — no Tcl interpreter. Commands are plain Magic command strings. |
|
||||||
|
| **tcl** | `magic-vlsi-wasm/tcl` | Embeds a full Tcl 9 interpreter. Commands are evaluated as Tcl; Magic commands are available as the `::magic::` ensemble. |
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
The package is published to GitHub Packages. Add the following to your
|
||||||
|
project's `.npmrc` so npm knows where to find it:
|
||||||
|
|
||||||
|
```
|
||||||
|
@rtimothyedwards:registry=https://npm.pkg.github.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Then install:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @rtimothyedwards/magic-vlsi-wasm
|
||||||
|
```
|
||||||
|
|
||||||
|
If the package is private or you hit a 401, authenticate with a GitHub
|
||||||
|
[personal access token](https://github.com/settings/tokens) that has the
|
||||||
|
`read:packages` scope:
|
||||||
|
|
||||||
|
```
|
||||||
|
//npm.pkg.github.com/:_authToken=YOUR_TOKEN
|
||||||
|
@rtimothyedwards:registry=https://npm.pkg.github.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Requires Node.js 18 or newer.
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
### Default variant (no Tcl)
|
||||||
|
|
||||||
|
```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');
|
||||||
|
```
|
||||||
|
|
||||||
|
### TCL variant
|
||||||
|
|
||||||
|
```js
|
||||||
|
import createMagic from 'magic-vlsi-wasm/tcl';
|
||||||
|
|
||||||
|
const { runCommand, FS } = await createMagic();
|
||||||
|
|
||||||
|
// Pure Tcl works directly
|
||||||
|
runCommand('set x 42');
|
||||||
|
runCommand('puts $tcl_version');
|
||||||
|
|
||||||
|
// Magic commands are available as the ::magic:: ensemble
|
||||||
|
runCommand('magic::tech load scmos');
|
||||||
|
runCommand('magic::load /work/inv');
|
||||||
|
runCommand('magic::gds write /work/inv');
|
||||||
|
```
|
||||||
|
|
||||||
|
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 # both variants, debug build
|
||||||
|
bash npm/build.sh --variant=notcl # default variant only (faster)
|
||||||
|
bash npm/build.sh --variant=tcl # TCL variant only
|
||||||
|
bash npm/build.sh --release # optimized (-O2, no debug symbols)
|
||||||
|
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)
|
||||||
|
on your PATH. If you pass `EMSDK_DIR=/path/to/emsdk`, `build.sh` sources
|
||||||
|
`emsdk_env.sh` for you.
|
||||||
|
|
||||||
|
### TCL variant: cloning the TCL source tree
|
||||||
|
|
||||||
|
The TCL variant links against a static WASM build of
|
||||||
|
[tcltk/tcl](https://github.com/tcltk/tcl). `build.sh` clones the source tree
|
||||||
|
automatically into `build-tcl-wasm/tcl` on the first run and builds it
|
||||||
|
out-of-source in the same directory — everything stays under `build-tcl-wasm/`
|
||||||
|
(which is gitignored), so nothing outside it is touched. Subsequent runs reuse
|
||||||
|
the existing clone and build.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Override the TCL version or source repository
|
||||||
|
TCL_REF=core-9-0-3 bash npm/build.sh --variant=tcl
|
||||||
|
TCL_REPO_URL=https://github.com/tcltk/tcl.git bash npm/build.sh --variant=tcl
|
||||||
|
```
|
||||||
|
|
||||||
|
CI always resolves the latest stable `core-9-0-x` tag automatically. To build
|
||||||
|
against a specific version, set `TCL_REF` in the environment.
|
||||||
|
|
||||||
|
## Versioning
|
||||||
|
|
||||||
|
Published versions follow the scheme `{MAJOR}.{MINOR}.{PATCH}0{YYYYMMDD}+git{SHA}`,
|
||||||
|
for example `8.3.799020261231+git01234cde`.
|
||||||
|
|
||||||
|
The date is embedded directly into the patch number (separated by a leading
|
||||||
|
zero for readability). This means:
|
||||||
|
|
||||||
|
- Versions are orderable numerically — a later build date is always a higher
|
||||||
|
version number within the same patch series.
|
||||||
|
- Security or bugfix releases for `8.3.799` can be inserted as later dates
|
||||||
|
(`8.3.799020270101`, `8.3.799020270201`, …) without bumping the patch number.
|
||||||
|
- Users who want to lock to the `8.3.799` series and receive only those patches
|
||||||
|
can use the range `<=8.3.799900000000` or `<8.3.8000000000000`.
|
||||||
|
- `~8.3.799` matches all `8.3.*` versions (broader than the 799 series alone).
|
||||||
|
|
||||||
|
The `+git…` suffix is build metadata — it is ignored by npm for version
|
||||||
|
comparison and range matching. It exists purely for traceability.
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
- Headless only. There is no display driver, so commands that draw to a
|
||||||
|
window (`view`, `findbox`, interactive macros) are no-ops.
|
||||||
|
- 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.
|
||||||
|
|
@ -0,0 +1,215 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build Magic WASM and copy artifacts into this npm/ directory.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# npm/build.sh [--variant=<tcl|notcl|both>] [--release] [--test] [--pack]
|
||||||
|
#
|
||||||
|
# --variant=tcl Build only the TCL-embedded variant → npm/tcl/
|
||||||
|
# --variant=notcl Build only the plain (no Tcl/Tk) variant → npm/notcl/
|
||||||
|
# --variant=both Build both (default)
|
||||||
|
#
|
||||||
|
# --release Omit debug symbols (-g) and build with -O2.
|
||||||
|
# --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).
|
||||||
|
# TCL_REF git ref (tag/branch/SHA) of tcltk/tcl to build for the TCL
|
||||||
|
# variant. Default: main. (CI pins the latest stable tag.)
|
||||||
|
# TCL_REPO_URL git URL to clone tcltk/tcl from. Default: the upstream repo.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||||
|
# The TCL variant builds a static WASM Tcl from a pristine clone of tcltk/tcl.
|
||||||
|
# Both the clone (tcl/) and the out-of-source build artifacts live entirely
|
||||||
|
# under build-tcl-wasm/ (gitignored), so nothing outside it is ever touched.
|
||||||
|
TCL_BUILD_DIR="${TCL_BUILD_DIR:-$REPO_ROOT/build-tcl-wasm}"
|
||||||
|
TCL_SRC_DIR="$TCL_BUILD_DIR/tcl"
|
||||||
|
TCL_WASM_PREFIX="$TCL_BUILD_DIR/install"
|
||||||
|
|
||||||
|
OPT_RELEASE=0
|
||||||
|
OPT_TEST=0
|
||||||
|
OPT_PACK=0
|
||||||
|
OPT_VARIANT=both
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
--release) OPT_RELEASE=1 ;;
|
||||||
|
--test) OPT_TEST=1 ;;
|
||||||
|
--pack) OPT_PACK=1 ;;
|
||||||
|
--variant=tcl) OPT_VARIANT=tcl ;;
|
||||||
|
--variant=notcl) OPT_VARIANT=notcl ;;
|
||||||
|
--variant=both) OPT_VARIANT=both ;;
|
||||||
|
*) 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"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $OPT_RELEASE -eq 1 ]; then
|
||||||
|
EXTRA_CFLAGS="-O2"
|
||||||
|
else
|
||||||
|
EXTRA_CFLAGS="-g"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- TCL fork: clone and prebuild (TCL variant only) ------------------------
|
||||||
|
# Uses TCL_REPO_URL and TCL_REF from the environment (both have defaults).
|
||||||
|
# The source is cloned into build-tcl-wasm/tcl on the first run and checked
|
||||||
|
# out at the requested ref. Because this clone is private to the build dir,
|
||||||
|
# we manage its HEAD freely — no user-supplied tree is ever mutated.
|
||||||
|
#
|
||||||
|
# The actual WASM build runs out-of-source in $TCL_BUILD_DIR, driven by
|
||||||
|
# toolchains/emscripten/build-tcl-wasm.sh.
|
||||||
|
ensure_tcl_built() {
|
||||||
|
: "${TCL_REPO_URL:=https://github.com/tcltk/tcl.git}"
|
||||||
|
: "${TCL_REF:=main}"
|
||||||
|
|
||||||
|
if [ ! -d "$TCL_SRC_DIR/.git" ]; then
|
||||||
|
echo "=== cloning $TCL_REPO_URL into $TCL_SRC_DIR ==="
|
||||||
|
mkdir -p "$TCL_BUILD_DIR"
|
||||||
|
git -c core.autocrlf=false clone "$TCL_REPO_URL" "$TCL_SRC_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
( cd "$TCL_SRC_DIR"
|
||||||
|
current_sha=$(git rev-parse HEAD 2>/dev/null || echo "")
|
||||||
|
if [ "$current_sha" != "$TCL_REF" ]; then
|
||||||
|
git fetch --quiet origin
|
||||||
|
git checkout --quiet --detach "$TCL_REF"
|
||||||
|
fi
|
||||||
|
echo "Using TCL at $(git rev-parse HEAD) ($TCL_REPO_URL)"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Build TCL for WASM if it hasn't been built yet. The presence of
|
||||||
|
# tclConfig.sh in the install prefix is the canonical "TCL is built" marker.
|
||||||
|
if [ ! -f "$TCL_WASM_PREFIX/lib/tclConfig.sh" ]; then
|
||||||
|
echo "=== building TCL for WASM into $TCL_BUILD_DIR (one-time) ==="
|
||||||
|
bash "$REPO_ROOT/toolchains/emscripten/build-tcl-wasm.sh" \
|
||||||
|
--src="$TCL_SRC_DIR" --out="$TCL_BUILD_DIR"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- build a single variant --------------------------------------------------
|
||||||
|
# Each variant gets a fresh configure run because the two configurations
|
||||||
|
# select different code paths (MAGIC_WRAPPER on/off, MAGIC_NO_TK, link flags),
|
||||||
|
# so the object cache from one variant is not compatible with the other.
|
||||||
|
build_variant() {
|
||||||
|
local variant=$1
|
||||||
|
local out_dir="$SCRIPT_DIR/$variant"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "==============================================================="
|
||||||
|
echo "=== building variant: $variant"
|
||||||
|
echo "==============================================================="
|
||||||
|
|
||||||
|
cd "$REPO_ROOT"
|
||||||
|
|
||||||
|
# Full clean — distclean removes the generated defs.mak and module objects.
|
||||||
|
if [ -f defs.mak ]; then
|
||||||
|
emmake make distclean || true
|
||||||
|
fi
|
||||||
|
rm -f defs.mak database/database.h
|
||||||
|
|
||||||
|
# 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 [ "$variant" = "tcl" ]; then
|
||||||
|
ensure_tcl_built
|
||||||
|
CFLAGS="--std=c17 -D_DEFAULT_SOURCE=1 -DEMSCRIPTEN=1 ${EXTRA_CFLAGS}" \
|
||||||
|
emconfigure ./configure \
|
||||||
|
--without-cairo --without-opengl --without-x --without-tk \
|
||||||
|
--with-tcl="$TCL_WASM_PREFIX/lib" \
|
||||||
|
--with-tclincls="$TCL_WASM_PREFIX/include" \
|
||||||
|
--with-tcllibs="$TCL_WASM_PREFIX/lib" \
|
||||||
|
--disable-readline --disable-compression \
|
||||||
|
--host=asmjs-unknown-emscripten \
|
||||||
|
--target=asmjs-unknown-emscripten
|
||||||
|
else
|
||||||
|
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
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat toolchains/emscripten/defs.mak >> defs.mak
|
||||||
|
|
||||||
|
emmake make depend
|
||||||
|
emmake make -j"$(ncpu)" modules libs
|
||||||
|
emmake make techs
|
||||||
|
emmake make mains
|
||||||
|
|
||||||
|
mkdir -p "$out_dir"
|
||||||
|
cp magic/magic.js "$out_dir/"
|
||||||
|
cp magic/magic.wasm "$out_dir/"
|
||||||
|
echo "Copied magic.js + magic.wasm into npm/$variant/"
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$OPT_VARIANT" in
|
||||||
|
tcl|notcl) build_variant "$OPT_VARIANT" ;;
|
||||||
|
both) build_variant notcl
|
||||||
|
build_variant tcl ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# --- optional test -----------------------------------------------------------
|
||||||
|
# Runs the same smoke test that CI runs (see .github/workflows/main-wasm.yml).
|
||||||
|
# Run in a subshell so the cd does not leak into the --pack step below, which
|
||||||
|
# relies on the script's working directory being unchanged.
|
||||||
|
if [ $OPT_TEST -eq 1 ]; then
|
||||||
|
( cd "$SCRIPT_DIR" && npm run test && npm run test:tcl )
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- optional pack -----------------------------------------------------------
|
||||||
|
if [ $OPT_PACK -eq 1 ]; then
|
||||||
|
"$SCRIPT_DIR/pack.sh"
|
||||||
|
echo "npm package tarball created in npm/"
|
||||||
|
fi
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue