diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/README.md b/README.md new file mode 100755 index 00000000..5acd1862 --- /dev/null +++ b/README.md @@ -0,0 +1,58 @@ +# FOSS-TOOLS + +FOSS-Tools Manager + +## Prerequisites + +- [docker](https://docs.docker.com/engine/install/) +- python3 +- python virtualenv + + - `pip3 install virtualenv` + + - Setup the venv: + ``` + virtualenv -p python3 venv + source venv/bin/activate + pip3 install -r requirements.txt + ``` + +## Installation and Running + +- Using a recipe csv file + ``` + python3 run.py recipe --csv recipe.csv + ``` +- Buidling an individual image + ``` + python3 run.py build openlane + ``` +- Updating an individual image + - Run: + ``` + python3 run.py update open_pdks + ``` + - You will be prompted with: + ``` + A new commit for (open_pdks) is available: + 44c13e2256d5907090d6a2a62d9b9f8ddf23758d + Would you like to update? (y/N) + ``` +- Running foss-tools: + ``` + docker run -it -p 80:80 foss-tools:alpha + ``` + +## Notes + +- Images are under images directory +- Versions in recipe file overwrite the image version +- The images are tagged `:` +- The final image is called `foss-tools:`, so if you want to run + multiple recipes modify the tag of `foss-tools` + +## Todo + +- Dependancies handling +- Differentiate between git and non git based packages + diff --git a/build-all.sh b/build-all.sh new file mode 100755 index 00000000..76dccb2d --- /dev/null +++ b/build-all.sh @@ -0,0 +1,5 @@ +virtualenv -p python3 venv +source venv/bin/activate +pip3 install -r requirements.txt +python3 run.py recipe --csv recipe.csv + diff --git a/docker_builder/__pycache__/docker_builder.cpython-37.pyc b/docker_builder/__pycache__/docker_builder.cpython-37.pyc new file mode 100755 index 00000000..84f58790 Binary files /dev/null and b/docker_builder/__pycache__/docker_builder.cpython-37.pyc differ diff --git a/docker_builder/__pycache__/docker_builder.cpython-39.pyc b/docker_builder/__pycache__/docker_builder.cpython-39.pyc new file mode 100755 index 00000000..22fdfd48 Binary files /dev/null and b/docker_builder/__pycache__/docker_builder.cpython-39.pyc differ diff --git a/docker_builder/docker_builder.py b/docker_builder/docker_builder.py new file mode 100755 index 00000000..bfa8883d --- /dev/null +++ b/docker_builder/docker_builder.py @@ -0,0 +1,59 @@ +#!/usr/bin/python3 + +import docker +import time +import logging + + +class DockerBuilder(): + def __init__(self): + self.rm = True + self.client = self.createClient() + self.logger = logging.getLogger("DockerBuilder logger") + self.configLogger() + + def createClient(self): + client = docker.from_env() + return client + + def configLogger(self): + self.logger.setLevel(logging.INFO) + handler = logging.StreamHandler() + formatter = logging.Formatter( + fmt='[%(levelname)s %(asctime)s] %(message)s', datefmt='%d-%b-%y %H:%M:%S' + ) + handler.setFormatter(formatter) + self.logger.addHandler(handler) + + def build(self, target): + self.logger.info("Building %s", target.name) + default_tag = target.name + ":" + "latest" + version_tag = target.name + ":" + target.version + build_status = False + try: + response = self.client.api.build( + path=target.path, + rm=self.rm, + tag=version_tag, + buildargs=target.args, + decode=True + ) + for line in response: + self.printResponse(line, target.name) + + self.client.api.tag(version_tag, default_tag) + build_status = True + except docker.errors.APIError as e: + self.logger.error(e) + time.sleep(2) + + return build_status + + def printResponse(self, response, name): + if 'stream' in response: + for line in response['stream'].splitlines(): + if (line != ''): + if (line.rstrip() != '\n' and (line.rstrip() != '')): + self.logger.info("[" + name + "] :: " + line.rstrip()) + elif 'error' in response: + raise docker.errors.APIError(response['error']) diff --git a/image/__pycache__/image.cpython-37.pyc b/image/__pycache__/image.cpython-37.pyc new file mode 100755 index 00000000..1cab183f Binary files /dev/null and b/image/__pycache__/image.cpython-37.pyc differ diff --git a/image/__pycache__/image.cpython-39.pyc b/image/__pycache__/image.cpython-39.pyc new file mode 100755 index 00000000..d51dd97b Binary files /dev/null and b/image/__pycache__/image.cpython-39.pyc differ diff --git a/image/image.py b/image/image.py new file mode 100755 index 00000000..a1449972 --- /dev/null +++ b/image/image.py @@ -0,0 +1,101 @@ +#!/usr/bin/python3 + +import os +import json +import git +import json + + +class Image(): + def __init__(self, name, path, args, json_file, meta_data): + self.name = name + self.path = path + self.args = args + self.url = self.args['REPO_URL'] + self.json_file = json_file + self.meta_data = meta_data + self.version = self.args["REPO_COMMIT"] + self.build_status = False + + + @classmethod + def createFromPath(cls, path): + JSON_FILE = "info.json" + json_file = os.path.join(path, JSON_FILE) + + return cls.createFromJSON(json_file) + + @classmethod + def createFromJSON(cls, json_file): + f = open(json_file) + meta_data = json.load(f) + f.close() + + args = meta_data['args'] + name = args['NAME'] + + path = os.path.dirname(os.path.abspath(json_file)) + + return cls( + name=name, + path=path, + args=args, + json_file=json_file, + meta_data=meta_data + ) + + + def getLatestVersion(self): + url = self.url + g = git.cmd.Git() + response = g.ls_remote(url, 'HEAD') + latest_version = response.split()[0] + + return latest_version + + + def updatePrompt(self, new_version): + print("A new commit for (%s) is available:\n%s" % (self.name, new_version)) + user_response = input("Would you like to update? (y/N) ").lower() + + if (user_response == 'y'): + response = True + else: + response = False + + return response + + + def update(self, updateFlag=False): + current_version = self.version + new_version = self.getLatestVersion() + + if (new_version != current_version): + if (updateFlag == True): + self.commitVersion(new_version) + else: + response = self.updatePrompt(new_version) + if (response == True): + self.commitVersion(new_version) + print("New version commited!") + else: + print("Latest version for (%s) synced.\n" + "Run install to install it.\n" + "Nothing to be done." % self.name) + + + def commitVersion(self, new_version): + self.version = new_version + + self.meta_data['args']['REPO_COMMIT'] = new_version + + with open(self.json_file, 'w') as f: + f.write(json.dumps(self.meta_data, indent=4)) + + + + def setVersion(self, version): + old_version = self.version + if (old_version != version): + self.commitVersion(version) + diff --git a/images/base/Dockerfile b/images/base/Dockerfile new file mode 100755 index 00000000..061c49a8 --- /dev/null +++ b/images/base/Dockerfile @@ -0,0 +1,5 @@ +ARG BASE_IMAGE +FROM ${BASE_IMAGE} as builder + +ADD scripts/dependencies.sh dependencies.sh +RUN bash dependencies.sh diff --git a/images/base/info.json b/images/base/info.json new file mode 100755 index 00000000..d49c6f0f --- /dev/null +++ b/images/base/info.json @@ -0,0 +1,8 @@ +{ + "args" : { + "BASE_IMAGE" : "centos:centos7", + "NAME": "base", + "REPO_COMMIT": "alpha", + "REPO_URL": "n/a" + } +} diff --git a/images/base/scripts/dependencies.sh b/images/base/scripts/dependencies.sh new file mode 100755 index 00000000..1588c0da --- /dev/null +++ b/images/base/scripts/dependencies.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +yum install -y https://repo.ius.io/ius-release-el7.rpm +yum install centos-release-scl -y +yum install -y \ + autoconf \ + automake \ + bison \ + boost169-devel \ + boost169-static \ + bzip2 \ + cairo \ + cairo-devel \ + clang \ + csh \ + curl \ + devtoolset-8 \ + devtoolset-8-libatomic-devel \ + flex \ + gawk \ + gcc \ + gdb \ + gettext \ + gettext-devel \ + git \ + glibc-static \ + graphviz \ + help2man \ + libSM \ + libX11-devel \ + libXext \ + libXft \ + libffi \ + libffi-devel \ + libgomp \ + libjpeg \ + libstdc++ \ + libxml2-devel \ + libxslt-devel \ + make \ + mesa-libGLU-devel \ + ncurses-devel \ + ninja-build \ + patch \ + pcre-devel \ + python-devel \ + python36u \ + python36u-devel \ + python36u-libs \ + python36u-pip \ + python36u-tkinter \ + readline-devel \ + rh-python35 \ + strace \ + spdlog-devel \ + swig3 \ + tcl \ + tcl-devel \ + tcllib \ + tclx \ + texinfo \ + tk \ + tk-devel \ + vim-common \ + wget \ + which \ + xdot \ + Xvfb \ + zlib-devel \ + zlib-static + +alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 60 + +pip3.6 install --no-cache-dir --upgrade pip +pip install --no-cache-dir \ + matplotlib \ + "jinja2<3.0.0" \ + pandas \ + install \ + XlsxWriter diff --git a/images/covered/Dockerfile b/images/covered/Dockerfile new file mode 100755 index 00000000..d42a6e28 --- /dev/null +++ b/images/covered/Dockerfile @@ -0,0 +1,12 @@ +ARG BASE_IMAGE +FROM ${BASE_IMAGE} as builder + +ARG REPO_URL +ARG REPO_COMMIT +ARG NAME + +ADD scripts/dependencies.sh dependencies.sh +RUN bash dependencies.sh + +ADD scripts/install.sh install.sh +RUN bash install.sh diff --git a/images/covered/info.json b/images/covered/info.json new file mode 100755 index 00000000..ded59dbe --- /dev/null +++ b/images/covered/info.json @@ -0,0 +1,8 @@ +{ + "args" : { + "BASE_IMAGE" : "base", + "NAME": "covered", + "REPO_URL": "https://github.com/Manarabdelaty/verilog-covered", + "REPO_COMMIT": "93bee2e0d89c1beb5943a329109dcf24d59498e6" + } +} diff --git a/images/covered/scripts/dependencies.sh b/images/covered/scripts/dependencies.sh new file mode 100755 index 00000000..c82189be --- /dev/null +++ b/images/covered/scripts/dependencies.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +yum install -y gperf diff --git a/images/covered/scripts/install.sh b/images/covered/scripts/install.sh new file mode 100755 index 00000000..e7f0285d --- /dev/null +++ b/images/covered/scripts/install.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +source scl_source enable devtoolset-8 + +git clone ${REPO_URL} ${NAME} + +cd ${NAME} +git checkout ${REPO_COMMIT} + +./configure --prefix=/foss/tools/${NAME}/${REPO_COMMIT} +make -j$(nproc) +make install + diff --git a/images/foss-asic-tools/Dockerfile b/images/foss-asic-tools/Dockerfile new file mode 100755 index 00000000..3d4ffc85 --- /dev/null +++ b/images/foss-asic-tools/Dockerfile @@ -0,0 +1,94 @@ +ARG BASE_IMAGE +FROM ${BASE_IMAGE} as base + + +## Connection ports for controlling the UI: +# VNC port:5901 +# noVNC webport, connect via http://IP:80/?password=start + +ENV DISPLAY=:1 \ + VNC_PORT=5901 \ + NO_VNC_PORT=80 +EXPOSE $VNC_PORT $NO_VNC_PORT + +### Envrionment config +ENV HOME=/headless \ + TERM=xterm \ + STARTUPDIR=/dockerstartup \ + NO_VNC_HOME=/dockerstartup/noVNC \ + VNC_COL_DEPTH=24 \ + VNC_RESOLUTION=1680x1050 \ + VNC_PW=start \ + VNC_VIEW_ONLY=false \ + DESIGNS=/foss/designs \ + TOOLS=/foss/tools \ + PDK_ROOT=/foss/pdks + +ADD ./scripts/ $STARTUPDIR/scripts +RUN find $STARTUPDIR/scripts -name '*.sh' -exec chmod a+x {} + +RUN $STARTUPDIR/scripts/tools.sh + +### Install xvnc-server & noVNC - HTML5 based VNC viewer +RUN $STARTUPDIR/scripts/tigervnc.sh +RUN $STARTUPDIR/scripts/no_vnc.sh + +### Install firefox +RUN $STARTUPDIR/scripts/firefox.sh + +### Install xfce UI +RUN $STARTUPDIR/scripts/xfce_ui.sh +ADD ./addons/xfce/ $HOME/ + + +FROM openlane:latest as openlane +FROM klayout:latest as klayout +FROM gtkwave:latest as gtkwave +FROM iverilog:latest as iverilog +FROM open_pdks:latest as pdk +FROM magic:latest as magic +FROM netgen:latest as netgen +FROM riscv-gnu-toolchain-rv32i as rv32i +FROM gaw3 as gaw3 +FROM ngscope as ngscope +FROM ngspice as ngspice +FROM xyce as xyce +FROM covered as covered +FROM base + + +COPY --from=pdk /foss/pdks/ /foss/pdks/ +COPY --from=openlane /foss/tools /foss/tools +COPY --from=gtkwave /foss/tools/ /foss/tools/ +COPY --from=iverilog /foss/tools/ /foss/tools/ +COPY --from=magic /foss/tools/ /foss/tools/ +COPY --from=netgen /foss/tools/ /foss/tools/ +COPY --from=klayout /foss/tools/ /foss/tools/ +COPY --from=rv32i /foss/tools/ /foss/tools/ +COPY --from=gaw3 /foss/tools/ /foss/tools/ +COPY --from=ngscope /foss/tools/ /foss/tools/ +COPY --from=ngspice /foss/tools/ /foss/tools/ +COPY --from=xschem /foss/tools/ /foss/tools/ +COPY --from=xyce /foss/tools/ /foss/tools/ +COPY --from=covered /foss/tools/ /foss/tools/ + + +ADD ./addons/sak /foss/tools/sak + +ADD ./scripts/miscellaneous.sh $STARTUPDIR/scripts/miscellaneous.sh +RUN bash $STARTUPDIR/scripts/miscellaneous.sh + +ADD ./scripts/env.sh $HOME/.bashrc +RUN bash $HOME/.bashrc + +### configure startup +RUN $STARTUPDIR/scripts/libnss_wrapper.sh +RUN $STARTUPDIR/scripts/set_user_permission.sh $STARTUPDIR $HOME + +WORKDIR $DESIGNS + +USER 1000 + +ENTRYPOINT ["/dockerstartup/scripts/vnc_startup.sh"] + +CMD ["--wait"] + diff --git a/images/foss-asic-tools/addons/sak/bin/antenna-check-gds.sh b/images/foss-asic-tools/addons/sak/bin/antenna-check-gds.sh new file mode 120000 index 00000000..9eba63d6 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/antenna-check-gds.sh @@ -0,0 +1 @@ +../magic/antenna-check-gds.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/caldrc-post b/images/foss-asic-tools/addons/sak/bin/caldrc-post new file mode 100755 index 00000000..0eed93b0 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/caldrc-post @@ -0,0 +1,511 @@ +#!/bin/bash +#@ usage: caldrc-post [-y] [-a] [-l ] [-S ] [-C ] +#@ [-R ] [-b ] [-w ] [[-L] []] [] +#@ caldrc-post -h : show usage only +#@ Run calibreSummary.py on one calibre-output directory. +#@ -w : optional path to a file of waivers to pass to calibreSummary.py. +#@ Set by env-var CDRCWAIVE, if no -w option given. Else no waiver file used. +#@ -b : optional, force processing of this branch (of form output*, not latest-*) +#@ TODO: using -b latest-* form does NOT WORK yet; does not enumerate cells beneath. +#@ If branch (-b) not specified one (or group) are selected of form outputNNN_* using: +#@ : optional, the commitId used to push the source GDS to master branch. +#@ CommitId can be long, or short so long as uniquely identifies one commit. +#@ : optional, the topcell-name latest results to find and post-process. +#@ If only the latest results for that will be used. +#@ Neither: latest is used. See details below on how branch-name is selected. +#@ For a commitId match, IFF no topcell specified: ALL matching branches are processed. +#@ (TODO: -a: process all recent branches (TBD what this means, depending on how/where results stored)). +#@ -S : path to executable calibreSummary.py script. No need if 'calibreSummary.py' is found in $PATH. +#@ Set by env-var CDRCSUMMARY, if no -S option given. Else it must be found in $PATH. +#@ -C : dir of local clone, https://foss-eda-tools.googlesource.com/openflow-drc-tests +#@ Set by env-var CDRCREPO, if no -C option given. +#@ "." default: If neither env-var nor -C option given, "." (CWD) is tested for same. +#@ It is a fatal error if this local repo-dir cannot be found & confirmed. +#@ -R : dir in which to write .csv's from caldrc-put results. +#@ Set by env-var CDRCPOST, if no -R option given. +#@ -l : optional path to a log-file to write one line to on success. +#@ Else set by env-var CDRCLOG, if no -l option given. Else no log is written. +#@ -L : Find & parse the "last" ^caldrc-put: commit-id & topcell from specified log. +#@ Either or both of log's commid-id/topcell will be applied/used in place of missing +#@ cmd-line's commidId or topcell. If cmd-line gave both already -L is ignored. +#@ This is too simple: Best to use -L without explicitly giving any commit or topcell. +#@ TODO: if cmd-line names topcell, get log's last *-put line match of same cell: & use its commit. +#@ -a : also copy (with rsync) the calibre results dirs & contents (drc/*, latchup/*, ...) into +#@ //... +#@ -y : Do not prompt. Default when STDIN is a terminal is to prompt before main git ops. +#@ +#@ TODO: correct below pseudo-code, esp for multi-cell case in same outputNNN_* branch group: +#@ Below the openflow-drc-tests dir the following will happen. Most steps exit on error. +#@ git fetch +#@ determine a to process. +#@ If have -b: use that branch. +#@ If have & find branch matching pattern: +#@ b=output_*drc*-g_ +#@ If have only , extract from branch matching pattern: +#@ b=output_*drc*-g_* +#@ If have only , select branch by highest matching matching pattern: +#@ b= output_*drc*-g*_ +#@ and extract from branch name. +#@ Else (none of above) select highest of output_* and extract putCommitId & topcell. +#@ (TODO: If -A: Process all not-yet-processed branches). +#@ +#@ +#@ git checkout +#@ git pull +#@ determine from +#@ determine of torture_tests//.gds +#@ +#@ post-process torture_tests//*/*.results : +#@ TBD... Run calibreSummary.py on each of torture_tests//*/.drc.results +#@ Writing to dir-structures within +#@ +#@ if env-var exists CALDRCLOG: +#@ append line to the log: "caldrc-post: .gds put= md5= " +#@ +#@ examples: +#@ Process single named output* branch, specify all other parameters via env-vars, use prompts: +#@ export CDRCREPO=~/git/openflow-drc-tests CDRCLOG=~/x.log CDRCWAIVE=~/waivers CDRCPOST=~/calsumout +#@ export CDRCSUMMARY=~/git/sak2/calibreSummary.py +#@ caldrc-post -b output254_pdk78-ge85b3090d_drc176-g5f2d7b3_caravel +#@ ... no prompting: +#@ caldrc-post -y -b output254_pdk78-ge85b3090d_drc176-g5f2d7b3_caravel +#@ Specify all parameters on cmd-line, use prompts, process all topcells of commit +#@ caldrc-post -C ~/git/openflow-drc-tests -l ~/x.log -w ~/waivers -S ~/git/sak2/calibreSummary.py -R ~/calsumout +#@ Use env-vars, process all output* branches (multiple topcells) of given commit: +#@ caldrc-post 5f2d7b3 +#@ -> branches: output254_pdk78-ge85b3090d_drc176-g5f2d7b3_sram_1rw1r_32_256_8_sky130 +#@ output254_pdk78-ge85b3090d_drc176-g5f2d7b3_fpga_core +#@ output254_pdk78-ge85b3090d_drc176-g5f2d7b3_chip_io +#@ output254_pdk78-ge85b3090d_drc176-g5f2d7b3_caravel +#@ ... use full commitid: +#@ caldrc-post 5f2d7b35eb2c5ba4c7eb3486d2f6739ccc590e5e +#@ ... use short commitid, process only one topcell: +#@ caldrc-post 5f2d7b3 chip_io +#@ ... process latest outputNNN_* branch GROUP (branch(es) embedding same commitid, corresponding to one or more topcells): +#@ caldrc-post +#@ + +PROG=caldrc-post +PROGF=$0 +errs=0 +caldrc=$CDRCREPO # opt. env-var, override by -C cmd-line option +outdir=$CDRCPOST # opt. env-var, override by -R cmd-line option +sumbin=$CDRCSUMMARY # opt. env-var, override by -S cmd-line option +waive=$CDRCWAIVE # opt. env-var, override by -w cmd-line option +log=$CDRCLOG # opt. env-var, override by -l cmd-line option +putdir=torture_tests + +# is STDIN a terminal? If not: no prompting for anything +inter="" +[[ -t 0 ]] && inter=1 + +usage() { + sed -n -e '/^#@/s/^#@//p' <$PROGF + exit $errs +} + +err () { + (( errs++ )) + echo "${PROG}: ERROR, $*" >&2 +} +msg () { + echo "${PROG}: $*" +} +vrb () { + [ -n "$verbose" ] && echo "${PROG}: $*" >&2 +} +die0 () { + exit $errs +} +die () { + err "$*" + exit $errs +} +dieu0 () { + usage "${PROG}: ERROR, $*" +} + +# gitcd function: echo and eval a (git) command, DIE if it fails (and write msg to stderr). +# $1 is var to be assigned the STDOUT of the command. +# Use this only when must pass. +gitcd () { + local _val="" _outvar=$1 _stat=0 + shift + echo "$*" + [[ -z "$dryrun" ]] && { + _val=$("$@") || die "failed($?) in: $*" + _stat=$? + } + eval "$_outvar=\${_val}" + return $_stat +} +# gitc function: echo and eval a (git) command. +# $1 is var to be assigned the STDOUT of the command. +# Status of the command is propagated. +gitc () { + local _val="" _outvar=$1 _stat=0 + shift + echo "$*" + [[ -z "$dryrun" ]] && { + _val=$("$@") + _stat=$? + } + eval "$_outvar=\${_val}" + return $_stat +} + +# main start + +branch=() +while getopts "ab:C:FhLl:R:S:w:y" o; do + : echo got "optchar $o, with optarg $OPTARG" + case "$o" in \?) + (( errs++ )) + continue ; esac + case "$o" in y) + inter="" + continue ; esac + case "$o" in a) + allres=1 + continue ; esac + case "$o" in L) + loglast=1 + continue ; esac + case "$o" in F) + force=1 + continue ; esac + case "$o" in h) + usage # does not return + continue ; esac + case "$o" in l) + log=$(readlink -m "$OPTARG") # we chdir below; ensure absolute path + continue ; esac + case "$o" in w) + waive=$(readlink -m "$OPTARG") # we chdir below; ensure absolute path + continue ; esac + case "$o" in b) + branch=("$OPTARG") + continue ; esac + case "$o" in C) + caldrc=$(readlink -m "$OPTARG") # we chdir below; ensure absolute path + continue ; esac + case "$o" in S) + sumbin=$(readlink -m "$OPTARG") # we chdir below; ensure absolute path + continue ; esac + case "$o" in R) + outdir=$(readlink -m "$OPTARG") # we chdir below; ensure absolute path + continue ; esac +done + +[[ $errs != 0 ]] && { + usage +} + +(( OPTIND-- )) +shift $OPTIND + +arg1= +arg2= +[[ -n "$1" ]] && { + arg1="$1" + shift +} +[[ -n "$1" ]] && { + arg2="$1" + shift +} +[[ -n "$1" ]] && { + die "extra args not supported: $*" +} + +[[ -z "$caldrc" ]] && { + caldrc=$(pwd) +} +caldrc=$(readlink -m "$caldrc") # ensure absolute path + +[[ -n "$log" ]] && { + log=$(readlink -m "$log") + [[ ! -e "$log" ]] && (touch "$log" || die "failed to create log, $log") + [[ ! -w "$log" ]] && die "log not writable, $log" + msg "log: '$log'" +} +[[ -n "$waive" ]] && { + waive=$(readlink -m "$waive") + [[ ! -r "$waive" ]] && die "waiver-file not readable, '$waive'" +} + +[[ ! -s "$log" && -n "$loglast" ]] && die "no data to support -L option, log is empty, $log" + +# if not given by env-var or cmd-line default to calibreSummary.py (i.e. in PATH) +[[ -z "$sumbin" ]] && { + sumbin=calibreSummary.py +} +# verify executable calibreSummary.py (in PATH if necessary); make an absolute path to it. +sumbin=$(which $sumbin 2>/dev/null) || die "can't find executable calibreSummary.py" +sumbin=$(readlink -m $sumbin) # expands tilde +msg "calibreSummary.py: '$sumbin'" + +[[ -z "$outdir" ]] && { + die "no determined" +} +outdir=$(readlink -m $outdir) # make absolute +msg "outputDataDir: '$outdir'" +msg "waiverFile: '$waive'" + +cd "$caldrc" || die "failed: cd $caldrc" + +# get original branch. ALSO doubles as hard-stop if this dir is NOT within a git-repo. +# Although gitcd exits on error (such as not a repo), the detached-HEAD is not an error. +gitcd br git branch --show-current +[[ -z "$br" ]] && die "no current branch (perhaps: detached HEAD)" +msg "original branch '$br'" + +# Path may not be root of the repo, goto it. +gitcd caldrcr git rev-parse --show-toplevel +msg "normalized caldrcrepo: '$caldrcr'" +cd "$caldrcr" || die "failed: cd $caldrcr" + +echo +printf "NEXT: git fetch origin\n" +dofetch= +[[ -n "$inter" ]] && read -p "Enter to CONTINUE, 'n' for NO FETCH (^C to quit)> " dofetch +if [[ "$dofetch" != "" && "$dofetch" != "n" ]]; then + echo "unsupported reply, '$dofetch', aborting..." + exit 1 +fi + +if [[ "$dofetch" != "n" ]]; then + gitcd res git fetch origin + echo "$res" +else + echo "SKIPPED: git fetch origin, WARNING: possibly using non-latest data..." +fi + +[[ -n "$arg2" && -n "$loglast" ]] && { + msg "WARNING, ignoring -L, since cmd-line specifies explicit commitId & topcell" + loglast="" +} +[[ -n "$branch" && -n "$loglast" ]] && { + msg "WARNING, ignoring -L, since cmd-line specified explicit branch to process" + loglast="" +} + +# determine if arg1,2 refer to existing commits and make 7-char short form +# git rev-parse --short=7 -q "5f2d7b35eb2c5ba4c7eb3486d2f6739ccc590e5e^{commit}" -> 5f2d7b3 +sarg1= +sarg2= +[[ -n "$arg1" ]] && { + gitc sarg1 git rev-parse --short=7 -q "${arg1}^{commit}" + [[ $? != 0 ]] && sarg1="" +} +[[ -n "$arg2" ]] && { + gitc sarg2 git rev-parse --short=7 -q "${arg2}^{commit}" + [[ $? != 0 ]] && sarg2="" +} +# error: if have arg2, but neither were a branch. +# error: if have arg2, but both were a branch. +[[ -n "$arg2" && -z "$sarg1" && -z "$sarg2" ]] && die "neither arguments '$arg1' '$arg2' were valid commitIds" +[[ -n "$arg2" && -n "$sarg1" && -n "$sarg2" ]] && die "both arguments '$arg1' '$arg2' are commitIds" + +# use canonical 7-char short form of commits args from here onwards +[[ -n "$sarg1" ]] && { + msg "canonical arg1: '$sarg1'" + arg1=$sarg1 +} +[[ -n "$sarg2" ]] && { + msg "canonical arg2: '$sarg2'" + arg2=$sarg2 +} + +# for -L option, examine existing log's last put entry for a +# example: caldrc-put: the_sram.gds 290a7e324d857a9fef7793ccf07d7f0fafe5419f ... +logline= +[[ -n "$loglast" ]] && { + logline=$(awk '/^caldrc-put:/{ line=$2 " " $3 } END { print line }' $log) + [[ -z "$logline" ]] && die "cannot use -L, didn't find any '^caldrc-put:' line in log, $log" +} +[[ -n "$logline" ]] && { + lgds=${logline%% *} # get first word, blank delimited + lcid=${logline##* } # get 2nd/last word, blank delimited + ltopc=${lgds%.gds} # strip .gds suffix + [[ -z "$lgds" || -z "$lcid" || -z "$ltopc" ]] && die "internal-error, failed to parse log's last '^caldrc-put:' fields, line={$logline}" + # msg "for -L recovered: gds='$lgds', topc=$ltopc, cid='$lcid'" + # get canonical 7-char form of log's commit + gitcd lsid git rev-parse --short=7 -q "${lcid}^{commit}" + + # At present we know we do not have both arg1,arg2 (-L ignored in that case). + # We may or may not have an arg1. If not, apply log-entries to arg1,2. + # If we do have arg1, is it a commitId?: Yes: apply log-topcell to arg2. No: apply log-cid to arg2. + if [[ -z "$arg1" ]]; then + sarg1="$lsid" + arg1="$lsid" + arg2="$ltopc" + elif [[ -n "$sarg1" ]]; then + arg2="$ltopc" + else + sarg2="$lsid" + arg2="$lsid" + fi + msg "due -L, from log's last -put entry reconstructed arg1,2 as: '$arg1' '$arg2'" +} + +# determine branch to use. +[[ -z "$branch" ]] && { + # get all remote branches of pattern: origin/output\*_\*-g\*_drc\*-g\*_\* + brfile=$(mktemp) + set -o pipefail + echo "git branch -r -l 'origin/output*_*-g*_drc*-g*_*' | awk '{\$1=\$1};1' | LC_COLLATE=C sort -nr >$brfile" + git branch -r -l "origin/output*_*-g*_drc*-g*_*" | awk '{$1=$1};1' | LC_COLLATE=C sort -nr >$brfile + stat=$? + set +o pipefail + [[ "$stat" != 0 ]] && die "failed($?) in: git branch -r -l 'origin/output*_*-g*_drc*-g*_*' | awk '{$1=$1};1' | LC_COLLATE=C sort -nr >$brfile" + # mapfile -t brary $brfile + # echo see branches in $brfile ... + [[ ! -s "$brfile" ]] && die "no remote branch pattern matches" + + # read (one) latest output* branch + read brlast <"$brfile" + # get commitId from brlast + topc=${brlast##*-g} # strip prefix to start of (2nd) commitId + commitlast=${topc%%_*} # strip suffix from _ to isolate commitId + topc=${topc#*_} # strip prefix thru (1st) underscore: start of topc + # gitc scommit git rev-parse --short=7 -q "${commitlast}^{commit}" + # [[ $? != 0 ]] && scommit="" + + # apply commitlast (in place of arg1) if had no explicit arg1,2, so we default we process all cells of latest output* branch: + [[ -n "$commitlast" && -z "$arg1" ]] && { + arg1="$commitlast" + msg "by default, inferred commitid: $commitlast, to do all topcells of last branch: $brlast" + } + + # setup zero (neither arg1 nor arg2) or two patterns to look for. + # When only arg1: interpret it as both commitId and topcell. + # When both arg1,arg2: interpret as both commitId,topcell and topcell,commitId. + p1= + p2= + # example: origin/output257_pdk78-ge85b3090d_drc179-g5566566_sram_1rw1r_32_256_8_sky130 + if [[ -n "$arg1" && -n "$arg2" ]]; then + p1="output*_*-g*_drc*-g${arg1}_${arg2}" + p2="output*_*-g*_drc*-g${arg2}_${arg1}" # reversed + elif [[ -n "$arg1" ]]; then + p1="output*_*-g*_drc*-g${arg1}_*" # arg1 as commitId + p2="output*_*-g*_drc*-g*_${arg1}" # arg1 as topcell + fi + last= + match1=() + match2= + while read line; do # input on the done: <"$brfile" + line=${line#origin/} # strip 'origin/' prefix + + [[ -z "$last" ]] && last="$line" + + # no patterns: we're done, last branch is it. + [[ -z "$p1" ]] && { + match1=("$last") + break + } + + # find latest match of p1 or p2; as soon as found both: quit loop. + [[ "$line" == $p1 ]] && { + match1+=("$line") + } + [[ -z "$match2" && "$line" == $p2 ]] && { + match2="$line" + } + [[ -n "$match1" && -n "$match2" ]] && { + break + } + done <"$brfile" + rm -f "$brfile" + + # no last branch: an error + [[ -z "$last" ]] && die "internal-error, no latest branch found" + msg "unconstained latest output branch: $last" + + # ambiguity: if have both match1,2 + if [[ -n "$match1" && -n "$match2" ]]; then + die "internal-error, branch-match is ambiguous between: '$match1' '$match2'" + elif [[ -n "$match1" ]]; then + branch=("${match1[@]}") + elif [[ -n "$match2" ]]; then + branch=("$match2") + elif [[ -n "$arg1" ]]; then + # no matches, though we had at least arg1 (and optionally arg2): ERROR. + die "no branch-match found for given args" + else + # Shouldn't be possible to get here. + die "internal-error, shouldn't get here" + fi + + [[ -z "$branch" ]] && die "internal-error, no branch match(es) found" + + msg "selected output branch(es): ${branch[*]}" +} + +mkdir -p "$outdir" || die "failed: mkdir -p $outdir" + +# loop over the 1 or more branches found +for br in "${branch[@]}"; do + # checkout branch and pull (or just pull if already on that branch) + printf "NEXT: git checkout $br --\n : git pull\n" + [[ -n "$inter" ]] && read -p "Enter to CONTINUE (^C to quit)> " + gitcd res git checkout $br -- + echo "$res" + gitcd res git pull + echo "$res" + + # get topcell from branch + topc=${br##*-g} # strip prefix to start of (2nd) commitId + commit=${topc%%_*} # strip suffix from _ to isolate commitId + topc=${topc#*_} # strip prefix thru (1st) underscore: start of topc + + msg "for branch=$br got commit=$commit, topcell=$topc ..." + trg=$putdir/$topc + + # md5 of gds + gds="$putdir/$topc/$topc.gds" + if [[ -r "$gds" ]]; then + line=($(md5sum "$gds")) || die "failed: md5sum $gds" + md5=${line[0]} + else + md5="(no-gds-file)" + fi + msg "got md5: $md5" + + # info about the drc-results commit + TZ=UTC gitcd stamp git log -n 1 --pretty=format:%cd --date=format-local:%Y-%m-%d.%T.%Z HEAD + echo "timestamp is $stamp" + + # construct calibreSummary cmd-line + # usage: calibreSummary.py [-h] --targetPath TARGETPATH + # [--waivableList WAIVABLELIST] + # [--outputDirectory OUTPUTDIRECTORY] + cmd=($sumbin --outputDirectory "$outdir" --targetPath "$trg") + [[ -n "$waive" ]] && { + cmd+=("--waivableList" $waive) + } + msg "running: ${cmd[*]}" + ${cmd[@]} + stat=$? + [[ $stat != 0 ]] && die "failed($stat) in ${cmd[*]}" + + # -a: copy all result SUBDIRS into/below outdir; but BELOW a / subdir + [[ -n "$allres" ]] && { + msg "running: rsync -a --exclude='*.gds' --exclude='*.gds.gz' $trg/ $outdir/$topc/" + rsync -a --exclude='*.gds' "$trg"/ "$outdir/$topc/" + stat=$? + [[ $stat != 0 ]] && die "failed($stat) in rsync" + } + + message="caldrc-post: $topc.gds put=$commit $stamp md5=$md5 $br" + [[ -n "$log" ]] && { + echo "logging: '$message'" + echo "$message" >> $log || die "failed append to log, $log" + } + + +done + + +echo done +exit $errs diff --git a/images/foss-asic-tools/addons/sak/bin/caldrc-put b/images/foss-asic-tools/addons/sak/bin/caldrc-put new file mode 100755 index 00000000..267c7e81 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/caldrc-put @@ -0,0 +1,296 @@ +#!/bin/bash +#@ usage: caldrc-put [-y] [-N] [-l ] [-C ] [-c ] +#@ : required. The basename, minus one dot-suffix, determines default topcell, +#@ after having stripped a .gz or .xz suffix. +#@ The GDS is NOT tested to verify that same-named topcell exists. Examples: +#@ a/b/joe -> cell=joe -> torture_tests/joe/joe.gds +#@ a/b/joe.xz -> cell=joe -> torture_tests/joe/joe.gds.xz +#@ a/b/joe.123 -> cell=joe -> torture_tests/joe/joe.gds +#@ a/b/joe.123.gz -> cell=joe -> torture_tests/joe/joe.gds.gz +#@ a/b/joe.123.gds -> cell=joe.123 -> torture_tests/joe.123/joe.123.gds +#@ a/b/joe.123.gds.gz -> cell=joe.123 -> torture_tests/joe.123/joe.123.gds.gz +#@ a/b/joe.123.gds.xz -> cell=joe.123 -> torture_tests/joe.123/joe.123.gds.xz +#@ -c : optionally name the topcell. Default is to determine it from the +#@ path only (not its data contents) as above. +#@ a/b/joe.123.gds -> cell=joe.123 -> torture_tests/joe.123/joe.123.gds +#@ -c chip1 a/b/joe.123.gds -> cell=chip1 -> torture_tests/chip1/chip1.gds +#@ -c chip1 a/b/joe.123.gds.xz -> cell=chip1 -> torture_tests/chip1/chip1.gds.xz +#@ -C : dir of local clone br=master, https://foss-eda-tools.googlesource.com/openflow-drc-tests +#@ Else set by env-var CDRCREPO, if no -C option given. +#@ Else "." default: If neither env-var nor -C option given, "." (CWD) is tested for same. +#@ It is a fatal error if this local repo-dir cannot be found & confirmed. +#@ Branch=master will be checked-out, pulled, and have the GDS add/commit/pushed to it. +#@ -l : optional path to a log-file to write one line to on commit success. +#@ Else set by env-var CDRCLOG, if no -l option given. Else no log is written. +#@ -y : Do not prompt. Default when STDIN is a terminal is to prompt before main git ops. +#@ -N : Do NOT push. The commit is done, and commitID still is logged. +#@ +#@ On optional COMPRESSION: A .gz or .xz suffix will be stripped, before stripping one +#@ more suffix to isolate a default topcell name from source file (unless given explicitly by +#@ the -c option). An original .gz or .xz will be reapplied to the filename when git-add-ed to the repo. +#@ In all cases FILE DATA IS COPIED AS-IS, there is NO uncompress nor auto compress in this script. +#@ If there's a mismatch between what the extension indicates (compressed or not, and type: gz/xz), +#@ and actual file data contents there will be failures: run_calibre.sh recognizes when to +#@ uncompress by the extension. +#@ +#@ Below the openflow-drc-tests dir the following will happen. Most steps exit on error. +#@ +#@ git checkout master +#@ git pull +#@ +#@ mkdir -p torture_tests// +#@ cmp torture_tests//.gds (IIF EXISTS & IDENTICAL: exit with error) +#@ cp -f torture_tests//.gds +#@ determine of torture_tests//.gds +#@ +#@ +#@ git add torture_tests//.gds +#@ git commit -m ".gds md5=" +#@ if not no-push: +#@ git push +#@ extract short of commit +#@ extract short of commit +#@ +#@ if env-var exists CDRCLOG: +#@ append line to the log: "caldrc-put: .gds md5= " +#@ +#@ examples: +#@ All on command-line, with log, prompting: +#@ caldrc-put -C ~/git/openflow-drc-tests -l ~/caldrc.log ~/my_sram.gds +#@ ... no log: +#@ caldrc-put -C ~/git/openflow-drc-tests ~/my_sram.gds +#@ ... with log, no prompts: +#@ caldrc-put -y -C ~/git/openflow-drc-tests -l ~/caldrc.log ~/my_sram.gds +#@ Use env-vars, with log, no prompts: +#@ export CDRCREPO=~/git/openflow-drc-tests CDRCLOG=~/caldrc.log +#@ caldrc-put -y ~/my_sram.gds +#@ ... name the topcell explicitly (don't infer from gds filename): +#@ export CDRCREPO=~/git/openflow-drc-tests CDRCLOG=~/caldrc.log +#@ caldrc-put -y -c my_sram ~/data.gds +#@ + +PROG=caldrc-put +PROGF=$0 +errs=0 +caldrc=$CDRCREPO # opt. env-var, override by -C cmd-line option +log=$CDRCLOG # opt. env-var, override by -l cmd-line option +putbr=master +putdir=torture_tests + +# is STDIN a terminal? If not: no prompting for anything +inter="" +[[ -t 0 ]] && inter=1 + +dopush=1 + +usage() { + sed -n -e '/^#@/s/^#@//p' <$PROGF + exit $errs +} + +err () { + (( errs++ )) + echo "${PROG}: ERROR, $*" >&2 +} +msg () { + echo "${PROG}: $*" +} +vrb () { + [ -n "$verbose" ] && echo "${PROG}: $*" >&2 +} +die0 () { + exit $errs +} +die () { + err "$*" + exit $errs +} +dieu0 () { + usage "${PROG}: ERROR, $*" +} + +# gitcd function: echo and eval a (git) command, DIE if it fails (and write msg to stderr). +# $1 is var to be assigned the STDOUT of the command. +# Use this only when must pass. +gitcd () { + local _val="" _outvar=$1 _stat=0 + shift + echo "$*" + [[ -z "$dryrun" ]] && { + _val=$("$@") || die "failed($?) in: $*" + _stat=$? + } + eval "$_outvar=\${_val}" + return $_stat +} +# gitc function: echo and eval a (git) command. +# $1 is var to be assigned the STDOUT of the command. +# Status of the command is propagated. +gitc () { + local _val="" _outvar=$1 _stat=0 + shift + echo "$*" + [[ -z "$dryrun" ]] && { + _val=$("$@") + _stat=$? + } + eval "$_outvar=\${_val}" + return $_stat +} + +# main start + +while getopts "c:C:l:Ny" o; do + : echo got "optchar $o, with optarg $OPTARG" + case "$o" in \?) + (( errs++ )) + continue ; esac + case "$o" in y) + inter="" + continue ; esac + case "$o" in N) + dopush="" + continue ; esac + case "$o" in l) + log=$(readlink -m "$OPTARG") # we chdir below; ensure absolute path + continue ; esac + case "$o" in c) + topc="$OPTARG" + continue ; esac + case "$o" in C) + caldrc=$(readlink -m "$OPTARG") # we chdir below; ensure absolute path + continue ; esac +done + +[[ $errs != 0 ]] && { + usage +} + +(( OPTIND-- )) +shift $OPTIND + +[[ -z "$1" ]] && { + die "missing required gdsFilePath argument" +} +gds="$1" +shift +[[ ! -r "$gds" ]] && { + die "gdsFile not readable, $gds" +} +gds=$(readlink -m "$gds") # we chdir below; ensure absolute path + +# if no topcell option, determine from $gds file. +# But regardless if explicit topcell specified, capture optional compress-suffix from gds file. +compsuf="" +topc1=$(basename "$gds") # strip dirs +topc2=${topc1%.xz} # strip compression extensions +topc3=${topc2%.gz} +[[ -z "$topc" ]] && { + topc=${topc3%.*} # strip just one(last) dot-extension (i.e. normally .gds) +} +if [[ "$topc2" != "$topc1" ]]; then + compsuf=.xz +elif [[ "$topc3" != "$topc2" ]]; then + compsuf=.gz +fi + +[[ -z "$caldrc" ]] && { + caldrc=$(pwd) +} +caldrc=$(readlink -m "$caldrc") # ensure absolute path +msg "topcell: '$topc'" + +[[ -n "$log" ]] && { + log=$(readlink -m "$log") + [[ ! -e "$log" ]] && (touch "$log" || die "failed to create log, $log") + [[ ! -w "$log" ]] && die "log not writable, $log" + msg "log: '$log'" +} + +cd "$caldrc" || die "failed: cd $caldrc" + +# get original branch. ALSO doubles as hard-stop if this dir is NOT within a git-repo. +# Although gitcd exits on error (such as not a repo), the detached-HEAD is not an error. +gitcd br git branch --show-current +[[ -z "$br" ]] && die "no current branch (perhaps: detached HEAD)" +msg "original branch '$br'" + +# Path may not be root of the repo, goto it. +gitcd caldrcr git rev-parse --show-toplevel +msg "normalized caldrcrepo: '$caldrcr'" +cd "$caldrcr" || die "failed: cd $caldrcr" + +# checkout put-branch and pull (or just pull if already on that branch) +if [[ "$br" != "$putbr" ]]; then + echo + printf "NEXT: git checkout $putbr --\n : git pull\n" + [[ -n "$inter" ]] && read -p "Enter to CONTINUE (^C to quit)> " + gitcd res git checkout $putbr -- + echo "$res" + gitcd res git pull + echo "$res" +else + echo + printf "NEXT: git pull\n" + [[ -n "$inter" ]] && read -p "Enter to CONTINUE (^C to quit)> " + gitcd res git pull + echo "$res" +fi + +mkdir -p "$putdir/$topc" || die "failed: mkdir -p $putdir/$topc" +trg="$putdir/$topc/$topc.gds${compsuf}" +[[ -e $trg ]] && { + cmp -s "$gds" "$trg" && die "file is unchanged: $gds, $trg" +} + +# copy +echo "cp -f $gds $trg" +cp -f "$gds" "$trg" || die "failed: cp -f $gds $trg" + +# md5 of gds +line=($(md5sum "$gds")) || die "failed: md5sum $gds" +md5=${line[0]} +msg "got md5: $md5" +message="$topc.gds md5=$md5" + +if [[ -n "$dopush" ]]; then + logpush="git push" +else + logpush="[no-git-push]" +fi + +echo +printf "NEXT: git add $trg\n : git commit -m '$message'\n : $logpush\n" +[[ -n "$inter" ]] && read -p "Enter to CONTINUE (^C to quit)> " + +# git add +gitcd res git add $trg + echo "$res" + +# git commit +gitcd res git commit -m "$message" + echo "$res" + +if [[ -n "$dopush" ]]; then + gitcd res git push + echo "$res" + logpush="" +else + msg "SKIPPED 'git push' (still logging commit). Remember: 'git push' manually." + logpush=" [no-git-push]" +fi + +# info about the commit +gitcd commit git rev-parse HEAD + echo "commitId is $commit" +TZ=UTC gitcd stamp git log -n 1 --pretty=format:%cd --date=format-local:%Y-%m-%d.%T.%Z HEAD + echo "timestamp is $stamp" + +message="caldrc-put: $topc.gds $commit $stamp md5=$md5 ${gds}${logpush}" +[[ -n "$log" ]] && { + echo "logging: '$message'" + echo "$message" >> $log || die "failed append to log, $log" +} + +echo done +exit $errs diff --git a/images/foss-asic-tools/addons/sak/bin/cp_shapes.py b/images/foss-asic-tools/addons/sak/bin/cp_shapes.py new file mode 120000 index 00000000..d68390dd --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/cp_shapes.py @@ -0,0 +1 @@ +../klayout/cp_shapes.py \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/cp_shapes.sh b/images/foss-asic-tools/addons/sak/bin/cp_shapes.sh new file mode 120000 index 00000000..16f523a9 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/cp_shapes.sh @@ -0,0 +1 @@ +../klayout/cp_shapes.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/def2gds.py b/images/foss-asic-tools/addons/sak/bin/def2gds.py new file mode 120000 index 00000000..a55abae5 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/def2gds.py @@ -0,0 +1 @@ +../klayout/def2gds.py \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/def2gds.sh b/images/foss-asic-tools/addons/sak/bin/def2gds.sh new file mode 120000 index 00000000..09fd9a5d --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/def2gds.sh @@ -0,0 +1 @@ +../klayout/def2gds.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/delete_areaid.py b/images/foss-asic-tools/addons/sak/bin/delete_areaid.py new file mode 120000 index 00000000..e5dd27e3 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/delete_areaid.py @@ -0,0 +1 @@ +../klayout/delete_areaid.py \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/dot.magicrc b/images/foss-asic-tools/addons/sak/bin/dot.magicrc new file mode 120000 index 00000000..719c9ce9 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/dot.magicrc @@ -0,0 +1 @@ +../magic/dot.magicrc \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/drc-def-sky130A.sh b/images/foss-asic-tools/addons/sak/bin/drc-def-sky130A.sh new file mode 120000 index 00000000..066c4132 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/drc-def-sky130A.sh @@ -0,0 +1 @@ +../magic/drc-def-sky130A.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/drc-gds-full-EFS8A.sh b/images/foss-asic-tools/addons/sak/bin/drc-gds-full-EFS8A.sh new file mode 120000 index 00000000..8a934f01 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/drc-gds-full-EFS8A.sh @@ -0,0 +1 @@ +../magic/drc-gds-full-EFS8A.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/drc-gds-sky130A.sh b/images/foss-asic-tools/addons/sak/bin/drc-gds-sky130A.sh new file mode 120000 index 00000000..2d39c15e --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/drc-gds-sky130A.sh @@ -0,0 +1 @@ +../magic/drc-gds-sky130A.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/drc-mag-full-EFS8A.sh b/images/foss-asic-tools/addons/sak/bin/drc-mag-full-EFS8A.sh new file mode 120000 index 00000000..ea654e30 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/drc-mag-full-EFS8A.sh @@ -0,0 +1 @@ +../magic/drc-mag-full-EFS8A.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/drc-mag-sky130A.sh b/images/foss-asic-tools/addons/sak/bin/drc-mag-sky130A.sh new file mode 120000 index 00000000..eaaaf718 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/drc-mag-sky130A.sh @@ -0,0 +1 @@ +../magic/drc-mag-sky130A.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/erase_box.sh b/images/foss-asic-tools/addons/sak/bin/erase_box.sh new file mode 120000 index 00000000..859c1546 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/erase_box.sh @@ -0,0 +1 @@ +../magic/erase_box.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/ext-def-sky130A.sh b/images/foss-asic-tools/addons/sak/bin/ext-def-sky130A.sh new file mode 120000 index 00000000..8815f830 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/ext-def-sky130A.sh @@ -0,0 +1 @@ +../magic/ext-def-sky130A.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/ext-gds-sky130A.sh b/images/foss-asic-tools/addons/sak/bin/ext-gds-sky130A.sh new file mode 120000 index 00000000..a14bb11d --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/ext-gds-sky130A.sh @@ -0,0 +1 @@ +../magic/ext-gds-sky130A.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/ext-mag-sky130A.sh b/images/foss-asic-tools/addons/sak/bin/ext-mag-sky130A.sh new file mode 120000 index 00000000..25d681c0 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/ext-mag-sky130A.sh @@ -0,0 +1 @@ +../magic/ext-mag-sky130A.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/gds2mag.sh b/images/foss-asic-tools/addons/sak/bin/gds2mag.sh new file mode 120000 index 00000000..8742f503 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/gds2mag.sh @@ -0,0 +1 @@ +../magic/gds2mag.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/gds2oas-batch.sh b/images/foss-asic-tools/addons/sak/bin/gds2oas-batch.sh new file mode 120000 index 00000000..2b941ce8 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/gds2oas-batch.sh @@ -0,0 +1 @@ +../klayout/gds2oas-all.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/gds2oas.sh b/images/foss-asic-tools/addons/sak/bin/gds2oas.sh new file mode 120000 index 00000000..8d1fcfad --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/gds2oas.sh @@ -0,0 +1 @@ +../klayout/gds2oas.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/gdsAllcells.rb b/images/foss-asic-tools/addons/sak/bin/gdsAllcells.rb new file mode 120000 index 00000000..8e7066b0 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/gdsAllcells.rb @@ -0,0 +1 @@ +../klayout/gdsAllcells.rb \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/gdsFlat.rb b/images/foss-asic-tools/addons/sak/bin/gdsFlat.rb new file mode 120000 index 00000000..30240ebd --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/gdsFlat.rb @@ -0,0 +1 @@ +../klayout/gdsFlat.rb \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/gdsLayers.rb b/images/foss-asic-tools/addons/sak/bin/gdsLayers.rb new file mode 120000 index 00000000..03a059c3 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/gdsLayers.rb @@ -0,0 +1 @@ +../klayout/gdsLayers.rb \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/gdsLyrdel.rb b/images/foss-asic-tools/addons/sak/bin/gdsLyrdel.rb new file mode 120000 index 00000000..26dfa65e --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/gdsLyrdel.rb @@ -0,0 +1 @@ +../klayout/gdsLyrdel.rb \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/gdsRename.rb b/images/foss-asic-tools/addons/sak/bin/gdsRename.rb new file mode 120000 index 00000000..74b3c098 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/gdsRename.rb @@ -0,0 +1 @@ +../klayout/gdsRename.rb \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/gdsSize.rb b/images/foss-asic-tools/addons/sak/bin/gdsSize.rb new file mode 120000 index 00000000..68a85d51 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/gdsSize.rb @@ -0,0 +1 @@ +../klayout/gdsSize.rb \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/gdsTopcells.rb b/images/foss-asic-tools/addons/sak/bin/gdsTopcells.rb new file mode 120000 index 00000000..d91a4471 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/gdsTopcells.rb @@ -0,0 +1 @@ +../klayout/gdsTopcells.rb \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/git-sizer b/images/foss-asic-tools/addons/sak/bin/git-sizer new file mode 120000 index 00000000..da7ac0f1 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/git-sizer @@ -0,0 +1 @@ +../common/git-sizer \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/gm.py b/images/foss-asic-tools/addons/sak/bin/gm.py new file mode 100755 index 00000000..3dc7999a --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/gm.py @@ -0,0 +1,23 @@ +#!/bin/python3 + +# gather all dbs and rdbs in the current directory into +# a ./dbs directory to be easily navigatable by klayout +# so that you can switch easily between markers + +import os +from shutil import copyfile +from pathlib import Path +from glob import glob + + +def copy_all_dbs(ext): + db_files = glob('./*/*.{ext}'.format(ext=ext)) + relative_path_db_files = [Path(filename) for filename in db_files] + for afile in relative_path_db_files: + os.makedirs('dbs', exist_ok=True) + copyfile(str(afile), 'dbs/'+str(afile.parent)+'_'+afile.name) + +if __name__ == "__main__": + copy_all_dbs('db') + copy_all_dbs('rdb') + diff --git a/images/foss-asic-tools/addons/sak/bin/hspice2ngspice.sh b/images/foss-asic-tools/addons/sak/bin/hspice2ngspice.sh new file mode 120000 index 00000000..23522fa1 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/hspice2ngspice.sh @@ -0,0 +1 @@ +../common/hspice2ngspice.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/klayoutDrc.sh b/images/foss-asic-tools/addons/sak/bin/klayoutDrc.sh new file mode 120000 index 00000000..defebec3 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/klayoutDrc.sh @@ -0,0 +1 @@ +../klayout/klayoutDrc.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/label2pin_inplace.sh b/images/foss-asic-tools/addons/sak/bin/label2pin_inplace.sh new file mode 120000 index 00000000..5819822c --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/label2pin_inplace.sh @@ -0,0 +1 @@ +../klayout/label2pin_inplace.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/lef2maglef.sh b/images/foss-asic-tools/addons/sak/bin/lef2maglef.sh new file mode 120000 index 00000000..c399b6b9 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/lef2maglef.sh @@ -0,0 +1 @@ +../magic/lef2maglef.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/mag2gds.sh b/images/foss-asic-tools/addons/sak/bin/mag2gds.sh new file mode 120000 index 00000000..b1a47252 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/mag2gds.sh @@ -0,0 +1 @@ +../magic/mag2gds.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/mag2lvs.sh b/images/foss-asic-tools/addons/sak/bin/mag2lvs.sh new file mode 120000 index 00000000..0c0d1fd5 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/mag2lvs.sh @@ -0,0 +1 @@ +../magic/mag2lvs.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/mag2maglef.sh b/images/foss-asic-tools/addons/sak/bin/mag2maglef.sh new file mode 120000 index 00000000..1c7bcce7 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/mag2maglef.sh @@ -0,0 +1 @@ +../magic/mag2maglef.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/magic-drc.sh b/images/foss-asic-tools/addons/sak/bin/magic-drc.sh new file mode 120000 index 00000000..13518b3e --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/magic-drc.sh @@ -0,0 +1 @@ +../magic/magic-drc.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/magic-ext.sh b/images/foss-asic-tools/addons/sak/bin/magic-ext.sh new file mode 120000 index 00000000..8a191c03 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/magic-ext.sh @@ -0,0 +1 @@ +../magic/magic-ext.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/magicDrc b/images/foss-asic-tools/addons/sak/bin/magicDrc new file mode 120000 index 00000000..3abf4b21 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/magicDrc @@ -0,0 +1 @@ +../magic/magicDrc \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/magicGdrc b/images/foss-asic-tools/addons/sak/bin/magicGdrc new file mode 120000 index 00000000..3d9b379b --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/magicGdrc @@ -0,0 +1 @@ +../magic/magicGdrc \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/maglef2gds.sh b/images/foss-asic-tools/addons/sak/bin/maglef2gds.sh new file mode 120000 index 00000000..3da5f27f --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/maglef2gds.sh @@ -0,0 +1 @@ +../magic/maglef2gds.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/maglef2lvs.sh b/images/foss-asic-tools/addons/sak/bin/maglef2lvs.sh new file mode 120000 index 00000000..7d600853 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/maglef2lvs.sh @@ -0,0 +1 @@ +../magic/maglef2lvs.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/mv_shapes.py b/images/foss-asic-tools/addons/sak/bin/mv_shapes.py new file mode 120000 index 00000000..51122439 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/mv_shapes.py @@ -0,0 +1 @@ +../klayout/mv_shapes.py \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/mv_shapes.sh b/images/foss-asic-tools/addons/sak/bin/mv_shapes.sh new file mode 120000 index 00000000..8c972a11 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/mv_shapes.sh @@ -0,0 +1 @@ +../klayout/mv_shapes.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/pin2drawing_inplace.sh b/images/foss-asic-tools/addons/sak/bin/pin2drawing_inplace.sh new file mode 100755 index 00000000..f76d5efc --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/pin2drawing_inplace.sh @@ -0,0 +1,9 @@ +layers=(67 68 69 70 71 72) +files=( "$@" ) + +for f in "${files[@]}"; do + echo "Working on $f" + for l in "${layers[@]}"; do + sh $(dirname $0)/cp_shapes.sh $f $l/16 $l/20 + done +done diff --git a/images/foss-asic-tools/addons/sak/bin/run_gds2oas.sh b/images/foss-asic-tools/addons/sak/bin/run_gds2oas.sh new file mode 120000 index 00000000..81ad03aa --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/run_gds2oas.sh @@ -0,0 +1 @@ +../klayout/run_gds2oas.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/verilog2spice.py b/images/foss-asic-tools/addons/sak/bin/verilog2spice.py new file mode 120000 index 00000000..7b92d075 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/verilog2spice.py @@ -0,0 +1 @@ +../common/verilog2spice.py \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/bin/vlog2Spice b/images/foss-asic-tools/addons/sak/bin/vlog2Spice new file mode 120000 index 00000000..93844407 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/bin/vlog2Spice @@ -0,0 +1 @@ +../qflow/vlog2Spice \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/common/LICENSE b/images/foss-asic-tools/addons/sak/common/LICENSE new file mode 100755 index 00000000..261eeb9e --- /dev/null +++ b/images/foss-asic-tools/addons/sak/common/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/images/foss-asic-tools/addons/sak/common/get_description.py b/images/foss-asic-tools/addons/sak/common/get_description.py new file mode 100755 index 00000000..ee51ec01 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/common/get_description.py @@ -0,0 +1,16 @@ +#! /usr/bin/python3 + +import yaml +import io +#import sys +#reload(sys) +#sys.setdefaultencoding('utf8') + +#with open('info.yaml','r') as file: +with open('info.yaml','r',encoding='utf-8') as file: + info = yaml.load(file, Loader=yaml.SafeLoader) + if 'project' in info and 'project_id' in info['project'].keys(): + print(info['project']['description']) + else: + print("--none--") + diff --git a/images/foss-asic-tools/addons/sak/common/git-sizer b/images/foss-asic-tools/addons/sak/common/git-sizer new file mode 100755 index 00000000..d6382bfc Binary files /dev/null and b/images/foss-asic-tools/addons/sak/common/git-sizer differ diff --git a/images/foss-asic-tools/addons/sak/common/hspice2ngspice.sh b/images/foss-asic-tools/addons/sak/common/hspice2ngspice.sh new file mode 100755 index 00000000..9f58e842 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/common/hspice2ngspice.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +: ${1?"Usage: $0 from_s8.hspice to_sky130.spice"} +: ${2?"Usage: $0 from_s8.hspice to_sky130.spice"} + +properties_to_delete=("\\\$X" "\\\$Y" "\\\$D" "r" "N" "mult" "IP" "EP"\ + "FDC" "area" "ahftempperim" "PJ" "model") + +input=$1 +output=$2 + + +cp $input $output + +# apply mappings from rewrites.csv +: > _sed.script + +tail -n +2 $(dirname $0)/../common/rewrites.csv > rewrites.txt + +while IFS=, read -r from to +do + echo "s#\<$from\>#$to#g" >> _sed.script +#done <<< $(tail -n +2 $(dirname $0)/rewrites.csv) + +done < rewrites.txt + +sed -f _sed.script -i $output +\rm _sed.script rewrites.txt + +# remove properties_to_delete +for p in ${properties_to_delete[@]}; do + sed -i -E "s# $p=[^[:space:]]+##g" $output +done + +# remove empty subckts +# sed -i '/\.SUBCKT.*/{$!N;/\n\.ENDS/!P;D;D}' $output + +# remove $T=number number number number properties +sed -i -E "s# \\\$T=[^[:space:]]+ [^[:space:]]+ [^[:space:]]+ [^[:space:]]+##g" $output + +# M-instances -> X-instances +# D-instances -> X-instances +# C-instances -> X-instances +sed -i -E "s#^(M|D|C)#X\1#g" $output + +# fix up $[device_name] devices +# for R-devices (resistors) apply the following transformation: +# RXX x y value m=1 a=1 b=2 $[sky130_fd_pr__res_generic_po] -> RXX x y sky130_fd_pr__res_generic_po m=1 a=1 b=2 +sed -i -E "s#^(R[^[:space:]]+ [^[:space:]]+ [^[:space:]]+) ([\.0-9]+) (.*) \\\$\[sky130_fd_pr__res_generic_po\]#\1 sky130_fd_pr__res_generic_po \3#g" $output +sed -i -E "s#^(R[^[:space:]]+ [^[:space:]]+ [^[:space:]]+) ([\.0-9]+) (.*) \\\$\[short\]#\1 \2 short \3#g" $output + +# RXX x y m=1 a=1 b=2 $[device_name] -> RXX x y device_name m=1 a=1 b=2 +sed -i -E "s#^(R[^[:space:]]+ [^[:space:]]+ [^[:space:]]+) (.*)? \\\$\[([^[:space:]]+)\]#\1 \3 \2#g" $output + +# RXX x y m=1 a=1 b=2 $[device_name] -> RXX x y device_name m=1 a=1 b=2 +sed -i -E "s#^(R[^[:space:]]+ [^[:space:]]+ [^[:space:]]+) (.*) \\\$\[([^[:space:]]+)\]#\1 \3 \2#g" $output + +# RXX x y $[device_name] m=1 a=1 b=2 -> RXX x y device_name m=1 a=1 b=2 +sed -i -E "s#^(R[^[:space:]]+ [^[:space:]]+ [^[:space:]]+) \\\$\[([^[:space:]]+)\] (.*)#\1 \2 \3#g" $output + +# add w=480000u l=45000u to sky130_fd_pr__res_generic_po instances +# sed -i -E "s#(^R.* sky130_fd_pr__res_generic_po .*)#\1 w=480000u l=45000u#g" $output + +# for "Dpar"s +# XXXX x y Dpar m=1 a=1 $[device_name] -> +# XXXX x y device_name m=1 a=1 +sed -i -E "s#^(X[^[:space:]]+ [^[:space:]]+ [^[:space:]]+) Dpar (.*) \\\$\[([^[:space:]]+)\]#\1 \3 \2#g" $output +# for now comment them out +# sed -i -E "s#^(X.*Dpar.*)#* \1#g" $output + +# XC x y m=1 L=2 $[cap_device_name] -> XC x y cap_device_name m=1 L=2 +sed -i -E "s#^(X[^[:space:]]+ [^[:space:]]+ [^[:space:]]+) (.*) \\\$\[([^[:space:]]+)\]#\1 \3 \2#g" $output + +# handle Probes -> subckt pins +top_level_subckt=$(tac $output | grep -i -E -o -m 1 ".SUBCKT.*" | awk '{print $2}') + +echo "Top-level subckt name: $top_level_subckt" +# replace subckt declaration +pins=$(sed -E -n "s#^X.* ([^[:space:]]+) Probe.*#\1#p" $output) +readarray -t ARRAY <<< $pins; +IFS=' '; pins="${ARRAY[*]}" +subckt=".SUBCKT $top_level_subckt $pins" +echo "New subckt definition:" +echo "$subckt" +sed -i "s#^.subckt $top_level_subckt\>#$subckt#i" $output +# delete all Probes +sed -i "s#^X.* Probe .*##g" $output + + +###### +## Remove .subckts without any pins + +awk 'BEGIN { IGNORECASE=1 } $1==".subckt" && NF==2 { hide=1 } hide==0 { print } $1==".ends" { hide=0 }' $output > ${output}.tmp + +mv ${output}.tmp $output + diff --git a/images/foss-asic-tools/addons/sak/common/install-pdk.sh b/images/foss-asic-tools/addons/sak/common/install-pdk.sh new file mode 100755 index 00000000..61b31b49 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/common/install-pdk.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +#---------------- Setting up the PDK: skywater-pdk + +export PDK_ROOT=~/foss/pdks +cd $PDK_ROOT +git clone https://github.com/google/skywater-pdk.git +cd skywater-pdk + +git checkout master + +git submodule update --init libraries/sky130_fd_sc_hd/latest +git submodule update --init libraries/sky130_fd_sc_hvl/latest +git submodule update --init libraries/sky130_fd_sc_hs/latest +git submodule update --init libraries/sky130_fd_sc_ms/latest +git submodule update --init libraries/sky130_fd_sc_ls/latest +git submodule update --init libraries/sky130_fd_sc_hdll/latest +git submodule update --init libraries/sky130_fd_io/latest +git submodule update --init libraries/sky130_fd_pr/latest +git submodule update +make -j 8 timing + +#---------------- OpenPDKs + +cd $PDK_ROOT +git clone https://github.com/RTimothyEdwards/open_pdks.git +## git clone git://opencircuitdesign.com/open_pdks +cd open_pdks +./configure --enable-sky130-pdk=$PDK_ROOT/skywater-pdk --with-sky130-local-path=$PDK_ROOT --enable-alpha-sky130 --enable-xschem-sky130 +make +make install + +#---------------- diff --git a/images/foss-asic-tools/addons/sak/common/parse_klayout_xor_log.py b/images/foss-asic-tools/addons/sak/common/parse_klayout_xor_log.py new file mode 100755 index 00000000..842b484d --- /dev/null +++ b/images/foss-asic-tools/addons/sak/common/parse_klayout_xor_log.py @@ -0,0 +1,42 @@ +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import re + +parser = argparse.ArgumentParser( + description='extracts the total xor differnces from an xor log') + +parser.add_argument('--log_file', '-l',required=True, + help='log file') + +parser.add_argument('--output', '-o', required=True, + help='output file to store results') + +args = parser.parse_args() +log_file_name = args.log_file +out_file_name = args.output + +string = "XOR differences:" +pattern = re.compile(r'\s*%s\s*([\d+]+)' % string) +tot_cnt = 0 +with open(log_file_name, "r") as f: + for line in f: + m = pattern.match(line) + if m: + tot_cnt += int(m.group(1)) + +outFileOpener = open(out_file_name, "w") +outFileOpener.write("Total XOR differences = "+ str(tot_cnt)) +outFileOpener.close() diff --git a/images/foss-asic-tools/addons/sak/common/parse_summary.py b/images/foss-asic-tools/addons/sak/common/parse_summary.py new file mode 100755 index 00000000..458688a2 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/common/parse_summary.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Prerequisite: pip install pyyaml + +import argparse +import subprocess +import os +import yaml + +parser = argparse.ArgumentParser( + description="Parses a summary report into info.yaml") + + +parser.add_argument('--summary_report', '-s', action='store', default="final_summary_report.csv", + help="The csv file to be parsed, defaults to final_summary_report.csv") + +parser.add_argument('--info_yaml', '-i', action='store', default="info.yaml", + help="The info.yaml file, defaults to info.yaml") + +parser.add_argument('--target_path', '-t', action='store', default=None, + help="The run path, will be used to search for any missing files.") + +args = parser.parse_args() +summary_report = args.summary_report +info_yaml = args.info_yaml +target_path = args.target_path +if target_path is None: + target_path = str(os.getcwd()) + +stats= ["DIEAREA_mm^2", "CellPer_mm^2", "cell_count","STD_CELL_LIBRARY"] +def findIdx(header, label): + for idx in range(len(header)): + if label == header[idx]: + return idx + else: + return -1 +def parseCSV(csv_file): + map_out = dict() + csvOpener = open(csv_file, 'r') + csvData = csvOpener.read().split("\n") + headerInfo = csvData[0].split(",") + designNameIdx = findIdx(headerInfo, "design") + if designNameIdx == -1: + print("invalid report. No design names.") + exit(-1) + for i in range(1, len(csvData)): + if len(csvData[i]): + entry = csvData[i].split(",") + designName=entry[designNameIdx] + for idx in range(len(headerInfo)): + if idx != designNameIdx: + if designName not in map_out.keys(): + map_out[designName] = dict() + map_out[designName][headerInfo[idx]] = str(entry[idx]) + return map_out + +def read_yaml(yaml_file): + with open(yaml_file,'r+',encoding='utf-8') as f: + list_doc = yaml.load(f, Loader=yaml.FullLoader) + return list_doc + +def write_yaml(yaml_file,list_doc): + with open(yaml_file,'w+',encoding='utf-8') as f: + yaml.dump(list_doc, f) + +designs_map=parseCSV(str(target_path)+"/"+str(summary_report)) + +yaml_map = read_yaml(str(target_path)+"/"+str(info_yaml)) + + +def form_map(designs_map,stats): + write_map =dict() + for design in designs_map: + design_map = designs_map[design] + design_name = design_map["design_name"] + write_map[design_name] = dict() + for stat in stats: + write_map[design_name][stat]=design_map[stat] + return write_map + +write_map = form_map(designs_map, stats) + +if "stats" not in yaml_map["project"]: + yaml_map["project"]["stats"] = write_map + write_yaml(str(target_path)+"/"+str(info_yaml),yaml_map) + print("Done.") +else: + print("stats already exists") \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/common/rewrites.csv b/images/foss-asic-tools/addons/sak/common/rewrites.csv new file mode 100755 index 00000000..de11d156 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/common/rewrites.csv @@ -0,0 +1,2061 @@ +from,to +rf2_xcmvppx4_2xnhvnative10x4_noextrafingers_raphael,sky130_fd_pr__cap_vpp_11p3x11p8_m1m2_noshield_nhv2raphael +rf_xcmvppx4_2xnhvnative10x4_noextrafingers_raphael,sky130_fd_pr__cap_vpp_11p3x11p8_m1m2_noshield_nhv2raphael +xcmvppx4_2xnhvnative10x4_noextrafingers_raphael,sky130_fd_pr__cap_vpp_11p3x11p8_m1m2_noshield_nhv2raphael +rf2_xcmvpp11p5x11p7_m3m4_m2m5shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m3m4_shieldm2m5_raphael +rf2_xcmvpp11p5x11p7_polym5modshield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_m5pullin +rf2_xcmvppx4_2xnhvnative10x4_noextrafingers,sky130_fd_pr__cap_vpp_11p3x11p8_m1m2_noshield_2nhv +rf_xcmvpp11p5x11p7_m3m4_m2m5shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m3m4_shieldm2m5_raphael +rf_xcmvpp11p5x11p7_polym5modshield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_m5pullin +rf_xcmvppx4_2xnhvnative10x4_noextrafingers,sky130_fd_pr__cap_vpp_11p3x11p8_m1m2_noshield_2nhv +rf2_xcmvpp11p5x11p7_m3_lim5shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_shieldl1m5_floatm4_raphael +rf2_xcmvpp11p5x11p7_m1m4m5shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldm5_raphael +rf2_xcmvpp11p5x11p7_polym4shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldpom4_raphael +rf2_xcmvpp11p5x11p7_polym50p4shield_rcx6,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_x6 +rf2_xcmvpp11p5x11p7_polym50p4shield_rcx7,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_x7 +rf2_xcmvpp11p5x11p7_polym50p4shield_rcx8,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_x8 +rf2_xcmvpp11p5x11p7_polym50p4shield_rcx9,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_x9 +rf2_xcmvpp11p5x11p7_polym5shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_raphael +rf_xcmvpp11p5x11p7_m3_lim5shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_shieldl1m5_floatm4_raphael +rf2_xcmvpp11p5x11p7_m3_lishield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_shieldl1_raphael +rf2_xcmvpp11p5x11p7_polym50p4shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_xtop +rf2_xcmvpp4p4x4p6_m3_lim5shield_raphael,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1m5_floatm4_raphael +rf2_xcmvpp8p6x7p9_m3_lim5shield_raphael,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_shieldl1m5_floatm4_raphael +rf_xcmvpp11p5x11p7_m1m4m5shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldm5_raphael +rf_xcmvpp11p5x11p7_polym4shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldpom4_raphael +rf_xcmvpp11p5x11p7_polym50p4shield_rcx6,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_x6 +rf_xcmvpp11p5x11p7_polym50p4shield_rcx7,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_x7 +rf_xcmvpp11p5x11p7_polym50p4shield_rcx8,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_x8 +rf_xcmvpp11p5x11p7_polym50p4shield_rcx9,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_x9 +rf_xcmvpp11p5x11p7_polym5shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_raphael +xcmvpp11p5x11p7_m3m4_m2m5shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m3m4_shieldm2m5_raphael +xcmvpp11p5x11p7_polym5modshield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_m5pullin +xcmvppx4_2xnhvnative10x4_noextrafingers,sky130_fd_pr__cap_vpp_11p3x11p8_m1m2_noshield_2nhv +rf2_xcmvpp11p5x11p7_lim5shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldl1m5_raphael +rf2_xcmvpp6p8x6p1_polym4shield_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4_raphael +rf_xcmvpp11p5x11p7_m3_lishield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_shieldl1_raphael +rf_xcmvpp11p5x11p7_polym50p4shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_xtop +rf_xcmvpp4p4x4p6_m3_lim5shield_raphael,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1m5_floatm4_raphael +rf_xcmvpp8p6x7p9_m3_lim5shield_raphael,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_shieldl1m5_floatm4_raphael +rf2_xcmvpp11p5x11p7_m3_lim5shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_shieldl1m5_floatm4_top +rf2_xcmvpp4p4x4p6_m3_lishield_raphael,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1_raphael +rf2_xcmvpp6p8x6p_polym4shield_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4_raphael +rf2_xcmvpp8p6x7p9_m3_lishield_raphael,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_shieldl1_raphael +rf_xcmvpp11p5x11p7_lim5shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldl1m5_raphael +rf_xcmvpp6p8x6p1_polym4shield_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4_raphael +s8rf2_xcmvpp11p5x11p7_polym50p4shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_x +xcmvpp11p5x11p7_m3_lim5shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_shieldl1m5_floatm4_raphael +rf2_xcmvpp11p5x11p7_lishield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2_shieldl1_raphael +rf2_xcmvpp11p5x11p7_m1m4m5shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldm5_top +rf2_xcmvpp11p5x11p7_m3shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2_shieldpom3_raphael +rf2_xcmvpp11p5x11p7_m4shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldm4_raphael +rf2_xcmvpp11p5x11p7_m5shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldm5_raphael +rf2_xcmvpp11p5x11p7_polym4shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldpom4_top +rf2_xcmvpp11p5x11p7_polym5shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_top +rf2_xcmvpp6p8x6p1_lim4shield_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4_raphael +rf2_xcmvppx4_2xnhvnative10x4_raphael,sky130_fd_pr__cap_vpp_11p3x11p8_l1m1m2m3m4_shieldm5_nhvraphael +rf_xcmvpp11p5x11p7_m3_lim5shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_shieldl1m5_floatm4_top +rf_xcmvpp4p4x4p6_m3_lishield_raphael,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1_raphael +rf_xcmvpp6p8x6p_polym4shield_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4_raphael +rf_xcmvpp8p6x7p9_m3_lishield_raphael,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_shieldl1_raphael +s8rf2_xcmvpp_hd5_atlas_fingercap2_l5,sky130_fd_pr__cap_vpp_02p9x06p1_m1m2m3m4_shieldl1_fingercap2 +s8rf2_xcmvpp_hd5_atlas_fingercap_l10,sky130_fd_pr__cap_vpp_02p7x11p1_m1m2m3m4_shieldl1_fingercap +s8rf2_xcmvpp_hd5_atlas_fingercap_l20,sky130_fd_pr__cap_vpp_02p7x21p1_m1m2m3m4_shieldl1_fingercap +s8rf2_xcmvpp_hd5_atlas_fingercap_l40,sky130_fd_pr__cap_vpp_02p7x41p1_m1m2m3m4_shieldl1_fingercap +xcmvpp11p5x11p7_m1m4m5shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldm5_raphael +xcmvpp11p5x11p7_polym4shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldpom4_raphael +xcmvpp11p5x11p7_polym50p4shield_rcx6,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_x6 +xcmvpp11p5x11p7_polym50p4shield_rcx7,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_x7 +xcmvpp11p5x11p7_polym50p4shield_rcx8,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_x8 +xcmvpp11p5x11p7_polym50p4shield_rcx9,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_x9 +xcmvpp11p5x11p7_polym5shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_raphael +rf2_xcmvpp11p5x11p7_m3m4_m2m5shield,sky130_fd_pr__cap_vpp_11p5x11p7_m3m4_shieldm2m5 +rf2_xcmvpp11p5x11p7_polym50p4shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_x +rf2_xcmvpp11p5x11p7_polym5modshield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_m5pullin +rf2_xcmvpp4p4x4p6_m3_lim5shield_top,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1m5_floatm4_top +rf2_xcmvpp6p8x6p_lim4shield_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4_raphael +rf2_xcmvpp8p6x7p9_m3_lim5shield_top,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_shieldl1m5_floatm4_top +rf_xcmvpp11p5x11p7_lishield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2_shieldl1_raphael +rf_xcmvpp11p5x11p7_m1m4m5shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldm5_top +rf_xcmvpp11p5x11p7_m3shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2_shieldpom3_raphael +rf_xcmvpp11p5x11p7_m4shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldm4_raphael +rf_xcmvpp11p5x11p7_m5shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldm5_raphael +rf_xcmvpp11p5x11p7_polym4shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldpom4_top +rf_xcmvpp11p5x11p7_polym5shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_top +rf_xcmvpp6p8x6p1_lim4shield_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4_raphael +rf_xcmvppx4_2xnhvnative10x4_raphael,sky130_fd_pr__cap_vpp_11p3x11p8_l1m1m2m3m4_shieldm5_nhvraphael +s8rf2_xcmvpp11p5x11p7_m3_lim5shield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_shieldl1m5_floatm4 +s8rf2_xcmvpp4p4x4p6_fltpolym3shield,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_shieldm3_floatpo +s8rf2_xcmvpp_hd5_atlas_fingercap_l5,sky130_fd_pr__cap_vpp_02p7x06p1_m1m2m3m4_shieldl1_fingercap +xcmvpp11p5x11p7_m3_lishield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_shieldl1_raphael +xcmvpp11p5x11p7_polym50p4shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_xtop +xcmvpp4p4x4p6_m3_lim5shield_raphael,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1m5_floatm4_raphael +xcmvpp8p6x7p9_m3_lim5shield_raphael,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_shieldl1m5_floatm4_raphael +rf2_xcmvpp11p5x11p7_lim5shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldl1m5_top +rf2_xcmvpp6p8x6p1_m1m4_fom_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield_fom +rf2_xcmvpp6p8x6p1_polym4shield_top,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4_top +rf2_xcmvpp_hd5_atlas_fingercap2_l5,sky130_fd_pr__cap_vpp_02p9x06p1_m1m2m3m4_shieldl1_fingercap2 +rf2_xcmvpp_hd5_atlas_fingercap_l10,sky130_fd_pr__cap_vpp_02p7x11p1_m1m2m3m4_shieldl1_fingercap +rf2_xcmvpp_hd5_atlas_fingercap_l20,sky130_fd_pr__cap_vpp_02p7x21p1_m1m2m3m4_shieldl1_fingercap +rf2_xcmvpp_hd5_atlas_fingercap_l40,sky130_fd_pr__cap_vpp_02p7x41p1_m1m2m3m4_shieldl1_fingercap +rf_xcmvpp11p5x11p7_m3m4_m2m5shield,sky130_fd_pr__cap_vpp_11p5x11p7_m3m4_shieldm2m5 +rf_xcmvpp11p5x11p7_polym50p4shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_x +rf_xcmvpp11p5x11p7_polym5modshield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_m5pullin +rf_xcmvpp4p4x4p6_m3_lim5shield_top,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1m5_floatm4_top +rf_xcmvpp6p8x6p_lim4shield_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4_raphael +rf_xcmvpp8p6x7p9_m3_lim5shield_top,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_shieldl1m5_floatm4_top +s8rf2_xcmvpp11p5x11p7_m1m4m5shield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldm5 +s8rf2_xcmvpp11p5x11p7_polym4shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldpom4 +s8rf2_xcmvpp11p5x11p7_polym5shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5 +xcmvpp11p5x11p7_lim5shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldl1m5_raphael +xcmvpp6p8x6p1_polym4shield_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4_raphael +rf2_xcmvpp11p5x11p7_m3_lim5shield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_shieldl1m5_floatm4 +rf2_xcmvpp4p4x4p6_fltpolym3shield,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_shieldm3_floatpo +rf2_xcmvpp4p4x4p6_m3_lishield_top,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1_top +rf2_xcmvpp6p8x6p_m1m4_fom_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield_fom +rf2_xcmvpp6p8x6p_polym4shield_top,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4_top +rf2_xcmvpp_hd5_atlas_fingercap_l5,sky130_fd_pr__cap_vpp_02p7x06p1_m1m2m3m4_shieldl1_fingercap +rf_xcmvpp11p5x11p7_lim5shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldl1m5_top +rf_xcmvpp6p8x6p1_m1m4_fom_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield_fom +rf_xcmvpp6p8x6p1_polym4shield_top,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4_top +rf_xcmvpp_hd5_atlas_fingercap2_l5,sky130_fd_pr__cap_vpp_02p9x06p1_m1m2m3m4_shieldl1_fingercap2 +rf_xcmvpp_hd5_atlas_fingercap_l10,sky130_fd_pr__cap_vpp_02p7x11p1_m1m2m3m4_shieldl1_fingercap +rf_xcmvpp_hd5_atlas_fingercap_l20,sky130_fd_pr__cap_vpp_02p7x21p1_m1m2m3m4_shieldl1_fingercap +rf_xcmvpp_hd5_atlas_fingercap_l40,sky130_fd_pr__cap_vpp_02p7x41p1_m1m2m3m4_shieldl1_fingercap +s8rf2_xcmvpp4p4x4p6_m3_lim5shield,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1m5_floatm4 +s8rf2_xcmvpp8p6x7p9_m3_lim5shield,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_shieldl1m5_floatm4 +s8rf2_xcmvpp_hd5_atlas_fingercap2,sky130_fd_pr__cap_vpp_02p9x06p1_m1m2m3m4_shieldl1_basefingercap2 +s8rf2_xcmvpp_hd5_atlas_wafflecap1,sky130_fd_pr__cap_vpp_11p3x11p3_m1m2m3m4_shieldl1_wafflecap +s8rf2_xcmvpp_hd5_atlas_wafflecap2,sky130_fd_pr__cap_vpp_05p9x05p9_m1m2m3m4_shieldl1_wafflecap +xcmvpp11p5x11p7_m3_lim5shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_shieldl1m5_floatm4_top +xcmvpp4p4x4p6_m3_lishield_raphael,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1_raphael +xcmvpp6p8x6p_polym4shield_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4_raphael +xcmvpp8p6x7p9_m3_lishield_raphael,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_shieldl1_raphael +rf2_xcmvpp11p5x11p7_lishield_top,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2_shieldl1_top +rf2_xcmvpp11p5x11p7_m1m2_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2_noshield_raphael +rf2_xcmvpp11p5x11p7_m1m4_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m4_noshield_raphael +rf2_xcmvpp11p5x11p7_m1m4m5shield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldm5 +rf2_xcmvpp11p5x11p7_m3shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2_shieldpom3_top +rf2_xcmvpp11p5x11p7_m4shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldm4_top +rf2_xcmvpp11p5x11p7_m5shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldm5_top +rf2_xcmvpp11p5x11p7_polym4shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldpom4 +rf2_xcmvpp11p5x11p7_polym5shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5 +rf2_xcmvpp6p8x6p1_lim4shield_top,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4_top +rf2_xcmvppx4_2xnhvnative10x4_top,sky130_fd_pr__cap_vpp_11p3x11p8_l1m1m2m3m4_shieldm5_nhvtop +rf_xcmvpp11p5x11p7_m3_lim5shield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_shieldl1m5_floatm4 +rf_xcmvpp4p4x4p6_fltpolym3shield,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_shieldm3_floatpo +rf_xcmvpp4p4x4p6_m3_lishield_top,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1_top +rf_xcmvpp6p8x6p_m1m4_fom_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield_fom +rf_xcmvpp6p8x6p_polym4shield_top,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4_top +rf_xcmvpp_hd5_atlas_fingercap_l5,sky130_fd_pr__cap_vpp_02p7x06p1_m1m2m3m4_shieldl1_fingercap +s8rf2_xcmvpp11p5x11p7_lim5shield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldl1m5 +s8rf2_xcmvpp4p4x4p6_polym5shield,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2m3m4_shieldpom5 +s8rf2_xcmvpp6p8x6p1_polym4shield,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4 +s8rf2_xcmvpp6p8x6p1_polym5shield,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3m4_shieldpo_floatm5 +s8rf2_xcmvpp8p6x7p9_polym5shield,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3m4_shieldpom5 +s8rf2_xcmvpp_hd5_atlas_fingercap,sky130_fd_pr__cap_vpp_02p7x11p1_m1m2m3m4_shieldl1_basefingercap +s8rf_xcmvpp11p5x11p7_m3_lishield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_shieldl1 +xcmvpp11p5x11p7_lishield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2_shieldl1_raphael +xcmvpp11p5x11p7_m1m4m5shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldm5_top +xcmvpp11p5x11p7_m3shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2_shieldpom3_raphael +xcmvpp11p5x11p7_m4shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldm4_raphael +xcmvpp11p5x11p7_m5shield_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldm5_raphael +xcmvpp11p5x11p7_polym4shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldpom4_top +xcmvpp11p5x11p7_polym5shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_top +xcmvpp6p8x6p1_lim4shield_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4_raphael +xcmvppx4_2xnhvnative10x4_raphael,sky130_fd_pr__cap_vpp_11p3x11p8_l1m1m2m3m4_shieldm5_nhvraphael +rf2_xcmvpp11p5x11p7_m3_lishield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_shieldl1 +rf2_xcmvpp4p4x4p6_m3_lim5shield,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1m5_floatm4 +rf2_xcmvpp6p8x6p_lim4shield_top,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4_top +rf2_xcmvpp8p6x7p9_m3_lim5shield,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_shieldl1m5_floatm4 +rf2_xcmvpp_hd5_atlas_fingercap2,sky130_fd_pr__cap_vpp_02p9x06p1_m1m2m3m4_shieldl1_basefingercap2 +rf2_xcmvpp_hd5_atlas_wafflecap1,sky130_fd_pr__cap_vpp_11p3x11p3_m1m2m3m4_shieldl1_wafflecap +rf2_xcmvpp_hd5_atlas_wafflecap2,sky130_fd_pr__cap_vpp_05p9x05p9_m1m2m3m4_shieldl1_wafflecap +rf_xcmvpp11p5x11p7_lishield_top,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2_shieldl1_top +rf_xcmvpp11p5x11p7_m1m2_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2_noshield_raphael +rf_xcmvpp11p5x11p7_m1m4_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m4_noshield_raphael +rf_xcmvpp11p5x11p7_m1m4m5shield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldm5 +rf_xcmvpp11p5x11p7_m3shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2_shieldpom3_top +rf_xcmvpp11p5x11p7_m4shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldm4_top +rf_xcmvpp11p5x11p7_m5shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldm5_top +rf_xcmvpp11p5x11p7_polym4shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldpom4 +rf_xcmvpp11p5x11p7_polym5shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5 +rf_xcmvpp6p8x6p1_lim4shield_top,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4_top +rf_xcmvppx4_2xnhvnative10x4_top,sky130_fd_pr__cap_vpp_11p3x11p8_l1m1m2m3m4_shieldm5_nhvtop +s8rf2_xcmvpp_hd5_5x1_met5pullin,sky130_fd_pr__cap_vpp_55p8x11p7_pol1m1m2m3m4m5_noshield_m5pullin +s8rf2_xcmvpp_hd5_5x2_met5pullin,sky130_fd_pr__cap_vpp_55p8x23p1_pol1m1m2m3m4m5_noshield_m5pullin +xcmvpp11p5x11p7_m3m4_m2m5shield,sky130_fd_pr__cap_vpp_11p5x11p7_m3m4_shieldm2m5 +xcmvpp11p5x11p7_polym50p4shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_x +xcmvpp11p5x11p7_polym5modshield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5_m5pullin +xcmvpp4p4x4p6_m3_lim5shield_top,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1m5_floatm4_top +xcmvpp6p8x6p_lim4shield_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4_raphael +xcmvpp8p6x7p9_m3_lim5shield_top,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_shieldl1m5_floatm4_top +hrpoly_0p35_l1m1con$$175323180,sky130_fd_pr__res_high_pol1m1_0p35__example_175323180 +hrpoly_0p35_rpl1con$$175321132,sky130_fd_pr__res_high_pol1_0p35__example_175321132 +hrpoly_0p69_l1m1con$$174839852,sky130_fd_pr__res_high_pol1m1_0p69__example_174839852 +hrpoly_0p69_rpl1con$$174837804,sky130_fd_pr__res_high_pol1_0p69__example_174837804 +hrpoly_1p41_l1m1con$$174845996,sky130_fd_pr__res_high_pol1m1_1p41__example_174845996 +hrpoly_1p41_rpl1con$$174843948,sky130_fd_pr__res_high_pol1_1p41__example_174843948 +hrpoly_2p85_l1m1con$$173901868,sky130_fd_pr__res_high_pol1m1_2p85__example_173901868 +hrpoly_2p85_rpl1con$$174850092,sky130_fd_pr__res_high_pol1_2p85__example_174850092 +hrpoly_5p73_l1m1con$$173908012,sky130_fd_pr__res_high_pol1m1_5p73__example_173908012 +hrpoly_5p73_rpl1con$$173905964,sky130_fd_pr__res_high_pol1_5p73__example_173905964 +rf2_xcmvpp11p5x11p7_lim5shield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldl1m5 +rf2_xcmvpp11p5x11p7_m3_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_noshield_raphael +rf2_xcmvpp4p4x4p6_m1m2_raphael,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield_raphael +rf2_xcmvpp4p4x4p6_m1m4_raphael,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3m4_noshield_raphael +rf2_xcmvpp4p4x4p6_polym5shield,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2m3m4_shieldpom5 +rf2_xcmvpp6p8x6p1_m1m4_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield_raphael +rf2_xcmvpp6p8x6p1_polym4shield,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4 +rf2_xcmvpp6p8x6p1_polym5shield,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3m4_shieldpo_floatm5 +rf2_xcmvpp8p6x7p9_polym5shield,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3m4_shieldpom5 +rf2_xcmvpp_hd5_atlas_fingercap,sky130_fd_pr__cap_vpp_02p7x11p1_m1m2m3m4_shieldl1_basefingercap +rf2_xcmvpp_hd5_atlas_wafflecap,sky130_fd_pr__cap_vpp_m1m2m3m4_shieldl1_wafflecap +rf_xcmvpp11p5x11p7_m3_lishield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_shieldl1 +rf_xcmvpp4p4x4p6_m3_lim5shield,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1m5_floatm4 +rf_xcmvpp6p8x6p_lim4shield_top,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4_top +rf_xcmvpp8p6x7p9_m3_lim5shield,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_shieldl1m5_floatm4 +rf_xcmvpp_hd5_atlas_fingercap2,sky130_fd_pr__cap_vpp_02p9x06p1_m1m2m3m4_shieldl1_basefingercap2 +rf_xcmvpp_hd5_atlas_wafflecap1,sky130_fd_pr__cap_vpp_11p3x11p3_m1m2m3m4_shieldl1_wafflecap +rf_xcmvpp_hd5_atlas_wafflecap2,sky130_fd_pr__cap_vpp_05p9x05p9_m1m2m3m4_shieldl1_wafflecap +s8rf2_xcmvpp11p5x11p7_m4shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldm4 +s8rf2_xcmvpp11p5x11p7_m5shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldm5 +s8rf2_xcmvpp6p8x6p1_lim4shield,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4 +s8rf2_xcmvppx4_2xnhvnative10x4,sky130_fd_pr__cap_vpp_11p3x11p8_l1m1m2m3m4_shieldm5_nhv +s8rf_n20nativevhviso1_withptap,sky130_fd_pr__rf_nfet_20v0_nvt_withptap_iso +s8rf_xcmvpp4p4x4p6_m3_lishield,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1 +s8rf_xcmvpp8p6x7p9_m3_lishield,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_shieldl1 +xcmvpp11p5x11p7_lim5shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldl1m5_top +xcmvpp6p8x6p1_m1m4_fom_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield_fom +xcmvpp6p8x6p1_polym4shield_top,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4_top +xcmvpp_hd5_atlas_fingercap2_l5,sky130_fd_pr__cap_vpp_02p9x06p1_m1m2m3m4_shieldl1_fingercap2 +xcmvpp_hd5_atlas_fingercap_l10,sky130_fd_pr__cap_vpp_02p7x11p1_m1m2m3m4_shieldl1_fingercap +xcmvpp_hd5_atlas_fingercap_l20,sky130_fd_pr__cap_vpp_02p7x21p1_m1m2m3m4_shieldl1_fingercap +xcmvpp_hd5_atlas_fingercap_l40,sky130_fd_pr__cap_vpp_02p7x41p1_m1m2m3m4_shieldl1_fingercap +hrpoly_0p35_l1m1con_175323180,sky130_fd_pr__res_high_pol1m1_0p35__example_175323180 +hrpoly_0p35_rpl1con_175321132,sky130_fd_pr__res_high_pol1_0p35__example_175321132 +hrpoly_0p69_l1m1con_174839852,sky130_fd_pr__res_high_pol1m1_0p69__example_174839852 +hrpoly_0p69_rpl1con_174837804,sky130_fd_pr__res_high_pol1_0p69__example_174837804 +hrpoly_1p41_l1m1con_174845996,sky130_fd_pr__res_high_pol1m1_1p41__example_174845996 +hrpoly_1p41_rpl1con_174843948,sky130_fd_pr__res_high_pol1_1p41__example_174843948 +hrpoly_2p85_l1m1con_173901868,sky130_fd_pr__res_high_pol1m1_2p85__example_173901868 +hrpoly_2p85_rpl1con_174850092,sky130_fd_pr__res_high_pol1_2p85__example_174850092 +hrpoly_5p73_l1m1con_173908012,sky130_fd_pr__res_high_pol1m1_5p73__example_173908012 +hrpoly_5p73_rpl1con_173905964,sky130_fd_pr__res_high_pol1_5p73__example_173905964 +n20vhvisoreverse1_fs_discrete,sky130_fd_pr__nfet_20v0_reverse_iso__fs_discrete +n20vhvisoreverse1_sf_discrete,sky130_fd_pr__nfet_20v0_reverse_iso__sf_discrete +n20vhvisoreverse1_tt_discrete,sky130_fd_pr__nfet_20v0_reverse_iso__tt_discrete +rf2_xcmvpp4p4x4p6_m3_lishield,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1 +rf2_xcmvpp6p8x6p_m1m4_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield_raphael +rf2_xcmvpp6p8x6p_polym4shield,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4 +rf2_xcmvpp6p8x6p_polym5shield,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3m4_shieldpo_floatm5 +rf2_xcmvpp8p6x7p9_m3_lishield,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_shieldl1 +rf2_xcmvpp_hd5_5x1_met5pullin,sky130_fd_pr__cap_vpp_55p8x11p7_pol1m1m2m3m4m5_noshield_m5pullin +rf2_xcmvpp_hd5_5x2_met5pullin,sky130_fd_pr__cap_vpp_55p8x23p1_pol1m1m2m3m4m5_noshield_m5pullin +rf_xcmvpp11p5x11p7_lim5shield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldl1m5 +rf_xcmvpp11p5x11p7_m3_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_noshield_raphael +rf_xcmvpp4p4x4p6_m1m2_raphael,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield_raphael +rf_xcmvpp4p4x4p6_m1m4_raphael,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3m4_noshield_raphael +rf_xcmvpp4p4x4p6_polym5shield,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2m3m4_shieldpom5 +rf_xcmvpp6p8x6p1_m1m4_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield_raphael +rf_xcmvpp6p8x6p1_polym4shield,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4 +rf_xcmvpp6p8x6p1_polym5shield,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3m4_shieldpo_floatm5 +rf_xcmvpp8p6x7p9_polym5shield,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3m4_shieldpom5 +rf_xcmvpp_hd5_atlas_fingercap,sky130_fd_pr__cap_vpp_02p7x11p1_m1m2m3m4_shieldl1_basefingercap +rf_xcmvpp_hd5_atlas_wafflecap,sky130_fd_pr__cap_vpp_m1m2m3m4_shieldl1_wafflecap +s8rf2_xcmvpp_hd5_5x2_testcase,sky130_fd_pr__cap_vpp_55p8x23p1_pol1m1m2m3m4m5_noshield_test +s8rf2_xcmvpp_hd5_6p8x6p1_m1m4,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield +s8rf_xcmvpp11p5x11p7_lishield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2_shieldl1 +s8rf_xcmvpp11p5x11p7_m3shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2_shieldpom3 +xcmvpp11p5x11p7_m3_lim5shield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_shieldl1m5_floatm4 +xcmvpp4p4x4p6_fltpolym3shield,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_shieldm3_floatpo +xcmvpp4p4x4p6_m3_lishield_top,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1_top +xcmvpp6p8x6p_m1m4_fom_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield_fom +xcmvpp6p8x6p_polym4shield_top,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4_top +xcmvpp_hd5_atlas_fingercap_l5,sky130_fd_pr__cap_vpp_02p7x06p1_m1m2m3m4_shieldl1_fingercap +dnwdiode_psub_n20zvtvh1defet,sky130_fd_pr__nfet_20v0_zvt__parasitic__diode_ps2dn__extended_drain +n20nativevhviso1_fs_discrete,sky130_fd_pr__nfet_20v0_nvt_iso__fs_discrete +n20nativevhviso1_sf_discrete,sky130_fd_pr__nfet_20v0_nvt_iso__sf_discrete +n20nativevhviso1_tt_discrete,sky130_fd_pr__nfet_20v0_nvt_iso__tt_discrete +n20vhviso1reverse_subcircuit,sky130_fd_pr__nfet_20v0_reverse_iso__subcircuit +n20vhvisoreverse1_subcircuit,sky130_fd_pr__nfet_20v0_reverse_iso__subcircuit +n20vhvisoreverse_fs_discrete,sky130_fd_pr__nfet_20v0_reverse_iso__fs_discrete +n20vhvisoreverse_sf_discrete,sky130_fd_pr__nfet_20v0_reverse_iso__sf_discrete +n20vhvisoreverse_tt_discrete,sky130_fd_pr__nfet_20v0_reverse_iso__tt_discrete +rf2_xcmvpp11p5x11p7_lishield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2_shieldl1 +rf2_xcmvpp11p5x11p7_m3shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2_shieldpom3 +rf2_xcmvpp11p5x11p7_m4shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldm4 +rf2_xcmvpp11p5x11p7_m5shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldm5 +rf2_xcmvpp6p8x6p1_lim4shield,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4 +rf2_xcmvppx4_2xnhvnative10x4,sky130_fd_pr__cap_vpp_11p3x11p8_l1m1m2m3m4_shieldm5_nhv +rf_xcmvpp4p4x4p6_m3_lishield,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1 +rf_xcmvpp6p8x6p_m1m4_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield_raphael +rf_xcmvpp6p8x6p_polym4shield,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4 +rf_xcmvpp6p8x6p_polym5shield,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3m4_shieldpo_floatm5 +rf_xcmvpp8p6x7p9_m3_lishield,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_shieldl1 +rf_xcmvpp_hd5_5x1_met5pullin,sky130_fd_pr__cap_vpp_55p8x11p7_pol1m1m2m3m4m5_noshield_m5pullin +rf_xcmvpp_hd5_5x2_met5pullin,sky130_fd_pr__cap_vpp_55p8x23p1_pol1m1m2m3m4m5_noshield_m5pullin +s8rf_n20nativevhviso1_noptap,sky130_fd_pr__rf_nfet_20v0_nvt_noptap_iso +s8rf_n20vhv1_esd_hbm_21v_w60,sky130_fd_pr__esd_rf_nfet_20v0_hbm_21vW60p00 +s8rf_n20vhv1_esd_hbm_32v_w60,sky130_fd_pr__esd_rf_nfet_20v0_hbm_32vW60p00 +s8rf_n20vhv1_esd_iec_21v_w60,sky130_fd_pr__esd_rf_nfet_20v0_iec_21vW60p00 +s8rf_n20vhv1_esd_iec_32v_w60,sky130_fd_pr__esd_rf_nfet_20v0_iec_32vW60p00 +s8rf_nlowvt_w1p65_l0p15_m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W1p65L0p15 +s8rf_nlowvt_w1p65_l0p15_m2_c,sky130_fd_pr__rf_nfet_01v8_lvt_cM02W1p65L0p15 +s8rf_nlowvt_w1p65_l0p15_m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W1p65L0p15 +s8rf_nlowvt_w1p65_l0p15_m4_c,sky130_fd_pr__rf_nfet_01v8_lvt_cM04W1p65L0p15 +s8rf_nlowvt_w1p65_l0p18_m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W1p65L0p18 +s8rf_nlowvt_w1p65_l0p18_m2_c,sky130_fd_pr__rf_nfet_01v8_lvt_cM02W1p65L0p18 +s8rf_nlowvt_w1p65_l0p18_m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W1p65L0p18 +s8rf_nlowvt_w1p65_l0p18_m4_c,sky130_fd_pr__rf_nfet_01v8_lvt_cM04W1p65L0p18 +s8rf_nlowvt_w1p65_l0p25_m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W1p65L0p25 +s8rf_nlowvt_w1p65_l0p25_m2_c,sky130_fd_pr__rf_nfet_01v8_lvt_cM02W1p65L0p25 +s8rf_nlowvt_w1p65_l0p25_m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W1p65L0p25 +s8rf_nlowvt_w1p65_l0p25_m4_c,sky130_fd_pr__rf_nfet_01v8_lvt_cM04W1p65L0p25 +s8rf_nshort_w1p65_l0p15_m2_b,sky130_fd_pr__rf_nfet_01v8_bM02W1p65L0p15 +s8rf_nshort_w1p65_l0p15_m4_b,sky130_fd_pr__rf_nfet_01v8_bM04W1p65L0p15 +s8rf_nshort_w1p65_l0p18_m2_b,sky130_fd_pr__rf_nfet_01v8_bM02W1p65L0p18 +s8rf_nshort_w1p65_l0p18_m4_b,sky130_fd_pr__rf_nfet_01v8_bM04W1p65L0p18 +s8rf_nshort_w1p65_l0p25_m2_b,sky130_fd_pr__rf_nfet_01v8_bM02W1p65L0p25 +s8rf_nshort_w1p65_l0p25_m4_b,sky130_fd_pr__rf_nfet_01v8_bM04W1p65L0p25 +s8rf_nshort_w3p0_l0p15_m4_hc,sky130_fd_pr__rf_nfet_01v8_hcM04W3p00L0p15 +s8rf_nshort_w3p0_l0p15_m4_mc,sky130_fd_pr__rf_nfet_01v8_mcM04W3p00L0p15 +s8rf_nshort_w5p0_l0p15_m4_hc,sky130_fd_pr__rf_nfet_01v8_hcM04W5p00L0p15 +s8rf_nshort_w5p0_l0p15_m4_mc,sky130_fd_pr__rf_nfet_01v8_mcM04W5p00L0p15 +s8rf_pshort_w1p65_l0p15_m2_b,sky130_fd_pr__rf_pfet_01v8_bM02W1p65L0p15 +s8rf_pshort_w1p65_l0p15_m4_b,sky130_fd_pr__rf_pfet_01v8_bM04W1p65L0p15 +s8rf_pshort_w1p65_l0p18_m2_b,sky130_fd_pr__rf_pfet_01v8_bM02W1p65L0p18 +s8rf_pshort_w1p65_l0p18_m4_b,sky130_fd_pr__rf_pfet_01v8_bM04W1p65L0p18 +s8rf_pshort_w1p65_l0p25_m2_b,sky130_fd_pr__rf_pfet_01v8_bM02W1p65L0p25 +s8rf_pshort_w1p65_l0p25_m4_b,sky130_fd_pr__rf_pfet_01v8_bM04W1p65L0p25 +s8rf_pshort_w3p0_l0p15_m4_hc,sky130_fd_pr__rf_pfet_01v8_hcM04W3p00L0p15 +s8rf_pshort_w3p0_l0p15_m4_mc,sky130_fd_pr__rf_pfet_01v8_mcM04W3p00L0p15 +s8rf_pshort_w5p0_l0p15_m4_hc,sky130_fd_pr__rf_pfet_01v8_hcM04W5p00L0p15 +s8rf_pshort_w5p0_l0p15_m4_mc,sky130_fd_pr__rf_pfet_01v8_mcM04W5p00L0p15 +xcmvpp11p5x11p7_lishield_top,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2_shieldl1_top +xcmvpp11p5x11p7_m1m2_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2_noshield_raphael +xcmvpp11p5x11p7_m1m4_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m4_noshield_raphael +xcmvpp11p5x11p7_m1m4m5shield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldm5 +xcmvpp11p5x11p7_m3shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2_shieldpom3_top +xcmvpp11p5x11p7_m4shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldm4_top +xcmvpp11p5x11p7_m5shield_top,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldm5_top +xcmvpp11p5x11p7_polym4shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldpom4 +xcmvpp11p5x11p7_polym5shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldpom5 +xcmvpp6p8x6p1_lim4shield_top,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4_top +xcmvppx4_2xnhvnative10x4_top,sky130_fd_pr__cap_vpp_11p3x11p8_l1m1m2m3m4_shieldm5_nhvtop +dnwdiode_psub_n20nativevhv1,sky130_fd_pr__nfet_20v0_nvt__parasitic__diode_ps2dn +n20nativevhviso1_subcircuit,sky130_fd_pr__nfet_20v0_nvt_iso__subcircuit +n20nativevhviso_fs_discrete,sky130_fd_pr__nfet_20v0_nvt_iso__fs_discrete +n20nativevhviso_sf_discrete,sky130_fd_pr__nfet_20v0_nvt_iso__sf_discrete +n20nativevhviso_tt_discrete,sky130_fd_pr__nfet_20v0_nvt_iso__tt_discrete +n20vhvisoreverse_subcircuit,sky130_fd_pr__nfet_20v0_reverse_iso__subcircuit +nlowvt_rf_base_m2_b_w5_lp18,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W5p00L0p18 +nlowvt_rf_base_m2_b_w5_lp25,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W5p00L0p25 +nlowvt_rf_base_m4_b_w5_lp18,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W5p00L0p18 +nlowvt_rf_base_m4_b_w5_lp25,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W5p00L0p25 +rf2_xcmvpp11p5x11p7_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2_noshield_raphael +rf2_xcmvpp6p8x6p_lim4shield,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4 +rf2_xcmvpp_hd5_5x2_testcase,sky130_fd_pr__cap_vpp_55p8x23p1_pol1m1m2m3m4m5_noshield_test +rf2_xcmvpp_hd5_6p8x6p1_m1m4,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield +rf_xcmvpp11p5x11p7_lishield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2_shieldl1 +rf_xcmvpp11p5x11p7_m3shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2_shieldpom3 +rf_xcmvpp11p5x11p7_m4shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldm4 +rf_xcmvpp11p5x11p7_m5shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldm5 +rf_xcmvpp6p8x6p1_lim4shield,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4 +rf_xcmvppx4_2xnhvnative10x4,sky130_fd_pr__cap_vpp_11p3x11p8_l1m1m2m3m4_shieldm5_nhv +s8rf_n20nativevhv1_withptap,sky130_fd_pr__rf_nfet_20v0_nvt_withptap +s8rf_nlowvt_w3p0_l0p15_m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W3p00L0p15 +s8rf_nlowvt_w3p0_l0p15_m2_c,sky130_fd_pr__rf_nfet_01v8_lvt_cM02W3p00L0p15 +s8rf_nlowvt_w3p0_l0p15_m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W3p00L0p15 +s8rf_nlowvt_w3p0_l0p15_m4_c,sky130_fd_pr__rf_nfet_01v8_lvt_cM04W3p00L0p15 +s8rf_nlowvt_w3p0_l0p18_m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W3p00L0p18 +s8rf_nlowvt_w3p0_l0p18_m2_c,sky130_fd_pr__rf_nfet_01v8_lvt_cM02W3p00L0p18 +s8rf_nlowvt_w3p0_l0p18_m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W3p00L0p18 +s8rf_nlowvt_w3p0_l0p18_m4_c,sky130_fd_pr__rf_nfet_01v8_lvt_cM04W3p00L0p18 +s8rf_nlowvt_w3p0_l0p25_m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W3p00L0p25 +s8rf_nlowvt_w3p0_l0p25_m2_c,sky130_fd_pr__rf_nfet_01v8_lvt_cM02W3p00L0p25 +s8rf_nlowvt_w3p0_l0p25_m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W3p00L0p25 +s8rf_nlowvt_w3p0_l0p25_m4_c,sky130_fd_pr__rf_nfet_01v8_lvt_cM04W3p00L0p25 +s8rf_nlowvt_w5p0_l0p15_m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W5p00L0p15 +s8rf_nlowvt_w5p0_l0p15_m2_c,sky130_fd_pr__rf_nfet_01v8_lvt_cM02W5p00L0p15 +s8rf_nlowvt_w5p0_l0p15_m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W5p00L0p15 +s8rf_nlowvt_w5p0_l0p15_m4_c,sky130_fd_pr__rf_nfet_01v8_lvt_cM04W5p00L0p15 +s8rf_nlowvt_w5p0_l0p18_m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W5p00L0p18 +s8rf_nlowvt_w5p0_l0p18_m2_c,sky130_fd_pr__rf_nfet_01v8_lvt_cM02W5p00L0p18 +s8rf_nlowvt_w5p0_l0p18_m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W5p00L0p18 +s8rf_nlowvt_w5p0_l0p18_m4_c,sky130_fd_pr__rf_nfet_01v8_lvt_cM04W5p00L0p18 +s8rf_nlowvt_w5p0_l0p25_m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W5p00L0p25 +s8rf_nlowvt_w5p0_l0p25_m2_c,sky130_fd_pr__rf_nfet_01v8_lvt_cM02W5p00L0p25 +s8rf_nlowvt_w5p0_l0p25_m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W5p00L0p25 +s8rf_nlowvt_w5p0_l0p25_m4_c,sky130_fd_pr__rf_nfet_01v8_lvt_cM04W5p00L0p25 +s8rf_nshort_w3p0_l0p15_m2_b,sky130_fd_pr__rf_nfet_01v8_bM02W3p00L0p15 +s8rf_nshort_w3p0_l0p15_m4_b,sky130_fd_pr__rf_nfet_01v8_bM04W3p00L0p15 +s8rf_nshort_w3p0_l0p18_m2_b,sky130_fd_pr__rf_nfet_01v8_bM02W3p00L0p18 +s8rf_nshort_w3p0_l0p18_m4_b,sky130_fd_pr__rf_nfet_01v8_bM04W3p00L0p18 +s8rf_nshort_w3p0_l0p25_m2_b,sky130_fd_pr__rf_nfet_01v8_bM02W3p00L0p25 +s8rf_nshort_w3p0_l0p25_m4_b,sky130_fd_pr__rf_nfet_01v8_bM04W3p00L0p25 +s8rf_nshort_w5p0_l0p15_m2_b,sky130_fd_pr__rf_nfet_01v8_bM02W5p00L0p15 +s8rf_nshort_w5p0_l0p15_m4_b,sky130_fd_pr__rf_nfet_01v8_bM04W5p00L0p15 +s8rf_nshort_w5p0_l0p18_m2_b,sky130_fd_pr__rf_nfet_01v8_bM02W5p00L0p18 +s8rf_nshort_w5p0_l0p18_m4_b,sky130_fd_pr__rf_nfet_01v8_bM04W5p00L0p18 +s8rf_nshort_w5p0_l0p25_m2_b,sky130_fd_pr__rf_nfet_01v8_bM02W5p00L0p25 +s8rf_nshort_w5p0_l0p25_m4_b,sky130_fd_pr__rf_nfet_01v8_bM04W5p00L0p25 +s8rf_plowvt_w3p0_l0p35_m2_b,sky130_fd_pr__rf_pfet_01v8_lvt_bM02W3p00L0p35 +s8rf_plowvt_w3p0_l0p35_m4_b,sky130_fd_pr__rf_pfet_01v8_lvt_bM04W3p00L0p35 +s8rf_plowvt_w3p0_l0p50_m2_b,sky130_fd_pr__rf_pfet_01v8_lvt_bM02W3p00L0p50 +s8rf_plowvt_w3p0_l0p50_m4_b,sky130_fd_pr__rf_pfet_01v8_lvt_bM04W3p00L0p50 +s8rf_plowvt_w5p0_l0p35_m2_b,sky130_fd_pr__rf_pfet_01v8_lvt_bM02W5p00L0p35 +s8rf_plowvt_w5p0_l0p35_m4_b,sky130_fd_pr__rf_pfet_01v8_lvt_bM04W5p00L0p35 +s8rf_plowvt_w5p0_l0p50_m2_b,sky130_fd_pr__rf_pfet_01v8_lvt_bM02W5p00L0p50 +s8rf_plowvt_w5p0_l0p50_m4_b,sky130_fd_pr__rf_pfet_01v8_lvt_bM04W5p00L0p50 +s8rf_pmedlvt_w0p84_l0p15_2f,sky130_fd_pr__rf_pfet_01v8_mvt_aF02W0p84L0p15 +s8rf_pmedlvt_w1p68_l0p15_2f,sky130_fd_pr__rf_pfet_01v8_mvt_aF02W1p68L0p15 +s8rf_pmedlvt_w1p68_l0p15_4f,sky130_fd_pr__rf_pfet_01v8_mvt_aF04W1p68L0p15 +s8rf_pshort_w3p0_l0p15_m2_b,sky130_fd_pr__rf_pfet_01v8_bM02W3p00L0p15 +s8rf_pshort_w3p0_l0p15_m4_b,sky130_fd_pr__rf_pfet_01v8_bM04W3p00L0p15 +s8rf_pshort_w3p0_l0p18_m2_b,sky130_fd_pr__rf_pfet_01v8_bM02W3p00L0p18 +s8rf_pshort_w3p0_l0p18_m4_b,sky130_fd_pr__rf_pfet_01v8_bM04W3p00L0p18 +s8rf_pshort_w3p0_l0p25_m2_b,sky130_fd_pr__rf_pfet_01v8_bM02W3p00L0p25 +s8rf_pshort_w3p0_l0p25_m4_b,sky130_fd_pr__rf_pfet_01v8_bM04W3p00L0p25 +s8rf_pshort_w5p0_l0p15_m2_b,sky130_fd_pr__rf_pfet_01v8_bM02W5p00L0p15 +s8rf_pshort_w5p0_l0p15_m4_b,sky130_fd_pr__rf_pfet_01v8_bM04W5p00L0p15 +s8rf_pshort_w5p0_l0p18_m2_b,sky130_fd_pr__rf_pfet_01v8_bM02W5p00L0p18 +s8rf_pshort_w5p0_l0p18_m4_b,sky130_fd_pr__rf_pfet_01v8_bM04W5p00L0p18 +s8rf_pshort_w5p0_l0p25_m2_b,sky130_fd_pr__rf_pfet_01v8_bM02W5p00L0p25 +s8rf_pshort_w5p0_l0p25_m4_b,sky130_fd_pr__rf_pfet_01v8_bM04W5p00L0p25 +s8rf_xcmvpp1p8x1p8_lishield,sky130_fd_pr__cap_vpp_01p8x01p8_m1m2_shieldl1 +s8rf_xcmvpp1p8x1p8_m3shield,sky130_fd_pr__cap_vpp_03p9x03p9_m1m2_shieldl1_floatm3 +s8rf_xcmvpp4p4x4p6_lishield,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_shieldl1 +s8rf_xcmvpp4p4x4p6_m3shield,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_shieldpo_floatm3 +s8rf_xcmvpp8p6x7p9_lishield,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2_shieldl1 +s8rf_xcmvpp8p6x7p9_m3shield,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_shieldpo_floatm3 +xcmvpp11p5x11p7_m3_lishield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_shieldl1 +xcmvpp4p4x4p6_m3_lim5shield,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1m5_floatm4 +xcmvpp6p8x6p_lim4shield_top,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4_top +xcmvpp8p6x7p9_m3_lim5shield,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_shieldl1m5_floatm4 +xcmvpp_hd5_atlas_fingercap2,sky130_fd_pr__cap_vpp_02p9x06p1_m1m2m3m4_shieldl1_basefingercap2 +xcmvpp_hd5_atlas_wafflecap1,sky130_fd_pr__cap_vpp_11p3x11p3_m1m2m3m4_shieldl1_wafflecap +xcmvpp_hd5_atlas_wafflecap2,sky130_fd_pr__cap_vpp_05p9x05p9_m1m2m3m4_shieldl1_wafflecap +dnwdiode_psub_n20nativevhv,sky130_fd_pr__nfet_20v0_nvt__parasitic__diode_ps2dn +n20nativevhviso_subcircuit,sky130_fd_pr__nfet_20v0_nvt_iso__subcircuit +n20vhvisoreverse1_withptap,sky130_fd_pr__nfet_20v0_withptap_reverse_iso +nlowvt_rf_base_b_ttcorreln,sky130_fd_pr__rf_nfet_01v8_lvt_b__tt_correln +nlowvt_rf_base_b_ttcorrelp,sky130_fd_pr__rf_nfet_01v8_lvt_b__tt_correlp +nshort_rf_base_b_ttcorreln,sky130_fd_pr__rf_nfet_01v8_b__tt_correln +nshort_rf_base_b_ttcorrelp,sky130_fd_pr__rf_nfet_01v8_b__tt_correlp +pmedlvt_rf_ttleak_discrete,sky130_fd_pr__rf_pfet_01v8_mvt__tt_leak_discrete +pshort_rf_base_b_ttcorreln,sky130_fd_pr__rf_pfet_01v8_b__tt_correln +pshort_rf_base_b_ttcorrelp,sky130_fd_pr__rf_pfet_01v8_b__tt_correlp +rf2_xcmvpp11p5x11p7_m3_top,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_noshield_top +rf2_xcmvpp1p8x1p8_lishield,sky130_fd_pr__cap_vpp_01p8x01p8_m1m2_shieldl1 +rf2_xcmvpp1p8x1p8_m3shield,sky130_fd_pr__cap_vpp_03p9x03p9_m1m2_shieldl1_floatm3 +rf2_xcmvpp4p4x4p6_lishield,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_shieldl1 +rf2_xcmvpp4p4x4p6_m3shield,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_shieldpo_floatm3 +rf2_xcmvpp6p8x6p1_m1m4_fom,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield_fom +rf2_xcmvpp8p6x7p9_lishield,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2_shieldl1 +rf2_xcmvpp8p6x7p9_m3shield,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_shieldpo_floatm3 +rf_xcmvpp11p5x11p7_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2_noshield_raphael +rf_xcmvpp6p8x6p_lim4shield,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4 +rf_xcmvpp_hd5_5x2_testcase,sky130_fd_pr__cap_vpp_55p8x23p1_pol1m1m2m3m4m5_noshield_test +rf_xcmvpp_hd5_6p8x6p1_m1m4,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield +s8rf2_xcmvpp11p5x11p7_m1m2,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2_noshield +s8rf2_xcmvpp11p5x11p7_m1m4,sky130_fd_pr__cap_vpp_11p5x11p7_m1m4_noshield +s8rf_nlowvt_w0p42_l0p15_2f,sky130_fd_pr__rf_nfet_01v8_lvt_aF02W0p42L0p15 +s8rf_nlowvt_w0p42_l0p15_4f,sky130_fd_pr__rf_nfet_01v8_lvt_aF04W0p42L0p15 +s8rf_nlowvt_w0p42_l0p15_6f,sky130_fd_pr__rf_nfet_01v8_lvt_aF06W0p42L0p15 +s8rf_nlowvt_w0p42_l0p15_8f,sky130_fd_pr__rf_nfet_01v8_lvt_aF08W0p42L0p15 +s8rf_nlowvt_w0p84_l0p15_2f,sky130_fd_pr__rf_nfet_01v8_lvt_aF02W0p84L0p15 +s8rf_nlowvt_w0p84_l0p15_4f,sky130_fd_pr__rf_nfet_01v8_lvt_aF04W0p84L0p15 +s8rf_nlowvt_w0p84_l0p15_6f,sky130_fd_pr__rf_nfet_01v8_lvt_aF06W0p84L0p15 +s8rf_nlowvt_w0p84_l0p15_8f,sky130_fd_pr__rf_nfet_01v8_lvt_aF08W0p84L0p15 +s8rf_nlowvt_w1p65_l0p15_2f,sky130_fd_pr__rf_nfet_01v8_lvt_aF02W1p65L0p15 +s8rf_nlowvt_w1p65_l0p15_4f,sky130_fd_pr__rf_nfet_01v8_lvt_aF04W1p65L0p15 +s8rf_nlowvt_w1p65_l0p15_6f,sky130_fd_pr__rf_nfet_01v8_lvt_aF06W1p65L0p15 +s8rf_nlowvt_w1p65_l0p15_8f,sky130_fd_pr__rf_nfet_01v8_lvt_aF08W1p65L0p15 +s8rf_nlowvt_w1p65_l0p15_m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02W1p65L0p15 +s8rf_nlowvt_w1p65_l0p15_m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04W1p65L0p15 +s8rf_nlowvt_w1p65_l0p18_m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02W1p65L0p18 +s8rf_nlowvt_w1p65_l0p18_m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04W1p65L0p18 +s8rf_nlowvt_w1p65_l0p25_m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02W1p65L0p25 +s8rf_nlowvt_w1p65_l0p25_m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04W1p65L0p25 +s8rf_nshort_w1p65_l0p15_m2,sky130_fd_pr__rf_nfet_01v8_aM02W1p65L0p15 +s8rf_nshort_w1p65_l0p15_m4,sky130_fd_pr__rf_nfet_01v8_aM04W1p65L0p15 +s8rf_nshort_w1p65_l0p18_m2,sky130_fd_pr__rf_nfet_01v8_aM02W1p65L0p18 +s8rf_nshort_w1p65_l0p18_m4,sky130_fd_pr__rf_nfet_01v8_aM04W1p65L0p18 +s8rf_nshort_w1p65_l0p25_m2,sky130_fd_pr__rf_nfet_01v8_aM02W1p65L0p25 +s8rf_nshort_w1p65_l0p25_m4,sky130_fd_pr__rf_nfet_01v8_aM04W1p65L0p25 +s8rf_pshort_w0p84_l0p15_2f,sky130_fd_pr__rf_pfet_01v8_aF02W0p84L0p15 +s8rf_pshort_w0p84_l0p15_4f,sky130_fd_pr__rf_pfet_01v8_aF04W0p84L0p15 +s8rf_pshort_w0p84_l0p15_6f,sky130_fd_pr__rf_pfet_01v8_aF06W0p84L0p15 +s8rf_pshort_w0p84_l0p15_8f,sky130_fd_pr__rf_pfet_01v8_aF08W0p84L0p15 +s8rf_pshort_w1p65_l0p15_m2,sky130_fd_pr__rf_pfet_01v8_aM02W1p65L0p15 +s8rf_pshort_w1p65_l0p15_m4,sky130_fd_pr__rf_pfet_01v8_aM04W1p65L0p15 +s8rf_pshort_w1p65_l0p18_m2,sky130_fd_pr__rf_pfet_01v8_aM02W1p65L0p18 +s8rf_pshort_w1p65_l0p18_m4,sky130_fd_pr__rf_pfet_01v8_aM04W1p65L0p18 +s8rf_pshort_w1p65_l0p25_m2,sky130_fd_pr__rf_pfet_01v8_aM02W1p65L0p25 +s8rf_pshort_w1p65_l0p25_m4,sky130_fd_pr__rf_pfet_01v8_aM04W1p65L0p25 +s8rf_pshort_w1p68_l0p15_2f,sky130_fd_pr__rf_pfet_01v8_aF02W1p68L0p15 +s8rf_pshort_w1p68_l0p15_4f,sky130_fd_pr__rf_pfet_01v8_aF04W1p68L0p15 +s8rf_pshort_w1p68_l0p15_6f,sky130_fd_pr__rf_pfet_01v8_aF06W1p68L0p15 +s8rf_pshort_w1p68_l0p15_8f,sky130_fd_pr__rf_pfet_01v8_aF08W1p68L0p15 +xcmvpp11p5x11p7_lim5shield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3m4_shieldl1m5 +xcmvpp11p5x11p7_m3_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_noshield_raphael +xcmvpp4p4x4p6_m1m2_raphael,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield_raphael +xcmvpp4p4x4p6_m1m4_raphael,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3m4_noshield_raphael +xcmvpp4p4x4p6_polym5shield,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2m3m4_shieldpom5 +xcmvpp6p8x6p1_m1m4_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield_raphael +xcmvpp6p8x6p1_polym4shield,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4 +xcmvpp6p8x6p1_polym5shield,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3m4_shieldpo_floatm5 +xcmvpp8p6x7p9_polym5shield,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3m4_shieldpom5 +xcmvpp_hd5_atlas_fingercap,sky130_fd_pr__cap_vpp_02p7x11p1_m1m2m3m4_shieldl1_basefingercap +xcmvpp_hd5_atlas_wafflecap,sky130_fd_pr__cap_vpp_m1m2m3m4_shieldl1_wafflecap +n20nativevhv1_fs_discrete,sky130_fd_pr__nfet_20v0_nvt__fs_discrete +n20nativevhv1_sf_discrete,sky130_fd_pr__nfet_20v0_nvt__sf_discrete +n20nativevhv1_tt_discrete,sky130_fd_pr__nfet_20v0_nvt__tt_discrete +n20nativevhviso1_withptap,sky130_fd_pr__nfet_20v0_nvt_withptap_iso +n20vhvisoreverse_withptap,sky130_fd_pr__nfet_20v0_withptap_reverse_iso +pmedlvt_rf_wafer_discrete,sky130_fd_pr__rf_pfet_01v8_mvt__wafer_discrete +rf2_xcmvpp2_nhvnative10x4,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield_o1nhv +rf_xcmvpp11p5x11p7_m3_top,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_noshield_top +rf_xcmvpp1p8x1p8_lishield,sky130_fd_pr__cap_vpp_01p8x01p8_m1m2_shieldl1 +rf_xcmvpp1p8x1p8_m3shield,sky130_fd_pr__cap_vpp_03p9x03p9_m1m2_shieldl1_floatm3 +rf_xcmvpp4p4x4p6_lishield,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_shieldl1 +rf_xcmvpp4p4x4p6_m3shield,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_shieldpo_floatm3 +rf_xcmvpp6p8x6p1_m1m4_fom,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield_fom +rf_xcmvpp8p6x7p9_lishield,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2_shieldl1 +rf_xcmvpp8p6x7p9_m3shield,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_shieldpo_floatm3 +s8rf_nlowvt_w3p0_l0p15_2f,sky130_fd_pr__rf_nfet_01v8_lvt_aF02W3p00L0p15 +s8rf_nlowvt_w3p0_l0p15_4f,sky130_fd_pr__rf_nfet_01v8_lvt_aF04W3p00L0p15 +s8rf_nlowvt_w3p0_l0p15_6f,sky130_fd_pr__rf_nfet_01v8_lvt_aF06W3p00L0p15 +s8rf_nlowvt_w3p0_l0p15_8f,sky130_fd_pr__rf_nfet_01v8_lvt_aF08W3p00L0p15 +s8rf_nlowvt_w3p0_l0p15_m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02W3p00L0p15 +s8rf_nlowvt_w3p0_l0p15_m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04W3p00L0p15 +s8rf_nlowvt_w3p0_l0p18_m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02W3p00L0p18 +s8rf_nlowvt_w3p0_l0p18_m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04W3p00L0p18 +s8rf_nlowvt_w3p0_l0p25_m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02W3p00L0p25 +s8rf_nlowvt_w3p0_l0p25_m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04W3p00L0p25 +s8rf_nlowvt_w5p0_l0p15_m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02W5p00L0p15 +s8rf_nlowvt_w5p0_l0p15_m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04W5p00L0p15 +s8rf_nlowvt_w5p0_l0p18_m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02W5p00L0p18 +s8rf_nlowvt_w5p0_l0p18_m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04W5p00L0p18 +s8rf_nlowvt_w5p0_l0p25_m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02W5p00L0p25 +s8rf_nlowvt_w5p0_l0p25_m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04W5p00L0p25 +s8rf_nshort_w3p0_l0p15_m2,sky130_fd_pr__rf_nfet_01v8_aM02W3p00L0p15 +s8rf_nshort_w3p0_l0p15_m4,sky130_fd_pr__rf_nfet_01v8_aM04W3p00L0p15 +s8rf_nshort_w3p0_l0p18_m2,sky130_fd_pr__rf_nfet_01v8_aM02W3p00L0p18 +s8rf_nshort_w3p0_l0p18_m4,sky130_fd_pr__rf_nfet_01v8_aM04W3p00L0p18 +s8rf_nshort_w3p0_l0p25_m2,sky130_fd_pr__rf_nfet_01v8_aM02W3p00L0p25 +s8rf_nshort_w3p0_l0p25_m4,sky130_fd_pr__rf_nfet_01v8_aM04W3p00L0p25 +s8rf_nshort_w5p0_l0p15_m2,sky130_fd_pr__rf_nfet_01v8_aM02W5p00L0p15 +s8rf_nshort_w5p0_l0p15_m4,sky130_fd_pr__rf_nfet_01v8_aM04W5p00L0p15 +s8rf_nshort_w5p0_l0p18_m2,sky130_fd_pr__rf_nfet_01v8_aM02W5p00L0p18 +s8rf_nshort_w5p0_l0p18_m4,sky130_fd_pr__rf_nfet_01v8_aM04W5p00L0p18 +s8rf_nshort_w5p0_l0p25_m2,sky130_fd_pr__rf_nfet_01v8_aM02W5p00L0p25 +s8rf_nshort_w5p0_l0p25_m4,sky130_fd_pr__rf_nfet_01v8_aM04W5p00L0p25 +s8rf_plowvt_w3p0_l0p25_m2,sky130_fd_pr__rf_pfet_01v8_lvt_aM02W3p00L0p25 +s8rf_plowvt_w3p0_l0p25_m4,sky130_fd_pr__rf_pfet_01v8_lvt_aM04W3p00L0p25 +s8rf_plowvt_w3p0_l0p35_m2,sky130_fd_pr__rf_pfet_01v8_lvt_aM02W3p00L0p35 +s8rf_plowvt_w3p0_l0p35_m4,sky130_fd_pr__rf_pfet_01v8_lvt_aM04W3p00L0p35 +s8rf_plowvt_w3p0_l0p50_m2,sky130_fd_pr__rf_pfet_01v8_lvt_aM02W3p00L0p50 +s8rf_plowvt_w3p0_l0p50_m4,sky130_fd_pr__rf_pfet_01v8_lvt_aM04W3p00L0p50 +s8rf_plowvt_w5p0_l0p25_m2,sky130_fd_pr__rf_pfet_01v8_lvt_aM02W5p00L0p25 +s8rf_plowvt_w5p0_l0p25_m4,sky130_fd_pr__rf_pfet_01v8_lvt_aM04W5p00L0p25 +s8rf_plowvt_w5p0_l0p35_m2,sky130_fd_pr__rf_pfet_01v8_lvt_aM02W5p00L0p35 +s8rf_plowvt_w5p0_l0p35_m4,sky130_fd_pr__rf_pfet_01v8_lvt_aM04W5p00L0p35 +s8rf_plowvt_w5p0_l0p50_m2,sky130_fd_pr__rf_pfet_01v8_lvt_aM02W5p00L0p50 +s8rf_plowvt_w5p0_l0p50_m4,sky130_fd_pr__rf_pfet_01v8_lvt_aM04W5p00L0p50 +s8rf_pshort_w2p0_l0p15_2f,sky130_fd_pr__rf_pfet_01v8_aF02W2p00L0p15 +s8rf_pshort_w2p0_l0p15_4f,sky130_fd_pr__rf_pfet_01v8_aF04W2p00L0p15 +s8rf_pshort_w2p0_l0p15_6f,sky130_fd_pr__rf_pfet_01v8_aF06W2p00L0p15 +s8rf_pshort_w3p0_l0p15_2f,sky130_fd_pr__rf_pfet_01v8_aF02W3p00L0p15 +s8rf_pshort_w3p0_l0p15_4f,sky130_fd_pr__rf_pfet_01v8_aF04W3p00L0p15 +s8rf_pshort_w3p0_l0p15_6f,sky130_fd_pr__rf_pfet_01v8_aF06W3p00L0p15 +s8rf_pshort_w3p0_l0p15_m2,sky130_fd_pr__rf_pfet_01v8_aM02W3p00L0p15 +s8rf_pshort_w3p0_l0p15_m4,sky130_fd_pr__rf_pfet_01v8_aM04W3p00L0p15 +s8rf_pshort_w3p0_l0p18_m2,sky130_fd_pr__rf_pfet_01v8_aM02W3p00L0p18 +s8rf_pshort_w3p0_l0p18_m4,sky130_fd_pr__rf_pfet_01v8_aM04W3p00L0p18 +s8rf_pshort_w3p0_l0p25_m2,sky130_fd_pr__rf_pfet_01v8_aM02W3p00L0p25 +s8rf_pshort_w3p0_l0p25_m4,sky130_fd_pr__rf_pfet_01v8_aM04W3p00L0p25 +s8rf_pshort_w5p0_l0p15_2f,sky130_fd_pr__rf_pfet_01v8_aF02W5p00L0p15 +s8rf_pshort_w5p0_l0p15_4f,sky130_fd_pr__rf_pfet_01v8_aF04W5p00L0p15 +s8rf_pshort_w5p0_l0p15_m2,sky130_fd_pr__rf_pfet_01v8_aM02W5p00L0p15 +s8rf_pshort_w5p0_l0p15_m4,sky130_fd_pr__rf_pfet_01v8_aM04W5p00L0p15 +s8rf_pshort_w5p0_l0p18_m2,sky130_fd_pr__rf_pfet_01v8_aM02W5p00L0p18 +s8rf_pshort_w5p0_l0p18_m4,sky130_fd_pr__rf_pfet_01v8_aM04W5p00L0p18 +s8rf_pshort_w5p0_l0p25_m2,sky130_fd_pr__rf_pfet_01v8_aM02W5p00L0p25 +s8rf_pshort_w5p0_l0p25_m4,sky130_fd_pr__rf_pfet_01v8_aM04W5p00L0p25 +xcmvpp4p4x4p6_m3_lishield,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_shieldl1 +xcmvpp6p8x6p_m1m4_raphael,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield_raphael +xcmvpp6p8x6p_polym4shield,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3_shieldpom4 +xcmvpp6p8x6p_polym5shield,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2m3m4_shieldpo_floatm5 +xcmvpp8p6x7p9_m3_lishield,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_shieldl1 +xcmvpp_hd5_5x1_met5pullin,sky130_fd_pr__cap_vpp_55p8x11p7_pol1m1m2m3m4m5_noshield_m5pullin +xcmvpp_hd5_5x2_met5pullin,sky130_fd_pr__cap_vpp_55p8x23p1_pol1m1m2m3m4m5_noshield_m5pullin +n20nativevhv1_subcircuit,sky130_fd_pr__nfet_20v0_nvt__subcircuit +n20nativevhv_fs_discrete,sky130_fd_pr__nfet_20v0_nvt__fs_discrete +n20nativevhv_sf_discrete,sky130_fd_pr__nfet_20v0_nvt__sf_discrete +n20nativevhv_tt_discrete,sky130_fd_pr__nfet_20v0_nvt__tt_discrete +n20nativevhviso_withptap,sky130_fd_pr__nfet_20v0_nvt_withptap_iso +n20vhvisoreverse1_noptap,sky130_fd_pr__nfet_20v0_reverse_noptap_iso +n20zvtvhv1_leak_discrete,sky130_fd_pr__nfet_20v0_zvt__leak_discrete +nlowvt_rf_base_b_tt_leak,sky130_fd_pr__rf_nfet_01v8_lvt_b__tt_leak +nshort_rf_base_b_tt_leak,sky130_fd_pr__rf_nfet_01v8_b__tt_leak +pmedlvt_rf_leak_discrete,sky130_fd_pr__rf_pfet_01v8_mvt__leak_discrete +pshort_rf_base_b_tt_leak,sky130_fd_pr__rf_pfet_01v8_b__tt_leak +rf2_xcmvpp11p5x11p7_m1m2,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2_noshield +rf2_xcmvpp11p5x11p7_m1m4,sky130_fd_pr__cap_vpp_11p5x11p7_m1m4_noshield +rf2_xcmvpp11p5x11p7_m3m4,sky130_fd_pr__cap_vpp_11p5x11p7_m3m4_noshield +rf_xcmvpp2_nhvnative10x4,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield_o1nhv +s8rf2_xcmvpp11p5x11p7_m3,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_noshield +s8rf2_xcmvpp4p4x4p6_m1m2,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield +s8rf2_xcmvpp_hd5_6p8x6p1,sky130_fd_pr__cap_vpp_06p8x06p1_pol1m1m2m3m4m5_noshield +s8rf_n20vhv1_esd_hbm_21v,sky130_fd_pr__esd_rf_nfet_20v0_hbm_21v +s8rf_n20vhv1_esd_hbm_32v,sky130_fd_pr__esd_rf_nfet_20v0_hbm_32v +s8rf_n20vhv1_esd_iec_21v,sky130_fd_pr__esd_rf_nfet_20v0_iec_21v +s8rf_n20vhv1_esd_iec_32v,sky130_fd_pr__esd_rf_nfet_20v0_iec_32v +s8rf_n20vhviso1_withptap,sky130_fd_pr__rf_nfet_20v0_withptap_iso +s8rf_n20zvtvhv1_withptap,sky130_fd_pr__rf_nfet_20v0_zvt_withptap +s8rf_nhv_w3p0_l0p5_m10_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM10W3p00L0p50 +s8rf_nhv_w5p0_l0p5_m10_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM10W5p00L0p50 +s8rf_nhv_w7p0_l0p5_m10_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM10W7p00L0p50 +s8rf_pmedlvt_w0p84_l0p15,sky130_fd_pr__rf_pfet_01v8_mvt_aW0p84L0p15 +s8rf_pmedlvt_w1p68_l0p15,sky130_fd_pr__rf_pfet_01v8_mvt_aW1p68L0p15 +xcmvpp11p5x11p7_lishield,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2_shieldl1 +xcmvpp11p5x11p7_m3shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2_shieldpom3 +xcmvpp11p5x11p7_m4shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3_shieldm4 +xcmvpp11p5x11p7_m5shield,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2m3m4_shieldm5 +xcmvpp6p8x6p1_lim4shield,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4 +xcmvppx4_2xnhvnative10x4,sky130_fd_pr__cap_vpp_11p3x11p8_l1m1m2m3m4_shieldm5_nhv +n20nativevhv_subcircuit,sky130_fd_pr__nfet_20v0_nvt__subcircuit +n20nativevhviso1_noptap,sky130_fd_pr__nfet_20v0_nvt_noptap_iso +n20vhv1_esd_hbm_21v_w60,sky130_fd_pr__esd_nfet_20v0_hbm_21vW60p00 +n20vhv1_esd_hbm_32v_w60,sky130_fd_pr__esd_nfet_20v0_hbm_32vW60p00 +n20vhv1_esd_iec_21v_w60,sky130_fd_pr__esd_nfet_20v0_iec_21vW60p00 +n20vhv1_esd_iec_32v_w60,sky130_fd_pr__esd_nfet_20v0_iec_32vW60p00 +n20vhvisoreverse_noptap,sky130_fd_pr__nfet_20v0_reverse_noptap_iso +n20zvtvhv_leak_discrete,sky130_fd_pr__nfet_20v0_zvt__leak_discrete +nhv_rf_base_b_ttcorreln,sky130_fd_pr__rf_nfet_g5v0d10v5_b__tt_correln +nhv_rf_base_b_ttcorrelp,sky130_fd_pr__rf_nfet_g5v0d10v5_b__tt_correlp +nlowvt_w1p65_l0p15_m2_b,sky130_fd_pr__nfet_01v8_lvt_bM02W1p65L0p15 +nlowvt_w1p65_l0p15_m2_c,sky130_fd_pr__nfet_01v8_lvt_cM02W1p65L0p15 +nlowvt_w1p65_l0p15_m4_b,sky130_fd_pr__nfet_01v8_lvt_bM04W1p65L0p15 +nlowvt_w1p65_l0p15_m4_c,sky130_fd_pr__nfet_01v8_lvt_cM04W1p65L0p15 +nlowvt_w1p65_l0p18_m2_b,sky130_fd_pr__nfet_01v8_lvt_bM02W1p65L0p18 +nlowvt_w1p65_l0p18_m2_c,sky130_fd_pr__nfet_01v8_lvt_cM02W1p65L0p18 +nlowvt_w1p65_l0p18_m4_b,sky130_fd_pr__nfet_01v8_lvt_bM04W1p65L0p18 +nlowvt_w1p65_l0p18_m4_c,sky130_fd_pr__nfet_01v8_lvt_cM04W1p65L0p18 +nlowvt_w1p65_l0p25_m2_b,sky130_fd_pr__nfet_01v8_lvt_bM02W1p65L0p25 +nlowvt_w1p65_l0p25_m2_c,sky130_fd_pr__nfet_01v8_lvt_cM02W1p65L0p25 +nlowvt_w1p65_l0p25_m4_b,sky130_fd_pr__nfet_01v8_lvt_bM04W1p65L0p25 +nlowvt_w1p65_l0p25_m4_c,sky130_fd_pr__nfet_01v8_lvt_cM04W1p65L0p25 +nshort_w1p65_l0p15_m2_b,sky130_fd_pr__nfet_01v8_bM02W1p65L0p15 +nshort_w1p65_l0p15_m4_b,sky130_fd_pr__nfet_01v8_bM04W1p65L0p15 +nshort_w1p65_l0p18_m2_b,sky130_fd_pr__nfet_01v8_bM02W1p65L0p18 +nshort_w1p65_l0p18_m4_b,sky130_fd_pr__nfet_01v8_bM04W1p65L0p18 +nshort_w1p65_l0p25_m2_b,sky130_fd_pr__nfet_01v8_bM02W1p65L0p25 +nshort_w1p65_l0p25_m4_b,sky130_fd_pr__nfet_01v8_bM04W1p65L0p25 +nshort_w3p0_l0p15_m4_hc,sky130_fd_pr__nfet_01v8_hcM04W3p00L0p15 +nshort_w3p0_l0p15_m4_mc,sky130_fd_pr__nfet_01v8_mcM04W3p00L0p15 +nshort_w5p0_l0p15_m4_hc,sky130_fd_pr__nfet_01v8_hcM04W5p00L0p15 +nshort_w5p0_l0p15_m4_mc,sky130_fd_pr__nfet_01v8_mcM04W5p00L0p15 +pshort_w1p65_l0p15_m2_b,sky130_fd_pr__pfet_01v8_bM02W1p65L0p15 +pshort_w1p65_l0p15_m4_b,sky130_fd_pr__pfet_01v8_bM04W1p65L0p15 +pshort_w1p65_l0p18_m2_b,sky130_fd_pr__pfet_01v8_bM02W1p65L0p18 +pshort_w1p65_l0p18_m4_b,sky130_fd_pr__pfet_01v8_bM04W1p65L0p18 +pshort_w1p65_l0p25_m2_b,sky130_fd_pr__pfet_01v8_bM02W1p65L0p25 +pshort_w1p65_l0p25_m4_b,sky130_fd_pr__pfet_01v8_bM04W1p65L0p25 +pshort_w3p0_l0p15_m4_hc,sky130_fd_pr__pfet_01v8_hcM04W3p00L0p15 +pshort_w3p0_l0p15_m4_mc,sky130_fd_pr__pfet_01v8_mcM04W3p00L0p15 +pshort_w5p0_l0p15_m4_hc,sky130_fd_pr__pfet_01v8_hcM04W5p00L0p15 +pshort_w5p0_l0p15_m4_mc,sky130_fd_pr__pfet_01v8_mcM04W5p00L0p15 +rf_xcmvpp11p5x11p7_m1m2,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2_noshield +rf_xcmvpp11p5x11p7_m1m4,sky130_fd_pr__cap_vpp_11p5x11p7_m1m4_noshield +rf_xcmvpp11p5x11p7_m3m4,sky130_fd_pr__cap_vpp_11p5x11p7_m3m4_noshield +s8rf_nhv_w3p0_l0p5_m2_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM02W3p00L0p50 +s8rf_nhv_w3p0_l0p5_m4_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM04W3p00L0p50 +s8rf_nhv_w5p0_l0p5_m2_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM02W5p00L0p50 +s8rf_nhv_w5p0_l0p5_m4_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM04W5p00L0p50 +s8rf_nhv_w7p0_l0p5_m4_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM04W7p00L0p50 +s8rf_nlowvt_w0p42_l0p15,sky130_fd_pr__rf_nfet_01v8_lvt_aW0p42L0p15 +s8rf_nlowvt_w0p84_l0p15,sky130_fd_pr__rf_nfet_01v8_lvt_aW0p84L0p15 +s8rf_nlowvt_w1p65_l0p15,sky130_fd_pr__rf_nfet_01v8_lvt_aW1p65L0p15 +s8rf_nlowvt_w1p65_l0p18,sky130_fd_pr__rf_nfet_01v8_lvt_aW1p65L0p18 +s8rf_nlowvt_w1p65_l0p25,sky130_fd_pr__rf_nfet_01v8_lvt_aW1p65L0p25 +s8rf_nshort_w1p65_l0p15,sky130_fd_pr__rf_nfet_01v8_aW1p65L0p15 +s8rf_nshort_w1p65_l0p18,sky130_fd_pr__rf_nfet_01v8_aW1p65L0p18 +s8rf_nshort_w1p65_l0p25,sky130_fd_pr__rf_nfet_01v8_aW1p65L0p25 +s8rf_pshort_w0p84_l0p15,sky130_fd_pr__rf_pfet_01v8_aW0p84L0p15 +s8rf_pshort_w1p65_l0p15,sky130_fd_pr__rf_pfet_01v8_aW1p65L0p15 +s8rf_pshort_w1p65_l0p18,sky130_fd_pr__rf_pfet_01v8_aW1p65L0p18 +s8rf_pshort_w1p65_l0p25,sky130_fd_pr__rf_pfet_01v8_aW1p65L0p25 +s8rf_pshort_w1p68_l0p15,sky130_fd_pr__rf_pfet_01v8_aW1p68L0p15 +s8rf_xcmvpp11p5x11p7_m3,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_noshield +xcmvpp11p5x11p7_raphael,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2_noshield_raphael +xcmvpp6p8x6p_lim4shield,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3_shieldl1m4 +xcmvpp_hd5_5x2_testcase,sky130_fd_pr__cap_vpp_55p8x23p1_pol1m1m2m3m4m5_noshield_test +xcmvpp_hd5_6p8x6p1_m1m4,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield +n20nativevhv1_withptap,sky130_fd_pr__nfet_20v0_nvt_withptap +n20nativevhviso_noptap,sky130_fd_pr__nfet_20v0_nvt_noptap_iso +n20vhv_esd_hbm_21v_w60,sky130_fd_pr__esd_nfet_20v0_hbm_21vW60p00 +n20vhv_esd_hbm_32v_w60,sky130_fd_pr__esd_nfet_20v0_hbm_32vW60p00 +n20vhv_esd_iec_21v_w60,sky130_fd_pr__esd_nfet_20v0_iec_21vW60p00 +n20vhv_esd_iec_32v_w60,sky130_fd_pr__esd_nfet_20v0_iec_32vW60p00 +n20zvtvhv1_fs_discrete,sky130_fd_pr__nfet_20v0_zvt__fs_discrete +n20zvtvhv1_sf_discrete,sky130_fd_pr__nfet_20v0_zvt__sf_discrete +n20zvtvhv1_tt_discrete,sky130_fd_pr__nfet_20v0_zvt__tt_discrete +nlowvt_rf_base_b_wafer,sky130_fd_pr__rf_nfet_01v8_lvt_b__wafer +nlowvt_rf_base_m2_b_w3,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W3p00 +nlowvt_rf_base_m2_b_w5,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W5p00 +nlowvt_rf_base_m4_b_w3,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W3p00 +nlowvt_rf_base_m4_b_w5,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W5p00 +nlowvt_ttleak_discrete,sky130_fd_pr__nfet_01v8_lvt__tt_leak_discrete +nlowvt_w3p0_l0p15_m2_b,sky130_fd_pr__nfet_01v8_lvt_bM02W3p00L0p15 +nlowvt_w3p0_l0p15_m2_c,sky130_fd_pr__nfet_01v8_lvt_cM02W3p00L0p15 +nlowvt_w3p0_l0p15_m4_b,sky130_fd_pr__nfet_01v8_lvt_bM04W3p00L0p15 +nlowvt_w3p0_l0p15_m4_c,sky130_fd_pr__nfet_01v8_lvt_cM04W3p00L0p15 +nlowvt_w3p0_l0p18_m2_b,sky130_fd_pr__nfet_01v8_lvt_bM02W3p00L0p18 +nlowvt_w3p0_l0p18_m2_c,sky130_fd_pr__nfet_01v8_lvt_cM02W3p00L0p18 +nlowvt_w3p0_l0p18_m4_b,sky130_fd_pr__nfet_01v8_lvt_bM04W3p00L0p18 +nlowvt_w3p0_l0p18_m4_c,sky130_fd_pr__nfet_01v8_lvt_cM04W3p00L0p18 +nlowvt_w3p0_l0p25_m2_b,sky130_fd_pr__nfet_01v8_lvt_bM02W3p00L0p25 +nlowvt_w3p0_l0p25_m2_c,sky130_fd_pr__nfet_01v8_lvt_cM02W3p00L0p25 +nlowvt_w3p0_l0p25_m4_b,sky130_fd_pr__nfet_01v8_lvt_bM04W3p00L0p25 +nlowvt_w3p0_l0p25_m4_c,sky130_fd_pr__nfet_01v8_lvt_cM04W3p00L0p25 +nlowvt_w5p0_l0p15_m2_b,sky130_fd_pr__nfet_01v8_lvt_bM02W5p00L0p15 +nlowvt_w5p0_l0p15_m2_c,sky130_fd_pr__nfet_01v8_lvt_cM02W5p00L0p15 +nlowvt_w5p0_l0p15_m4_b,sky130_fd_pr__nfet_01v8_lvt_bM04W5p00L0p15 +nlowvt_w5p0_l0p15_m4_c,sky130_fd_pr__nfet_01v8_lvt_cM04W5p00L0p15 +nlowvt_w5p0_l0p18_m2_b,sky130_fd_pr__nfet_01v8_lvt_bM02W5p00L0p18 +nlowvt_w5p0_l0p18_m2_c,sky130_fd_pr__nfet_01v8_lvt_cM02W5p00L0p18 +nlowvt_w5p0_l0p18_m4_b,sky130_fd_pr__nfet_01v8_lvt_bM04W5p00L0p18 +nlowvt_w5p0_l0p18_m4_c,sky130_fd_pr__nfet_01v8_lvt_cM04W5p00L0p18 +nlowvt_w5p0_l0p25_m2_b,sky130_fd_pr__nfet_01v8_lvt_bM02W5p00L0p25 +nlowvt_w5p0_l0p25_m2_c,sky130_fd_pr__nfet_01v8_lvt_cM02W5p00L0p25 +nlowvt_w5p0_l0p25_m4_b,sky130_fd_pr__nfet_01v8_lvt_bM04W5p00L0p25 +nlowvt_w5p0_l0p25_m4_c,sky130_fd_pr__nfet_01v8_lvt_cM04W5p00L0p25 +nshort_rf_base_b_wafer,sky130_fd_pr__rf_nfet_01v8_b__wafer +nshort_rf_base_m2_b_w3,sky130_fd_pr__rf_nfet_01v8_bM02W3p00 +nshort_rf_base_m2_b_w5,sky130_fd_pr__rf_nfet_01v8_bM02W5p00 +nshort_rf_base_m4_b_w3,sky130_fd_pr__rf_nfet_01v8_bM04W3p00 +nshort_rf_base_m4_b_w5,sky130_fd_pr__rf_nfet_01v8_bM04W5p00 +nshort_w3p0_l0p15_m2_b,sky130_fd_pr__nfet_01v8_bM02W3p00L0p15 +nshort_w3p0_l0p15_m4_b,sky130_fd_pr__nfet_01v8_bM04W3p00L0p15 +nshort_w3p0_l0p18_m2_b,sky130_fd_pr__nfet_01v8_bM02W3p00L0p18 +nshort_w3p0_l0p18_m4_b,sky130_fd_pr__nfet_01v8_bM04W3p00L0p18 +nshort_w3p0_l0p25_m2_b,sky130_fd_pr__nfet_01v8_bM02W3p00L0p25 +nshort_w3p0_l0p25_m4_b,sky130_fd_pr__nfet_01v8_bM04W3p00L0p25 +nshort_w5p0_l0p15_m2_b,sky130_fd_pr__nfet_01v8_bM02W5p00L0p15 +nshort_w5p0_l0p15_m4_b,sky130_fd_pr__nfet_01v8_bM04W5p00L0p15 +nshort_w5p0_l0p18_m2_b,sky130_fd_pr__nfet_01v8_bM02W5p00L0p18 +nshort_w5p0_l0p18_m4_b,sky130_fd_pr__nfet_01v8_bM04W5p00L0p18 +nshort_w5p0_l0p25_m2_b,sky130_fd_pr__nfet_01v8_bM02W5p00L0p25 +nshort_w5p0_l0p25_m4_b,sky130_fd_pr__nfet_01v8_bM04W5p00L0p25 +plowvt_ttleak_discrete,sky130_fd_pr__pfet_01v8_lvt__tt_leak_discrete +plowvt_w3p0_l0p35_m2_b,sky130_fd_pr__pfet_01v8_lvt_bM02W3p00L0p35 +plowvt_w3p0_l0p35_m4_b,sky130_fd_pr__pfet_01v8_lvt_bM04W3p00L0p35 +plowvt_w3p0_l0p50_m2_b,sky130_fd_pr__pfet_01v8_lvt_bM02W3p00L0p50 +plowvt_w3p0_l0p50_m4_b,sky130_fd_pr__pfet_01v8_lvt_bM04W3p00L0p50 +plowvt_w5p0_l0p35_m2_b,sky130_fd_pr__pfet_01v8_lvt_bM02W5p00L0p35 +plowvt_w5p0_l0p35_m4_b,sky130_fd_pr__pfet_01v8_lvt_bM04W5p00L0p35 +plowvt_w5p0_l0p50_m2_b,sky130_fd_pr__pfet_01v8_lvt_bM02W5p00L0p50 +plowvt_w5p0_l0p50_m4_b,sky130_fd_pr__pfet_01v8_lvt_bM04W5p00L0p50 +pmedlvt_rf_ff_discrete,sky130_fd_pr__rf_pfet_01v8_mvt__ff_discrete +pmedlvt_rf_fs_discrete,sky130_fd_pr__rf_pfet_01v8_mvt__fs_discrete +pmedlvt_rf_sf_discrete,sky130_fd_pr__rf_pfet_01v8_mvt__sf_discrete +pmedlvt_rf_ss_discrete,sky130_fd_pr__rf_pfet_01v8_mvt__ss_discrete +pmedlvt_rf_tt_discrete,sky130_fd_pr__rf_pfet_01v8_mvt__tt_discrete +pmedlvt_w0p84_l0p15_2f,sky130_fd_pr__pfet_01v8_mvt_aF02W0p84L0p15 +pmedlvt_w1p68_l0p15_2f,sky130_fd_pr__pfet_01v8_mvt_aF02W1p68L0p15 +pmedlvt_w1p68_l0p15_4f,sky130_fd_pr__pfet_01v8_mvt_aF04W1p68L0p15 +pshort_rf_base_b_wafer,sky130_fd_pr__rf_pfet_01v8_b__wafer +pshort_rf_base_m2_b_w3,sky130_fd_pr__rf_pfet_01v8_bM02W3p00 +pshort_rf_base_m2_b_w5,sky130_fd_pr__rf_pfet_01v8_bM02W5p00 +pshort_rf_base_m4_b_w3,sky130_fd_pr__rf_pfet_01v8_bM04W3p00 +pshort_rf_base_m4_b_w5,sky130_fd_pr__rf_pfet_01v8_bM04W5p00 +pshort_ttleak_discrete,sky130_fd_pr__pfet_01v8__tt_leak_discrete +pshort_w3p0_l0p15_m2_b,sky130_fd_pr__pfet_01v8_bM02W3p00L0p15 +pshort_w3p0_l0p15_m4_b,sky130_fd_pr__pfet_01v8_bM04W3p00L0p15 +pshort_w3p0_l0p18_m2_b,sky130_fd_pr__pfet_01v8_bM02W3p00L0p18 +pshort_w3p0_l0p18_m4_b,sky130_fd_pr__pfet_01v8_bM04W3p00L0p18 +pshort_w3p0_l0p25_m2_b,sky130_fd_pr__pfet_01v8_bM02W3p00L0p25 +pshort_w3p0_l0p25_m4_b,sky130_fd_pr__pfet_01v8_bM04W3p00L0p25 +pshort_w5p0_l0p15_m2_b,sky130_fd_pr__pfet_01v8_bM02W5p00L0p15 +pshort_w5p0_l0p15_m4_b,sky130_fd_pr__pfet_01v8_bM04W5p00L0p15 +pshort_w5p0_l0p18_m2_b,sky130_fd_pr__pfet_01v8_bM02W5p00L0p18 +pshort_w5p0_l0p18_m4_b,sky130_fd_pr__pfet_01v8_bM04W5p00L0p18 +pshort_w5p0_l0p25_m2_b,sky130_fd_pr__pfet_01v8_bM02W5p00L0p25 +pshort_w5p0_l0p25_m4_b,sky130_fd_pr__pfet_01v8_bM04W5p00L0p25 +rf2_xcmvpp11p5x11p7_m3,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_noshield +rf2_xcmvpp4p4x4p6_m1m2,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield +rf2_xcmvpp4p4x4p6_m1m4,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3m4_noshield +rf2_xcmvpp6p8x6p1_m1m4,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield +rf2_xcmvpp_hd5_6p8x6p1,sky130_fd_pr__cap_vpp_06p8x06p1_pol1m1m2m3m4m5_noshield +s8rf2_xcmvpp4p4x4p6_m3,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_noshield +s8rf2_xcmvpp8p6x7p9_m3,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_noshield +s8rf_n20nativevhv1_aup,sky130_fd_pr__rf_nfet_20v0_nvt_aup +s8rf_n20vhviso1_noptap,sky130_fd_pr__rf_nfet_20v0_noptap_iso +s8rf_nhv_w3p0_l0p5_m10,sky130_fd_pr__rf_nfet_g5v0d10v5_aM10W3p00L0p50 +s8rf_nhv_w5p0_l0p5_m10,sky130_fd_pr__rf_nfet_g5v0d10v5_aM10W5p00L0p50 +s8rf_nhv_w7p0_l0p5_m10,sky130_fd_pr__rf_nfet_g5v0d10v5_aM10W7p00L0p50 +s8rf_nlowvt_w3p0_l0p15,sky130_fd_pr__rf_nfet_01v8_lvt_aW3p00L0p15 +s8rf_nlowvt_w3p0_l0p18,sky130_fd_pr__rf_nfet_01v8_lvt_aW3p00L0p18 +s8rf_nlowvt_w3p0_l0p25,sky130_fd_pr__rf_nfet_01v8_lvt_aW3p00L0p25 +s8rf_nlowvt_w5p0_l0p15,sky130_fd_pr__rf_nfet_01v8_lvt_aW5p00L0p15 +s8rf_nlowvt_w5p0_l0p18,sky130_fd_pr__rf_nfet_01v8_lvt_aW5p00L0p18 +s8rf_nlowvt_w5p0_l0p25,sky130_fd_pr__rf_nfet_01v8_lvt_aW5p00L0p25 +s8rf_nshort_w3p0_l0p15,sky130_fd_pr__rf_nfet_01v8_aW3p00L0p15 +s8rf_nshort_w3p0_l0p18,sky130_fd_pr__rf_nfet_01v8_aW3p00L0p18 +s8rf_nshort_w3p0_l0p25,sky130_fd_pr__rf_nfet_01v8_aW3p00L0p25 +s8rf_nshort_w5p0_l0p15,sky130_fd_pr__rf_nfet_01v8_aW5p00L0p15 +s8rf_nshort_w5p0_l0p18,sky130_fd_pr__rf_nfet_01v8_aW5p00L0p18 +s8rf_nshort_w5p0_l0p25,sky130_fd_pr__rf_nfet_01v8_aW5p00L0p25 +s8rf_plowvt_w3p0_l0p25,sky130_fd_pr__rf_pfet_01v8_lvt_aW3p00L0p25 +s8rf_plowvt_w3p0_l0p35,sky130_fd_pr__rf_pfet_01v8_lvt_aW3p00L0p35 +s8rf_plowvt_w3p0_l0p50,sky130_fd_pr__rf_pfet_01v8_lvt_aW3p00L0p50 +s8rf_plowvt_w5p0_l0p25,sky130_fd_pr__rf_pfet_01v8_lvt_aW5p00L0p25 +s8rf_plowvt_w5p0_l0p35,sky130_fd_pr__rf_pfet_01v8_lvt_aW5p00L0p35 +s8rf_plowvt_w5p0_l0p50,sky130_fd_pr__rf_pfet_01v8_lvt_aW5p00L0p50 +s8rf_pshort_w2p0_l0p15,sky130_fd_pr__rf_pfet_01v8_aW2p00L0p15 +s8rf_pshort_w3p0_l0p15,sky130_fd_pr__rf_pfet_01v8_aW3p00L0p15 +s8rf_pshort_w3p0_l0p18,sky130_fd_pr__rf_pfet_01v8_aW3p00L0p18 +s8rf_pshort_w3p0_l0p25,sky130_fd_pr__rf_pfet_01v8_aW3p00L0p25 +s8rf_pshort_w5p0_l0p15,sky130_fd_pr__rf_pfet_01v8_aW5p00L0p15 +s8rf_pshort_w5p0_l0p18,sky130_fd_pr__rf_pfet_01v8_aW5p00L0p18 +s8rf_pshort_w5p0_l0p25,sky130_fd_pr__rf_pfet_01v8_aW5p00L0p25 +xcmvpp11p5x11p7_m3_top,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_noshield_top +xcmvpp1p8x1p8_lishield,sky130_fd_pr__cap_vpp_01p8x01p8_m1m2_shieldl1 +xcmvpp1p8x1p8_m3shield,sky130_fd_pr__cap_vpp_03p9x03p9_m1m2_shieldl1_floatm3 +xcmvpp4p4x4p6_lishield,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_shieldl1 +xcmvpp4p4x4p6_m3shield,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_shieldpo_floatm3 +xcmvpp6p8x6p1_m1m4_fom,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield_fom +xcmvpp8p6x7p9_lishield,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2_shieldl1 +xcmvpp8p6x7p9_m3shield,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_shieldpo_floatm3 +xesd_ndiode_h_dnwl_100,sky130_fd_pr__esd_rf_diode_pw2nd_11v0_100__parasitic__diode_pw2dn +xesd_ndiode_h_dnwl_200,sky130_fd_pr__esd_rf_diode_pw2nd_11v0_200__parasitic__diode_pw2dn +xesd_ndiode_h_dnwl_300,sky130_fd_pr__esd_rf_diode_pw2nd_11v0_300__parasitic__diode_pw2dn +hrpoly_0p35_175320108,sky130_fd_pr__res_high_po_0p35__example_175320108 +hrpoly_0p69_174836780,sky130_fd_pr__res_high_po_0p69__example_174836780 +hrpoly_1p41_174842924,sky130_fd_pr__res_high_po_1p41__example_174842924 +hrpoly_2p85_174849068,sky130_fd_pr__res_high_po_2p85__example_174849068 +hrpoly_5p73_173904940,sky130_fd_pr__res_high_po_5p73__example_173904940 +n20nativevhv_withptap,sky130_fd_pr__nfet_20v0_nvt_withptap +n20vhv_wafer_discrete,sky130_fd_pr__nfet_20v0__wafer_discrete +n20vhviso1_subcircuit,sky130_fd_pr__nfet_20v0_iso__subcircuit +n20zvtvhv1_subcircuit,sky130_fd_pr__nfet_20v0_zvt__subcircuit +n20zvtvhv_fs_discrete,sky130_fd_pr__nfet_20v0_zvt__fs_discrete +n20zvtvhv_sf_discrete,sky130_fd_pr__nfet_20v0_zvt__sf_discrete +n20zvtvhv_tt_discrete,sky130_fd_pr__nfet_20v0_zvt__tt_discrete +nhv_rf_base_b_tt_leak,sky130_fd_pr__rf_nfet_g5v0d10v5_b__tt_leak +nlowvt_rf_base_b_leak,sky130_fd_pr__rf_nfet_01v8_lvt_b__leak +nlowvt_w0p42_l0p15_2f,sky130_fd_pr__nfet_01v8_lvt_aF02W0p42L0p15 +nlowvt_w0p42_l0p15_4f,sky130_fd_pr__nfet_01v8_lvt_aF04W0p42L0p15 +nlowvt_w0p42_l0p15_6f,sky130_fd_pr__nfet_01v8_lvt_aF06W0p42L0p15 +nlowvt_w0p42_l0p15_8f,sky130_fd_pr__nfet_01v8_lvt_aF08W0p42L0p15 +nlowvt_w0p84_l0p15_2f,sky130_fd_pr__nfet_01v8_lvt_aF02W0p84L0p15 +nlowvt_w0p84_l0p15_4f,sky130_fd_pr__nfet_01v8_lvt_aF04W0p84L0p15 +nlowvt_w0p84_l0p15_6f,sky130_fd_pr__nfet_01v8_lvt_aF06W0p84L0p15 +nlowvt_w0p84_l0p15_8f,sky130_fd_pr__nfet_01v8_lvt_aF08W0p84L0p15 +nlowvt_w1p65_l0p15_2f,sky130_fd_pr__nfet_01v8_lvt_aF02W1p65L0p15 +nlowvt_w1p65_l0p15_4f,sky130_fd_pr__nfet_01v8_lvt_aF04W1p65L0p15 +nlowvt_w1p65_l0p15_6f,sky130_fd_pr__nfet_01v8_lvt_aF06W1p65L0p15 +nlowvt_w1p65_l0p15_8f,sky130_fd_pr__nfet_01v8_lvt_aF08W1p65L0p15 +nlowvt_w1p65_l0p15_m2,sky130_fd_pr__nfet_01v8_lvt_aM02W1p65L0p15 +nlowvt_w1p65_l0p15_m4,sky130_fd_pr__nfet_01v8_lvt_aM04W1p65L0p15 +nlowvt_w1p65_l0p18_m2,sky130_fd_pr__nfet_01v8_lvt_aM02W1p65L0p18 +nlowvt_w1p65_l0p18_m4,sky130_fd_pr__nfet_01v8_lvt_aM04W1p65L0p18 +nlowvt_w1p65_l0p25_m2,sky130_fd_pr__nfet_01v8_lvt_aM02W1p65L0p25 +nlowvt_w1p65_l0p25_m4,sky130_fd_pr__nfet_01v8_lvt_aM04W1p65L0p25 +nshort_rf_base_b_leak,sky130_fd_pr__rf_nfet_01v8_b__leak +nshort_w1p65_l0p15_m2,sky130_fd_pr__nfet_01v8_aM02W1p65L0p15 +nshort_w1p65_l0p15_m4,sky130_fd_pr__nfet_01v8_aM04W1p65L0p15 +nshort_w1p65_l0p18_m2,sky130_fd_pr__nfet_01v8_aM02W1p65L0p18 +nshort_w1p65_l0p18_m4,sky130_fd_pr__nfet_01v8_aM04W1p65L0p18 +nshort_w1p65_l0p25_m2,sky130_fd_pr__nfet_01v8_aM02W1p65L0p25 +nshort_w1p65_l0p25_m4,sky130_fd_pr__nfet_01v8_aM04W1p65L0p25 +pshort_rf_base_b_leak,sky130_fd_pr__rf_pfet_01v8_b__leak +pshort_w0p84_l0p15_2f,sky130_fd_pr__pfet_01v8_aF02W0p84L0p15 +pshort_w0p84_l0p15_4f,sky130_fd_pr__pfet_01v8_aF04W0p84L0p15 +pshort_w0p84_l0p15_6f,sky130_fd_pr__pfet_01v8_aF06W0p84L0p15 +pshort_w0p84_l0p15_8f,sky130_fd_pr__pfet_01v8_aF08W0p84L0p15 +pshort_w1p65_l0p15_m2,sky130_fd_pr__pfet_01v8_aM02W1p65L0p15 +pshort_w1p65_l0p15_m4,sky130_fd_pr__pfet_01v8_aM04W1p65L0p15 +pshort_w1p65_l0p18_m2,sky130_fd_pr__pfet_01v8_aM02W1p65L0p18 +pshort_w1p65_l0p18_m4,sky130_fd_pr__pfet_01v8_aM04W1p65L0p18 +pshort_w1p65_l0p25_m2,sky130_fd_pr__pfet_01v8_aM02W1p65L0p25 +pshort_w1p65_l0p25_m4,sky130_fd_pr__pfet_01v8_aM04W1p65L0p25 +pshort_w1p68_l0p15_2f,sky130_fd_pr__pfet_01v8_aF02W1p68L0p15 +pshort_w1p68_l0p15_4f,sky130_fd_pr__pfet_01v8_aF04W1p68L0p15 +pshort_w1p68_l0p15_6f,sky130_fd_pr__pfet_01v8_aF06W1p68L0p15 +pshort_w1p68_l0p15_8f,sky130_fd_pr__pfet_01v8_aF08W1p68L0p15 +rf2_vpp_nhvnative10x4,sky130_fd_pr__cap_vpp_11p3x11p8_l1m1m2m3m4_shieldm5_nhv__base +rf_xcmvpp11p5x11p7_m3,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_noshield +rf_xcmvpp4p4x4p6_m1m2,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield +rf_xcmvpp4p4x4p6_m1m4,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3m4_noshield +rf_xcmvpp6p8x6p1_m1m4,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield +rf_xcmvpp_hd5_6p8x6p1,sky130_fd_pr__cap_vpp_06p8x06p1_pol1m1m2m3m4m5_noshield +s8rf2_xcmvpp11p5x11p7,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2_noshield +s8rf_n20nativevhviso1,sky130_fd_pr__rf_nfet_20v0_nvt_iso +s8rf_n20vhv1_withptap,sky130_fd_pr__rf_nfet_20v0_withptap +s8rf_nhv_w3p0_l0p5_m2,sky130_fd_pr__rf_nfet_g5v0d10v5_aM02W3p00L0p50 +s8rf_nhv_w3p0_l0p5_m4,sky130_fd_pr__rf_nfet_g5v0d10v5_aM04W3p00L0p50 +s8rf_nhv_w5p0_l0p5_m2,sky130_fd_pr__rf_nfet_g5v0d10v5_aM02W5p00L0p50 +s8rf_nhv_w5p0_l0p5_m4,sky130_fd_pr__rf_nfet_g5v0d10v5_aM04W5p00L0p50 +s8rf_nhv_w7p0_l0p5_m4,sky130_fd_pr__rf_nfet_g5v0d10v5_aM04W7p00L0p50 +s8rf_p20vhv1_withptap,sky130_fd_pr__rf_pfet_20v0_withptap +s8rf_xcmvpp4p4x4p6_m3,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_noshield +s8rf_xcmvpp8p6x7p9_m3,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_noshield +xcmvpp2_nhvnative10x4,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield_o1nhv +n20vhv_leak_discrete,sky130_fd_pr__nfet_20v0__leak_discrete +n20vhviso_subcircuit,sky130_fd_pr__nfet_20v0_iso__subcircuit +n20vhvisoreverse1_fs,sky130_fd_pr__nfet_20v0_reverse_iso__fs +n20vhvisoreverse1_sf,sky130_fd_pr__nfet_20v0_reverse_iso__sf +n20vhvisoreverse1_tt,sky130_fd_pr__nfet_20v0_reverse_iso__tt +n20zvtvhv_subcircuit,sky130_fd_pr__nfet_20v0_zvt__subcircuit +nhv_rf_base_m10_b_w5,sky130_fd_pr__rf_nfet_g5v0d10v5_bM10W5p00 +nhv_rf_base_m10_b_w7,sky130_fd_pr__rf_nfet_g5v0d10v5_bM10W7p00 +nlowvt_leak_discrete,sky130_fd_pr__nfet_01v8_lvt__leak_discrete +nlowvt_w3p0_l0p15_2f,sky130_fd_pr__nfet_01v8_lvt_aF02W3p00L0p15 +nlowvt_w3p0_l0p15_4f,sky130_fd_pr__nfet_01v8_lvt_aF04W3p00L0p15 +nlowvt_w3p0_l0p15_6f,sky130_fd_pr__nfet_01v8_lvt_aF06W3p00L0p15 +nlowvt_w3p0_l0p15_8f,sky130_fd_pr__nfet_01v8_lvt_aF08W3p00L0p15 +nlowvt_w3p0_l0p15_m2,sky130_fd_pr__nfet_01v8_lvt_aM02W3p00L0p15 +nlowvt_w3p0_l0p15_m4,sky130_fd_pr__nfet_01v8_lvt_aM04W3p00L0p15 +nlowvt_w3p0_l0p18_m2,sky130_fd_pr__nfet_01v8_lvt_aM02W3p00L0p18 +nlowvt_w3p0_l0p18_m4,sky130_fd_pr__nfet_01v8_lvt_aM04W3p00L0p18 +nlowvt_w3p0_l0p25_m2,sky130_fd_pr__nfet_01v8_lvt_aM02W3p00L0p25 +nlowvt_w3p0_l0p25_m4,sky130_fd_pr__nfet_01v8_lvt_aM04W3p00L0p25 +nlowvt_w5p0_l0p15_m2,sky130_fd_pr__nfet_01v8_lvt_aM02W5p00L0p15 +nlowvt_w5p0_l0p15_m4,sky130_fd_pr__nfet_01v8_lvt_aM04W5p00L0p15 +nlowvt_w5p0_l0p18_m2,sky130_fd_pr__nfet_01v8_lvt_aM02W5p00L0p18 +nlowvt_w5p0_l0p18_m4,sky130_fd_pr__nfet_01v8_lvt_aM04W5p00L0p18 +nlowvt_w5p0_l0p25_m2,sky130_fd_pr__nfet_01v8_lvt_aM02W5p00L0p25 +nlowvt_w5p0_l0p25_m4,sky130_fd_pr__nfet_01v8_lvt_aM04W5p00L0p25 +nshort_w3p0_l0p15_m2,sky130_fd_pr__nfet_01v8_aM02W3p00L0p15 +nshort_w3p0_l0p15_m4,sky130_fd_pr__nfet_01v8_aM04W3p00L0p15 +nshort_w3p0_l0p18_m2,sky130_fd_pr__nfet_01v8_aM02W3p00L0p18 +nshort_w3p0_l0p18_m4,sky130_fd_pr__nfet_01v8_aM04W3p00L0p18 +nshort_w3p0_l0p25_m2,sky130_fd_pr__nfet_01v8_aM02W3p00L0p25 +nshort_w3p0_l0p25_m4,sky130_fd_pr__nfet_01v8_aM04W3p00L0p25 +nshort_w5p0_l0p15_m2,sky130_fd_pr__nfet_01v8_aM02W5p00L0p15 +nshort_w5p0_l0p15_m4,sky130_fd_pr__nfet_01v8_aM04W5p00L0p15 +nshort_w5p0_l0p18_m2,sky130_fd_pr__nfet_01v8_aM02W5p00L0p18 +nshort_w5p0_l0p18_m4,sky130_fd_pr__nfet_01v8_aM04W5p00L0p18 +nshort_w5p0_l0p25_m2,sky130_fd_pr__nfet_01v8_aM02W5p00L0p25 +nshort_w5p0_l0p25_m4,sky130_fd_pr__nfet_01v8_aM04W5p00L0p25 +nvhv_ttleak_discrete,sky130_fd_pr__nfet_g5v0d16v0__tt_leak_discrete +p20vhv_leak_discrete,sky130_fd_pr__pfet_20v0__leak_discrete +plowvt_leak_discrete,sky130_fd_pr__pfet_01v8_lvt__leak_discrete +plowvt_w3p0_l0p25_m2,sky130_fd_pr__pfet_01v8_lvt_aM02W3p00L0p25 +plowvt_w3p0_l0p25_m4,sky130_fd_pr__pfet_01v8_lvt_aM04W3p00L0p25 +plowvt_w3p0_l0p35_m2,sky130_fd_pr__pfet_01v8_lvt_aM02W3p00L0p35 +plowvt_w3p0_l0p35_m4,sky130_fd_pr__pfet_01v8_lvt_aM04W3p00L0p35 +plowvt_w3p0_l0p50_m2,sky130_fd_pr__pfet_01v8_lvt_aM02W3p00L0p50 +plowvt_w3p0_l0p50_m4,sky130_fd_pr__pfet_01v8_lvt_aM04W3p00L0p50 +plowvt_w5p0_l0p25_m2,sky130_fd_pr__pfet_01v8_lvt_aM02W5p00L0p25 +plowvt_w5p0_l0p25_m4,sky130_fd_pr__pfet_01v8_lvt_aM04W5p00L0p25 +plowvt_w5p0_l0p35_m2,sky130_fd_pr__pfet_01v8_lvt_aM02W5p00L0p35 +plowvt_w5p0_l0p35_m4,sky130_fd_pr__pfet_01v8_lvt_aM04W5p00L0p35 +plowvt_w5p0_l0p50_m2,sky130_fd_pr__pfet_01v8_lvt_aM02W5p00L0p50 +plowvt_w5p0_l0p50_m4,sky130_fd_pr__pfet_01v8_lvt_aM04W5p00L0p50 +pmedlvtrf_1p68p15nf2,sky130_fd_pr__rf_pfet_01v8_mvt_aF02W1p68L0p15 +pmedlvtrf_1p68p15nf4,sky130_fd_pr__rf_pfet_01v8_mvt_aF04W1p68L0p15 +pshort_leak_discrete,sky130_fd_pr__pfet_01v8__leak_discrete +pshort_w2p0_l0p15_2f,sky130_fd_pr__pfet_01v8_aF02W2p00L0p15 +pshort_w2p0_l0p15_4f,sky130_fd_pr__pfet_01v8_aF04W2p00L0p15 +pshort_w2p0_l0p15_6f,sky130_fd_pr__pfet_01v8_aF06W2p00L0p15 +pshort_w3p0_l0p15_2f,sky130_fd_pr__pfet_01v8_aF02W3p00L0p15 +pshort_w3p0_l0p15_4f,sky130_fd_pr__pfet_01v8_aF04W3p00L0p15 +pshort_w3p0_l0p15_6f,sky130_fd_pr__pfet_01v8_aF06W3p00L0p15 +pshort_w3p0_l0p15_m2,sky130_fd_pr__pfet_01v8_aM02W3p00L0p15 +pshort_w3p0_l0p15_m4,sky130_fd_pr__pfet_01v8_aM04W3p00L0p15 +pshort_w3p0_l0p18_m2,sky130_fd_pr__pfet_01v8_aM02W3p00L0p18 +pshort_w3p0_l0p18_m4,sky130_fd_pr__pfet_01v8_aM04W3p00L0p18 +pshort_w3p0_l0p25_m2,sky130_fd_pr__pfet_01v8_aM02W3p00L0p25 +pshort_w3p0_l0p25_m4,sky130_fd_pr__pfet_01v8_aM04W3p00L0p25 +pshort_w5p0_l0p15_2f,sky130_fd_pr__pfet_01v8_aF02W5p00L0p15 +pshort_w5p0_l0p15_4f,sky130_fd_pr__pfet_01v8_aF04W5p00L0p15 +pshort_w5p0_l0p15_m2,sky130_fd_pr__pfet_01v8_aM02W5p00L0p15 +pshort_w5p0_l0p15_m4,sky130_fd_pr__pfet_01v8_aM04W5p00L0p15 +pshort_w5p0_l0p18_m2,sky130_fd_pr__pfet_01v8_aM02W5p00L0p18 +pshort_w5p0_l0p18_m4,sky130_fd_pr__pfet_01v8_aM04W5p00L0p18 +pshort_w5p0_l0p25_m2,sky130_fd_pr__pfet_01v8_aM02W5p00L0p25 +pshort_w5p0_l0p25_m4,sky130_fd_pr__pfet_01v8_aM04W5p00L0p25 +rf2_s8blref_xind4_01,sky130_fd_pr__ind_01_04 +rf2_xcmvpp4p4x4p6_m3,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_noshield +rf2_xcmvpp8p6x7p9_m3,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_noshield +rf_vpp_nhvnative10x4,sky130_fd_pr__cap_vpp_11p3x11p8_l1m1m2m3m4_shieldm5_nhv__base +s8rf2_xcmvpp_hd5_1x1,sky130_fd_pr__cap_vpp_11p5x11p7_pol1m1m2m3m4m5_noshield +s8rf2_xcmvpp_hd5_1x2,sky130_fd_pr__cap_vpp_11p5x23p1_pol1m1m2m3m4m5_noshield +s8rf2_xcmvpp_hd5_2x1,sky130_fd_pr__cap_vpp_22p5x11p7_pol1m1m2m3m4m5_noshield +s8rf2_xcmvpp_hd5_2x2,sky130_fd_pr__cap_vpp_22p5x23p1_pol1m1m2m3m4m5_noshield +s8rf2_xcmvpp_hd5_3x1,sky130_fd_pr__cap_vpp_33p6x11p7_pol1m1m2m3m4m5_noshield +s8rf2_xcmvpp_hd5_3x2,sky130_fd_pr__cap_vpp_33p6x23p1_pol1m1m2m3m4m5_noshield +s8rf2_xcmvpp_hd5_4x1,sky130_fd_pr__cap_vpp_44p7x11p7_pol1m1m2m3m4m5_noshield +s8rf2_xcmvpp_hd5_4x2,sky130_fd_pr__cap_vpp_44p7x23p1_pol1m1m2m3m4m5_noshield +s8rf2_xcmvpp_hd5_5x1,sky130_fd_pr__cap_vpp_55p8x11p7_pol1m1m2m3m4m5_noshield +s8rf2_xcmvpp_hd5_5x2,sky130_fd_pr__cap_vpp_55p8x23p1_pol1m1m2m3m4m5_noshield +s8rf_n20vhv1_esd_hbm,sky130_fd_pr__esd_rf_nfet_20v0_hbm +s8rf_n20vhv1_esd_iec,sky130_fd_pr__esd_rf_nfet_20v0_iec +s8rf_xcmvpp11p5x11p7,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2_noshield +xcmvpp11p5x11p7_m1m2,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2_noshield +xcmvpp11p5x11p7_m1m4,sky130_fd_pr__cap_vpp_11p5x11p7_m1m4_noshield +xcmvpp11p5x11p7_m3m4,sky130_fd_pr__cap_vpp_11p5x11p7_m3m4_noshield +dnwdiode_psub_defet,sky130_fd_pr__model__parasitic__diode_ps2dn__extended_drain +hrpoly_0p35_l1m1con,sky130_fd_pr__res_high_pol1m1_0p35 +hrpoly_0p35_rpl1con,sky130_fd_pr__res_high_pol1_0p35 +hrpoly_0p69_l1m1con,sky130_fd_pr__res_high_pol1m1_0p69 +hrpoly_0p69_rpl1con,sky130_fd_pr__res_high_pol1_0p69 +hrpoly_1p41_l1m1con,sky130_fd_pr__res_high_pol1m1_1p41 +hrpoly_1p41_rpl1con,sky130_fd_pr__res_high_pol1_1p41 +hrpoly_2p85_l1m1con,sky130_fd_pr__res_high_pol1m1_2p85 +hrpoly_2p85_rpl1con,sky130_fd_pr__res_high_pol1_2p85 +hrpoly_5p73_l1m1con,sky130_fd_pr__res_high_pol1m1_5p73 +hrpoly_5p73_rpl1con,sky130_fd_pr__res_high_pol1_5p73 +n20nativevhviso1_fs,sky130_fd_pr__nfet_20v0_nvt_iso__fs +n20nativevhviso1_sf,sky130_fd_pr__nfet_20v0_nvt_iso__sf +n20nativevhviso1_tt,sky130_fd_pr__nfet_20v0_nvt_iso__tt +n20vhv1_esd_hbm_21v,sky130_fd_pr__esd_nfet_20v0_hbm_21v +n20vhv1_esd_hbm_32v,sky130_fd_pr__esd_nfet_20v0_hbm_32v +n20vhv1_esd_iec_21v,sky130_fd_pr__esd_nfet_20v0_iec_21v +n20vhv1_esd_iec_32v,sky130_fd_pr__esd_nfet_20v0_iec_32v +n20vhviso1_withptap,sky130_fd_pr__nfet_20v0_withptap_iso +n20vhvisoreverse_fs,sky130_fd_pr__nfet_20v0_reverse_iso__fs +n20vhvisoreverse_sf,sky130_fd_pr__nfet_20v0_reverse_iso__sf +n20vhvisoreverse_tt,sky130_fd_pr__nfet_20v0_reverse_iso__tt +n20zvtvhv1_withptap,sky130_fd_pr__nfet_20v0_zvt_withptap +nhv_rf_base_b_wafer,sky130_fd_pr__rf_nfet_g5v0d10v5_b__wafer +nhv_rf_base_m2_b_w5,sky130_fd_pr__rf_nfet_g5v0d10v5_bM02W5p00 +nhv_rf_base_m4_b_w5,sky130_fd_pr__rf_nfet_g5v0d10v5_bM04W5p00 +nhv_rf_base_m4_b_w7,sky130_fd_pr__rf_nfet_g5v0d10v5_bM04W7p00 +nhv_ttleak_discrete,sky130_fd_pr__nfet_g5v0d10v5__tt_leak_discrete +nhv_w3p0_l0p5_m10_b,sky130_fd_pr__nfet_g5v0d10v5_bM10W3p00L0p50 +nhv_w5p0_l0p5_m10_b,sky130_fd_pr__nfet_g5v0d10v5_bM10W5p00L0p50 +nhv_w7p0_l0p5_m10_b,sky130_fd_pr__nfet_g5v0d10v5_bM10W7p00L0p50 +nhvnative_ttcorreln,sky130_fd_pr__nfet_05v0_nvt__tt_correln +nhvnative_ttcorrelp,sky130_fd_pr__nfet_05v0_nvt__tt_correlp +nlowvt_rf_base_b_ff,sky130_fd_pr__rf_nfet_01v8_lvt_b__ff +nlowvt_rf_base_b_fs,sky130_fd_pr__rf_nfet_01v8_lvt_b__fs +nlowvt_rf_base_b_sf,sky130_fd_pr__rf_nfet_01v8_lvt_b__sf +nlowvt_rf_base_b_ss,sky130_fd_pr__rf_nfet_01v8_lvt_b__ss +nlowvt_rf_base_b_tt,sky130_fd_pr__rf_nfet_01v8_lvt_b__tt +nlowvt_rf_base_m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02 +nlowvt_rf_base_m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04 +nshort_rf_base_b_ff,sky130_fd_pr__rf_nfet_01v8_b__ff +nshort_rf_base_b_fs,sky130_fd_pr__rf_nfet_01v8_b__fs +nshort_rf_base_b_sf,sky130_fd_pr__rf_nfet_01v8_b__sf +nshort_rf_base_b_ss,sky130_fd_pr__rf_nfet_01v8_b__ss +nshort_rf_base_b_tt,sky130_fd_pr__rf_nfet_01v8_b__tt +nshort_rf_base_m2_b,sky130_fd_pr__rf_nfet_01v8_bM02 +nshort_rf_base_m4_b,sky130_fd_pr__rf_nfet_01v8_bM04 +ntvnative_ttcorreln,sky130_fd_pr__nfet_03v3_nvt__tt_correln +ntvnative_ttcorrelp,sky130_fd_pr__nfet_03v3_nvt__tt_correlp +phv_ttleak_discrete,sky130_fd_pr__pfet_g5v0d10v5__tt_leak_discrete +pmedlvt_w0p84_l0p15,sky130_fd_pr__pfet_01v8_mvt_aW0p84L0p15 +pmedlvt_w1p68_l0p15,sky130_fd_pr__pfet_01v8_mvt_aW1p68L0p15 +pmedlvtrf_p84p15nf2,sky130_fd_pr__rf_pfet_01v8_mvt_aF02W0p84L0p15 +pshort_rf_base_b_ff,sky130_fd_pr__rf_pfet_01v8_b__ff +pshort_rf_base_b_fs,sky130_fd_pr__rf_pfet_01v8_b__fs +pshort_rf_base_b_sf,sky130_fd_pr__rf_pfet_01v8_b__sf +pshort_rf_base_b_ss,sky130_fd_pr__rf_pfet_01v8_b__ss +pshort_rf_base_b_tt,sky130_fd_pr__rf_pfet_01v8_b__tt +pshort_rf_base_m2_b,sky130_fd_pr__rf_pfet_01v8_bM02 +pshort_rf_base_m4_b,sky130_fd_pr__rf_pfet_01v8_bM04 +rf2_xcmvpp11p5x11p7,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2_noshield +rf2_xcmvpp1_raphael,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield_o1raphael +rf2_xcmvpp1_subcell,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield_o1subcell +rf2_xcmvpp2_raphael,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_noshield_o1raphael +rf2_xcmvpp2_subcell,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_noshield_o1subcell +rf2_xcmvpp3_raphael,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2_noshield_raphael +rf2_xcmvpp4_raphael,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield_o2raphael +rf2_xcmvpp5_raphael,sky130_fd_pr__cap_vpp_02p4x04p6_m1m2_noshield_raphael +rf_s8blref_xind4_01,sky130_fd_pr__ind_01_04 +rf_xcmvpp4p4x4p6_m3,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_noshield +rf_xcmvpp8p6x7p9_m3,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_noshield +s8rf2_xcmvpp4p4x4p6,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_noshield +s8rf2_xcmvpp6p8x6p1,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2_noshield +s8rf2_xcmvpp8p6x7p9,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield +s8rf_npn_1x1_2p0_hv,sky130_fd_pr__rf_npn_11v0_W1p00L1p00 +n20nativevhviso_fs,sky130_fd_pr__nfet_20v0_nvt_iso__fs +n20nativevhviso_sf,sky130_fd_pr__nfet_20v0_nvt_iso__sf +n20nativevhviso_tt,sky130_fd_pr__nfet_20v0_nvt_iso__tt +n20vhv1_subcircuit,sky130_fd_pr__nfet_20v0__subcircuit +n20vhv_esd_hbm_21v,sky130_fd_pr__esd_nfet_20v0_hbm_21v +n20vhv_esd_hbm_32v,sky130_fd_pr__esd_nfet_20v0_hbm_32v +n20vhv_esd_iec_21v,sky130_fd_pr__esd_nfet_20v0_iec_21v +n20vhv_esd_iec_32v,sky130_fd_pr__esd_nfet_20v0_iec_32v +n20vhv_fs_discrete,sky130_fd_pr__nfet_20v0__fs_discrete +n20vhv_sf_discrete,sky130_fd_pr__nfet_20v0__sf_discrete +n20vhv_tt_discrete,sky130_fd_pr__nfet_20v0__tt_discrete +n20vhviso_withptap,sky130_fd_pr__nfet_20v0_withptap_iso +n20zvtvhv_withptap,sky130_fd_pr__nfet_20v0_zvt_withptap +nhv_rf_base_b_leak,sky130_fd_pr__rf_nfet_g5v0d10v5_b__leak +nhv_w3p0_l0p5_m2_b,sky130_fd_pr__nfet_g5v0d10v5_bM02W3p00L0p50 +nhv_w3p0_l0p5_m4_b,sky130_fd_pr__nfet_g5v0d10v5_bM04W3p00L0p50 +nhv_w5p0_l0p5_m2_b,sky130_fd_pr__nfet_g5v0d10v5_bM02W5p00L0p50 +nhv_w5p0_l0p5_m4_b,sky130_fd_pr__nfet_g5v0d10v5_bM04W5p00L0p50 +nhv_w7p0_l0p5_m4_b,sky130_fd_pr__nfet_g5v0d10v5_bM04W7p00L0p50 +nlowvt_ff_discrete,sky130_fd_pr__nfet_01v8_lvt__ff_discrete +nlowvt_fs_discrete,sky130_fd_pr__nfet_01v8_lvt__fs_discrete +nlowvt_sf_discrete,sky130_fd_pr__nfet_01v8_lvt__sf_discrete +nlowvt_ss_discrete,sky130_fd_pr__nfet_01v8_lvt__ss_discrete +nlowvt_tt_discrete,sky130_fd_pr__nfet_01v8_lvt__tt_discrete +nlowvt_w0p42_l0p15,sky130_fd_pr__nfet_01v8_lvt_aW0p42L0p15 +nlowvt_w0p84_l0p15,sky130_fd_pr__nfet_01v8_lvt_aW0p84L0p15 +nlowvt_w1p65_l0p15,sky130_fd_pr__nfet_01v8_lvt_aW1p65L0p15 +nlowvt_w1p65_l0p18,sky130_fd_pr__nfet_01v8_lvt_aW1p65L0p18 +nlowvt_w1p65_l0p25,sky130_fd_pr__nfet_01v8_lvt_aW1p65L0p25 +nshort_w1p65_l0p15,sky130_fd_pr__nfet_01v8_aW1p65L0p15 +nshort_w1p65_l0p18,sky130_fd_pr__nfet_01v8_aW1p65L0p18 +nshort_w1p65_l0p25,sky130_fd_pr__nfet_01v8_aW1p65L0p25 +nvhv_leak_discrete,sky130_fd_pr__nfet_g5v0d16v0__leak_discrete +p20vhv_fs_discrete,sky130_fd_pr__pfet_20v0__fs_discrete +p20vhv_sf_discrete,sky130_fd_pr__pfet_20v0__sf_discrete +p20vhv_tt_discrete,sky130_fd_pr__pfet_20v0__tt_discrete +plowvt_ff_discrete,sky130_fd_pr__pfet_01v8_lvt__ff_discrete +plowvt_fs_discrete,sky130_fd_pr__pfet_01v8_lvt__fs_discrete +plowvt_sf_discrete,sky130_fd_pr__pfet_01v8_lvt__sf_discrete +plowvt_ss_discrete,sky130_fd_pr__pfet_01v8_lvt__ss_discrete +plowvt_tt_discrete,sky130_fd_pr__pfet_01v8_lvt__tt_discrete +pshort_ff_discrete,sky130_fd_pr__pfet_01v8__ff_discrete +pshort_fs_discrete,sky130_fd_pr__pfet_01v8__fs_discrete +pshort_sf_discrete,sky130_fd_pr__pfet_01v8__sf_discrete +pshort_ss_discrete,sky130_fd_pr__pfet_01v8__ss_discrete +pshort_tt_discrete,sky130_fd_pr__pfet_01v8__tt_discrete +pshort_w0p84_l0p15,sky130_fd_pr__pfet_01v8_aW0p84L0p15 +pshort_w1p65_l0p15,sky130_fd_pr__pfet_01v8_aW1p65L0p15 +pshort_w1p65_l0p18,sky130_fd_pr__pfet_01v8_aW1p65L0p18 +pshort_w1p65_l0p25,sky130_fd_pr__pfet_01v8_aW1p65L0p25 +pshort_w1p68_l0p15,sky130_fd_pr__pfet_01v8_aW1p68L0p15 +rf2_xcmvpp2_phv5x4,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield_o1phv +rf2_xcmvpp_hd5_1x1,sky130_fd_pr__cap_vpp_11p5x11p7_pol1m1m2m3m4m5_noshield +rf2_xcmvpp_hd5_1x2,sky130_fd_pr__cap_vpp_11p5x23p1_pol1m1m2m3m4m5_noshield +rf2_xcmvpp_hd5_2x1,sky130_fd_pr__cap_vpp_22p5x11p7_pol1m1m2m3m4m5_noshield +rf2_xcmvpp_hd5_2x2,sky130_fd_pr__cap_vpp_22p5x23p1_pol1m1m2m3m4m5_noshield +rf2_xcmvpp_hd5_3x1,sky130_fd_pr__cap_vpp_33p6x11p7_pol1m1m2m3m4m5_noshield +rf2_xcmvpp_hd5_3x2,sky130_fd_pr__cap_vpp_33p6x23p1_pol1m1m2m3m4m5_noshield +rf2_xcmvpp_hd5_4x1,sky130_fd_pr__cap_vpp_44p7x11p7_pol1m1m2m3m4m5_noshield +rf2_xcmvpp_hd5_4x2,sky130_fd_pr__cap_vpp_44p7x23p1_pol1m1m2m3m4m5_noshield +rf2_xcmvpp_hd5_5x1,sky130_fd_pr__cap_vpp_55p8x11p7_pol1m1m2m3m4m5_noshield +rf2_xcmvpp_hd5_5x2,sky130_fd_pr__cap_vpp_55p8x23p1_pol1m1m2m3m4m5_noshield +rf_xcmvpp11p5x11p7,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2_noshield +rf_xcmvpp1_raphael,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield_o2raphael +rf_xcmvpp1_subcell,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield_o2subcell +rf_xcmvpp2_raphael,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_noshield_o2raphael +rf_xcmvpp2_subcell,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_noshield_o2subcell +rf_xcmvpp3_raphael,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2_noshield_raphael +rf_xcmvpp4_raphael,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield_o2raphael +rf_xcmvpp5_raphael,sky130_fd_pr__cap_vpp_02p4x04p6_m1m2_noshield_raphael +s8rf_n20nativevhv1,sky130_fd_pr__rf_nfet_20v0_nvt +s8rf_nhv_w3p0_l0p5,sky130_fd_pr__rf_nfet_g5v0d10v5_aW3p00L0p50 +s8rf_nhv_w5p0_l0p5,sky130_fd_pr__rf_nfet_g5v0d10v5_aW5p00L0p50 +s8rf_nhv_w7p0_l0p5,sky130_fd_pr__rf_nfet_g5v0d10v5_aW7p00L0p50 +s8rf_pmedlvt_w0p84,sky130_fd_pr__rf_pfet_01v8_mvt_aW0p84 +s8rf_pmedlvt_w1p68,sky130_fd_pr__rf_pfet_01v8_mvt_aW1p68 +s8rf_xcmvpp1_nwell,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_shieldnw_nwell +s8rf_xcmvpp1p8x1p8,sky130_fd_pr__cap_vpp_01p8x01p8_m1m2_noshield +s8rf_xcmvpp2_nwell,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_shieldnw_o1well +s8rf_xcmvpp4p4x4p6,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_noshield +s8rf_xcmvpp8p6x7p9,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield +xcmvpp11p5x11p7_m3,sky130_fd_pr__cap_vpp_11p5x11p7_m1m2m3_noshield +xcmvpp4p4x4p6_m1m2,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield +xcmvpp4p4x4p6_m1m4,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3m4_noshield +xcmvpp6p8x6p1_m1m4,sky130_fd_pr__cap_vpp_06p8x06p1_m1m2m3m4_noshield +xcmvpp_hd5_6p8x6p1,sky130_fd_pr__cap_vpp_06p8x06p1_pol1m1m2m3m4m5_noshield +xdnwdiode_pwell_rf,sky130_fd_pr__model__parasitic__rf_diode_pw2dn +xesd_ndiode_h_dnwl,sky130_fd_pr__esd_rf_diode_pw2nd_11v0__parasitic__diode_pw2dn +dnwdiode_pw_defet,sky130_fd_pr__model__parasitic__diode_pw2dn__extended_drain +dnwdiode_pw_no_rs,sky130_fd_pr__model__parasitic__diode_pw2dn_nors +n20nativevhv1_aup,sky130_fd_pr__nfet_20v0_nvt_aup +n20vhv_subcircuit,sky130_fd_pr__nfet_20v0__subcircuit +n20vhviso1_noptap,sky130_fd_pr__nfet_20v0_noptap_iso +n20vhviso1reverse,sky130_fd_pr__nfet_20v0_reverse_iso +n20vhvisoreverse1,sky130_fd_pr__nfet_20v0_reverse_iso +nhv_leak_discrete,sky130_fd_pr__nfet_g5v0d10v5__leak_discrete +nhv_rf_base_m10_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM10 +nhv_w3p0_l0p5_m10,sky130_fd_pr__nfet_g5v0d10v5_aM10W3p00L0p50 +nhv_w5p0_l0p5_m10,sky130_fd_pr__nfet_g5v0d10v5_aM10W5p00L0p50 +nhv_w7p0_l0p5_m10,sky130_fd_pr__nfet_g5v0d10v5_aM10W7p00L0p50 +nlowvt_rf_base_m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02 +nlowvt_rf_base_m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04 +nlowvt_w3p0_l0p15,sky130_fd_pr__nfet_01v8_lvt_aW3p00L0p15 +nlowvt_w3p0_l0p18,sky130_fd_pr__nfet_01v8_lvt_aW3p00L0p18 +nlowvt_w3p0_l0p25,sky130_fd_pr__nfet_01v8_lvt_aW3p00L0p25 +nlowvt_w5p0_l0p15,sky130_fd_pr__nfet_01v8_lvt_aW5p00L0p15 +nlowvt_w5p0_l0p18,sky130_fd_pr__nfet_01v8_lvt_aW5p00L0p18 +nlowvt_w5p0_l0p25,sky130_fd_pr__nfet_01v8_lvt_aW5p00L0p25 +nshort_rf_base_m2,sky130_fd_pr__rf_nfet_01v8_aM02 +nshort_rf_base_m4,sky130_fd_pr__rf_nfet_01v8_aM04 +nshort_w3p0_l0p15,sky130_fd_pr__nfet_01v8_aW3p00L0p15 +nshort_w3p0_l0p18,sky130_fd_pr__nfet_01v8_aW3p00L0p18 +nshort_w3p0_l0p25,sky130_fd_pr__nfet_01v8_aW3p00L0p25 +nshort_w5p0_l0p15,sky130_fd_pr__nfet_01v8_aW5p00L0p15 +nshort_w5p0_l0p18,sky130_fd_pr__nfet_01v8_aW5p00L0p18 +nshort_w5p0_l0p25,sky130_fd_pr__nfet_01v8_aW5p00L0p25 +p20vhv_subcircuit,sky130_fd_pr__pfet_20v0__subcircuit +phighvt_ttcorreln,sky130_fd_pr__pfet_01v8_hvt__tt_correln +phighvt_ttcorrelp,sky130_fd_pr__pfet_01v8_hvt__tt_correlp +phv_leak_discrete,sky130_fd_pr__pfet_g5v0d10v5__leak_discrete +plowvt_w3p0_l0p25,sky130_fd_pr__pfet_01v8_lvt_aW3p00L0p25 +plowvt_w3p0_l0p35,sky130_fd_pr__pfet_01v8_lvt_aW3p00L0p35 +plowvt_w3p0_l0p50,sky130_fd_pr__pfet_01v8_lvt_aW3p00L0p50 +plowvt_w5p0_l0p25,sky130_fd_pr__pfet_01v8_lvt_aW5p00L0p25 +plowvt_w5p0_l0p35,sky130_fd_pr__pfet_01v8_lvt_aW5p00L0p35 +plowvt_w5p0_l0p50,sky130_fd_pr__pfet_01v8_lvt_aW5p00L0p50 +pmedlvt_rf_ttleak,sky130_fd_pr__rf_pfet_01v8_mvt__tt_leak +pshort_rf_base_m2,sky130_fd_pr__rf_pfet_01v8_aM02 +pshort_rf_base_m4,sky130_fd_pr__rf_pfet_01v8_aM04 +pshort_w2p0_l0p15,sky130_fd_pr__pfet_01v8_aW2p00L0p15 +pshort_w3p0_l0p15,sky130_fd_pr__pfet_01v8_aW3p00L0p15 +pshort_w3p0_l0p18,sky130_fd_pr__pfet_01v8_aW3p00L0p18 +pshort_w3p0_l0p25,sky130_fd_pr__pfet_01v8_aW3p00L0p25 +pshort_w5p0_l0p15,sky130_fd_pr__pfet_01v8_aW5p00L0p15 +pshort_w5p0_l0p18,sky130_fd_pr__pfet_01v8_aW5p00L0p18 +pshort_w5p0_l0p25,sky130_fd_pr__pfet_01v8_aW5p00L0p25 +rf2_xcmvpp1_nwell,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_shieldnw_nwell +rf2_xcmvpp1p8x1p8,sky130_fd_pr__cap_vpp_01p8x01p8_m1m2_noshield +rf2_xcmvpp2_nwell,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_shieldnw_o1well +rf2_xcmvpp4p4x4p6,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_noshield +rf2_xcmvpp6p8x6p1,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2_noshield +rf2_xcmvpp8p6x7p9,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield +rf_npn_1x1_2p0_hv,sky130_fd_pr__rf_npn_11v0_W1p00L1p00 +rf_xcmvpp2_phv5x4,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield_o1phv +rf_xcmvpp_hd5_1x1,sky130_fd_pr__cap_vpp_11p5x11p7_pol1m1m2m3m4m5_noshield +rf_xcmvpp_hd5_1x2,sky130_fd_pr__cap_vpp_11p5x23p1_pol1m1m2m3m4m5_noshield +rf_xcmvpp_hd5_2x1,sky130_fd_pr__cap_vpp_22p5x11p7_pol1m1m2m3m4m5_noshield +rf_xcmvpp_hd5_2x2,sky130_fd_pr__cap_vpp_22p5x23p1_pol1m1m2m3m4m5_noshield +rf_xcmvpp_hd5_3x1,sky130_fd_pr__cap_vpp_33p6x11p7_pol1m1m2m3m4m5_noshield +rf_xcmvpp_hd5_3x2,sky130_fd_pr__cap_vpp_33p6x23p1_pol1m1m2m3m4m5_noshield +rf_xcmvpp_hd5_4x1,sky130_fd_pr__cap_vpp_44p7x11p7_pol1m1m2m3m4m5_noshield +rf_xcmvpp_hd5_4x2,sky130_fd_pr__cap_vpp_44p7x23p1_pol1m1m2m3m4m5_noshield +rf_xcmvpp_hd5_5x1,sky130_fd_pr__cap_vpp_55p8x11p7_pol1m1m2m3m4m5_noshield +rf_xcmvpp_hd5_5x2,sky130_fd_pr__cap_vpp_55p8x23p1_pol1m1m2m3m4m5_noshield +s8rf_nlowvt_w0p42,sky130_fd_pr__rf_nfet_01v8_lvt_aW0p42 +s8rf_nlowvt_w0p84,sky130_fd_pr__rf_nfet_01v8_lvt_aW0p84 +s8rf_nlowvt_w1p65,sky130_fd_pr__rf_nfet_01v8_lvt_aW1p65 +s8rf_nshort_w1p65,sky130_fd_pr__rf_nfet_01v8_aW1p65 +s8rf_pshort_w0p84,sky130_fd_pr__rf_pfet_01v8_aW0p84 +s8rf_pshort_w1p65,sky130_fd_pr__rf_pfet_01v8_aW1p65 +s8rf_pshort_w1p68,sky130_fd_pr__rf_pfet_01v8_aW1p68 +vpp_nhvnative10x4,sky130_fd_pr__cap_vpp_11p3x11p8_l1m1m2m3m4_shieldm5_nhv__base +xcmvpp_moscap_top,sky130_fd_pr__model__cap_vpp_only_mos +xcmvpp_pqonly_top,sky130_fd_pr__model__cap_vpp_only_pq +xesd_ndiode_h_100,sky130_fd_pr__esd_rf_diode_pw2nd_11v0_100 +xesd_ndiode_h_200,sky130_fd_pr__esd_rf_diode_pw2nd_11v0_200 +xesd_ndiode_h_300,sky130_fd_pr__esd_rf_diode_pw2nd_11v0_300 +xesd_pdiode_h_100,sky130_fd_pr__esd_rf_diode_pd2nw_11v0_100 +xesd_pdiode_h_200,sky130_fd_pr__esd_rf_diode_pd2nw_11v0_200 +xesd_pdiode_h_300,sky130_fd_pr__esd_rf_diode_pd2nw_11v0_300 +dnwdiode_p20vhv1,sky130_fd_pr__pfet_20v0__parasitic__diode_pw2dn +n20nativevhv1_fs,sky130_fd_pr__nfet_20v0_nvt__fs +n20nativevhv1_sf,sky130_fd_pr__nfet_20v0_nvt__sf +n20nativevhv1_tt,sky130_fd_pr__nfet_20v0_nvt__tt +n20nativevhv_aup,sky130_fd_pr__nfet_20v0_nvt_aup +n20nativevhviso1,sky130_fd_pr__nfet_20v0_nvt_iso +n20vhv1_withptap,sky130_fd_pr__nfet_20v0_withptap +n20vhviso_noptap,sky130_fd_pr__nfet_20v0_noptap_iso +n20vhvisoreverse,sky130_fd_pr__nfet_20v0_reverse_iso +nhv_rf_base_b_ff,sky130_fd_pr__rf_nfet_g5v0d10v5_b__ff +nhv_rf_base_b_fs,sky130_fd_pr__rf_nfet_g5v0d10v5_b__fs +nhv_rf_base_b_sf,sky130_fd_pr__rf_nfet_g5v0d10v5_b__sf +nhv_rf_base_b_ss,sky130_fd_pr__rf_nfet_g5v0d10v5_b__ss +nhv_rf_base_b_tt,sky130_fd_pr__rf_nfet_g5v0d10v5_b__tt +nhv_rf_base_m2_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM02 +nhv_rf_base_m4_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM04 +nhv_w3p0_l0p5_m2,sky130_fd_pr__nfet_g5v0d10v5_aM02W3p00L0p50 +nhv_w3p0_l0p5_m4,sky130_fd_pr__nfet_g5v0d10v5_aM04W3p00L0p50 +nhv_w5p0_l0p5_m2,sky130_fd_pr__nfet_g5v0d10v5_aM02W5p00L0p50 +nhv_w5p0_l0p5_m4,sky130_fd_pr__nfet_g5v0d10v5_aM04W5p00L0p50 +nhv_w7p0_l0p5_m4,sky130_fd_pr__nfet_g5v0d10v5_aM04W7p00L0p50 +nhvnative_ttleak,sky130_fd_pr__nfet_05v0_nvt__tt_leak +nlowvt_rf_base_b,sky130_fd_pr__rf_nfet_01v8_lvt_b +nlowvt_ttcorreln,sky130_fd_pr__nfet_01v8_lvt__tt_correln +nlowvt_ttcorrelp,sky130_fd_pr__nfet_01v8_lvt__tt_correlp +nlrf_1p65p15m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W1p65L0p15 +nlrf_1p65p15m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W1p65L0p15 +nlrf_1p65p18m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W1p65L0p18 +nlrf_1p65p18m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W1p65L0p18 +nlrf_1p65p25m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W1p65L0p25 +nlrf_1p65p25m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W1p65L0p25 +nshort_rf_base_b,sky130_fd_pr__rf_nfet_01v8_b +nshort_ttcorreln,sky130_fd_pr__nfet_01v8__tt_correln +nshort_ttcorrelp,sky130_fd_pr__nfet_01v8__tt_correlp +nshortesd_ttleak,sky130_fd_pr__esd_nfet_01v8__tt_leak +nsrf_1p65p15m2_b,sky130_fd_pr__rf_nfet_01v8_bM02W1p65L0p15 +nsrf_1p65p15m4_b,sky130_fd_pr__rf_nfet_01v8_bM04W1p65L0p15 +nsrf_1p65p18m2_b,sky130_fd_pr__rf_nfet_01v8_bM02W1p65L0p18 +nsrf_1p65p18m4_b,sky130_fd_pr__rf_nfet_01v8_bM04W1p65L0p18 +nsrf_1p65p25m2_b,sky130_fd_pr__rf_nfet_01v8_bM02W1p65L0p25 +nsrf_1p65p25m4_b,sky130_fd_pr__rf_nfet_01v8_bM04W1p65L0p25 +nvhv_ff_discrete,sky130_fd_pr__nfet_g5v0d16v0__ff_discrete +nvhv_fs_discrete,sky130_fd_pr__nfet_g5v0d16v0__fs_discrete +nvhv_sf_discrete,sky130_fd_pr__nfet_g5v0d16v0__sf_discrete +nvhv_ss_discrete,sky130_fd_pr__nfet_g5v0d16v0__ss_discrete +nvhv_tt_discrete,sky130_fd_pr__nfet_g5v0d16v0__tt_discrete +p20vhv1_withptap,sky130_fd_pr__pfet_20v0_withptap +plowvt_ttcorreln,sky130_fd_pr__pfet_01v8_lvt__tt_correln +plowvt_ttcorrelp,sky130_fd_pr__pfet_01v8_lvt__tt_correlp +pmedlvt_rf_wafer,sky130_fd_pr__rf_pfet_01v8_mvt__wafer +pshort_rf_base_b,sky130_fd_pr__rf_pfet_01v8_b +pshort_ttcorreln,sky130_fd_pr__pfet_01v8__tt_correln +pshort_ttcorrelp,sky130_fd_pr__pfet_01v8__tt_correlp +psrf_1p65p15m2_b,sky130_fd_pr__rf_pfet_01v8_bM02W1p65L0p15 +psrf_1p65p15m4_b,sky130_fd_pr__rf_pfet_01v8_bM04W1p65L0p15 +psrf_1p65p18m2_b,sky130_fd_pr__rf_pfet_01v8_bM02W1p65L0p18 +psrf_1p65p18m4_b,sky130_fd_pr__rf_pfet_01v8_bM04W1p65L0p18 +psrf_1p65p25m2_b,sky130_fd_pr__rf_pfet_01v8_bM02W1p65L0p25 +psrf_1p65p25m4_b,sky130_fd_pr__rf_pfet_01v8_bM04W1p65L0p25 +rf2_xcmvpp6p8x6p,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2_noshield +rf_xcmvpp1_nwell,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_shieldnw_nwell +rf_xcmvpp1p8x1p8,sky130_fd_pr__cap_vpp_01p8x01p8_m1m2_noshield +rf_xcmvpp2_nwell,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_shieldnw_o1well +rf_xcmvpp4p4x4p6,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_noshield +rf_xcmvpp6p8x6p1,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2_noshield +rf_xcmvpp8p6x7p9,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield +s8blref_xind4_01,sky130_fd_pr__ind_01_04 +s8rf2_xcmvpp_hd5,sky130_fd_pr__cap_vpp_11p5x11p7_pol1m1m2m3m4m5_noshield_base +s8rf_n20vhv1_aup,sky130_fd_pr__rf_nfet_20v0_aup +s8rf_n20vhv1_esd,sky130_fd_pr__esd_rf_nfet_20v0 +s8rf_nlowvt_w3p0,sky130_fd_pr__rf_nfet_01v8_lvt_aW3p00 +s8rf_nlowvt_w5p0,sky130_fd_pr__rf_nfet_01v8_lvt_aW5p00 +s8rf_npn_1x1_2p0,sky130_fd_pr__rf_npn_05v5_W1p00L1p00 +s8rf_nshort_w3p0,sky130_fd_pr__rf_nfet_01v8_aW3p00 +s8rf_nshort_w5p0,sky130_fd_pr__rf_nfet_01v8_aW5p00 +s8rf_plowvt_w3p0,sky130_fd_pr__rf_pfet_01v8_lvt_aW3p00 +s8rf_plowvt_w5p0,sky130_fd_pr__rf_pfet_01v8_lvt_aW5p00 +s8rf_pshort_w2p0,sky130_fd_pr__rf_pfet_01v8_aW2p00 +s8rf_pshort_w3p0,sky130_fd_pr__rf_pfet_01v8_aW3p00 +s8rf_pshort_w5p0,sky130_fd_pr__rf_pfet_01v8_aW5p00 +xcmvpp4p4x4p6_m3,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2m3_noshield +xcmvpp8p6x7p9_m3,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2m3_noshield +xcmvpp_atlas_top,sky130_fd_pr__model__cap_vpp_finger +xcmvpp_ponly_top,sky130_fd_pr__model__cap_vpp_only_p +dnwdiode_p20vhv,sky130_fd_pr__pfet_20v0__parasitic__diode_pw2dn +dnwdiode_pw_top,sky130_fd_pr__model__parasitic__diodes_pw2dn +dnwhvdiode_psub,sky130_fd_pr__model__parasitic__diode_ps2dn__hv +n20nativevhv_fs,sky130_fd_pr__nfet_20v0_nvt__fs +n20nativevhv_sf,sky130_fd_pr__nfet_20v0_nvt__sf +n20nativevhv_tt,sky130_fd_pr__nfet_20v0_nvt__tt +n20nativevhviso,sky130_fd_pr__nfet_20v0_nvt_iso +n20vhv1_esd_hbm,sky130_fd_pr__esd_nfet_20v0_hbm +n20vhv1_esd_iec,sky130_fd_pr__esd_nfet_20v0_iec +n20vhv_withptap,sky130_fd_pr__nfet_20v0_withptap +n20zvtvhv1_leak,sky130_fd_pr__nfet_20v0_zvt__leak +nhv_ff_discrete,sky130_fd_pr__nfet_g5v0d10v5__ff_discrete +nhv_fs_discrete,sky130_fd_pr__nfet_g5v0d10v5__fs_discrete +nhv_rf_base_m10,sky130_fd_pr__rf_nfet_g5v0d10v5_aM10 +nhv_sf_discrete,sky130_fd_pr__nfet_g5v0d10v5__sf_discrete +nhv_ss_discrete,sky130_fd_pr__nfet_g5v0d10v5__ss_discrete +nhv_tt_discrete,sky130_fd_pr__nfet_g5v0d10v5__tt_discrete +nhvnative_wafer,sky130_fd_pr__nfet_05v0_nvt__wafer +nhvrf_3p50m10_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM10W3p00L0p50 +nhvrf_5p50m10_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM10W5p00L0p50 +nhvrf_7p50m10_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM10W7p00L0p50 +nshortesd_wafer,sky130_fd_pr__esd_nfet_01v8__wafer +ntvnative_wafer,sky130_fd_pr__nfet_03v3_nvt__wafer +nvhv_subcircuit,sky130_fd_pr__nfet_g5v0d16v0__subcircuit +par_polyres_sub,sky130_fd_pr__model__parasitic__res_po +phighvt_subvtmm,sky130_fd_pr__pfet_01v8_hvt__subvt_mismatch +phv_ff_discrete,sky130_fd_pr__pfet_g5v0d10v5__ff_discrete +phv_fs_discrete,sky130_fd_pr__pfet_g5v0d10v5__fs_discrete +phv_sf_discrete,sky130_fd_pr__pfet_g5v0d10v5__sf_discrete +phv_ss_discrete,sky130_fd_pr__pfet_g5v0d10v5__ss_discrete +phv_tt_discrete,sky130_fd_pr__pfet_g5v0d10v5__tt_discrete +pmedlvt_rf_leak,sky130_fd_pr__rf_pfet_01v8_mvt__leak +psrf_1p68p15nf2,sky130_fd_pr__rf_pfet_01v8_aF02W1p68L0p15 +psrf_1p68p15nf4,sky130_fd_pr__rf_pfet_01v8_aF04W1p68L0p15 +pvhv_subcircuit,sky130_fd_pr__pfet_g5v0d16v0__subcircuit +rf_xcmvpp6p8x6p,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2_noshield +s8rf_n20vhviso1,sky130_fd_pr__rf_nfet_20v0_iso +s8rf_n20zvtvhv1,sky130_fd_pr__rf_nfet_20v0_zvt +xcmvpp11p5x11p7,sky130_fd_pr__cap_vpp_11p5x11p7_l1m1m2_noshield +xcmvpp1_raphael,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield_o1raphael +xcmvpp1_subcell,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield_o1subcell +xcmvpp2_raphael,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_noshield_o1raphael +xcmvpp2_subcell,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_noshield_o1subcell +xcmvpp3_raphael,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2_noshield_raphael +xcmvpp4_raphael,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield_o2raphael +xcmvpp5_raphael,sky130_fd_pr__cap_vpp_02p4x04p6_m1m2_noshield_raphael +xdnwdiode_pwell,sky130_fd_pr__model__parasitic__diode_pw2dn +condiodehvpsub,sky130_fd_pr__model__parasitic__diode_ps2dn_highvoltage +n20vhv_esd_hbm,sky130_fd_pr__esd_nfet_20v0_hbm +n20vhv_esd_iec,sky130_fd_pr__esd_nfet_20v0_iec +n20zvtvhv_leak,sky130_fd_pr__nfet_20v0_zvt__leak +nhv_rf_base_m2,sky130_fd_pr__rf_nfet_g5v0d10v5_aM02 +nhv_rf_base_m4,sky130_fd_pr__rf_nfet_g5v0d10v5_aM04 +nhvnative_leak,sky130_fd_pr__nfet_05v0_nvt__leak +nhvrf_3p50m2_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM02W3p00L0p50 +nhvrf_3p50m4_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM04W3p00L0p50 +nhvrf_5p50m2_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM02W5p00L0p50 +nhvrf_5p50m4_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM04W5p00L0p50 +nhvrf_7p50m4_b,sky130_fd_pr__rf_nfet_g5v0d10v5_bM04W7p00L0p50 +nlowvt_rf_base,sky130_fd_pr__rf_nfet_01v8_lvt__base +nlowvt_subvtmm,sky130_fd_pr__nfet_01v8_lvt__subvt_mismatch +nlrf_1p65p15m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02W1p65L0p15 +nlrf_1p65p15m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04W1p65L0p15 +nlrf_1p65p18m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02W1p65L0p18 +nlrf_1p65p18m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04W1p65L0p18 +nlrf_1p65p25m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02W1p65L0p25 +nlrf_1p65p25m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04W1p65L0p25 +nlrf_p42p15nf2,sky130_fd_pr__rf_nfet_01v8_lvt_aF02W0p42L0p15 +nlrf_p84p15nf2,sky130_fd_pr__rf_nfet_01v8_lvt_aF02W0p84L0p15 +nlrf_p84p15nf4,sky130_fd_pr__rf_nfet_01v8_lvt_aF04W0p84L0p15 +nlrf_p84p15nf8,sky130_fd_pr__rf_nfet_01v8_lvt_aF08W0p84L0p15 +nlvtpass_wafer,sky130_fd_pr__special_nfet_pass_lvt__wafer +npn_1x1_2p0_hv,sky130_fd_pr__npn_11v0_W1p00L1p00 +nshort_rf_base,sky130_fd_pr__rf_nfet_01v8__base +nshort_subvtmm,sky130_fd_pr__nfet_01v8__subvt_mismatch +nshortesd_leak,sky130_fd_pr__esd_nfet_01v8__leak +nsrf_1p65p15m2,sky130_fd_pr__rf_nfet_01v8_aM02W1p65L0p15 +nsrf_1p65p15m4,sky130_fd_pr__rf_nfet_01v8_aM04W1p65L0p15 +nsrf_1p65p18m2,sky130_fd_pr__rf_nfet_01v8_aM02W1p65L0p18 +nsrf_1p65p18m4,sky130_fd_pr__rf_nfet_01v8_aM04W1p65L0p18 +nsrf_1p65p25m2,sky130_fd_pr__rf_nfet_01v8_aM02W1p65L0p25 +nsrf_1p65p25m4,sky130_fd_pr__rf_nfet_01v8_aM04W1p65L0p25 +phighvt_ttleak,sky130_fd_pr__pfet_01v8_hvt__tt_leak +plowvt_subvtmm,sky130_fd_pr__pfet_01v8_lvt__subvt_mismatch +pshort_rf_base,sky130_fd_pr__rf_pfet_01v8__base +pshort_subvtmm,sky130_fd_pr__pfet_01v8__subvt_mismatch +psrf_1p65p15m2,sky130_fd_pr__rf_pfet_01v8_aM02W1p65L0p15 +psrf_1p65p15m4,sky130_fd_pr__rf_pfet_01v8_aM04W1p65L0p15 +psrf_1p65p18m2,sky130_fd_pr__rf_pfet_01v8_aM02W1p65L0p18 +psrf_1p65p18m4,sky130_fd_pr__rf_pfet_01v8_aM04W1p65L0p18 +psrf_1p65p25m2,sky130_fd_pr__rf_pfet_01v8_aM02W1p65L0p25 +psrf_1p65p25m4,sky130_fd_pr__rf_pfet_01v8_aM04W1p65L0p25 +psrf_p84p15nf2,sky130_fd_pr__rf_pfet_01v8_aF02W0p84L0p15 +rf2_xcmvpp_hd5,sky130_fd_pr__cap_vpp_11p5x11p7_pol1m1m2m3m4m5_noshield_base +s8rf2_xcmvppx4,sky130_fd_pr__cap_vpp_11p3x11p8_l1m1m2m3m4_shieldm5_nhv +sonos_bol_e_mm,sky130_fd_bs_flash__special_sonosfet_star__bol_mismatch +sonos_bol_p_mm,sky130_fd_bs_flash__special_sonosfet_original__bol_mismatch +sonos_ffteol_e,sky130_fd_bs_flash__special_sonosfet_star__ff_teol +sonos_ffteol_p,sky130_fd_bs_flash__special_sonosfet_original__ff_teol +sonos_ssteol_e,sky130_fd_bs_flash__special_sonosfet_star__ss_teol +sonos_ssteol_p,sky130_fd_bs_flash__special_sonosfet_original__ss_teol +sonos_ttteol_e,sky130_fd_bs_flash__special_sonosfet_star__tt_teol +sonos_ttteol_p,sky130_fd_bs_flash__special_sonosfet_original__tt_teol +xcmvpp2_phv5x4,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield_o1phv +xcmvpp_hd5_1x1,sky130_fd_pr__cap_vpp_11p5x11p7_pol1m1m2m3m4m5_noshield +xcmvpp_hd5_1x2,sky130_fd_pr__cap_vpp_11p5x23p1_pol1m1m2m3m4m5_noshield +xcmvpp_hd5_2x1,sky130_fd_pr__cap_vpp_22p5x11p7_pol1m1m2m3m4m5_noshield +xcmvpp_hd5_2x2,sky130_fd_pr__cap_vpp_22p5x23p1_pol1m1m2m3m4m5_noshield +xcmvpp_hd5_3x1,sky130_fd_pr__cap_vpp_33p6x11p7_pol1m1m2m3m4m5_noshield +xcmvpp_hd5_3x2,sky130_fd_pr__cap_vpp_33p6x23p1_pol1m1m2m3m4m5_noshield +xcmvpp_hd5_4x1,sky130_fd_pr__cap_vpp_44p7x11p7_pol1m1m2m3m4m5_noshield +xcmvpp_hd5_4x2,sky130_fd_pr__cap_vpp_44p7x23p1_pol1m1m2m3m4m5_noshield +xcmvpp_hd5_5x1,sky130_fd_pr__cap_vpp_55p8x11p7_pol1m1m2m3m4m5_noshield +xcmvpp_hd5_5x2,sky130_fd_pr__cap_vpp_55p8x23p1_pol1m1m2m3m4m5_noshield +dnwdiode_psub,sky130_fd_pr__model__parasitic__diode_ps2dn +dnwdiode_pvhv,sky130_fd_pr__pfet_g5v0d16v0__parasitic__diode_pw2dn +n20nativevhv1,sky130_fd_pr__nfet_20v0_nvt +n20zvtvhv1_fs,sky130_fd_pr__nfet_20v0_zvt__fs +n20zvtvhv1_sf,sky130_fd_pr__nfet_20v0_zvt__sf +n20zvtvhv1_tt,sky130_fd_pr__nfet_20v0_zvt__tt +ndiode_native,sky130_fd_pr__diode_pw2nd_05v5_nvt +nfet_symbolic,sky130_fd_pr__nfet_01v8__symbolic +nhv_rf_base_b,sky130_fd_pr__rf_nfet_g5v0d10v5_b +nhv_ttcorreln,sky130_fd_pr__nfet_g5v0d10v5__tt_correln +nhv_ttcorrelp,sky130_fd_pr__nfet_g5v0d10v5__tt_correlp +nhv_w3p0_l0p5,sky130_fd_pr__nfet_g5v0d10v5_aW3p00L0p50 +nhv_w5p0_l0p5,sky130_fd_pr__nfet_g5v0d10v5_aW5p00L0p50 +nhv_w7p0_l0p5,sky130_fd_pr__nfet_g5v0d10v5_aW7p00L0p50 +nhvesd_ttleak,sky130_fd_pr__esd_nfet_g5v0d10v5__tt_leak +nhvrf_3p50m10,sky130_fd_pr__rf_nfet_g5v0d10v5_aM10W3p00L0p50 +nhvrf_5p50m10,sky130_fd_pr__rf_nfet_g5v0d10v5_aM10W5p00L0p50 +nhvrf_7p50m10,sky130_fd_pr__rf_nfet_g5v0d10v5_aM10W7p00L0p50 +nlowvt_ttleak,sky130_fd_pr__nfet_01v8_lvt__tt_leak +nlrf_3p15m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W3p00L0p15 +nlrf_3p15m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W3p00L0p15 +nlrf_3p18m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W3p00L0p18 +nlrf_3p18m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W3p00L0p18 +nlrf_3p25m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W3p00L0p25 +nlrf_3p25m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W3p00L0p25 +nlrf_5p15m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W5p00L0p15 +nlrf_5p15m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W5p00L0p15 +nlrf_5p18m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W5p00L0p18 +nlrf_5p18m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W5p00L0p18 +nlrf_5p25m2_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM02W5p00L0p25 +nlrf_5p25m4_b,sky130_fd_pr__rf_nfet_01v8_lvt_bM04W5p00L0p25 +nlvtpass_leak,sky130_fd_pr__special_nfet_pass_lvt__leak +npnpar_polyhv,sky130_fd_pr__npn_11v0_W1p00L1p00 +nshort_ttleak,sky130_fd_pr__nfet_01v8__tt_leak +nsrf_3p15m2_b,sky130_fd_pr__rf_nfet_01v8_bM02W3p00L0p15 +nsrf_3p15m4_b,sky130_fd_pr__rf_nfet_01v8_bM04W3p00L0p15 +nsrf_3p18m2_b,sky130_fd_pr__rf_nfet_01v8_bM02W3p00L0p18 +nsrf_3p18m4_b,sky130_fd_pr__rf_nfet_01v8_bM04W3p00L0p18 +nsrf_3p25m2_b,sky130_fd_pr__rf_nfet_01v8_bM02W3p00L0p25 +nsrf_3p25m4_b,sky130_fd_pr__rf_nfet_01v8_bM04W3p00L0p25 +nsrf_5p15m2_b,sky130_fd_pr__rf_nfet_01v8_bM02W5p00L0p15 +nsrf_5p15m4_b,sky130_fd_pr__rf_nfet_01v8_bM04W5p00L0p15 +nsrf_5p18m2_b,sky130_fd_pr__rf_nfet_01v8_bM02W5p00L0p18 +nsrf_5p18m4_b,sky130_fd_pr__rf_nfet_01v8_bM04W5p00L0p18 +nsrf_5p25m2_b,sky130_fd_pr__rf_nfet_01v8_bM02W5p00L0p25 +nsrf_5p25m4_b,sky130_fd_pr__rf_nfet_01v8_bM04W5p00L0p25 +nwdiode_no_rs,sky130_fd_pr__model__parasitic__diode_ps2nw_nors +pfet_symbolic,sky130_fd_pr__pfet_01v8__symbolic +phighvt_wafer,sky130_fd_pr__pfet_01v8_hvt__wafer +phvesd_ttleak,sky130_fd_pr__esd_pfet_g5v0d10v5__tt_leak +plowvt_ttleak,sky130_fd_pr__pfet_01v8_lvt__tt_leak +pmedlvt_rf_ff,sky130_fd_pr__rf_pfet_01v8_mvt__ff +pmedlvt_rf_fs,sky130_fd_pr__rf_pfet_01v8_mvt__fs +pmedlvt_rf_mm,sky130_fd_pr__rf_pfet_01v8_mvt__mismatch +pmedlvt_rf_sf,sky130_fd_pr__rf_pfet_01v8_mvt__sf +pmedlvt_rf_ss,sky130_fd_pr__rf_pfet_01v8_mvt__ss +pmedlvt_rf_tt,sky130_fd_pr__rf_pfet_01v8_mvt__tt +pmedlvt_w0p84,sky130_fd_pr__pfet_01v8_mvt_aW0p84 +pmedlvt_w1p68,sky130_fd_pr__pfet_01v8_mvt_aW1p68 +pshort_ttleak,sky130_fd_pr__pfet_01v8__tt_leak +psrf_3p15m2_b,sky130_fd_pr__rf_pfet_01v8_bM02W3p00L0p15 +psrf_3p15m4_b,sky130_fd_pr__rf_pfet_01v8_bM04W3p00L0p15 +psrf_3p18m2_b,sky130_fd_pr__rf_pfet_01v8_bM02W3p00L0p18 +psrf_3p18m4_b,sky130_fd_pr__rf_pfet_01v8_bM04W3p00L0p18 +psrf_3p25m2_b,sky130_fd_pr__rf_pfet_01v8_bM02W3p00L0p25 +psrf_3p25m4_b,sky130_fd_pr__rf_pfet_01v8_bM04W3p00L0p25 +psrf_5p15m2_b,sky130_fd_pr__rf_pfet_01v8_bM02W5p00L0p15 +psrf_5p15m4_b,sky130_fd_pr__rf_pfet_01v8_bM04W5p00L0p15 +psrf_5p18m2_b,sky130_fd_pr__rf_pfet_01v8_bM02W5p00L0p18 +psrf_5p18m4_b,sky130_fd_pr__rf_pfet_01v8_bM04W5p00L0p18 +psrf_5p25m2_b,sky130_fd_pr__rf_pfet_01v8_bM02W5p00L0p25 +psrf_5p25m4_b,sky130_fd_pr__rf_pfet_01v8_bM04W5p00L0p25 +rf2_xind4_011,sky130_fd_pr__ind_11_04 +rf_xcmvpp_hd5,sky130_fd_pr__cap_vpp_11p5x11p7_pol1m1m2m3m4m5_noshield_base +s8rf2_xcmvpp3,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2_noshield +s8rf2_xcmvpp4,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield_o2 +s8rf2_xcmvpp5,sky130_fd_pr__cap_vpp_02p4x04p6_m1m2_noshield +s8rf2_xcmvpp6,sky130_fd_pr__cap_vpp_02p4x04p6_m1m2_shieldpom3 +s8rf_nhv_w3p0,sky130_fd_pr__rf_nfet_g5v0d10v5_aW3p00 +s8rf_nhv_w5p0,sky130_fd_pr__rf_nfet_g5v0d10v5_aW5p00 +s8rf_nhv_w7p0,sky130_fd_pr__rf_nfet_g5v0d10v5_aW7p00 +sonos_ffeol_e,sky130_fd_bs_flash__special_sonosfet_star__ff_eol +sonos_ffeol_p,sky130_fd_bs_flash__special_sonosfet_original__ff_eol +sonos_sseol_e,sky130_fd_bs_flash__special_sonosfet_star__ss_eol +sonos_sseol_p,sky130_fd_bs_flash__special_sonosfet_original__ss_eol +sonos_tteol_e,sky130_fd_bs_flash__special_sonosfet_star__tt_eol +sonos_tteol_p,sky130_fd_bs_flash__special_sonosfet_original__tt_eol +xcmvpp1_nwell,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_shieldnw_nwell +xcmvpp1p8x1p8,sky130_fd_pr__cap_vpp_01p8x01p8_m1m2_noshield +xcmvpp2_nwell,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_shieldnw_o1well +xcmvpp4p4x4p6,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_noshield +xcmvpp6p8x6p1,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2_noshield +xcmvpp8p6x7p9,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield +xcmvpp_moscap,sky130_fd_pr__model__cap_vpp_only_mos +xcmvpp_pqonly,sky130_fd_pr__model__cap_vpp_only_pq +xesd_ndiode_h,sky130_fd_pr__esd_rf_diode_pw2nd_11v0 +xesd_pdiode_h,sky130_fd_pr__esd_rf_diode_pd2nw_11v0 +xuhrpoly_0p35,sky130_fd_pr__res_xhigh_po_0p35 +xuhrpoly_0p69,sky130_fd_pr__res_xhigh_po_0p69 +xuhrpoly_1p41,sky130_fd_pr__res_xhigh_po_1p41 +xuhrpoly_2p85,sky130_fd_pr__res_xhigh_po_2p85 +xuhrpoly_5p73,sky130_fd_pr__res_xhigh_po_5p73 +n20nativevhv,sky130_fd_pr__nfet_20v0_nvt +n20vhv_wafer,sky130_fd_pr__nfet_20v0__wafer +n20zvtvhv_fs,sky130_fd_pr__nfet_20v0_zvt__fs +n20zvtvhv_sf,sky130_fd_pr__nfet_20v0_zvt__sf +n20zvtvhv_tt,sky130_fd_pr__nfet_20v0_zvt__tt +ndiode_defet,sky130_fd_pr__diode_pw2nd_05v5__extended_drain +nhvesd_wafer,sky130_fd_pr__esd_nfet_g5v0d10v5__wafer +nhvnative_ff,sky130_fd_pr__nfet_05v0_nvt__ff +nhvnative_fs,sky130_fd_pr__nfet_05v0_nvt__fs +nhvnative_mm,sky130_fd_pr__nfet_05v0_nvt__mismatch +nhvnative_sf,sky130_fd_pr__nfet_05v0_nvt__sf +nhvnative_ss,sky130_fd_pr__nfet_05v0_nvt__ss +nhvnative_tt,sky130_fd_pr__nfet_05v0_nvt__tt +nhvnativeesd,sky130_fd_pr__esd_nfet_05v0_nvt +nhvrf_3p50m2,sky130_fd_pr__rf_nfet_g5v0d10v5_aM02W3p00L0p50 +nhvrf_3p50m4,sky130_fd_pr__rf_nfet_g5v0d10v5_aM04W3p00L0p50 +nhvrf_5p50m2,sky130_fd_pr__rf_nfet_g5v0d10v5_aM02W5p00L0p50 +nhvrf_5p50m4,sky130_fd_pr__rf_nfet_g5v0d10v5_aM04W5p00L0p50 +nhvrf_7p50m4,sky130_fd_pr__rf_nfet_g5v0d10v5_aM04W7p00L0p50 +nlowvt_rf_mm,sky130_fd_pr__rf_nfet_01v8_lvt__mismatch +nlowvt_w0p42,sky130_fd_pr__nfet_01v8_lvt_aW0p42 +nlowvt_w0p84,sky130_fd_pr__nfet_01v8_lvt_aW0p84 +nlowvt_w1p65,sky130_fd_pr__nfet_01v8_lvt_aW1p65 +nlowvt_wafer,sky130_fd_pr__nfet_01v8_lvt__wafer +nlrf_3p15nf2,sky130_fd_pr__rf_nfet_01v8_lvt_aF02W3p00L0p15 +nlrf_3p15nf4,sky130_fd_pr__rf_nfet_01v8_lvt_aF04W3p00L0p15 +nlrf_3p15nf8,sky130_fd_pr__rf_nfet_01v8_lvt_aF08W3p00L0p15 +nshort_rf_mm,sky130_fd_pr__rf_nfet_01v8__mismatch +nshort_w1p65,sky130_fd_pr__nfet_01v8_aW1p65 +nshort_wafer,sky130_fd_pr__nfet_01v8__wafer +nshortesd_ff,sky130_fd_pr__esd_nfet_01v8__ff +nshortesd_fs,sky130_fd_pr__esd_nfet_01v8__fs +nshortesd_sf,sky130_fd_pr__esd_nfet_01v8__sf +nshortesd_ss,sky130_fd_pr__esd_nfet_01v8__ss +nshortesd_tt,sky130_fd_pr__esd_nfet_01v8__tt +ntvnative_ff,sky130_fd_pr__nfet_03v3_nvt__ff +ntvnative_fs,sky130_fd_pr__nfet_03v3_nvt__fs +ntvnative_mm,sky130_fd_pr__nfet_03v3_nvt__mismatch +ntvnative_sf,sky130_fd_pr__nfet_03v3_nvt__sf +ntvnative_ss,sky130_fd_pr__nfet_03v3_nvt__ss +ntvnative_tt,sky130_fd_pr__nfet_03v3_nvt__tt +phighvt_leak,sky130_fd_pr__pfet_01v8_hvt__leak +phvesd_wafer,sky130_fd_pr__esd_pfet_g5v0d10v5__wafer +plowvt_wafer,sky130_fd_pr__pfet_01v8_lvt__wafer +pshort_rf_mm,sky130_fd_pr__rf_pfet_01v8__mismatch +pshort_w0p84,sky130_fd_pr__pfet_01v8_aW0p84 +pshort_w1p65,sky130_fd_pr__pfet_01v8_aW1p65 +pshort_w1p68,sky130_fd_pr__pfet_01v8_aW1p68 +pshort_wafer,sky130_fd_pr__pfet_01v8__wafer +psrf_3p15nf2,sky130_fd_pr__rf_pfet_01v8_aF02W3p00L0p15 +psrf_5p15nf2,sky130_fd_pr__rf_pfet_01v8_aF02W5p00L0p15 +rf2_mimcap34,sky130_fd_pr__cap_mim_m3__base +rf2_mimcap45,sky130_fd_pr__cap_mim_m4__base +rf2_xcmim2c1,sky130_fd_pr__cap_mim_m4_1 +rf2_xcmim2c2,sky130_fd_pr__cap_mim_m4_2 +rf2_xcmvpp_2,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_noshield_o1 +rf2_xcmvppx4,sky130_fd_pr__cap_vpp_11p3x11p8_l1m1m2m3m4_shieldm5_nhv +rf2_xind4_02,sky130_fd_pr__ind_02_04 +rf_xind4_011,sky130_fd_pr__ind_11_04 +s8rf2_xcmvpp,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield_o1 +s8rf_n20vhv1,sky130_fd_pr__rf_nfet_20v0 +s8rf_npn_1x1,sky130_fd_pr__rf_npn_05v5_W1p00L1p00 +s8rf_npn_1x2,sky130_fd_pr__rf_npn_05v5_W1p00L2p00 +s8rf_npn_1x4,sky130_fd_pr__rf_npn_05v5_W1p00L4p00 +s8rf_npn_1x8,sky130_fd_pr__rf_npn_05v5_W1p00L8p00 +s8rf_npn_2x2,sky130_fd_pr__rf_npn_05v5_W2p00L2p00 +s8rf_npn_2x4,sky130_fd_pr__rf_npn_05v5_W2p00L4p00 +s8rf_npn_2x8,sky130_fd_pr__rf_npn_05v5_W2p00L8p00 +s8rf_npn_5x5,sky130_fd_pr__rf_npn_05v5_W5p00L5p00 +s8rf_p20vhv1,sky130_fd_pr__rf_pfet_20v0 +s8rf_pmedlvt,sky130_fd_pr__rf_pfet_01v8_mvt +s8rf_xcmvpp1,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield_o2 +s8rf_xcmvpp2,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_noshield_o2 +sonos_tbol_e,sky130_fd_bs_flash__special_sonosfet_star__tbol +sonos_tbol_p,sky130_fd_bs_flash__special_sonosfet_original__tbol +sonos_wbol_e,sky130_fd_bs_flash__special_sonosfet_star__wbol +sonos_wbol_p,sky130_fd_bs_flash__special_sonosfet_original__wbol +uhrpoly_0p35,sky130_fd_pr__res_xhigh_po_0p35 +uhrpoly_0p69,sky130_fd_pr__res_xhigh_po_0p69 +uhrpoly_1p41,sky130_fd_pr__res_xhigh_po_1p41 +uhrpoly_2p85,sky130_fd_pr__res_xhigh_po_2p85 +uhrpoly_5p73,sky130_fd_pr__res_xhigh_po_5p73 +xcmvpp6p8x6p,sky130_fd_pr__cap_vpp_06p8x06p1_l1m1m2_noshield +xcmvpp_atlas,sky130_fd_pr__model__cap_vpp_finger +xcmvpp_ponly,sky130_fd_pr__model__cap_vpp_only_p +xhrpoly_0p35,sky130_fd_pr__res_high_po_0p35 +xhrpoly_0p69,sky130_fd_pr__res_high_po_0p69 +xhrpoly_1p41,sky130_fd_pr__res_high_po_1p41 +xhrpoly_2p85,sky130_fd_pr__res_high_po_2p85 +xhrpoly_5p73,sky130_fd_pr__res_high_po_5p73 +dnwdiode_pw,sky130_fd_pr__model__parasitic__diode_pw2dn +hrpoly_0p35,sky130_fd_pr__res_high_po_0p35 +hrpoly_0p69,sky130_fd_pr__res_high_po_0p69 +hrpoly_1p41,sky130_fd_pr__res_high_po_1p41 +hrpoly_2p85,sky130_fd_pr__res_high_po_2p85 +hrpoly_5p73,sky130_fd_pr__res_high_po_5p73 +isopwellres,sky130_fd_pr__res_iso_pw +n20vhv1_aup,sky130_fd_pr__nfet_20v0_aup +n20vhv1_esd,sky130_fd_pr__esd_nfet_20v0 +n20vhv_leak,sky130_fd_pr__nfet_20v0__leak +nhv_rf_base,sky130_fd_pr__rf_nfet_g5v0d10v5__base +nhvesd_leak,sky130_fd_pr__esd_nfet_g5v0d10v5__leak +nlowvt_leak,sky130_fd_pr__nfet_01v8_lvt__leak +nlowvt_w3p0,sky130_fd_pr__nfet_01v8_lvt_aW3p00 +nlowvt_w5p0,sky130_fd_pr__nfet_01v8_lvt_aW5p00 +nlrf_3p15m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02W3p00L0p15 +nlrf_3p15m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04W3p00L0p15 +nlrf_3p18m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02W3p00L0p18 +nlrf_3p18m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04W3p00L0p18 +nlrf_3p25m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02W3p00L0p25 +nlrf_3p25m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04W3p00L0p25 +nlrf_5p15m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02W5p00L0p15 +nlrf_5p15m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04W5p00L0p15 +nlrf_5p18m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02W5p00L0p18 +nlrf_5p18m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04W5p00L0p18 +nlrf_5p25m2,sky130_fd_pr__rf_nfet_01v8_lvt_aM02W5p00L0p25 +nlrf_5p25m4,sky130_fd_pr__rf_nfet_01v8_lvt_aM04W5p00L0p25 +nlvtpass_ff,sky130_fd_pr__special_nfet_pass_lvt__ff +nlvtpass_ss,sky130_fd_pr__special_nfet_pass_lvt__ss +nlvtpass_tt,sky130_fd_pr__special_nfet_pass_lvt__tt +npn_1x1_2p0,sky130_fd_pr__npn_05v5_W1p00L1p00 +nshort_leak,sky130_fd_pr__nfet_01v8__leak +nshort_w3p0,sky130_fd_pr__nfet_01v8_aW3p00 +nshort_w5p0,sky130_fd_pr__nfet_01v8_aW5p00 +nsrf_3p15m2,sky130_fd_pr__rf_nfet_01v8_aM02W3p00L0p15 +nsrf_3p15m4,sky130_fd_pr__rf_nfet_01v8_aM04W3p00L0p15 +nsrf_3p18m2,sky130_fd_pr__rf_nfet_01v8_aM02W3p00L0p18 +nsrf_3p18m4,sky130_fd_pr__rf_nfet_01v8_aM04W3p00L0p18 +nsrf_3p25m2,sky130_fd_pr__rf_nfet_01v8_aM02W3p00L0p25 +nsrf_3p25m4,sky130_fd_pr__rf_nfet_01v8_aM04W3p00L0p25 +nsrf_5p15m2,sky130_fd_pr__rf_nfet_01v8_aM02W5p00L0p15 +nsrf_5p15m4,sky130_fd_pr__rf_nfet_01v8_aM04W5p00L0p15 +nsrf_5p18m2,sky130_fd_pr__rf_nfet_01v8_aM02W5p00L0p18 +nsrf_5p18m4,sky130_fd_pr__rf_nfet_01v8_aM04W5p00L0p18 +nsrf_5p25m2,sky130_fd_pr__rf_nfet_01v8_aM02W5p00L0p25 +nsrf_5p25m4,sky130_fd_pr__rf_nfet_01v8_aM04W5p00L0p25 +nvhv_ttleak,sky130_fd_pr__nfet_g5v0d16v0__tt_leak +p20vhv_leak,sky130_fd_pr__pfet_20v0__leak +phv_subvtmm,sky130_fd_pr__pfet_g5v0d10v5__subvt_mismatch +phvesd_leak,sky130_fd_pr__esd_pfet_g5v0d10v5__leak +plowvt_leak,sky130_fd_pr__pfet_01v8_lvt__leak +plowvt_w3p0,sky130_fd_pr__pfet_01v8_lvt_aW3p00 +plowvt_w5p0,sky130_fd_pr__pfet_01v8_lvt_aW5p00 +polyres_sub,sky130_fd_pr__res_high_po__subcell +pshort_leak,sky130_fd_pr__pfet_01v8__leak +pshort_w2p0,sky130_fd_pr__pfet_01v8_aW2p00 +pshort_w3p0,sky130_fd_pr__pfet_01v8_aW3p00 +pshort_w5p0,sky130_fd_pr__pfet_01v8_aW5p00 +psrf_3p15m2,sky130_fd_pr__rf_pfet_01v8_aM02W3p00L0p15 +psrf_3p15m4,sky130_fd_pr__rf_pfet_01v8_aM04W3p00L0p15 +psrf_3p18m2,sky130_fd_pr__rf_pfet_01v8_aM02W3p00L0p18 +psrf_3p18m4,sky130_fd_pr__rf_pfet_01v8_aM04W3p00L0p18 +psrf_3p25m2,sky130_fd_pr__rf_pfet_01v8_aM02W3p00L0p25 +psrf_3p25m4,sky130_fd_pr__rf_pfet_01v8_aM04W3p00L0p25 +psrf_5p15m2,sky130_fd_pr__rf_pfet_01v8_aM02W5p00L0p15 +psrf_5p15m4,sky130_fd_pr__rf_pfet_01v8_aM04W5p00L0p15 +psrf_5p18m2,sky130_fd_pr__rf_pfet_01v8_aM02W5p00L0p18 +psrf_5p18m4,sky130_fd_pr__rf_pfet_01v8_aM04W5p00L0p18 +psrf_5p25m2,sky130_fd_pr__rf_pfet_01v8_aM02W5p00L0p25 +psrf_5p25m4,sky130_fd_pr__rf_pfet_01v8_aM04W5p00L0p25 +pvhv_ttleak,sky130_fd_pr__pfet_g5v0d16v0__tt_leak +rf2_xchvnwc,sky130_fd_pr__cap_var +rf2_xcmim2c,sky130_fd_pr__cap_mim_m4 +rf2_xcmimc1,sky130_fd_pr__cap_mim_m3_1 +rf2_xcmimc2,sky130_fd_pr__cap_mim_m3_2 +rf2_xcmvpp1,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield_o1 +rf2_xcmvpp2,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_noshield_o1 +rf2_xcmvpp3,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2_noshield +rf2_xcmvpp4,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield_o2 +rf2_xcmvpp5,sky130_fd_pr__cap_vpp_02p4x04p6_m1m2_noshield +rf2_xcmvpp6,sky130_fd_pr__cap_vpp_02p4x04p6_m1m2_shieldpom3 +rf2_xcnwvc2,sky130_fd_pr__cap_var_hvt +rf_mimcap34,sky130_fd_pr__cap_mim_m3__base +rf_mimcap45,sky130_fd_pr__cap_mim_m4__base +rf_xcmim2c1,sky130_fd_pr__cap_mim_m4_1 +rf_xcmim2c2,sky130_fd_pr__cap_mim_m4_2 +rf_xcmvpp_2,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_noshield_o2 +rf_xcmvppx4,sky130_fd_pr__cap_vpp_11p3x11p8_l1m1m2m3m4_shieldm5_nhv +rf_xind4_01,sky130_fd_pr__ind_01_04 +rf_xind4_02,sky130_fd_pr__ind_02_04 +s8rf_nlowvt,sky130_fd_pr__rf_nfet_01v8_lvt +s8rf_nshort,sky130_fd_pr__rf_nfet_01v8 +s8rf_plowvt,sky130_fd_pr__rf_pfet_01v8_lvt +s8rf_pshort,sky130_fd_pr__rf_pfet_01v8 +sonos_bol_e,sky130_fd_bs_flash__special_sonosfet_star__bol +sonos_bol_p,sky130_fd_bs_flash__special_sonosfet_original__bol +xesd_ndiode,sky130_fd_pr__esd_rf_diode_pw2nd_05v5 +xesd_pdiode,sky130_fd_pr__esd_rf_diode_pd2nw_05v5 +xhrpoly_1p4,sky130_fd_pr__res_high_po_1p40 +xnwdiode_rf,sky130_fd_pr__model__parasitic__rf_diode_ps2nw +n20vhv_aup,sky130_fd_pr__nfet_20v0_aup +n20vhv_esd,sky130_fd_pr__esd_nfet_20v0 +n20vhviso1,sky130_fd_pr__nfet_20v0_iso +n20zvtvhv1,sky130_fd_pr__nfet_20v0_zvt +ndfbentres,sky130_fd_pr__res_bent_nd +ndiode_lvt,sky130_fd_pr__diode_pw2nd_05v5_lvt +nfet_debug,sky130_fd_pr__nfet_01v8__debug +nfet_fixed,sky130_fd_pr__nfet_01v8__fixed +nhv_ttleak,sky130_fd_pr__nfet_g5v0d10v5__tt_leak +nvhv_wafer,sky130_fd_pr__nfet_g5v0d16v0__wafer +pdfbentres,sky130_fd_pr__res_bent_pd +pdiode_hvt,sky130_fd_pr__diode_pd2nw_05v5_hvt +pdiode_lvt,sky130_fd_pr__diode_pd2nw_05v5_lvt +pfet_fixed,sky130_fd_pr__pfet_01v8__fixed +phighvt_ff,sky130_fd_pr__pfet_01v8_hvt__ff +phighvt_fs,sky130_fd_pr__pfet_01v8_hvt__fs +phighvt_mm,sky130_fd_pr__pfet_01v8_hvt__mismatch +phighvt_sf,sky130_fd_pr__pfet_01v8_hvt__sf +phighvt_ss,sky130_fd_pr__pfet_01v8_hvt__ss +phighvt_tt,sky130_fd_pr__pfet_01v8_hvt__tt +phv_ttleak,sky130_fd_pr__pfet_g5v0d10v5__tt_leak +pmedlvt_rf,sky130_fd_pr__rf_pfet_01v8_mvt +pvhv_wafer,sky130_fd_pr__pfet_g5v0d16v0__wafer +rf2_ind_03,sky130_fd_pr__ind_03 +rf2_ind_05,sky130_fd_pr__ind_05 +rf2_xcmimc,sky130_fd_pr__cap_mim_m3 +rf2_xcmvpp,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield_o1 +rf2_xcnwvc,sky130_fd_pr__cap_var_lvt +rf_npn_1x4,sky130_fd_pr__rf_npn_05v5_W1p00L4p00 +rf_npn_1x8,sky130_fd_pr__rf_npn_05v5_W1p00L8p00 +rf_npn_2x2,sky130_fd_pr__rf_npn_05v5_W2p00L2p00 +rf_npn_2x4,sky130_fd_pr__rf_npn_05v5_W2p00L4p00 +rf_npn_2x8,sky130_fd_pr__rf_npn_05v5_W2p00L8p00 +rf_npn_5x5,sky130_fd_pr__rf_npn_05v5_W5p00L5p00 +rf_xchvnwc,sky130_fd_pr__cap_var +rf_xcmim2c,sky130_fd_pr__cap_mim_m4 +rf_xcmimc1,sky130_fd_pr__cap_mim_m3_1 +rf_xcmimc2,sky130_fd_pr__cap_mim_m3_2 +rf_xcmvpp1,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield_o2 +rf_xcmvpp2,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_noshield_o2 +rf_xcmvpp3,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2_noshield +rf_xcmvpp4,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield_o2 +rf_xcmvpp5,sky130_fd_pr__cap_vpp_02p4x04p6_m1m2_noshield +rf_xcmvpp6,sky130_fd_pr__cap_vpp_02p4x04p6_m1m2_shieldpom3 +rf_xcnwvc2,sky130_fd_pr__cap_var_hvt +s8rf_pnp5x,sky130_fd_pr__pnp_05v5_W3p40L3p40 +xcmimc_top,sky130_fd_pr__model__cap_mim +xcmvpp_hd5,sky130_fd_pr__cap_vpp_11p5x11p7_pol1m1m2m3m4m5_noshield_base +xcmvpp_top,sky130_fd_pr__model__cap_vpp +xcnwvc_top,sky130_fd_pr__model__cap_var +xind_5_125,sky130_fd_pr__ind_05_125 +xind_5_220,sky130_fd_pr__ind_05_220 +extdntran,sky130_fd_pr__model__nfet_extendeddrain +extdptran,sky130_fd_pr__model__nfet_extendeddrain +fnpass_mm,sky130_fd_pr__special_nfet_pass_flash__mismatch +fuse_m3m4,sky130_fd_pr__fuse_m3m4 +n20vhv_fs,sky130_fd_pr__nfet_20v0__fs +n20vhv_sf,sky130_fd_pr__nfet_20v0__sf +n20vhv_tt,sky130_fd_pr__nfet_20v0__tt +n20vhviso,sky130_fd_pr__nfet_20v0_iso +n20zvtvhv,sky130_fd_pr__nfet_20v0_zvt +nhv_rf_mm,sky130_fd_pr__rf_nfet_g5v0d10v5__mismatch +nhv_wafer,sky130_fd_pr__nfet_g5v0d10v5__wafer +nhvesd_ff,sky130_fd_pr__esd_nfet_g5v0d10v5__ff +nhvesd_fs,sky130_fd_pr__esd_nfet_g5v0d10v5__fs +nhvesd_sf,sky130_fd_pr__esd_nfet_g5v0d10v5__sf +nhvesd_ss,sky130_fd_pr__esd_nfet_g5v0d10v5__ss +nhvesd_tt,sky130_fd_pr__esd_nfet_g5v0d10v5__tt +nhvnative,sky130_fd_pr__nfet_05v0_nvt +nlowvt_ff,sky130_fd_pr__nfet_01v8_lvt__ff +nlowvt_fs,sky130_fd_pr__nfet_01v8_lvt__fs +nlowvt_mm,sky130_fd_pr__nfet_01v8_lvt__mismatch +nlowvt_rf,sky130_fd_pr__rf_nfet_01v8_lvt +nlowvt_sf,sky130_fd_pr__nfet_01v8_lvt__sf +nlowvt_ss,sky130_fd_pr__nfet_01v8_lvt__ss +nlowvt_tt,sky130_fd_pr__nfet_01v8_lvt__tt +npn_wafer,sky130_fd_pr__npn_05v5__wafer +npnpar1x1,sky130_fd_pr__npn_05v5_W1p00L1p00 +npnpar1x2,sky130_fd_pr__npn_05v5_W1p00L2p00 +nshort_ff,sky130_fd_pr__nfet_01v8__ff +nshort_fs,sky130_fd_pr__nfet_01v8__fs +nshort_mm,sky130_fd_pr__nfet_01v8__mismatch +nshort_rf,sky130_fd_pr__rf_nfet_01v8 +nshort_sf,sky130_fd_pr__nfet_01v8__sf +nshort_ss,sky130_fd_pr__nfet_01v8__ss +nshort_tt,sky130_fd_pr__nfet_01v8__tt +nshortesd,sky130_fd_pr__esd_nfet_01v8 +ntvnative,sky130_fd_pr__nfet_03v3_nvt +nvhv_base,sky130_fd_pr__nfet_g5v0d16v0__base +nvhv_leak,sky130_fd_pr__nfet_g5v0d16v0__leak +p20vhv_fs,sky130_fd_pr__pfet_20v0__fs +p20vhv_sf,sky130_fd_pr__pfet_20v0__sf +p20vhv_tt,sky130_fd_pr__pfet_20v0__tt +phv_wafer,sky130_fd_pr__pfet_g5v0d10v5__wafer +phvesd_ff,sky130_fd_pr__esd_pfet_g5v0d10v5__ff +phvesd_fs,sky130_fd_pr__esd_pfet_g5v0d10v5__fs +phvesd_sf,sky130_fd_pr__esd_pfet_g5v0d10v5__sf +phvesd_ss,sky130_fd_pr__esd_pfet_g5v0d10v5__ss +phvesd_tt,sky130_fd_pr__esd_pfet_g5v0d10v5__tt +plowvt_ff,sky130_fd_pr__pfet_01v8_lvt__ff +plowvt_fs,sky130_fd_pr__pfet_01v8_lvt__fs +plowvt_mm,sky130_fd_pr__pfet_01v8_lvt__mismatch +plowvt_sf,sky130_fd_pr__pfet_01v8_lvt__sf +plowvt_ss,sky130_fd_pr__pfet_01v8_lvt__ss +plowvt_tt,sky130_fd_pr__pfet_01v8_lvt__tt +pmedlvtrf,sky130_fd_pr__rf_pfet_01v8_mvt +presistor,sky130_fd_pr__res_high_po__base +pshort_ff,sky130_fd_pr__pfet_01v8__ff +pshort_fs,sky130_fd_pr__pfet_01v8__fs +pshort_mm,sky130_fd_pr__pfet_01v8__mismatch +pshort_rf,sky130_fd_pr__rf_pfet_01v8 +pshort_sf,sky130_fd_pr__pfet_01v8__sf +pshort_ss,sky130_fd_pr__pfet_01v8__ss +pshort_tt,sky130_fd_pr__pfet_01v8__tt +pvhv_base,sky130_fd_pr__pfet_g5v0d16v0__base +pvhv_leak,sky130_fd_pr__pfet_g5v0d16v0__leak +pybentres,sky130_fd_pr__res_bent_po +rf_ind_03,sky130_fd_pr__ind_03 +rf_ind_05,sky130_fd_pr__ind_05 +rf_xcmimc,sky130_fd_pr__cap_mim_m3 +rf_xcmvpp,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield_o1 +rf_xcnwvc,sky130_fd_pr__cap_var_lvt +xind4_011,sky130_fd_pr__ind_11_04 +xind_3_90,sky130_fd_pr__ind_03_90 +xinductor,sky130_fd_pr__ind +mimcap34,sky130_fd_pr__cap_mim_m3__base +mimcap45,sky130_fd_pr__cap_mim_m4__base +nand2s_p,sky130_fd_pr__model__typical__nand2s +ndiode_h,sky130_fd_pr__diode_pw2nd_11v0 +nfetextd,sky130_fd_pr__nfet_01v8_extenddrain +nhv_leak,sky130_fd_pr__nfet_g5v0d10v5__leak +nhv_w3p0,sky130_fd_pr__nfet_g5v0d10v5_aW3p00 +nhv_w5p0,sky130_fd_pr__nfet_g5v0d10v5_aW5p00 +nhv_w7p0,sky130_fd_pr__nfet_g5v0d10v5_aW7p00 +nlvtpass,sky130_fd_pr__special_nfet_pass_lvt +npass_mm,sky130_fd_pr__special_nfet_pass__mismatch +pdiode_h,sky130_fd_pr__diode_pd2nw_11v0 +pfetextd,sky130_fd_pr__pfet_01v8_extenddrain +phv_leak,sky130_fd_pr__pfet_g5v0d10v5__leak +plyshort,sky130_fd_pr__short_pl +pnppar5x,sky130_fd_pr__pnp_05v5_W3p40L3p40 +rf_pnp5x,sky130_fd_pr__pnp_05v5_W3p40L3p40 +s8rf_nhv,sky130_fd_pr__rf_nfet_g5v0d10v5 +s8rf_npn,sky130_fd_pr__rf_npn_05v5 +s8rf_pnp,sky130_fd_pr__pnp_05v5_W3p40L3p40 +xcmim2c1,sky130_fd_pr__cap_mim_m4_1 +xcmim2c2,sky130_fd_pr__cap_mim_m4_2 +xcmvpp_2,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_noshield_o1 +xcmvppx4,sky130_fd_pr__cap_vpp_11p3x11p8_l1m1m2m3m4_shieldm5_nhv +xind4_02,sky130_fd_pr__ind_02_04 +xnwdiode,sky130_fd_pr__model__parasitic__diode_ps2nw +xuhrpoly,sky130_fd_pr__res_xhigh_po +bkeep_p,sky130_fd_pr__model__typical__bkeep +hvntran,sky130_fd_pr__model__nfet_highvoltage +hvptran,sky130_fd_pr__model__pfet_highvoltage +n20vhv1,sky130_fd_pr__nfet_20v0 +nand2_p,sky130_fd_pr__model__typical__nand2 +nand3_p,sky130_fd_pr__model__typical__nand3 +nand4_p,sky130_fd_pr__model__typical__nand4 +nand5_p,sky130_fd_pr__model__typical__nand5 +nor2s_p,sky130_fd_pr__model__typical__nor2s +npassll,sky130_fd_pr__special_nfet_pass_lowleakage +npn_1x1,sky130_fd_pr__npn_05v5_W1p00L1p00 +npn_1x2,sky130_fd_pr__npn_05v5_W1p00L2p00 +npn_1x4,sky130_fd_pr__npn_05v5_W1p00L4p00 +npn_1x8,sky130_fd_pr__npn_05v5_W1p00L8p00 +npn_2x2,sky130_fd_pr__npn_05v5_W2p00L2p00 +npn_2x4,sky130_fd_pr__npn_05v5_W2p00L4p00 +npn_2x8,sky130_fd_pr__npn_05v5_W2p00L8p00 +npn_5x5,sky130_fd_pr__npn_05v5_W5p00L5p00 +nvhv_ff,sky130_fd_pr__nfet_g5v0d16v0__ff +nvhv_fs,sky130_fd_pr__nfet_g5v0d16v0__fs +nvhv_sf,sky130_fd_pr__nfet_g5v0d16v0__sf +nvhv_ss,sky130_fd_pr__nfet_g5v0d16v0__ss +nvhv_tt,sky130_fd_pr__nfet_g5v0d16v0__tt +nwdiode,sky130_fd_pr__model__parasitic__diode_ps2nw +p20vhv1,sky130_fd_pr__pfet_20v0 +pesdfet,sky130_fd_pr__esd_pfet_01v8 +phighvt,sky130_fd_pr__pfet_01v8_hvt +pmedlvt,sky130_fd_pr__pfet_01v8_mvt +pvhv_ff,sky130_fd_pr__pfet_g5v0d16v0__ff +pvhv_fs,sky130_fd_pr__pfet_g5v0d16v0__fs +pvhv_sf,sky130_fd_pr__pfet_g5v0d16v0__sf +pvhv_ss,sky130_fd_pr__pfet_g5v0d16v0__ss +pvhv_tt,sky130_fd_pr__pfet_g5v0d16v0__tt +sonos_e,sky130_fd_bs_flash__special_sonosfet_star +sonos_p,sky130_fd_bs_flash__special_sonosfet_original +uhrpoly,sky130_fd_pr__res_xhigh_po +xchvnwc,sky130_fd_pr__cap_var +xcmim2c,sky130_fd_pr__cap_mim_m4 +xcmimc1,sky130_fd_pr__cap_mim_m3_1 +xcmimc2,sky130_fd_pr__cap_mim_m3_2 +xcmvpp1,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield_o1 +xcmvpp2,sky130_fd_pr__cap_vpp_04p4x04p6_l1m1m2_noshield_o1 +xcmvpp3,sky130_fd_pr__cap_vpp_08p6x07p8_m1m2_noshield +xcmvpp4,sky130_fd_pr__cap_vpp_04p4x04p6_m1m2_noshield_o2 +xcmvpp5,sky130_fd_pr__cap_vpp_02p4x04p6_m1m2_noshield +xcmvpp6,sky130_fd_pr__cap_vpp_02p4x04p6_m1m2_shieldpom3 +xcnwvc2,sky130_fd_pr__cap_var_hvt +xhrpoly,sky130_fd_pr__res_high_po +xndiode,sky130_fd_pr__esd_diode_pw2nd_05v5 +xnor2_p,sky130_fd_pr__model__typical__xnor2 +xpnppar,sky130_fd_pr__esd_pnp_05v5 +einv_p,sky130_fd_pr__model__typical__einv +fnpass,sky130_fd_pr__special_nfet_pass_flash +hrpoly,sky130_fd_pr__res_high_po +ind_03,sky130_fd_pr__ind_03 +ind_05,sky130_fd_pr__ind_05 +m4fuse,sky130_fd_pr__fuse_m4 +n20vhv,sky130_fd_pr__nfet_20v0 +nand2s,sky130_fd_pr__model__typical__nand2s +ndfres,sky130_fd_pr__res_generic_nd +ndiode,sky130_fd_pr__diode_pw2nd_05v5 +nhv_ff,sky130_fd_pr__nfet_g5v0d10v5__ff +nhv_fs,sky130_fd_pr__nfet_g5v0d10v5__fs +nhv_mm,sky130_fd_pr__nfet_g5v0d10v5__mismatch +nhv_rf,sky130_fd_pr__rf_nfet_g5v0d10v5 +nhv_sf,sky130_fd_pr__nfet_g5v0d10v5__sf +nhv_ss,sky130_fd_pr__nfet_g5v0d10v5__ss +nhv_tt,sky130_fd_pr__nfet_g5v0d10v5__tt +nhvesd,sky130_fd_pr__esd_nfet_g5v0d10v5 +nlowvt,sky130_fd_pr__nfet_01v8_lvt +nor2_p,sky130_fd_pr__model__typical__nor2 +nor3_p,sky130_fd_pr__model__typical__nor3 +nor4_p,sky130_fd_pr__model__typical__nor4 +npassd,sky130_fd_pr__special_nfet_pass_dual +npd_mm,sky130_fd_pr__special_nfet_latch__mismatch +npnpar,sky130_fd_pr__npn_05v5 +nshort,sky130_fd_pr__nfet_01v8 +p20vhv,sky130_fd_pr__pfet_20v0 +pdfres,sky130_fd_pr__res_generic_pd +pdiode,sky130_fd_pr__diode_pd2nw_05v5 +phv_ff,sky130_fd_pr__pfet_g5v0d10v5__ff +phv_fs,sky130_fd_pr__pfet_g5v0d10v5__fs +phv_mm,sky130_fd_pr__pfet_g5v0d10v5__mismatch +phv_sf,sky130_fd_pr__pfet_g5v0d10v5__sf +phv_ss,sky130_fd_pr__pfet_g5v0d10v5__ss +phv_tt,sky130_fd_pr__pfet_g5v0d10v5__tt +phvesd,sky130_fd_pr__esd_pfet_g5v0d10v5 +plowvt,sky130_fd_pr__pfet_01v8_lvt +pnppar,sky130_fd_pr__pnp_05v5_W0p68L0p68 +ppu_mm,sky130_fd_pr__special_pfet_pass__mismatch +pshort,sky130_fd_pr__pfet_01v8 +rf_pnp,sky130_fd_pr__pnp_05v5_W3p40L3p40 +xcmimc,sky130_fd_pr__cap_mim_m3 +xcmvpp,sky130_fd_pr__cap_vpp_08p6x07p8_l1m1m2_noshield_o1 +xcnwvc,sky130_fd_pr__cap_var_lvt +xind_3,sky130_fd_pr__ind_03 +xind_5,sky130_fd_pr__ind_05 +xpwres,sky130_fd_pr__res_iso_pw +bkeep,sky130_fd_pr__model__typical__bkeep +inv_p,sky130_fd_pr__model__typical__inv +jtran,sky130_fd_pr__model__jfet +lires,sky130_fd_pr__res_generic_l1 +m5rdl,sky130_fd_pr__via_m5r1 +nand2,sky130_fd_pr__model__typical__nand2 +nand3,sky130_fd_pr__model__typical__nand3 +nand4,sky130_fd_pr__model__typical__nand4 +nand5,sky130_fd_pr__model__typical__nand5 +nhvrf,sky130_fd_pr__rf_nfet_g5v0d10v5 +nor2s,sky130_fd_pr__model__typical__nor2s +npass,sky130_fd_pr__special_nfet_pass +npdll,sky130_fd_pr__special_nfet_latch_lowleakage +npn_f,sky130_fd_pr__npn_05v5__f +npn_s,sky130_fd_pr__npn_05v5__s +npn_t,sky130_fd_pr__npn_05v5__t +ntran,sky130_fd_pr__model__nfet +pnp5x,sky130_fd_pr__pnp_05v5_W3p40L3p40 +ppull,sky130_fd_pr__special_pfet_pass_lowleakage +ptran,sky130_fd_pr__model__pfet +pyres,sky130_fd_pr__res_generic_po +respw,sky130_fd_pr__res_generic_pw +xnor2,sky130_fd_pr__model__typical__xnor2 +einv,sky130_fd_pr__model__typical__einv +ind4,sky130_fd_pr__ind_04 +l1m1,sky130_fd_pr__via_l1m1 +l1m2,sky130_fd_pr__via_l1m2 +m1m2,sky130_fd_pr__via_m1m2 +m2m3,sky130_fd_pr__via_m2m3 +m3m4,sky130_fd_pr__via_m3m4 +m4m5,sky130_fd_pr__via_m4m5 +mrdn,sky130_fd_pr__res_generic_nd +mrdn_hv,sky130_fd_pr__res_generic_nd__hv +mrdp,sky130_fd_pr__res_generic_pd +mrdp_hv,sky130_fd_pr__res_generic_pd__hv +mrl1,sky130_fd_pr__res_generic_l1 +mrm1,sky130_fd_pr__res_generic_m1 +mrm2,sky130_fd_pr__res_generic_m2 +mrm3,sky130_fd_pr__res_generic_m3 +mrm4,sky130_fd_pr__res_generic_m4 +mrm5,sky130_fd_pr__res_generic_m5 +mrp1,sky130_fd_pr__res_generic_po +nfet,sky130_fd_pr__nfet_01v8 +nlrf,sky130_fd_pr__rf_nfet_01v8_lvt +nor2,sky130_fd_pr__model__typical__nor2 +nor3,sky130_fd_pr__model__typical__nor3 +nor4,sky130_fd_pr__model__typical__nor4 +npdd,sky130_fd_pr__special_nfet_latch_dual +npn4,sky130_fd_pr__npn_05v5_W1p00L1p00 +nsrf,sky130_fd_pr__rf_nfet_01v8 +nvhv,sky130_fd_pr__nfet_g5v0d16v0 +pfet,sky130_fd_pr__pfet_01v8 +plrf,sky130_fd_pr__rf_pfet_01v8_lvt +pnp4,sky130_fd_pr__pnp_05v5_W0p68L0p68 +psrf,sky130_fd_pr__rf_pfet_01v8 +pvhv,sky130_fd_pr__pfet_g5v0d16v0 +pyl1,sky130_fd_pr__via_pol1 +pym1,sky130_fd_pr__via_pom1 +pym2,sky130_fd_pr__via_pom2 +resn,sky130_fd_pr__res_generic_nd +resp,sky130_fd_pr__res_generic_pd +sc_p,sky130_fd_pr__model__typical__sc +short,short +xind,sky130_fd_pr__ind +xrdn,sky130_fd_pr__res_generic_nd +xrdp,sky130_fd_pr__res_generic_pd +inv,sky130_fd_pr__model__typical__inv +nhv,sky130_fd_pr__nfet_g5v0d10v5 +npd,sky130_fd_pr__special_nfet_latch +npn,sky130_fd_pr__npn_05v5_all +phv,sky130_fd_pr__pfet_g5v0d10v5 +pnp,sky130_fd_pr__pnp_05v5_W0p68L0p68 +ppu,sky130_fd_pr__special_pfet_pass +sc,sky130_fd_pr__model__typical__sc diff --git a/images/foss-asic-tools/addons/sak/common/sub-no-empty.sh b/images/foss-asic-tools/addons/sak/common/sub-no-empty.sh new file mode 100755 index 00000000..4476e9b9 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/common/sub-no-empty.sh @@ -0,0 +1,61 @@ +#! /bin/gawk -f +# Process a spice file. For back-to-back .subckt,.ends (possibly with comments +# in between) delete (do not output) the whole subckt...ends block. +# Does not support .include or .lib. +# TODO: implicitly handle unfolding confinued lines. Currently requires input passed thru an unfold filter. +# +# subsnoemtpy.sh out.spi +# or: +# subsnoemtpy.sh in.spi >out.spi +# +# recommend input be unfold-ed as in: +# unfold out.spi +# + +BEGIN { IGNORECASE=1 } + +# print but otherwise ignore 1st line of file +# FNR==1 { print $0 ; next } + +# start subckt: remember .subckt line, start accumulating lines... +$1 == ".subckt" { + if (accum > 0) { + print "f: " FILENAME " line#" FNR ", ERROR: start a subckt before last subckt closed" >>"/dev/stderr" + print sublines + } + sublines = $0 + accum=1 + noncomm=0 + next +} +# end subckt: if accumulation has any non-comment lines: output subckt block. +# ERROR if .ends while not accumulating: output line and continue. +$1 == ".ends" { + if (accum == 0) { + print "f: " FILENAME " line#" FNR ", ERROR: extra .ends without opening .subckt" >>"/dev/stderr" + print $0 + next + } + sublines = sublines "\n" $0 + if (noncomm > 0) print sublines + accum=0 + next +} +# not-accumulating, just print line +accum==0 { print $0; next } + +# accumulate lines, but count the non-comments (empty line not a non-comment) +accum==1 { + sublines = sublines "\n" $0; + if ( NF != 0 && index($1, "*") != 1 ) { + noncomm++ + } +} + +# still accumulating?: print'em. Should be error: .subckt without .ends. +END { + if (accum > 0) { + print "f: " FILENAME " line#" FNR ", ERROR: file ends without last subckt closed" >>"/dev/stderr" + print sublines + } +} diff --git a/images/foss-asic-tools/addons/sak/common/verilog2spice.py b/images/foss-asic-tools/addons/sak/common/verilog2spice.py new file mode 100755 index 00000000..f3b7c3d0 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/common/verilog2spice.py @@ -0,0 +1,198 @@ +#! /usr/bin/python + +# +# Simple structured VERILOG netlist to SPICE netlist translator +# +# usage example : assuming a verilog netlist called final.v +# based on a stdcells library and a memory : +# +# python verilog2spice.py -spice stdcells.cdl -spice memory.cdl -verilog final.v -output final.sp -pos_pwr VDD -neg_pwr VSS -delimiter +# +# if pos_pwr and neg_pwr are not specified, they are by default VDD and VSS +# +# if -delimiter is used the busses delimiter will be changed +# from [:] in the verilog netlist to <:> in the spice netlist +# +# distributed under GNU GPLv3 +############################################################################## + +import sys +import re +from datetime import datetime + +spi_files = [] +ver_file = '' +out_file = '' +pos_pwr = 'VDD' +neg_pwr = 'VSS' +del_on = False + +for arg in range(1,len(sys.argv)) : # parse all arguments + if sys.argv[arg] == '-spice' : + spi_files.append(sys.argv[arg+1]) + elif sys.argv[arg] == '-verilog' : + if ver_file != "" : + print ('ERROR : only one structured Verilog netlist can be specified !') + else : + ver_file = sys.argv[arg+1] + elif sys.argv[arg] == '-output' : + if out_file != "" : + print ('ERROR : only one output Spice netlist can be specified !') + else : + out_file = sys.argv[arg+1] + if sys.argv[arg] == '-pos_pwr' : + pos_pwr = sys.argv[arg+1] + if sys.argv[arg] == '-neg_pwr' : + neg_pwr = sys.argv[arg+1] + elif sys.argv[arg] == '-delimiter' : + del_on = True + +if len(spi_files) == 0 : + sys.exit("Spice library netlist not specified") +if ver_file == "" : + sys.exit("Verilog netlist not specified") +if out_file == "" : + sys.exit("Output Spice netlist not specified") +if del_on : + print ('The positive power supply is : ' + pos_pwr + ' The negative one : ' + neg_pwr + ' Busses are delimited by <:>') +else : + print ('The positive power supply is : ' + pos_pwr + ' The negative one : ' + neg_pwr + ' Busses are delimited by [:]') + +nb_subckt = 0 # number of cells in the spice netlist +cells = [] # list of cell of the spice netlist +cell_num = 0 #same as nb_subckt + 1 +inst_on = False +subckt_on = False +spi_inc = "" + +# parse the SPICE cells library file : +###################################### +for spi_file in spi_files : + spifl = open(spi_file,'r') # open a SPICE library file + if spi_file.find('\\') != -1 : # remove any path from the reference SPICE netlist + spi_file = spi_file[spi_file.rfind('\\')+1:] + if spi_file.find('/') != -1 : # remove any path from the reference SPICE netlist + spi_file = spi_file[spi_file.rfind('/')+1:] + spi_inc = spi_inc + spi_file + ' ' + for line1 in spifl: + words = line1.upper().rstrip('\r\n').strip().split() + if len(words) > 0: + if words[0].find('SUBCKT') == 1 : + subckt_on = True + nb_subckt += 1 + words.pop(0) + cells.append(words) + elif subckt_on and words[0] == '+' : # case of .SUBCKT defined on several lines + cells[cell_num].extend(words) # store each cell_name and pins in a list + else : + subckt_on = False + if words[0].find('ENDS') == 1 : # end of SUBCKT + #print (cells[cell_num]) + cell_num += 1 + spifl.close() + +if nb_subckt == 0 : + sys.exit('\nERROR : NO subckt found in the Spice netlist !\n') +else : + print ('... end of SPICE netlist parsing : ' + str(nb_subckt) + ' cells found in the SPICE netist.\n') + +# parse the VERILOG netlist : +############################# +verfl = open(ver_file,'r') # open VERILOG file to translate +outfl = open(out_file,'w') # open the output SPICE netlist + +nb_subckt = 0 +nb_pins = 0 +outfl.write('*\n* ' +out_file + ' : SPICE netlist translated from the VERILOG netlist : ' + ver_file + '\n') +outfl.write('*'+ ' '* (len(out_file) + 5 ) + 'on the ' + str(datetime.now())+ '\n*\n') +outfl.write('*' * (len(out_file) + len(ver_file) + 60) + '\n\n') +outfl.write('.INCLUDE ' + spi_inc + '\n\n') + +for line1 in verfl: + words = line1.upper().rstrip('\r\n').strip().split() + if len(words) > 0: + if words[0].find('MODULE') == 0 : #first build the toplevel subckt + subckt_name = words[1] + subckt = '.SUBCKT ' + subckt_name + ' ' + if words[0].startswith('INPUT') or words[0].startswith('OUTPUT') or words[0].startswith('INOUT') : + subckt_on = True + if line1.find('[') == -1 : # pins that are not a bus + subckt += line1[line1.upper().find(words[0])+6:].strip() + ' ' + subckt = subckt.replace(',','') + subckt = subckt.replace(';','') + + else : # busses treatment + lsb = min(int(line1[line1.find('[')+1 : line1.find(':')]) , int(line1[line1.find(':')+1 : line1.find(']')])) + msb = max(int(line1[line1.find('[')+1 : line1.find(':')]) , int(line1[line1.find(':')+1 : line1.find(']')])) + words = re.split(', *', line1[line1.find(']')+1:].rstrip('\r\n').strip().replace(';','')) + for word in words: + for i in range(lsb,msb+1): # spread each bit of each bus + subckt += word + '[' + str(i) + '] ' + + if subckt_on and line1.find('(')>0 : # first cell detected : write the toplevel .SUBCKT + subckt_on = False + if del_on : # change the busses delimiter + subckt = subckt.replace('[','<').replace(']','>') + outfl.write('.GLOBAL ' + pos_pwr + ' ' + neg_pwr + '\n\n' + subckt.upper() + '\n\n') + + if (not subckt_on) and (not inst_on) and re.search('\(\s*\.',line1) : + words = line1.upper().rstrip('\r\n').strip().split() + if words[1][0] == 'X' : # avoid double XX at the beginning of the instance name + instance = words[1] + else : + instance = 'X' + words[1] + subckt = words[0] + inst_on = True + line2 = line1[line1.find('(')+1:] + elif (not subckt_on) and inst_on : # store all the instance description into line2 + line2 = line2 + line1.upper() + + if inst_on and line1.find(';')>0 : # end of the cell description + inst_on = False + if del_on : # change the busses delimiter + line2 = line2.replace('\[','\<').replace('\]','\>') + pins=[] # list of pins + nodes=[] # list of netlist nodes + words = line2.upper().rstrip('\r\n').strip().split('.') + all_pins = ' ' + for word in words : + pins.append(word[:word.find('(')]) + nodes.append(word[word.find('(')+1:word.find(')')]) + i = 0 + while subckt != cells[i][0] and i < len(cells) : # search for the cell on the list of cells stored with the SPICE + i += 1 + if i == len(cells) : + print ('ERROR : subckt ' + subckt + ' not found in the Spice netlist !') + nb_subckt += 1 + else : + inst_name = instance + for pin in range(1,len(cells[i])) : # search for the pins of the SPICE subckt + if cells[i][pin] == pos_pwr : + instance = instance + ' ' + pos_pwr + elif cells[i][pin] == neg_pwr : + instance = instance + ' ' + neg_pwr + else : + j = 0 + while cells[i][pin] != pins[j] and j < len(pins) : # if the verilog pin name = spice pin name + j += 1 + if j == len(nodes) : + print ( 'ERROR : pin ' + cells[i][pin] + ' of the Spice netlist not found for the cell ' + inst_name + ' of the Verilog netlist !') + nb_pins += 1 + else : + instance = instance + ' ' + nodes[j] + # print (instance + ' ' + subckt) + outfl.write(instance + ' ' + subckt + '\n') + +outfl.write('\n' + '.ENDS ' + subckt_name ) + +if nb_subckt > 0 : + print ('\nERROR : during the translation : ' + str(nb_subckt) + ' cells from the VERILOG netlist not found in the SPICE netlist !\n') +if nb_pins > 0 : + print ('\nERROR : during the translation : ' + str(nb_pins) + ' pins from the VERILOG netlist not found in the SPICE netlist !\n') +if nb_subckt + nb_pins == 0 : + print (ver_file + ' : VERILOG netlist successfully translated to the SPICE netlist : ' + out_file + '\n') + +verfl.close() +outfl.close() + +exit(0) # Successful exit diff --git a/images/foss-asic-tools/addons/sak/common/xor.sh b/images/foss-asic-tools/addons/sak/common/xor.sh new file mode 120000 index 00000000..829596f6 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/common/xor.sh @@ -0,0 +1 @@ +../klayout/xor.sh \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/common/xor_xbox.drc b/images/foss-asic-tools/addons/sak/common/xor_xbox.drc new file mode 100755 index 00000000..5d2d4dcb --- /dev/null +++ b/images/foss-asic-tools/addons/sak/common/xor_xbox.drc @@ -0,0 +1,54 @@ +# A general XOR script +# (https://www.klayout.de/forum/discussion/100/xor-vs-diff-tool) +# This script uses KLayout's DRC language to implement a generic +# XOR between two layouts. The name of the layouts is given +# in $a and $b. + +# For layout-to-layout XOR with multiple cores, run this script with +# ./klayout -r xor.drc -rd thr=NUM_CORES -rd top_cell=TOP_CELL_NAME -rd a=a.gds -rd b=b.gds -rd ol=xor.gds -zz +# (replace NUM_CORES by the desired number of cores to utilize + +# enable timing output +verbose + +# set up input a +a = source($a, $top_cell) + +# set up input b +b = source($b, $top_cell) + +#xbox = box($x1.to_f, $y1.to_f, $x2.to_f, $y2.to_f) +#xbox = RBA::CellView::active +#xbox.cell.shapes(xbox.layout.layer(104, 0)).insert(RBA::Box::new($x1.to_f, $y1.to_f, $x2.to_f, $y2.to_f)) +xbox = source("./xbox.gds","user_project_wrapper") + +$o && $ext != "gds" && report("XOR #{$a} vs. #{$b}", $o) +$ol && $ext == "gds" && target($ol, $co || "XOR") + +$thr && threads($thr) || threads(2) + +# collect all common layers +layers = {} +[ a.layout, b.layout ].each do |ly| + ly.layer_indices.each do |li| + i = ly.get_info(li) + layers[i.to_s] = i + end +end + +xinner = xbox.input("68/20") +xouter = xbox.input("69/20") + +# perform the XOR's +layers.keys.sort.each do |l| + i = layers[l] + info("--- Running XOR for #{l} ---") + m = a.input(l) ^ xinner + info("chk 1") + n = b.input(l) ^ xinner + info("chk 2") + x = m ^ n + info("XOR differences: #{x.data.size}") + $o && $ext != "gds" && x.output(l, "XOR results for layer #{l} #{i.name}") + $ol && $ext == "gds" && x.output(i.layer, i.datatype, i.name) +end diff --git a/images/foss-asic-tools/addons/sak/common/xor_xbox.sh b/images/foss-asic-tools/addons/sak/common/xor_xbox.sh new file mode 100755 index 00000000..b82769d9 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/common/xor_xbox.sh @@ -0,0 +1,44 @@ +#!/bin/sh +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +: ${1?"Usage: $0 file1.gds file2.gds output.gds|markers.xml x1 y1 x2 y2"} +: ${2?"Usage: $0 file1.gds file2.gds output.gds|markers.xml x1 y1 x2 y2"} +: ${3?"Usage: $0 file1.gds file2.gds output.gds|markers.xml x1 y1 x2 y2"} +: ${4?"Usage: $0 file1.gds file2.gds output.gds|markers.xml x1 y1 x2 y2"} +: ${5?"Usage: $0 file1.gds file2.gds output.gds|markers.xml x1 y1 x2 y2"} +: ${6?"Usage: $0 file1.gds file2.gds output.gds|markers.xml x1 y1 x2 y2"} +: ${7?"Usage: $0 file1.gds file2.gds output.gds|markers.xml x1 y1 x2 y2"} +: ${8?"Usage: $0 file1.gds file2.gds output.gds|markers.xml x1 y1 x2 y2"} + + +echo "First Layout: $1" +echo "Second Layout: $2" +echo "Design Name: $3" +echo "Output GDS will be: $4" +echo "Exclude box: $5, $6, $7, $8" + +klayout -b -r $(dirname $0)/xor_xbox.drc \ + -rd top_cell=$3 \ + -rd a=$1 \ + -rd b=$2 \ + -rd thr=$(nproc) \ + -rd ol=$4 \ + -rd o=$4 \ + -rd ext=${4##*.} \ + -rd x1=$5 \ + -rd y1=$6 \ + -rd x2=$7 \ + -rd y2=$8 \ + -zz diff --git a/images/foss-asic-tools/addons/sak/klayout/coordinates.rb b/images/foss-asic-tools/addons/sak/klayout/coordinates.rb new file mode 100755 index 00000000..5cafee8c --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/coordinates.rb @@ -0,0 +1,59 @@ +# SPDX-FileCopyrightText: 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +# This script finds origin of the user_project_wrapper and returns if they are equivalent +# +# To Run the script: +# klayout -rd file1= -rd file2= -z -r coordinates.rb + +layout = RBA::Layout.new +lmap = layout.read($file1) + +origin = Struct.new(:instx, :insty, :instrot) +origins = Array.new + +lmap2 = layout.read($file2) + +ind = 0 + +layout.each_cell do |c| + # change and the instances + if c.name == "user_project_wrapper" + ind = Integer(c.cell_index) + end +end + +layout.each_cell do |c| + c.each_inst do |inst| + if inst.cell_index.equal? ind + iindex = inst.cell_index + name = layout.cell_name(iindex) + itrans = inst.trans.to_s.gsub(",", "\s").split("\s") + instrot = itrans[0] + instx = (itrans[1].to_i * layout.dbu).round(6) + insty = (itrans[2].to_i * layout.dbu).round(6) + origin.new(instx, insty, instrot) + origins.append(origin) + puts("#{name},#{instx},#{insty},#{instrot}") + end + end +end + +if origins.uniq.size > 1 + puts "They are not equivalent" +else + puts "They are equivalent" +end diff --git a/images/foss-asic-tools/addons/sak/klayout/cp_shapes.py b/images/foss-asic-tools/addons/sak/klayout/cp_shapes.py new file mode 100755 index 00000000..b9361b51 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/cp_shapes.py @@ -0,0 +1,68 @@ +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pya +from time import sleep +import os + +try: + if output_layout == "": + raise NameError + _output_layout = output_layout +except NameError: + _output_layout = input_layout + print("Warning: output_layout was not provided; will do the modifications in place!") + print("Hit CTRL-C to cancel...") + sleep(3) + +print("Starting...") +app = pya.Application.instance() +win = app.main_window() + +# Load technology file +tech = pya.Technology() +tech.load(tech_file) +layoutOptions = tech.load_layout_options + +# Load def/gds file in the main window +cell_view = win.load_layout(input_layout, layoutOptions, 0) +layout_view = cell_view.view() +layout_view.load_layer_props(os.path.splitext(tech_file)[0]+'.lyp') +layout_view.max_hier_levels = 1 +layout_view.min_hier_levels = 1 + +# gets the corresponding layout object +layout = cell_view.layout() + +# gets the cell to change is "INV2X" +# cell = layout.cell("Active_area") +cell = cell_view.cell + +# finds source layer +layer, purpose = source_layer.split('/') +assert layer and purpose +_source_layer = layout.layer(int(layer), int(purpose)) + +# finds (or creates) target layer +layer, purpose = target_layer.split('/') +assert layer and purpose +_target_layer = layout.layer(int(layer), int(purpose)) + +layout.copy_layer(_source_layer, _target_layer) + +layout.write(_output_layout) + +print("Successfully wrote", _output_layout) + +app.exit(0) diff --git a/images/foss-asic-tools/addons/sak/klayout/cp_shapes.sh b/images/foss-asic-tools/addons/sak/klayout/cp_shapes.sh new file mode 100755 index 00000000..fe8a65ce --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/cp_shapes.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +: ${1?"Usage: $0 file.gds src_layer/src_purpose targ_layer/targ_purpose [output.gds]"} +: ${2?"Usage: $0 file.gds src_layer/src_purpose targ_layer/targ_purpose [output.gds]"} +: ${3?"Usage: $0 file.gds src_layer/src_purpose targ_layer/targ_purpose [output.gds]"} +: ${PDK_ROOT?"You need to export PDK_ROOT"} +TECH=${TECH:-sky130A} + +xvfb-run klayout -z -rd input_layout=$1 -rd tech_file=$PDK_ROOT/$TECH/libs.tech/klayout/$TECH.lyt -rd source_layer=$2 -rd target_layer=$3 -rd output_layout=$4 -rm $(dirname $0)/cp_shapes.py diff --git a/images/foss-asic-tools/addons/sak/klayout/def-lef/import_def.rb b/images/foss-asic-tools/addons/sak/klayout/def-lef/import_def.rb new file mode 100755 index 00000000..f8497ac7 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/def-lef/import_def.rb @@ -0,0 +1,38 @@ +# Usage +# +# klayout -rd input=in.def -rd map=in.map -rd lefs=in.lef,in_tech.lef -rm path_to_script/import_def.rb +# +# Variables (-rd =\S+) # The layer name + (?: # Non-capturing group + \s+\+\ MASK\ (?P\d+) # Mask, None if absent + )? + (?P # OPC, None if absent + \s+\+\ OPC + )? + \s+RECT\ + \(\ (?P\d+)\ (?P\d+)\ \)\ # rect lower-left pt + \(\ (?P\d+)\ (?P\d+)\ \)\ ; # rect upper-right pt + ''', + re.VERBOSE) + +def read_fills(top): + if config_file == '': + print('WARNING: no fill config file specified') + return + # KLayout doesn't support FILL in DEF so we have to side load them :( + cfg = read_cfg() + in_fills = False + units = None + with open(in_def) as fp: + for line in fp: + if in_fills: + if re.match('END FILLS', line): + break # done with fills; don't care what follows + m = re.match(rect_pat, line) + if not m: + raise Exception('Unrecognized fill: ' + line) + opc_type = 'opc' if m.group('opc') else 'non-opc' + mask = m.group('mask') + if not mask: #uncolored just uses first entry + mask = 0 + else: + mask = int(mask) - 1 # DEF is 1-based indexing + layer = cfg[m.group('layer')][opc_type]['klayout'][mask] + xlo = int(m.group('xlo')) / units + ylo = int(m.group('ylo')) / units + xhi = int(m.group('xhi')) / units + yhi = int(m.group('yhi')) / units + top.shapes(layer).insert(pya.DBox(xlo, ylo, xhi, yhi)) + elif re.match('FILLS \d+ ;', line): + in_fills = True + elif not units: + m = re.match('UNITS DISTANCE MICRONS (\d+)', line) + if m: + units = float(m.group(1)) + +# Load technology file +tech = pya.Technology() +tech.load(tech_file) +layoutOptions = tech.load_layout_options + +# Load def file +main_layout = pya.Layout() +main_layout.read(in_def, layoutOptions) + +# Clear cells +top_cell_index = main_layout.cell(design_name).cell_index() + +print("[INFO] Clearing cells...") +for i in main_layout.each_cell(): + if i.cell_index() != top_cell_index: + if not i.name.startswith("VIA"): + #print("\t" + i.name) + i.clear() + +# Load in the gds to merge +print("[INFO] Merging GDS files...") +for gds in in_gds.split(): + print("\t{0}".format(gds)) + main_layout.read(gds) + +# Copy the top level only to a new layout +print("[INFO] Copying toplevel cell '{0}'".format(design_name)) +top_only_layout = pya.Layout() +top_only_layout.dbu = main_layout.dbu +top = top_only_layout.create_cell(design_name) +top.copy_tree(main_layout.cell(design_name)) + +read_fills(top) + +print("[INFO] Checking for missing GDS...") +missing_gds = False +for i in top_only_layout.each_cell(): + if i.is_empty(): + missing_gds = True + print("[ERROR] LEF Cell '{0}' has no matching GDS cell. Cell will be empty".format(i.name)) + +if not missing_gds: + print("[INFO] All LEF cells have matching GDS cells") + +if seal_gds: + + top_cell = top_only_layout.top_cell() + + print("[INFO] Reading seal GDS file...") + print("\t{0}".format(seal_gds)) + top_only_layout.read(seal_gds) + + for cell in top_only_layout.top_cells(): + if cell != top_cell: + print("[INFO] Merging '{0}' as child of '{1}'".format(cell.name, top_cell.name)) + top.insert(pya.CellInstArray(cell.cell_index(), pya.Trans())) + +# Write out the GDS +print("[INFO] Writing out GDS '{0}'".format(out_gds)) +top_only_layout.write(out_gds) +print("Done") +sys.exit(0) diff --git a/images/foss-asic-tools/addons/sak/klayout/def2gds.sh b/images/foss-asic-tools/addons/sak/klayout/def2gds.sh new file mode 100755 index 00000000..fc764a49 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/def2gds.sh @@ -0,0 +1,14 @@ +export KLAYOUT_SKY130_TECH=/home/xrex/.klayout/tech/SKY130/SKY130.lyt + +: ${1?"Usage: $0 input.def design_name prereq1.gds prereq2.gds ...."} +: ${2?"Usage: $0 input.def design_name prereq1.gds prereq2.gds ...."} +: ${3?"Usage: $0 input.def design_name prereq1.gds prereq2.gds ...."} + +xvfb-run klayout -z -rd design_name=$2 \ + -rd in_def=$1 \ + -rd in_gds="${@:3}" \ + -rd config_file="" \ + -rd seal_gds="" \ + -rd out_gds=$(dirname $1)/$2.gds \ + -rd tech_file=$KLAYOUT_SKY130_TECH \ + -rm $(dirname $0)/def2gds.py diff --git a/images/foss-asic-tools/addons/sak/klayout/delete_areaid.py b/images/foss-asic-tools/addons/sak/klayout/delete_areaid.py new file mode 100755 index 00000000..6ef40c86 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/delete_areaid.py @@ -0,0 +1,41 @@ + +# Enter your Python code here + +import pya +from time import sleep + +print("Starting...") +app = pya.Application.instance() +win = app.main_window() + +# Load technology file +#tech = pya.Technology() +#tech.load(tech_file) +#layoutOptions = tech.load_layout_options + +# Load def/gds file in the main window +#cell_view = win.load_layout(input_layout, layoutOptions, 0) +#layout_view = cell_view.view() +#layout_view.max_hier() + +# gets the corresponding layout object +#layout = cell_view.layout() +layout = pya.Layout() +layout.read(input_layout) +#layout.clear_layer(81) +#layout.delete_layer(81) + +# gets the cell to change is "INV2X" +# cell = layout.cell("Active_area") +#cell = cell_view.cell + +# finds source layer +#areaid_layer = layout.layer(81, 14) +#areaid_layer.delete() + +#layout.write(input_layout) +layout.write('junk.gds') + +print("Successfully wrote", input_layout) + +app.exit(0) diff --git a/images/foss-asic-tools/addons/sak/klayout/density_check.lydrc b/images/foss-asic-tools/addons/sak/klayout/density_check.lydrc new file mode 100755 index 00000000..38d5efd4 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/density_check.lydrc @@ -0,0 +1,73 @@ + + + + + drc + + + + false + false + + true + drc_scripts + tools_menu.drc.end + dsl + drc-dsl-xml + verbose(true) + +li_wildcard = "67/0-4,6-43,45-*" +mcon_wildcard = "67/44" + +m1_wildcard = "68/0-4,6-43,45-*" +via_wildcard = "68/44" + +m2_wildcard = "69/0-4,6-43,45-*" +via2_wildcard = "69/44" + +m3_wildcard = "70/0-4,6-43,45-*" +via3_wildcard = "70/44" + +m4_wildcard = "71/0-4,6-43,45-*" +m4fill_wildcard = "51/28" +via4_wildcard = "71/44" + +m5_wildcard = "72/0-4,6-43,45-*" + +seal_wildcard = "61/20" + +li = polygons(li_wildcard) +mcon = polygons(mcon_wildcard) + +m1 = polygons(m1_wildcard) +via = polygons(via_wildcard) + +m2 = polygons(m2_wildcard) +via2 = polygons(via2_wildcard) + +m3 = polygons(m3_wildcard) +via3 = polygons(via3_wildcard) + +m4 = polygons(m4_wildcard) +m4fill = polygons(m4fill_wildcard) +via4 = polygons(via4_wildcard) + +m5 = polygons(m5_wildcard) + +seal_layer = input(seal_wildcard) + +##### + +area = (m4+m4fill).area + +bbox = seal_layer.bbox.area + +area_within_seal = bbox - seal_layer.area + +density = area / area_within_seal + +print("Density: #{density}\n") + +print("CADensity: #{1 - density}\n") + + diff --git a/images/foss-asic-tools/addons/sak/klayout/diff.py b/images/foss-asic-tools/addons/sak/klayout/diff.py new file mode 100755 index 00000000..332b132b --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/diff.py @@ -0,0 +1,29 @@ +import klayout.rdb as rdb +import sys +from collections import Counter +import contextlib + +kl_rd = rdb.ReportDatabase("klayout database") +kl_rd.load(str(sys.argv[1])) +cal_rd = rdb.ReportDatabase("calibre database") +cal_rd.load(str(sys.argv[2])) +cat_cal=[] +cat_kl=[] + +for kl in kl_rd.each_item(): + cat_kl.append(kl_rd.category_by_id(kl.category_id()).name()) +for kl in cal_rd.each_item(): + cat_cal.append(cal_rd.category_by_id(kl.category_id()).name().replace('MR_', '')) + +categories_kl = Counter(cat_kl) +categories_cal = Counter(cat_cal) + +with open(str(sys.argv[3]), 'w') as f: + with contextlib.redirect_stdout(f): + print('%-12s%-12s%-12s%s' % ('category', 'klayout', 'calibre', 'equivalent')) + + for c in categories_kl | categories_cal: + if categories_kl[c] == categories_cal[c]: + print('%-12s%-12d%-12d%s' % (c, categories_kl[c], categories_cal[c], 'yes')) + else: + print('%-12s%-12d%-12d%s' % (c, categories_kl[c], categories_cal[c], 'no')) diff --git a/images/foss-asic-tools/addons/sak/klayout/diff_report.py b/images/foss-asic-tools/addons/sak/klayout/diff_report.py new file mode 100755 index 00000000..69f8849e --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/diff_report.py @@ -0,0 +1,68 @@ +import klayout.rdb as rdb +import klayout.db as pya +import sys +from collections import Counter +import contextlib + +kl_rd = rdb.ReportDatabase("klayout database") +kl_rd.load(str(sys.argv[1])) +cal_rd = rdb.ReportDatabase("calibre database") +cal_rd.load(str(sys.argv[2])) +diff_rd = rdb.ReportDatabase("diff database") +cat_cal=[] +cat_kl=[] +diff = [] +cal_array = [] + +kl_cat_region = {} +cal_cat_region = {} +poly = 0 + +for kl in kl_rd.each_item(): + for value in kl.each_value(): + if value.is_edge_pair(): + poly = value.edge_pair().polygon(0) + elif value.polygon(): + poly = value.polygon() + if kl_rd.category_by_id(kl.category_id()).name() not in kl_cat_region: + kl_cat_region[kl_rd.category_by_id(kl.category_id()).name()] = [] + kl_cat_region[kl_rd.category_by_id(kl.category_id()).name()].append(poly) + +for cal in cal_rd.each_item(): + for value in cal.each_value(): + if value.is_edge_pair(): + poly = value.edge_pair().polygon(0) + elif value.polygon(): + poly = value.polygon() + if cal_rd.category_by_id(cal.category_id()).name().replace('MR_', '') not in cal_cat_region: + cal_cat_region[cal_rd.category_by_id(cal.category_id()).name().replace('MR_', '')] = [] + cal_cat_region[cal_rd.category_by_id(cal.category_id()).name().replace('MR_', '')].append(poly) + + +for val in cal_cat_region.values(): + for v in val: + cal_array.append(v) + + +for key, value in kl_cat_region.items(): + for val in value: + if val not in cal_array: + # print(val) + diff.append([key, value]) + +for i in diff: + cat = diff_rd.create_category(i[0]) + cell = diff_rd.create_cell(kl_rd.top_cell_name) + item = diff_rd.create_item(cell, cat) + for n in i[1]: + item.add_value(n) + +diff_rd.save(str(sys.argv[3])) + +arr = [] +for i in diff_rd.each_category(): + arr.append(i) +if len(arr) == 0: + print("\033[1;32m Klayout and Calibre Match!") +else: + print("\033[91m Klayout and Calibre Don't match!") diff --git a/images/foss-asic-tools/addons/sak/klayout/drc-gds-sky130A-klayout.sh b/images/foss-asic-tools/addons/sak/klayout/drc-gds-sky130A-klayout.sh new file mode 100755 index 00000000..2047c00a --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/drc-gds-sky130A-klayout.sh @@ -0,0 +1,65 @@ +#!/bin/sh +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +usage() { echo "Usage: $0 [ -f ] [ -m ] [ ]" 1>&2; exit 2; } + +drc_full=false +drc_mr=false +while getopts "fm" o; do + case "${o}" in + f) + drc_full=true + ;; + m) + drc_mr=true + ;; + *) + usage + ;; + esac +done +shift $((OPTIND-1)) + +set -e + +[[ $# -gt 3 ]] && export TAPEOUT_ROOT=$4 || export TAPEOUT_ROOT=/mnt/shuttles + +export SAK=$TAPEOUT_ROOT/sak +export PATH=$PATH:/ef/apps/bin:$SAK/tapeout:$SAK +export CARAVEL_ROOT=${TAPEOUT_ROOT}/${1}/caravel +export PDK_ROOT=${TAPEOUT_ROOT}/${1}/pdk + +target_path=${2} +input_gds=${3} +report=${target_path}/signoff/kdrc_results.txt + +tech_mr=${SAK}/klayout/tech/sky130A/sky130A_mr.lydrc +tech_full=${SAK}/klayout/tech/sky130A/sky130A.lydrc + +if [ $drc_full = true ]; then + klayout -b \ + -rd input=${input_gds} \ + -rd report=${report} \ + -r ${tech_full} |& tee ${target_path}/signoff/klayout_drc.log +fi + +if [ $drc_mr = true ]; then + klayout -b \ + -rd input=${input_gds} \ + -rd report=${report} \ + -r ${tech_mr} |& tee "${target_path}/signoff/klayout_drc.log" +fi + +exit 0 diff --git a/images/foss-asic-tools/addons/sak/klayout/drc_kl_all.sh b/images/foss-asic-tools/addons/sak/klayout/drc_kl_all.sh new file mode 100755 index 00000000..e6aaacc6 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/drc_kl_all.sh @@ -0,0 +1,3 @@ +#!/usr/bin/sh +/mnt/shuttles/precheck/drc_checks/drc_kl.sh $TAPEOUT_ROOT/precheck/tech-files/sky130A_mr.lydrc $1 ${1}.kl.report.db . +klayout $1 -m ${1}.kl.report.db & diff --git a/images/foss-asic-tools/addons/sak/klayout/drc_kl_feol.sh b/images/foss-asic-tools/addons/sak/klayout/drc_kl_feol.sh new file mode 100755 index 00000000..a2f733e3 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/drc_kl_feol.sh @@ -0,0 +1,3 @@ +#!/usr/bin/sh +/mnt/shuttles/precheck/drc_checks/run_drc_klayout.sh $TAPEOUT_ROOT/precheck/tech-files/sky130A_mr.lydrc $1 ${1}.kl.report.db . +klayout $1 -m ${1}.kl.report.db & diff --git a/images/foss-asic-tools/addons/sak/klayout/erase.rb b/images/foss-asic-tools/addons/sak/klayout/erase.rb new file mode 100755 index 00000000..e319ba56 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/erase.rb @@ -0,0 +1,246 @@ +# SPDX-FileCopyrightText: 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +# This script finds origin of the user_project_wrapper and returns if they are equivalent +# +# To Run the script: +# klayout -rd file1= -rd file2= -z -r layer_check.rb + + +# ---------------------------------------------------------------- +# A boolean processor class + +class BoolProcessor + + def initialize(layout, cell) + + @layout = layout + @cell = cell + + @proc = RBA::ShapeProcessor.new + + @temp_layers = [] + + end + + # Locate a layer for input. + # The layer is specified by a RBA::LayerInfo object which identifies the layer by + # a layer and datatype for example. If the layer does not exist, it is created. + # This method returns a layer index which can be used as input for other functions. + def input(lp) + + layer_index = nil + + # locate the layer if it already exists + (0..(@layout.layers-1)).each do |i| + if @layout.is_valid_layer?(i) && @layout.get_info(i).is_equivalent?(lp) + layer_index = i + break + end + end + + # create a new layer if it does not exist + return layer_index || @layout.insert_layer(lp) + + end + + # Create a new temporary layer and remember for removal on "cleanup". + # This method returns a layer index which can be used as input for other functions. + def tmp + lp = RBA::LayerInfo.new + layer_index = @layout.insert_layer(lp) + @temp_layers.push(layer_index) + return layer_index + end + + # Assign a layer as output. + # Change the layer given by the layer index to the output layer specified + # by a RBA::LayerInfo object. If the layer already exists, it is deleted. + def output(lp, layer_index) + + li = nil + + # locate the layer if it already exists + (0..(@layout.layers-1)).each do |i| + if @layout.is_valid_layer?(i) && @layout.get_info(i).is_equivalent?(lp) + li = i + break + end + end + + # clear the layer if it already exists + if li != layer_index + if li + @layout.delete_layer(li) + end + @layout.set_info(layer_index, lp) + end + + # remove the layer from the list of temporary layers + new_temp = [] + @temp_layers.each do |i| + if i != layer_index + new_temp.push(i) + end + end + @temp_layers = new_temp + + end + + # Clean up all temporary layers + def cleanup + @temp_layers.each do |i| + @layout.delete_layer(i) + end + @temp_layers = [] + end + + # Size a layer by the given value (in micron). + # "input" is the input layer, given by a layer index. + def size(input, d) + res = tmp() + @proc.size(@layout, @cell, input, @cell.shapes(res), to_dbu(d), + 2, true, true, true) + return res + end + + # Size a layer by the given values anisotropically (in micron) + # "input" is the input layer, given by a layer index. + def size2(input, dx, dy) + res = tmp() + @proc.size(@layout, @cell, input, @cell.shapes(res), to_dbu(dx), to_dbu(dy), + 2, true, true, true) + return res + end + + # OR two layers + # "a" and "b" are the input layers, given by a layer index. + def or(a, b) + res = tmp() + @proc.boolean(@layout, @cell, a, @layout, @cell, b, @cell.shapes(res), + RBA::EdgeProcessor::mode_or, true, true, true) + return res + end + + # XOR two layers + # "a" and "b" are the input layers, given by a layer index. + def xor(a, b) + res = tmp() + @proc.boolean(@layout, @cell, a, @layout, @cell, b, @cell.shapes(res), + RBA::EdgeProcessor::mode_xor, true, true, true) + return res + end + + # AND two layers + # "a" and "b" are the input layers, given by a layer index. + def and(a, b) + res = tmp() + @proc.boolean(@layout, @cell, a, @layout, @cell, b, @cell.shapes(res), + RBA::EdgeProcessor::mode_and, true, true, true) + return res + end + + # NOT two layers + # "a" and "b" are the input layers, given by a layer index. + def not(a, b) + res = tmp() + @proc.boolean(@layout, @cell, a, @layout, @cell, b, @cell.shapes(res), + RBA::EdgeProcessor::mode_anotb, true, true, true) + return res + end + + # Convert a value from micron to database units + # "a" and "b" are the input layers, given by a layer index. + def to_dbu(micron) + return (0.5 + micron / @layout.dbu).floor() + end + + # Run a procedure in the context of this object + def run(&action) + action.call(self) + cleanup + end + + private + @layout + @cell + @proc + +end + +layout = RBA::Layout::new +layout.read($file1) + +cell_to_change = layout.cell($cell_name) +cell_to_change.shapes(layout.layer(104, 0)).insert(RBA::Box::new(-42880, -1600, 2962500, 3521290)) +cell_to_change.shapes(layout.layer(106, 0)).insert(RBA::Box::new(-6980, -37520, 2926600, 3557210)) + +BoolProcessor.new(layout, layout.cell($cell_name)).run do |p| + boundry = p.input(RBA::LayerInfo.new(235, 4)) + bbox = p.input(RBA::LayerInfo.new(104, 0)) + bbox2 = p.input(RBA::LayerInfo.new(106, 0)) + tap = p.input(RBA::LayerInfo.new(81, 14)) + met5_pin = p.input(RBA::LayerInfo.new(72, 16)) + met5 = p.input(RBA::LayerInfo.new(72, 20)) + met4_pin = p.input(RBA::LayerInfo.new(71, 16)) + met4 = p.input(RBA::LayerInfo.new(71, 20)) + via = p.input(RBA::LayerInfo.new(71, 44)) + + layout.layer_indices.each do |li| + # if li != bbox + if li == met5 || li == met5_pin + active = p.input(RBA::LayerInfo.new(layout.get_info(li).layer, layout.get_info(li).datatype)) + gates = p.and(active, bbox) + p.output(RBA::LayerInfo.new(10, 0), gates) + active = p.xor(gates, active) + p.output(RBA::LayerInfo.new(layout.get_info(li).layer, layout.get_info(li).datatype), active) + end + # end + # if li != bbox2 + if li == met4 || li == met4_pin + active = p.input(RBA::LayerInfo.new(layout.get_info(li).layer, layout.get_info(li).datatype)) + gates = p.and(active, bbox2) + p.output(RBA::LayerInfo.new(10, 0), gates) + active = p.xor(gates, active) + p.output(RBA::LayerInfo.new(layout.get_info(li).layer, layout.get_info(li).datatype), active) + end + if li == via + active = p.input(RBA::LayerInfo.new(layout.get_info(li).layer, layout.get_info(li).datatype)) + gates = p.and(active, bbox2) + gates2 = p.and(active, bbox) + p.output(RBA::LayerInfo.new(10, 0), gates) + p.output(RBA::LayerInfo.new(11, 0), gates2) + act = p.xor(gates, active) + act2 = p.xor(gates2, active) + actt = p.and(act, act2) + p.output(RBA::LayerInfo.new(layout.get_info(li).layer, layout.get_info(li).datatype), actt) + end + # end + if li != boundry && li != tap + active = p.input(RBA::LayerInfo.new(layout.get_info(li).layer, layout.get_info(li).datatype)) + gates = p.and(active, boundry) + p.output(RBA::LayerInfo.new(10, 0), gates) + active = p.xor(gates, active) + p.output(RBA::LayerInfo.new(layout.get_info(li).layer, layout.get_info(li).datatype), active) + end + end + layout.delete_layer(layout.layer(10,0)) + layout.delete_layer(layout.layer(11,0)) + layout.delete_layer(layout.layer(104,0)) + layout.delete_layer(layout.layer(106,0)) +end + +layout.write($output) \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/klayout/gds2oas-all.sh b/images/foss-asic-tools/addons/sak/klayout/gds2oas-all.sh new file mode 100755 index 00000000..fe1e09f1 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/gds2oas-all.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -e + +echo "converting all gds files to oasis files" + +for filename in *.gds; do + out="${filename%%.*}" + out=$out".oas" + xvfb-run -a klayout -z \ + -rd input_layout=$filename \ + -rd output=$out \ + -rm $SAK/klayout/gds2oas.py; done + +echo 'Done converting all gds files to oasis files' +exit 0 diff --git a/images/foss-asic-tools/addons/sak/klayout/gds2oas.py b/images/foss-asic-tools/addons/sak/klayout/gds2oas.py new file mode 100755 index 00000000..1e3a0d4d --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/gds2oas.py @@ -0,0 +1,16 @@ +import pya + +app = pya.Application.instance() +opt = pya.SaveLayoutOptions() +view = pya.Layout() + +# Setting the name of the output file and setting the substitution character +print("[INFO] Changing from " + input_layout + " to " + output) +opt.set_format_from_filename(output) +opt.oasis_substitution_char='' + +# Reading the input file and writing it to the output file name +view.read(input_layout) +view.write(output, opt) + +app.exit(0) diff --git a/images/foss-asic-tools/addons/sak/klayout/gds2oas.sh b/images/foss-asic-tools/addons/sak/klayout/gds2oas.sh new file mode 100755 index 00000000..ebb78267 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/gds2oas.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +set -e + +echo "converting all gds files to oasis files" + + out="${filename%%.*}.oas" + klayout -z \ + -rd input_layout=$1 \ + -rd output=${1%.gds}.oas \ + -rm $SAK/klayout/gds2oas.py; + +echo 'Done converting all gds files to oasis files' + +echo 'Running XOR between gds and oasis files' + + $SAK/bin/xor.sh $1 ${1%.gds}.oas ${1%.gds} ${1%.gds}-gds2oas-xor.gds + +exit 0 diff --git a/images/foss-asic-tools/addons/sak/klayout/gds2spice-klayout.sh b/images/foss-asic-tools/addons/sak/klayout/gds2spice-klayout.sh new file mode 100755 index 00000000..68292327 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/gds2spice-klayout.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This script extract the netlist from a layout using Klayout + +: ${1? "Usage: $0 The gds file that will be extracted"} + +echo "converting $1 to spice netlist" + +klayout -b -rd input=$1 \ + -r ${SAK}/klayout/tech/sky130A/sky130A.lylvs diff --git a/images/foss-asic-tools/addons/sak/klayout/gdsAllcells.rb b/images/foss-asic-tools/addons/sak/klayout/gdsAllcells.rb new file mode 100755 index 00000000..c3d553e9 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/gdsAllcells.rb @@ -0,0 +1,178 @@ +#!/usr/bin/ruby +# usage: gdsAllcells.rb [-U|-E] [-V] +# +# Runs klayout (in batch) to read gdsFile, and enumerate all cellnames to STDOUT one per line. +# Script starts as regular ruby, then exec's via klayout passing self to it. +# (klayout requirement is this ruby script-name *must* end in .rb). +# +# -U : print unbound ("ghost") cells only; default is to print all cells incl/ unbound. +# Does not change STDERR output; does not change exit-status behavior. +# -E : print empty cells only; all "ghost" cells are empty too, but not all empty are ghost/unbound. +# -V : verbose-mode, each line of output, after cellname 1st-word, shows bbox & types of the cell +# Unbounds ALWAYS generate STDERR messages, a summary count error message, and set exit-status. +# +# For "unbound" cells STDERR messages are printed +# and exit-status is incremented (thus non-zero). +# +# Exit-status: +# I/O errors: 1 +# usage-error (missing arg): 1 +# unbound-cells: 1+number-of-unbounds (up to a maximum of 255) +# The exit status-range 2...255 indicates existence of unbounds. +# WARNING: thus status=255 indistinguishable from: there are 254 OR MORE unbounds. +# +prog="gdsAllcells.rb" +usage = "Usage: #{prog} [options] " + +InKlayout=$InKlayout +if InKlayout.to_s.empty? + thisScript = $0 + mode = "default" + verbose = 0 + empty = 0 + argvLenReq = 1 # min-# args, after options -U -V + + require 'optparse' + + argSum = ARGV.join(' ') + if ARGV.empty? + ARGV << '--help' + end + + OptionParser.new do |opts| + opts.banner = usage + opts.on("-v", "--version", "version: pass-thru, JUST show klayout version") do + exec "klayout -nc -zz -rx -v" + end + opts.on("-V", "verbose-mode, each line of output, after cellname 1st-word, shows bbox & types of the cell") do + verbose = 1 + end + opts.on("-U", "print unbound (ghost) cells only; default prints all incl. unbound") do + mode = "unbound" + end + opts.on("-E", "print empty cells only (ghosts are empty too); default prints all incl. empty; overrides -U") do + empty = 1 + end + opts.on("-h", "--help", "show usage") do + puts opts + exit 1 + end + opts.on("--usage", "show usage") do + puts opts + exit 1 + end + end.parse! + + # -E is superset of -U. We do this here, so -E overrides -U if both were given in any order. + mode = "empty" if empty == 1 + + if ARGV.length != argvLenReq + puts "ERROR, must give one non-option argument, usage: gdsAllcells.rb [-U|-E] [-V] " + puts " -U : just print unbound(ghost) cells (referenced, not defined); instead of all cells." + puts " -E : just print empty cells (ghosts are empty too); instead of all cells." + puts " -V : verbose-mode, each line of output, after cellname 1st-word, shows bbox & types of the cell." + puts " Regardless of -U or not, stderr messages are printed for unbound cells." + puts "Exit status: 0 success (no unbounds); 1 I/O or usage error; 2...255 for 1... unbounds. See also gdsSize.rb, gdsTopCells.rb" + # this works (to set exit status) from ruby, not in klayout + Kernel.exit(1) + end + + f = ARGV[0] + + # construct command from our script arguments, replace self with klayout... + exec "klayout -nc -zz -rx -rd InKlayout=1 -rd mode=#{mode} -rd verb=#{verbose} -rd file=#{f} -r #{thisScript}" + +end + +# +# -d : debug level, no details during GDS-reading however, try 20 or 40 or (timing too:) 21 or 41 +# -z/-zz : -z pseudo-batch mode, still needs X-DISPLAY connection; -zz true batch +# -nc : don't use/update configuration file +# -rx : disable built-in macros, stuff not needed for batch usually +# -rd : define variables the script can reference +# + +f = $file + +if f == "" + puts "ERROR: missing gdsFile argument" + STDOUT.flush + STDERR.flush + Kernel.exit!(1) +end + +m = 0 +if $mode == "unbound" + m = 1 +elsif $mode == "empty" + m = 2 +end +verb = 0 +if $verb == "1" + verb = 1 +end + +begin + +ly = RBA::Layout::new +ly.read(f) + +errs = 0 +ly.each_cell { |c| + msg = "" + isempty = c.is_empty? + isghost = c.is_ghost_cell? + if verb == 1 + istop = c.is_top? + isleaf = c.is_leaf? + ispcellv = c.is_pcell_variant? + isproxy = c.is_proxy? + islib = c.is_library_cell? + bbox = c.bbox + msg = " " + bbox.to_s + (msg << " top") if istop + (msg << " leaf") if isleaf + (msg << " pcellv") if ispcellv + (msg << " empty") if isempty + (msg << " ghost") if isghost + (msg << " proxy") if isproxy + (msg << " librarycell") if islib + end + + if isghost + STDERR.puts "ERROR: unbound (ghost) cell=#{c.name}" + errs = errs + 1 + end + + # print cell line in all three of these conditions: + # default(all): m == 0 + # -U ghost-only: m == 1 && isghost + # -E empty-only: m == 2 && (isempty || isghost) + # which simplify to: + if m == 0 || isghost || m == 2 && isempty + puts c.name + msg + end +} + +# if we roll-over to 256, exit-status seen by shell is zero. +# uncaught I/O errors will yield (built-in) exit status of 1. +if errs > 0 + STDERR.puts "ERROR: Found #{errs} total unbound (ghost) cells" + errs = errs + 1 +end +if errs > 255 + errs = 255 +end + +# In order to set exit-status, must use exit! not exit. +# But for exit! we'd lose buffered output unless we flush. +STDOUT.flush +STDERR.flush +Kernel.exit!(errs) + +# stdout is buffered, exit! quits without flushing buffered output: +# Kernel.exit!(errs) +# do not set exit-status: +# Kernel.exit(errs) +# exit errs +end diff --git a/images/foss-asic-tools/addons/sak/klayout/gdsArea0.rb b/images/foss-asic-tools/addons/sak/klayout/gdsArea0.rb new file mode 100755 index 00000000..922bb174 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/gdsArea0.rb @@ -0,0 +1,166 @@ +#!/bin/bash +# usage: gdsArea0.rb [-n] [ ] +# +# Process all layers, all cells, all cells: Find zero-area shapes. +# If gdsFileOut given: then delete such zero-area shapes and write new output file. +# Else report count of number of such shapes found. +# +# Intent is (default) deep-mode retains hier. as much as possible, just +# merging each layer of each cell "in-place". +# WARNING: if outFile is RELATIVE-PATH it is written in SAME-DIR as input-GDS. +# +# Exit status (does not work in klayout 0.23.11; does in 0.24 and later): +# 1 : I/O error or other internal error (uncaught exceptions). +# 2...127 : means 1... zero-area shapes found. If over 126 such shapes, status is 127 max. +# 0 : zero-area shapes found. +# If process dies thru signal, exit status is 128+SIGNUM, so that range is reserved. +# i.e. if kernel oom-killer sends kill -9: status=137. +# +# Runs klayout in batch AND edit-mode. +# (klayout requirement is this script-name *must* end in .rb). +# +# Shebang for: no outer ruby interpreter; generalize arg passing to script. +# for-bash: re-quote args, to import from an env-var +x=%{ + [[ "$1" == "--version" || "$1" == "-v" ]] && exec klayout -b -v # pass-thru -v + + export _M0= + for i in "$@" ; do _M0="$_M0${_M0:+,}\"${i//\"/\\\"}\""; done + exec klayout -e -b -r "$0" -rd tag="$_M0" + # tag= is NOT USED, cosmetic: So process-listing shows the arguments, and a + # user can distinguish one process from another, despite running same klayout-script. +} +# for-ruby: + +argv=eval("[ #{ENV["_M0"]} ]") # re-parse args from env-var +# puts "argv.size=#{argv.size}" +# argv.each{ |v| puts v } + + thisScript = $0 + prog="gdsArea0.rb" + usage = "Usage: #{prog} [options] [ ]" + usage += "\n Find (optionally delete) zero-area objects and optionally write modified gds out." + require 'optparse' + + if argv.empty? + argv << '--help' + end + + o = {:writeAlways=>true} + OptionParser.new do |opts| + opts.banner = usage + opts.on("-n", "Don't write gdsOutFile IF NO SHAPES DELETED. Default, if outFile given: always write.") do + o[:writeAlways] = false + end + + opts.on("-v", "--version", "version: pass-thru, JUST show klayout version") do + exec "klayout -b -v" + end + opts.on("--help", "show usage") do + puts opts + exit 1 + end + opts.on("--usage", "show usage") do + puts opts + exit 1 + end + end.parse!(argv) # default constant ARGV? Doesn't work here: not true ruby. + # "!" on end of parse: argv parameter is MODIFIED by OptionParser to delete the processed options. + + if argv.length < 1 || argv.length > 2 + puts "ERROR, not 1 or 2 arguments. #{usage}" + exit 1 + end +f = argv[0] +# c = argv[1] +fout = argv[1] + +if f == "" + puts "ERROR: insufficient arguments. #{usage}" + exit 1 +end + +doDel = fout && (fout != "") # actively do deletes IFF given an output file arg. + +# include RBA +begin + +if doDel + if o[:writeAlways] + puts "Running #{prog} on file=#{f}, output to #{fout} always" + else + puts "Running #{prog} on file=#{f}, output to #{fout} only if there were deletes" + end +else + puts "Running #{prog} on file=#{f} (passive, no gdsFileOut)" +end +puts " args: #{ENV["_M0"]}" + +STDOUT.flush +$errs = 0 +del = 0 + +# based in part on: https://www.klayout.de/forum/discussion/173/use-klayout-in-batch-mode +ly = RBA::Layout.new +ly.read(f) + +## source(f, c) +# s = source(f) +# layout = s.layout +# target(fout) + +ly.layer_indices.each { |li| + ly.each_cell { |cell| + cell.shapes(li).each { |shape| + # TODO: must we check that shape is one of: box, polygon, path? What happens to text? + if shape.is_valid? && (!shape.is_null?) && + (shape.is_box? || shape.is_path? || shape.is_polygon?) && + shape.area == 0 + $errs += 1 + if doDel + shape.delete + del += 1 + end + end + } + } +} + +if fout && fout != "" + if (! o[:writeAlways] ) && del == 0 + puts "Skipped write of #{fout} due -n and nothing deleted." + else + puts "writing #{fout} ..." + ly.write(fout) + end +end + +puts "#{$errs} zero-area shapes, #{del} shapes deleted." + +# if we roll-over to 256, exit-status seen by shell is zero. +# uncaught I/O errors will yield (built-in) exit status of 1. +if $errs > 0 + $errs = $errs + 1 +end +if $errs > 127 + $errs = 127 +end + +# experimental: report own peak process-stats. BUT: output-file isn't really written +# until we exit (during exit). So these results are not 100% accurate. +# VmHWM: max-resident-size, VmPeak: max virtual-size. +# don't need: pid=Process.pid +if File.readable?("/proc/self/status") + puts File.foreach("/proc/self/status").grep(/^(VmPeak|VmHWM)/) +end + +end # end begin + +# does not work (to set exit-status) in 0.23.11. Does work in 0.24.2, 0.27. +exit $errs + +# +# emacs syntax-mode: +# Local Variables: +# mode:ruby +# End: diff --git a/images/foss-asic-tools/addons/sak/klayout/gdsAreamin.drc b/images/foss-asic-tools/addons/sak/klayout/gdsAreamin.drc new file mode 100755 index 00000000..031674aa --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/gdsAreamin.drc @@ -0,0 +1,155 @@ +#!/usr/bin/ruby +# usage: gdsAreamin.rb +# +# Runs klayout (in batch) to flag shapes have area zero or less-than given-area. +# If you give zero: flags shapes with area EQUAL-TO zero. +# Else: flags shapes with area LESS-THAN (and NOT equal-to) the given area. +# Operates on RAW shapes (not merged) and all layers, all cells. See CAVEATS below. +# +# Script starts as regular ruby, then exec's via klayout passing self to it. +# (klayout requirement is this script-name *must* end in .rb). +# based on ://www.klayout.de/staging/forum/discussion/1066/extract-layer-list-and-top-cell-name-from-gds-file +# +# TODO: Take klayout .lyt tech-file as optional arg, and use to apply nice symbolic names to +# the output layers (instead of just "125/44" style numeric layernum/datatype). +# +# CAVEATS: Also intent was: flag zero-area shapes that commerical tools would die on since they +# are degenerate polygons. But so far this DOES NOT WORK: Suspect klayout absorbs/discards +# degenerate (or all zero area) polygons on read-in; and will never flag zero-area shapes. +# For that original purpose a non-PDK-specific script was sufficient: process all layers +# indiscriminately, and give an area=0 or very close to zero. +# For other uses a more general script should support any combo of either/both upper/lower +# area bounds, and to limit to specific layers or layer-intersections, and to disable RAW +# mode (i.e. operate on fully merged polygons: which is slower but usually desireable). +# +InKlayout=$InKlayout +if InKlayout.to_s.empty? + thisScript = $0 + f = ARGV[0] + a = ARGV[1] + fout = ARGV[2] + + if f == "--version" || f == "-v" + # these options don't prevent klayout from initializing ~/.klayout unfortunately... + exec "klayout -nc -rx -zz -v" + end + + if ARGV.length != 3 + puts "ERROR, must give one argument, usage: gdsAreamin.rb " + puts "If minAreaSqMicrons is 0, will flag RAW shapes with area == 0." + puts "If minAreaSqMicrons is not 0, will flag RAW shapes with area < minAreaSqMicrons." + puts "Exit-status: 0 on success; 1 on I/O or usage error. See also gdsAllcells.rb" + exit 1 + end + + + # construct command from our script arguments, replace self with klayout... + exec "klayout -nc -zz -rx -rd InKlayout=1 -rd file=#{f} -rd fileOut=#{fout} -rd area=#{a} -r #{thisScript}" +end + +# +# to just read a gds in batch (no useful info printed): +# klayout -d 40 -z xyz.gds >& klayout.read.log +# +# -d : debug level, no details during GDS-reading however, try 20 or 40 or (timing too:) 21 or 41 +# -z/-zz : -z pseudo-batch mode, still needs X-DISPLAY connection; -zz true batch +# -nc : don't use/update configuration file +# -rx : disable built-in macros, stuff not needed for batch usually +# -rd : define variables the script can reference +# + +f = $file +a = $area +fout = $fileOut + +if f == "" || a == "" || fout == "" + STDERR.puts "ERROR: missing gdsFile argument, usage: gdsAreamin.rb " + exit 1 +end + +a_invalid = !Float(a) rescue true +if a_invalid + STDERR.puts "ERROR: failed to parse min-area '#{a}' as a float." + exit 1 +end + +af = Float(a) +afs = af.to_s +# puts "got f='#{f}', a='#{a}' af.to_s='#{afs}'" + +if af < 0.0 + STDERR.puts "ERROR: min-area '#{afs}' cannot be negative." + exit 1 +end + +if af == 0.0 + why = "area == #{afs}" + whyt = "area == #{a}" +else + why = "area < #{afs}" + whyt = "area < #{a}" +end + +# include RBA + +begin + STDERR.puts "Reading file #{f}, to check shapes for #{whyt}, output to #{fout}" + # layout = Layout.new + # layout.read(f) + # dbu = layout.dbu + # STDERR.puts "dbu=#{dbu}" + s = source(f) + layout = s.layout + + title = "gdsAreamin.rb, input=#{f}, #{whyt}" + report(title, fout) + + threads(4) + deep + + errs = 0 + layers = 0 + total = 0 + ruleHeader = "--- #err|description" + + STDERR.flush + layout.layer_indices.each do |layer_id| + layers = layers + 1 + layer_info = layout.get_info(layer_id) + lpp = layer_info.to_s + # puts "checking #{lpp} ..." + layer = input(lpp).raw + if af == 0.0 + mark = layer.with_area(af).raw # area == af + else + mark = layer.with_area(nil, af).raw # area < af + end + mark.output("#{lpp} #{why}") + size = mark.data.size + if size > 0 + puts ruleHeader if errs == 0 + errs = errs + 1 + total = total + size + puts "%8d %s %s" % [size, lpp, why] + else + end + end + +end + +STDERR.puts "%8d total, among %d layers flagged, of %d source layers" % [total, errs, layers] + +# reserve status=1 for I/O errors +if errs > 0 + errs = errs + 1 +end +# don't roll-over exit-status to/past zero +if errs > 255 + errs = 255 +end + +# exit doesn't work to set status; exit! requires explicit buffered-IO flush. +STDOUT.flush +STDERR.flush +exit errs +# Kernel.exit! errs diff --git a/images/foss-asic-tools/addons/sak/klayout/gdsFlat.rb b/images/foss-asic-tools/addons/sak/klayout/gdsFlat.rb new file mode 100755 index 00000000..2f4e3365 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/gdsFlat.rb @@ -0,0 +1,125 @@ +#!/usr/bin/ruby +# usage: gdsFlat.rb +# +# Runs klayout (in batch) to flatten the topCell to a new output file. +# Script starts as regular ruby, then exec's via klayout passing self to it. +# (klayout requirement is this script-name *must* end in .rb). +# +InKlayout=$InKlayout +if InKlayout.to_s.empty? + thisScript = $0 + mode="flat" + argvLenReq = 3 + + f = ARGV[0] + c = ARGV[1] + fout = ARGV[2] + + if f == "--version" || f == "-v" + exec "klayout -nc -zz -rx -v" + end + + if f == "--hier" + argvLenReq = 4 + mode="hier" + f = ARGV[1] + c = ARGV[2] + fout = ARGV[3] + end + + if ARGV.length != argvLenReq + puts "ERROR, must give three non-option arguments, usage: gdsFlat.rb [--hier] " + puts 'Output format inferred from gdsOutFile: .gds[.gz] -> "GDS2", .oas[.gz] -> "OASIS"' + exit 1 + end + + + # construct command from our script arguments, replace self with klayout... + # puts "got: mode='#{mode}' f='#{f}' c='#{c}' fout='#{fout}'" + exec "klayout -nc -zz -rx -rd InKlayout=1 -rd mode=#{mode} -rd file=#{f} -rd topcell=#{c} -rd fileOut=#{fout} -r #{thisScript}" +end + +# +# -d : debug level, no details during GDS-reading however, try 20 or 40 or (timing too:) 21 or 41 +# -z/-zz : -z pseudo-batch mode, still needs X-DISPLAY connection; -zz true batch +# -nc : don't use/update configuration file +# -rx : disable built-in macros, stuff not needed for batch usually +# -rd : define variables the script can reference +# + +m = $mode +f = $file +c = $topcell +fout = $fileOut + +# puts "got: m='#{m}' f='#{f}' c='#{c}' fout='#{fout}'" + +if f == "" + puts "ERROR: missing gdsFile argument, usage: gdsFlat.rb " + exit 1 +elsif c == "" + puts "ERROR: missing gdsFile argument, usage: gdsFlat.rb " + exit 1 +elsif fout == "" + puts "ERROR: missing gdsFile argument, usage: gdsFlat.rb " + exit 1 +end + +if m == "hier" + puts "WARNING: hierarchical output is experimental (needs more testing)." +elsif m != "flat" + puts "ERROR: mode, '#{m}' is unknown/unsupported." + exit 1 +end + +include RBA + +begin + puts "Reading file #{f} for topcell #{c}" + # make new layout. Also editable: needed for flatten only (SLOWER, avoid if possible) + if m == "flat" + layout = Layout.new(true) + else + layout = Layout.new(false) + end + layout.read(f) + + cell = layout.cell(c) + if cell.to_s.empty? + puts "couldn't open the cell #{c}" + exit 1 + end + + # flatten cell (i.e. each instance replaced with direct content)? + if m == "flat" + puts "Flattening topcell #{c}" + cell.flatten(true) + end + # flatten within each subcell only? + # cell.each_child_cell do |subcellName| + # subcell = layout.cell(subCellName) + # subcell.flatten(true) + # end + + # make options that say: save just one cell (and its sub-hier) + slo = SaveLayoutOptions.new + cellNdx = cell.cell_index + slo.add_cell(cellNdx) + + # format="OASIS" + # compress = false + # slo.format=format + # ... + # layout.write(fout, compress, slo) + + # Infer format from output filename (i.e *.oas => "OASIS") + slo.set_format_from_filename(fout) + + # save (usually flattened) cell (and its sub-hier) + puts "Writing file #{fout} format:#{slo.format} for topcell: #{c} and sub-hier" + layout.write(fout, slo) + +end + +puts "Done." + diff --git a/images/foss-asic-tools/addons/sak/klayout/gdsLayers.rb b/images/foss-asic-tools/addons/sak/klayout/gdsLayers.rb new file mode 100755 index 00000000..81901e00 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/gdsLayers.rb @@ -0,0 +1,96 @@ +#!/usr/bin/ruby +# usage: gdsLayers.rb +# LIMITATION: effectively sees/processes layers present in all cells, +# not just the hierarchy of "the" one topcell of interest. i.e. Can be +# multiple topcells, where only the hier. of the "extra" topcells have +# certain layers; where better is to limit output to layers in the hier. +# of just one specific topcell. +# +# TODO: take optional topcell argument: If present, delete the other +# topcells, and loop, until just that one topcell is left. (Assumes +# deleting a topcell will expose/promote subcells as new topcells). +# +# Runs klayout (in batch) to print layer-info of all layers present in a GDS file. +# Script starts as regular ruby, then exec's via klayout passing self to it. +# (klayout requirement is this script-name *must* end in .rb). +# based on ://www.klayout.de/staging/forum/discussion/1066/extract-layer-list-and-top-cell-name-from-gds-file +# +InKlayout=$InKlayout +if InKlayout.to_s.empty? + thisScript = $0 + f = ARGV[0] + c = ARGV[1] + + if f == "--version" || f == "-v" + # these options don't prevent klayout from initializing ~/.klayout unfortunately... + exec "klayout -nc -rx -zz -v" + end + + if ARGV.length != 1 + puts "ERROR, must give one argument, usage: gdsLayers.rb " + puts "LIMITATION: effectively outputs layers from any cell, i.e. not limited to" + puts "layers used in hierarchy of just one topcell (if they are multiple topcells)." + puts "Work-around: 1st isolate the hier. of just one top cell via:" + puts " gdsFlat.rb --hier && gdsLayers.rb " + puts "Exit-status: 0 on success; 1 on I/O or usage error. See also gdsAllcells.rb" + exit 1 + end + + + # construct command from our script arguments, replace self with klayout... + exec "klayout -nc -zz -rx -rd InKlayout=1 -rd file=#{f} -r #{thisScript}" +end + +# +# to just read a gds in batch (no useful info printed): +# klayout -d 40 -z xyz.gds >& klayout.read.log +# +# -d : debug level, no details during GDS-reading however, try 20 or 40 or (timing too:) 21 or 41 +# -z/-zz : -z pseudo-batch mode, still needs X-DISPLAY connection; -zz true batch +# -nc : don't use/update configuration file +# -rx : disable built-in macros, stuff not needed for batch usually +# -rd : define variables the script can reference +# + +f = $file + +if f == "" + STDERR.puts "ERROR: missing gdsFile argument, usage: gdsLayers.rb " + exit 1 +end + +include RBA + +begin + STDERR.puts "Reading file #{f}" + layout = Layout.new + layout.read(f) + # dbu = layout.dbu + # STDERR.puts "dbu=#{dbu}" + + errs = 0 + + STDERR.puts "Layers:" + STDERR.flush + layout.layer_indices.each do |layer_id| + layer_info = layout.get_info(layer_id) + puts layer_info.to_s + end + +end + +# STDERR.puts "Done." + +# reserve status=1 for I/O errors +if errs > 0 + errs = errs + 1 +end +# don't roll-over exit-status to/past zero +if errs > 255 + errs = 255 +end + +# exit doesn't work to set status; exit! requires explicit buffered-IO flush. +STDOUT.flush +STDERR.flush +Kernel.exit! errs diff --git a/images/foss-asic-tools/addons/sak/klayout/gdsLyrdel.rb b/images/foss-asic-tools/addons/sak/klayout/gdsLyrdel.rb new file mode 100755 index 00000000..d411e253 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/gdsLyrdel.rb @@ -0,0 +1,79 @@ +#!/usr/bin/ruby +# usage: gdsLyrdel.rb +# +# Runs klayout (in batch) to flatten the topCell to a new output file. +# Script starts as regular ruby, then exec's via klayout passing self to it. +# (klayout requirement is this script-name *must* end in .rb). +# +InKlayout=$InKlayout +if InKlayout.to_s.empty? + thisScript = $0 + mode="flat" + argvLenReq = 4 + + fin = ARGV[0] + fout = ARGV[1] + lnum = ARGV[2] + dnum = ARGV[3] + + if fin == "--version" || fin == "-v" + exec "klayout -nc -zz -rx -v" + end + + if ARGV.length != argvLenReq + puts "ERROR, must give four non-option arguments, usage: gdsLyrdel.rb " + puts 'Output format inferred from gdsOutFile: .gds[.gz] -> "GDS2", .oas[.gz] -> "OASIS"' + exit 1 + end + + + # construct command from our script arguments, replace self with klayout... + exec "klayout -nc -zz -rx -r #{thisScript} -rd lnum=#{lnum} -rd dnum=#{dnum} -rd file=#{fin} -rd fileOut=#{fout} -rd InKlayout=1" +end + +# +# -d : debug level, no details during GDS-reading however, try 20 or 40 or (timing too:) 21 or 41 +# -z/-zz : -z pseudo-batch mode, still needs X-DISPLAY connection; -zz true batch +# -nc : don't use/update configuration file +# -rx : disable built-in macros, stuff not needed for batch usually +# -rd : define variables the script can reference +# + +fin = $file +fout = $fileOut +lnum = $lnum.to_i +dnum = $dnum.to_i + +puts "got: fin='#{fin}' fout='#{fout}' lnum='#{lnum}' dnum='#{dnum}'" + + +include RBA + +begin + puts "Reading file #{fin}" + # make new layout and editable. + layout = Layout.new(true) + layout.read(fin) + + lpp = layout.find_layer(lnum, dnum) + if lpp + puts "deleting layer: #{lnum}/#{dnum}" + STDOUT.flush + layout.delete_layer(lpp) + else + STDERR.puts "ERROR: layer not found: #{lnum}/#{dnum}" + STDERR.flush + exit 1 + end + + # Infer format from output filename (i.e *.oas => "OASIS") + slo = SaveLayoutOptions.new + slo.set_format_from_filename(fout) + + # save cell and its sub-hier + puts "Writing file #{fout} format:#{slo.format} ..." + layout.write(fout, slo) +end + +puts "Done." + diff --git a/images/foss-asic-tools/addons/sak/klayout/gdsRename.rb b/images/foss-asic-tools/addons/sak/klayout/gdsRename.rb new file mode 100755 index 00000000..dd0d42db --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/gdsRename.rb @@ -0,0 +1,86 @@ +#!/usr/bin/ruby +# usage: gdsRename.rb +# +# Runs klayout (in batch) to rename a cell and write a new output file. +# Script starts as regular ruby, then exec's via klayout passing self to it. +# (klayout requirement is this script-name *must* end in .rb). +# +InKlayout=$InKlayout +if InKlayout.to_s.empty? + thisScript = $0 + argvLenReq = 4 + + f1 = ARGV[0] + + if f1 == "--version" || f1 == "-v" + exec "klayout -nc -zz -rx -v" + end + + if ARGV.length != argvLenReq + puts "ERROR, 4 arguments required, usage: gdsRename.rb " + exit 1 + end + + f2 = ARGV[1] + c1 = ARGV[2] + c2 = ARGV[3] + + # construct command from our script arguments, replace self with klayout... + # puts "got: f1='#{f1}' f2='#{f2}' c1='#{c1}' c2='#{c2}'" + exec "klayout -nc -zz -rx -rd InKlayout=1 -rd file1=#{f1} -rd file2=#{f2} -rd cell1=#{c1} -rd cell2=#{c2} -r #{thisScript}" +end + +# +# -d : debug level, no details during GDS-reading however, try 20 or 40 or (timing too:) 21 or 41 +# -z/-zz : -z pseudo-batch mode, still needs X-DISPLAY connection; -zz true batch +# -nc : don't use/update configuration file +# -rx : disable built-in macros, stuff not needed for batch usually +# -rd : define variables the script can reference +# + +f1 = $file1 +f2 = $file2 +c1 = $cell1 +c2 = $cell2 +# puts "got: f1='#{f1}' f2='#{f2}' c1='#{c1}' c2='#{c2}'" + +if f1 == "" || f2 == "" || c1 == "" || c2 == "" + puts "ERROR, 4 arguments required, usage: gdsRename.rb " + exit 1 +end + +if c1 == c2 + puts "ERROR, cellFrom=#{c1} & cellTo=#{c2} cannot be the same." + exit 1 +end + +include RBA + +begin + puts "Reading file #{f1}" + # make new layout and editable (since we'll flatten) + layout = Layout.new(true) + layout.read(f1) + + cell1 = layout.cell(c1) + if cell1.to_s.empty? + puts "ERROR: couldn't open the cell #{c1}" + exit 1 + end + + cell2 = layout.cell(c2) + if ! cell2.to_s.empty? + puts "ERROR: replacement cellTo #{c2} already exists in source file #{f1}" + exit 1 + end + + layout.rename_cell(cell1.cell_index, c2) + puts "renamed cell: #{c1} to #{c2}" + + # save to file2 + puts "Writing file #{f2}" + layout.write(f2) + +end + +puts "Done." diff --git a/images/foss-asic-tools/addons/sak/klayout/gdsSize.rb b/images/foss-asic-tools/addons/sak/klayout/gdsSize.rb new file mode 100755 index 00000000..f4063bb7 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/gdsSize.rb @@ -0,0 +1,123 @@ +#!/usr/bin/ruby +# usage: gdsSize.rb +# +# Runs klayout (in batch) to get bbox of a cell in a GDS file. +# Script starts as regular ruby, then exec's via klayout passing self to it. +# (klayout requirement is this script-name *must* end in .rb). +# +InKlayout=$InKlayout +if InKlayout.to_s.empty? + thisScript = $0 + f = ARGV[0] + c = ARGV[1] + + if f == "--version" || f == "-v" + # these options don't prevent klayout from initializing ~/.klayout unfortunately... + exec "klayout -nc -rx -zz -v" + end + + if ARGV.length != 2 + puts "ERROR, must give two arguments, usage: gdsSize.rb " + puts " It's an error if unbound (referenced by others, not defined)." + puts " But that's the only unbound checked, no other cells checked or reported." + puts "Exit-status: 0 on success; 1 on I/O or usage error; 2 unbound. See also gdsAllcells.rb" + exit 1 + end + + + # construct command from our script arguments, replace self with klayout... + exec "klayout -nc -zz -rx -rd InKlayout=1 -rd file=#{f} -rd topcell=#{c} -r #{thisScript}" +end + +# +# to just read a gds in batch (no useful info printed): +# klayout -d 40 -z xyz.gds >& klayout.read.log +# +# -d : debug level, no details during GDS-reading however, try 20 or 40 or (timing too:) 21 or 41 +# -z/-zz : -z pseudo-batch mode, still needs X-DISPLAY connection; -zz true batch +# -nc : don't use/update configuration file +# -rx : disable built-in macros, stuff not needed for batch usually +# -rd : define variables the script can reference +# + +f = $file +c = $topcell + +if f == "" + STDERR.puts "ERROR: missing gdsFile argument, usage: gdsSize.rb " + exit 1 +elsif c == "" + STDERR.puts "ERROR: missing cellName argument, usage: gdsSize.rb " + exit 1 +end + +include RBA + +begin + puts "Reading file #{f} for cell #{c}" + layout = Layout.new + layout.read(f) + dbu = layout.dbu + puts "dbu=#{dbu}" + + errs = 0 + + # does not catch case where cell.bbox -> "()" + if ! layout.has_cell?(c) + STDERR.puts "ERROR: layout does not have the cell #{c}" + STDOUT.flush + STDERR.flush + Kernel.exit! 1 + end + + cell = layout.cell(c) + if cell.to_s.empty? + STDERR.puts "ERROR: couldn't open the cell #{c}" + STDOUT.flush + STDERR.flush + Kernel.exit! 1 + end + + bbox = cell.bbox + bbox_str = bbox.to_s + puts "cell #{c} dbu-bbox(ll;ur)=#{bbox}" + + if bbox_str == "()" + STDERR.puts "ERROR: no or empty bbox for the cell #{c}" + errs = errs + 1 + else + l = bbox.left + b = bbox.bottom + r = bbox.right + t = bbox.top + w = r - l + h = t - b + puts "cell #{c} dbu-bbox(left,bottom,right,top)=(#{l},#{b},#{r},#{t})" + puts "cell #{c} dbu-size(width,height)=(#{w},#{h})" + l = l * dbu + b = b * dbu + r = r * dbu + t = t * dbu + w = w * dbu + h = h * dbu + puts "cell #{c} micron-bbox(left,bottom,right,top)=(#{l},#{b},#{r},#{t})" + puts "cell #{c} micron-size(width,height)=(#{w},#{h})" + end + +end + +puts "Done." + +# reserve status=1 for I/O errors +if errs > 0 + errs = errs + 1 +end +# don't roll-over exit-status to/past zero +if errs > 255 + errs = 255 +end + +# exit doesn't work to set status; exit! requires explicit buffered-IO flush. +STDOUT.flush +STDERR.flush +Kernel.exit! errs diff --git a/images/foss-asic-tools/addons/sak/klayout/gdsTopcells.rb b/images/foss-asic-tools/addons/sak/klayout/gdsTopcells.rb new file mode 100755 index 00000000..540d6472 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/gdsTopcells.rb @@ -0,0 +1,51 @@ +#!/usr/bin/ruby +# usage: gdsTopcells.rb +# +# Runs klayout (in batch) to read gdsFile, and enumerate topcell(s) to STDOUT one per line. +# Script starts as regular ruby, then exec's via klayout passing self to it. +# (klayout requirement is this ruby script-name *must* end in .rb). +# +InKlayout=$InKlayout +if InKlayout.to_s.empty? + thisScript = $0 + f = ARGV[0] + + if f == "--version" || f == "-v" + exec "klayout -nc -zz -rx -v" + end + + if ARGV.length != 1 + puts "ERROR, must give one argument, usage: gdsTopcells.rb " + exit 1 + end + + # construct command from our script arguments, replace self with klayout... + exec "klayout -nc -zz -rx -rd InKlayout=1 -rd file=#{f} -r #{thisScript}" + +end + +# +# -d : debug level, no details during GDS-reading however, try 20 or 40 or (timing too:) 21 or 41 +# -z/-zz : -z pseudo-batch mode, still needs X-DISPLAY connection; -zz true batch +# -nc : don't use/update configuration file +# -rx : disable built-in macros, stuff not needed for batch usually +# -rd : define variables the script can reference +# + +f = $file + +if f == "" + puts "ERROR: missing gdsFile argument" + exit 1 +end + +begin + +ly = RBA::Layout::new +ly.read(f) + +ly.top_cells.each { |curCell| + puts "#{curCell.name}" +} +exit 0 +end diff --git a/images/foss-asic-tools/addons/sak/klayout/gdstk_merge.py b/images/foss-asic-tools/addons/sak/klayout/gdstk_merge.py new file mode 100755 index 00000000..ce508936 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/gdstk_merge.py @@ -0,0 +1,91 @@ +# SPDX-FileCopyrightText: 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +# Use caravel_xxxxyyyy as the golden caravel +from pathlib import Path +import gdstk +import argparse +import os.path +import sys + + +def gdstk_merge(layout_caravel, layout_merge): + # Now we load the existing libraries + lib2 = [] + if caravel_oas: + lib1 = gdstk.read_oas(layout_caravel) + else: + lib1 = gdstk.read_gds(layout_caravel) + if merge_oas: + for layout in layout_merge: + lib2.append(gdstk.read_oas(layout)) + else: + for layout in layout_merge: + lib2.append(gdstk.read_gds(layout_merge)) + + lib1 = change_uid(lib1) + + # We add all cells from the second library to the first + lib1_cell_names = set(c.name for c in lib1.cells) + for libs in lib2: + for cell in libs.cells: + # check if the cell already exist, if it does then replace it + if cell.name in lib1_cell_names: + lib1.replace(cell) + # Now we add the cell and update the set of names + lib1.add(cell) + lib1_cell_names.add(cell.name) + + lib1.write_gds("caravel_" + user_id_value + ".gds") + + +def change_uid(lib): + for cells in lib.cells: + if "xxxxyyyy" in cells.name: + cells.name = cells.name.replace("xxxxyyyy", user_id_value) + assert cells.name + return lib + + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("-uid", "--user_id", required=True, type=str, help="User ID character string of eight hex digits") + parser.add_argument("-l1", "--layout1_path", required=True, type=Path, help="template caravel path") + parser.add_argument("-l2", "--layout2_path", required=True, type=Path, help="gds to get merged file path", nargs=2) + args = parser.parse_args() + + layout_merge = [] + + layout_caravel = Path(args.layout1_path).absolute() + user_id_value = args.user_id + + for layout in args.layout2_path: + layout_merge.append(Path(layout).absolute()) + + extension = os.path.splitext(layout_caravel)[1] + if extension == ".oas": + caravel_oas = True + else: + caravel_oas = False + + extension = os.path.splitext(layout_merge[0])[1] + if extension == ".oas": + merge_oas = True + else: + merge_oas = False + + gdstk_merge(layout_caravel, layout_merge) diff --git a/images/foss-asic-tools/addons/sak/klayout/klayoutDrc.sh b/images/foss-asic-tools/addons/sak/klayout/klayoutDrc.sh new file mode 100755 index 00000000..83ceb1cc --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/klayoutDrc.sh @@ -0,0 +1,92 @@ +#!/bin/sh +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +usage() { echo "Usage: $0 [ -f ] [ -m ] [ -d ] [ -t ] " 1>&2; exit 2; } + +drc_full=false +drc_mr=false +drc_fom=false +thr=16 + +while getopts "fmdt:" o; do + case "${o}" in + f) + drc_full=true + ;; + m) + drc_mr=true + ;; + d) + drc_fom=true + ;; + t) + thr=${OPTARG} + ;; + *) + usage + ;; + esac +done +shift $((OPTIND-1)) + +set -e + +target_path=${1} +input_gds=${2} + +tech_mr=${SAK}/../klayout/tech/sky130A/sky130A-mr.lydrc +tech_full=${SAK}/../klayout/tech/sky130A/sky130A-full.lydrc +tech_fom=${SAK}/../klayout/tech/sky130A/sky130A-fom.lydrc + + +if [ $drc_full = true ]; then + klayout -b \ + -rd input=${input_gds} \ + -rd report=${target_path}/${2%.gds}-full.lyrdb \ + -rd thr=${thr} \ + -r ${tech_full} |& tee ${target_path}/${2%.gds}-full.log + + klayout $2 -m ${2%.gds}-full.lyrdb + +fi + +if [ $drc_mr = true ]; then + klayout -b \ + -rd input=${input_gds} \ + -rd report=${target_path}/${2%.gds}-mr.lyrdb \ + -rd thr=${thr} \ + -r ${tech_mr} |& tee ${target_path}/${2%.gds}-mr.log + + klayout $2 -m ${2%.gds}-mr.lyrdb + +fi + + +if [ $drc_fom = true ]; then + klayout -b \ + -rd input=${input_gds} \ + -rd report=${target_path}/${2%.gds}-fom.lyrdb \ + -rd thr=${thr} \ + -r ${tech_fom} |& tee ${target_path}/${2%.gds}-fom.log + + klayout $2 -m ${2%.gds}-fom.lyrdb + +fi + + + + + +exit 0 diff --git a/images/foss-asic-tools/addons/sak/klayout/label2pin_inplace.sh b/images/foss-asic-tools/addons/sak/klayout/label2pin_inplace.sh new file mode 100755 index 00000000..7cd2a4f7 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/label2pin_inplace.sh @@ -0,0 +1,9 @@ +layers=(67 68 69 70 71 72) +files=( "$@" ) + +for f in "${files[@]}"; do + echo "Working on $f" + for l in "${layers[@]}"; do + sh $(dirname $0)/cp_shapes.sh $f $l/5 $l/16 + done +done diff --git a/images/foss-asic-tools/addons/sak/klayout/lay2net.sh b/images/foss-asic-tools/addons/sak/klayout/lay2net.sh new file mode 100755 index 00000000..103e4840 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/lay2net.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This script extract the netlist from a layout using Klayout + +: ${1? "Usage: $0 The gds file that will be extracted"} + +echo "converting $1 to spice netlist" + +klayout -b -rd input=$1 \ + -r lvs_sky130.lylvs diff --git a/images/foss-asic-tools/addons/sak/klayout/lvs_sky130.lylvs b/images/foss-asic-tools/addons/sak/klayout/lvs_sky130.lylvs new file mode 100755 index 00000000..3663572f --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/lvs_sky130.lylvs @@ -0,0 +1,220 @@ + + + + + lvs + + + + false + false + + true + lvs_scripts + tools_menu.lvs.end + dsl + lvs-dsl-xml + +# Extraction for SKY130 +# +############################ + +#report_netlist("report.txt") + +# optionnal for a batch launch : klayout -b -rd input=my_layout.gds -rd report=my_report.lyrdb -rd schematic=reference_netlist.cir -rd target_netlist=extracted_netlist.cir -r sky130.lvs +if $input + source($input) +end + +# true: use net names instead of numbers +# false: use numbers for nets +spice_with_net_names = true + +# true: put in comments with details +# false: no comments +spice_with_comments = true + +# Write extracted netlist to extracted.cir using a special +# writer delegate + + +if $target_netlist + target_netlist($target_netlist) +else + # target_netlist("netlist.cir", write_spice(spice_with_net_names, spice_with_comments), "Generated by Klayout on : #{Time.now.strftime("%d/%m/%Y %H:%M")}") + target_netlist(File.join(File.dirname(RBA::CellView::active.filename), source.cell_name+"_extracted.spice"),write_spice(spice_with_net_names, spice_with_comments),"Extracted by KLayout on : #{Time.now.strftime("%d/%m/%Y %H:%M")}") +end + +# Hierarchical mode +deep +# Use 4 CPU cores +threads(4) +# Print details +verbose(true) + + +# layers definitions +######################## +BOUND = polygons(235, 4) +DNWELL = polygons(64, 18) +PWRES = polygons(64, 13) +NWELL = polygons(64, 20) +NWELLTXT = input(64, 5) +NWELLPIN = polygons(64, 16) +SUBTXT = input(122, 5) +SUBPIN = input(64, 59) +DIFF = polygons(65, 20) +TAP = polygons(65, 44) +PSDM = polygons(94, 20) +NSDM = polygons(93, 44) +LVTN = polygons(125, 44) +HVTR = polygons(18, 20) +HVTP = polygons(78, 44) +SONOS = polygons(80, 20) +COREID = polygons(81, 2) +STDCELL = polygons(81, 4) +NPNID = polygons(82, 20) +PNPID = polygons(82, 44) +RPM = polygons(86, 20) +URPM = polygons(79, 20) +LDNTM = polygons(11, 44) +HVNTM = polygons(125, 20) +POLY = polygons(66, 20) +POLYTXT = input(66, 5) +POLYPIN = polygons(66, 16) +HVI = polygons(75, 20) +LICON = polygons(66, 44) +NPC = polygons(95, 20) +DIFFRES = polygons(65, 13) +POLYRES = polygons(66, 13) +POLYSHO = polygons(66, 15) +DIODE = polygons(81, 23) +LI = polygons(67, 20) +LITXT = input(67, 5) +LIPIN = polygons(67, 16) +LIRES = polygons(67, 13) +MCON = polygons(67, 44) +MET1 = polygons(68, 20) +MET1TXT = input(68, 5) +MET1PIN = polygons(68, 16) +MET1RES = polygons(68, 13) +VIA1 = polygons(68, 44) +MET2 = polygons(69, 20) +MET2TXT = input(69, 5) +MET2PIN = polygons(69, 16) +MET2RES = polygons(69, 13) +VIA2 = polygons(69, 44) +MET3 = polygons(70, 20) +MET3TXT = input(70, 5) +MET3PIN = polygons(70, 16) +MET3RES = polygons(70, 13) +VIA3 = polygons(70, 44) +MET4 = polygons(71, 20) +MET4TXT = input(71, 5) +MET4PIN = polygons(71, 16) +MET4RES = polygons(71, 13) +VIA4 = polygons(71, 44) +MET5 = polygons(72, 20) +MET5TXT = input(72, 5) +MET5PIN = polygons(72, 16) +MET5RES = polygons(72, 13) +RDL = polygons(74, 20) +RDLTXT = input(74, 5) +RDLPIN = polygons(74, 16) +GLASS = polygons(76, 20) +CAPM = polygons(89, 44) +CAPM2 = polygons(97, 44) +LOWTAPD = polygons(81, 14) +FILLOBSM1 = polygons(62, 24) +FILLOBSM2 = polygons(105, 52) +FILLOBSM3 = polygons(107, 24) +FILLOBSM4 = polygons(112, 4) +NCM = polygons(92, 44) + +# Bulk layer for terminal provisioning +SUB = polygons(236, 0) +# SUB = polygon_layer + +# Computed layers +PDIFF = DIFF & NWELL & PSDM +NTAP = TAP & NWELL & NSDM +PGATE = PDIFF & POLY +PSD = PDIFF - PGATE +STD_PGATE = PGATE - HVTP - NCM - HVI +HVT_PGATE = PGATE & HVTP - NCM - HVI +HV5_PGATE = PGATE - HVTP - NCM & HVI + +NDIFF = DIFF - NWELL & NSDM +PTAP = TAP - NWELL & PSDM +NGATE = NDIFF & POLY +NSD = NDIFF - NGATE +STD_NGATE = NGATE - NCM - LVTN - HVI +LVT_NGATE = NGATE - NCM & LVTN - HVI +HV5_NGATE = NGATE - NCM - LVTN & HVI +HV5NA_NGATE = NGATE - NCM & LVTN & HVI + +# drawing to physical +device_scaling(1000000) + +# PMOS transistor device extraction +extract_devices(mos4("pfet_01v8"), { "SD" => PSD, "G" => STD_PGATE, "tS" => PSD, "tD" => PSD, "tG" => POLY, "W" => NWELL }) +extract_devices(mos4("pfet_01v8_hvt"), { "SD" => PSD, "G" => HVT_PGATE, "tS" => PSD, "tD" => PSD, "tG" => POLY, "W" => NWELL }) +extract_devices(mos4("pfet_g5v0d10v5"), { "SD" => PSD, "G" => HV5_PGATE, "tS" => PSD, "tD" => PSD, "tG" => POLY, "W" => NWELL }) + +# NMOS transistor device extraction +extract_devices(mos4("nfet_01v8"), { "SD" => NSD, "G" => STD_NGATE, "tS" => NSD, "tD" => NSD, "tG" => POLY, "W" => SUB }) +extract_devices(mos4("nfet_01v8_lvt"), { "SD" => NSD, "G" => LVT_NGATE, "tS" => NSD, "tD" => NSD, "tG" => POLY, "W" => SUB }) +extract_devices(mos4("nfet_g5v0d10v5"), { "SD" => NSD, "G" => HV5_NGATE, "tS" => NSD, "tD" => NSD, "tG" => POLY, "W" => SUB }) +extract_devices(mos4("nfet_01v8_nvt"), { "SD" => NSD, "G" => HV5NA_NGATE, "tS" => NSD, "tD" => NSD, "tG" => POLY, "W" => SUB }) + + +# Define connectivity for netlist extraction + +# Inter-layer +connect(SUB, PTAP) +connect(NWELL, NTAP) +connect(LICON, PTAP) +connect(LICON, NTAP) +connect(PSD, LICON) +connect(NSD, LICON) +connect(POLY, LICON) +connect(LICON, LI) +connect(LI, MCON) +connect(MCON, MET1) +connect(MET1,VIA1) +connect(VIA1, MET2) +connect(MET2, VIA2) +connect(VIA2, MET3) +connect(MET3, VIA3) +connect(VIA3, MET4) +connect(MET4, VIA4) +connect(VIA4, MET5) +# Attaching labels +connect(SUB, SUBTXT) +connect(SUB, SUBPIN) +connect(NWELL, NWELLTXT) +connect(POLY, POLYTXT) +connect(LI, LITXT) +connect(MET1, MET1TXT) +connect(MET2, MET2TXT) +connect(MET3, MET3TXT) +connect(MET4, MET4TXT) +connect(MET5, MET5TXT) + +# Global +connect_global(SUB, "VNB") + +# Actually performs the extraction +netlist # ... not really required + +# Flatten cells which are present in one netlist only +# align +# SIMPLIFICATION of the netlist +netlist.make_top_level_pins +netlist.combine_devices +netlist.purge +netlist.purge_nets +netlist.simplify +puts netlist.to_s + + \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/klayout/macros/array_of_labels.lym b/images/foss-asic-tools/addons/sak/klayout/macros/array_of_labels.lym new file mode 100755 index 00000000..36fd30af --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/macros/array_of_labels.lym @@ -0,0 +1,291 @@ + + + Create array of labels for manifold pins + + + + + + false + false + + true + + + ruby + + # +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# DESCRIPTION: Creates an array of labels +# +# Run the script with +# klayout -rm array_of_labels.lym ... +# or put the script as "array_of_labels.lym" into the installation path. +# +# This script will install a new entry in the "Macros" menu called "Create array of labels for manifold pins". +# On running it, a dialog will be shown where you can enter the parameters of your label array. +# Each label is given an individual number which can be embedded in the label string. +# +# The parameters are: +# * start position: the point of the first label +# * distance vector: the distance (x,y) between the labels +# * start number: the number of the first label +# * end number: the number of the last label (start number can be larger than end number to get a reverse sequence) +# * format: the label text format (use sprintf notation to embed the number, e.g. "text<%d>") +# * size: the size of the label in µm units +# * orientation: check this box to get vertical labels +# * layer: the layer where to put the labels +# +# Upon "Ok", the label sequence will be generated. Undo/redo is available. + +class ArrayOfLabelsDialog < RBA::QDialog + + def initialize + + mw = RBA::MainWindow::instance + super(mw) + + build_dialog + + end + + def build_dialog + + self.windowTitle = "Create Array Of Labels" + + gl = RBA::QGridLayout::new(self) + + row = 0 + + label = RBA::QLabel::new + label.text = "Position of first label (x,y)" + gl.addWidget(label, row, 0) + + @position = RBA::QLineEdit::new + @position.text = "0,0" + gl.addWidget(@position, row, 1) + + row += 1 + + label = RBA::QLabel::new + label.text = "distance vector between labels (x,y)" + gl.addWidget(label, row, 0) + + @distance = RBA::QLineEdit::new + @distance.text = "0,0" + gl.addWidget(@distance, row, 1) + + row += 1 + + label = RBA::QLabel::new + label.text = "Start number" + gl.addWidget(label, row, 0) + + @start = RBA::QLineEdit::new + @start.text = "1" + gl.addWidget(@start, row, 1) + + row += 1 + + label = RBA::QLabel::new + label.text = "End number" + gl.addWidget(label, row, 0) + + @end = RBA::QLineEdit::new + @end.text = "1" + gl.addWidget(@end, row, 1) + + row += 1 + + label = RBA::QLabel::new + label.text = "Label format (sprintf)" + gl.addWidget(label, row, 0) + + @format = RBA::QLineEdit::new + @format.text = "pin<%d>" + gl.addWidget(@format, row, 1) + + row += 1 + + label = RBA::QLabel::new + label.text = "Text size (µm)" + gl.addWidget(label, row, 0) + + @text_size = RBA::QLineEdit::new + @text_size.text = "1.0" + gl.addWidget(@text_size, row, 1) + + row += 1 + + label = RBA::QLabel::new + label.text = "Text orientation" + gl.addWidget(label, row, 0) + + @text_rotated = RBA::QCheckBox::new + @text_rotated.text = "Rotated 90 degree" + gl.addWidget(@text_rotated, row, 1) + + row += 1 + + label = RBA::QLabel::new + label.text = "Layer (layer/datatype)" + gl.addWidget(label, row, 0) + + @layer = RBA::QLineEdit::new + @layer.text = "1/0" + gl.addWidget(@layer, row, 1) + + row += 1 + gl.setRowStretch(row, 1) + + row += 1 + + hbl = RBA::QHBoxLayout::new + gl.addLayout(hbl, row, 0, 1, 2) + hbl.addStretch(1) + + ok = RBA::QPushButton::new + ok.text = "Ok" + ok.clicked do + begin + self.check + self.accept + rescue => ex + RBA::QMessageBox::critical(self, "Error", ex.to_s) + end + end + hbl.addWidget(ok) + + cancel = RBA::QPushButton::new + cancel.text = "Cancel" + cancel.clicked do + self.reject + end + hbl.addWidget(cancel) + + end + + def check + + ly = RBA::CellView::active.layout + lspec = RBA::LayerInfo::from_string(@layer.text) + lindex = ly.find_layer(lspec) + if ! lindex + raise("No layer present with the given specification (#{@layer.text})") + end + + @lindex = lindex + + if !(@position.text.gsub(/\s/, "") =~ /^([\d.eE+-]+),([\d.eE+-]+)$/) + raise("Position is not a pair of coordinates (#{@position.text})") + end + @start_point = RBA::DPoint::new($1.to_f, $2.to_f) + + if !(@distance.text.gsub(/\s/, "") =~ /^([\d.eE+-]+),([\d.eE+-]+)$/) + raise("Distance vector is not a pair of coordinates (#{@distance.text})") + end + @distance_vector = RBA::DVector::new($1.to_f, $2.to_f) + + if !(@start.text.gsub(/\s/, "") =~ /^([\d-]+)$/) + raise("Start number is not an integer (#{@start.text})") + end + @start_number = $1.to_i + + if !(@end.text.gsub(/\s/, "") =~ /^([\d-]+)$/) + raise("End number is not an integer (#{@end.text})") + end + @end_number = $1.to_i + + end + + def start_point + @start_point + end + + def distance_vector + @distance_vector + end + + def start_number + @start_number + end + + def end_number + @end_number + end + + def lindex + @lindex + end + + def format + @format.text + end + + def text_size + @text_size.text.to_f + end + + def text_orientation + @text_rotated.isChecked ? 1 : 0 + end + +end + +view = RBA::LayoutView::current +cv = RBA::CellView::active +if ! view || !cv + RBA::QMessageBox::critical(RBA::MainWindow::instance, "Error", "No layout opened") +else + + # for debugging: + # $array_of_labels_dialog && !$array_of_labels_dialog._destroyed? && $array_of_labels_dialog._destroy + # $array_of_labels_dialog = ArrayOfLabelsDialog::new + + # for production: + $array_of_labels_dialog ||= ArrayOfLabelsDialog::new + + dia = $array_of_labels_dialog + if dia.exec != 0 + + begin + + view.transaction("Create array of labels") + + numbers = [] + if dia.start_number > dia.end_number + (dia.end_number..dia.start_number).reverse_each { |i| numbers << i } + else + (dia.start_number..dia.end_number).each { |i| numbers << i } + end + + pos = dia.start_point + numbers.each do |n| + + str = dia.format % n + text_trans = RBA::DTrans::new(dia.text_orientation, false, pos.x, pos.y) + text = RBA::DText::new(str, text_trans) + text.size = dia.text_size + cv.cell.shapes(dia.lindex).insert(text) + + pos += dia.distance_vector + + end + + ensure + view.commit + end + + end + +end + diff --git a/images/foss-asic-tools/addons/sak/klayout/macros/calc_area.lym b/images/foss-asic-tools/addons/sak/klayout/macros/calc_area.lym new file mode 100755 index 00000000..a999a9ec --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/macros/calc_area.lym @@ -0,0 +1,63 @@ + + + Compute total area of selected shapes + + + + + + false + false + + true + calc_area + tools_menu.end + ruby + + # +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# DESCRIPTION: Compute area of selected shapes +# +# Run the script with +# klayout -rm calc_area.lym ... +# or put the script as "calc_area.lym" into the installation path (on Unix for version <=0.21: +# set $KLAYOUTPATH to the installation folder). +# + +app = RBA::Application.instance +mw = app.main_window + +lv = mw.current_view +if lv == nil + raise "No view selected" +end + +total_area = 0.0 + +lv.each_object_selected do |obj| + + shape = obj.shape + layout = lv.cellview(obj.cv_index).layout + + if shape.is_polygon? || shape.is_box? || shape.is_path? + polygon = shape.polygon + a = polygon.area + m = obj.trans.mag * layout.dbu + total_area += a * m * m + end + +end + +RBA::MessageBox.info("Total area", "Total area of selected objects is #{total_area} square micron", RBA::MessageBox.b_ok) + + + diff --git a/images/foss-asic-tools/addons/sak/klayout/macros/calc_area_hier.lym b/images/foss-asic-tools/addons/sak/klayout/macros/calc_area_hier.lym new file mode 100755 index 00000000..c53cb217 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/macros/calc_area_hier.lym @@ -0,0 +1,128 @@ + + + Compute Layer Area + + + + + + false + false + + true + calc_area + tools_menu.end + ruby + + # +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# DESCRIPTION: Compute total area of all shapes on a layer. +# +# Run the script with +# klayout -rm calc_area_hier.lym ... +# or put the script as "calc_area_hier.lym" into the installation path (on Unix for version <=0.21: +# set $KLAYOUTPATH to the installation folder). +# +# The script will install a new menu item in the Tools menu: "Compute Layer Area". +# It will compute the area of all shapes (not considering overlaps) of the selected layer in the current cell. +# + +class CellCount + + def initialize(layout, cell) + @layout = layout + @cell = cell + @called_cells = {} + cell.called_cells.each do |c| + @called_cells[c] = true + end + @called_cells[cell.cell_index] = true + @cache = {} + end + + def inst_count(cell) + n = @cache[cell.cell_index] + if !n + cell.each_parent_inst do |pi| + if @called_cells[pi.parent_cell_index] + n ||= 0 + n += pi.inst.size * inst_count(@layout.cell(pi.parent_cell_index)) + end + end + n ||= 1 + @cache[cell.cell_index] = n + end + return n + end + +private + @layout + @cell + @called_cells + @cache +end + +# Main functionality + +app = RBA::Application.instance +mw = app.main_window + +lv = mw.current_view +if !lv + raise "No view selected" +end + +cv = lv.active_cellview +if !cv || !cv.is_valid? + raise "No cell selected" +end + +sel_layers = lv.selected_layers +if !sel_layers || sel_layers.size == 0 + raise "No layer(s) selected" +end + +cc = CellCount::new(cv.layout, cv.cell) + +t = "Area of layers in um^2:\n\n" + +sel_layers.each do |l| + + li = l.current.layer_index + if cv.layout.is_valid_layer?(li) + + cells = cv.cell.called_cells + cells.push(cv.cell.cell_index) + + atot = 0 + + cells.each do |ci| + c = cv.layout.cell(ci) + a = 0 + c.shapes(li).each do |s| + if s.is_path? || s.is_polygon? || s.is_box? + a += s.polygon.area + end + end + atot += cc.inst_count(c) * a + end + + t += sprintf(" %-10s\t", l.current.source(true).to_s) + sprintf("%.2f", (atot * cv.layout.dbu * cv.layout.dbu)) + "\n" + + end + +end + +RBA::MessageBox.info("Calculated Area Per Layer", t, RBA::MessageBox::b_ok) + + + diff --git a/images/foss-asic-tools/addons/sak/klayout/macros/cell_bbox.lym b/images/foss-asic-tools/addons/sak/klayout/macros/cell_bbox.lym new file mode 100755 index 00000000..94a9dfc0 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/macros/cell_bbox.lym @@ -0,0 +1,59 @@ + + + Cell Bounding Box + + + + + + false + false + + true + + tools_menu.end + ruby + + # +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# DESCRIPTION: Compute and output the bounding box of a cell (all layers) +# +# Run the script with +# klayout -rm cell_bbox.lym ... +# or put the script as "cell_bbox.lym" into the installation path (on Unix for version <=0.21: +# set $KLAYOUTPATH to the installation folder). +# + +app = RBA::Application.instance + +mw = app.main_window +view = mw.current_view +cv = view.cellview(view.active_cellview_index) + +if !cv.is_valid? + return +end + +cell = cv.cell +dbu = cv.layout.dbu + +text = "Cell: #{cv.layout.cell_name(cv.cell_index)}\n\n" +text += "xmin: #{cell.bbox.left*dbu} micron\n" +text += "ymin: #{cell.bbox.bottom*dbu} micron\n" +text += "xmax: #{cell.bbox.right*dbu} micron\n" +text += "ymax: #{cell.bbox.top*dbu} micron\n\n" +text += "width: #{cell.bbox.width*dbu} micron\n" +text += "height: #{cell.bbox.height*dbu} micron" + +RBA::MessageBox::info("Cell Information", text, RBA::MessageBox::b_ok) + + diff --git a/images/foss-asic-tools/addons/sak/klayout/macros/dump_flat_shapes.lym b/images/foss-asic-tools/addons/sak/klayout/macros/dump_flat_shapes.lym new file mode 100755 index 00000000..52ffd0f6 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/macros/dump_flat_shapes.lym @@ -0,0 +1,131 @@ + + + Dump Flat Shapes + + + + + + false + false + + true + dump_flat_shapes + tools_menu.end + ruby + + # +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# DESCRIPTION: Dump all shapes of the current cell recursively to a XML file +# +# Run the script with +# klayout -rm dump_flat_shapes.lym ... +# or put the script as "dump_flat_shapes.lym" into the installation path (on Unix for version <=0.21: +# set $KLAYOUTPATH to the installation folder). +# + +def dump_shapes(file, layout, cell, layer, trans) + + itrans = RBA::ICplxTrans.from_trans(trans) + + cell.shapes(layer).each do |shape| + + if shape.is_box? + box = shape.box.transformed(itrans) + file.puts(" <box>#{box.to_s}</box>") + elsif shape.is_path? + path = shape.path.transformed(itrans) + file.puts(" <path>#{path.to_s}</path>") + elsif shape.is_polygon? + polygon = shape.polygon.transformed(itrans) + file.puts(" <polygon>#{polygon.to_s}</polygon>") + elsif shape.is_text? + text = shape.text.transformed(itrans) + file.puts(" <text>#{text.to_s}</text>") + end + + end + + cell.each_inst do |inst| + + if inst.is_regular_array? + + na = inst.na + nb = inst.nb + a = inst.a + b = inst.b + + (0..(na-1)).each do |ia| + (0..(nb-1)).each do |ib| + disp = RBA::Point.new(a.x * ia + b.x * ib, a.y * ia + b.y * ib) + disp_trans = RBA::CplxTrans.new(RBA::Trans.new(disp)) + dump_shapes(file, layout, layout.cell(inst.cell_index), layer, trans * disp_trans * inst.cplx_trans) + end + end + + else + dump_shapes(file, layout, layout.cell(inst.cell_index), layer, trans * inst.cplx_trans) + end + + end + +end + +# main functionality + +app = RBA::Application.instance +mw = app.main_window + +lv = mw.current_view +if lv == nil + raise "No view selected" +end + +cv = lv.active_cellview +if !cv.is_valid? + raise "No cell or no layout found" +end + +layers = [] + +lnode = lv.begin_layers +while !lnode.at_end? + if !lnode.current.has_children? && lnode.current.layer_index >=0 && lnode.current.visible?(true) + layers.push(lnode.current.layer_index) + end + lnode.next +end + +# Ask for the file name +filename = RBA::FileDialog.get_save_file_name("Flat Dump", ".", "All files (*)") +if filename.has_value? + + File.open(filename.value, "w") do |file| + + file.puts("<shape_dump cell=\"#{cv.layout.cell_name(cv.cell_index)}\" dbu=\"#{cv.layout.dbu}\">") + + layers.each do |l| + + file.puts(" <layer source=\"#{cv.layout.get_info(l).to_s}\">") + dump_shapes(file, cv.layout, cv.cell, l, RBA::CplxTrans.new) + file.puts(" </layer>") + + end + + file.puts("</shape_dump>") + + end + +end + + + diff --git a/images/foss-asic-tools/addons/sak/klayout/macros/list_layers.lym b/images/foss-asic-tools/addons/sak/klayout/macros/list_layers.lym new file mode 100755 index 00000000..1b5d389b --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/macros/list_layers.lym @@ -0,0 +1,185 @@ + + + List Layers + + + + + + false + false + + true + list_layers + tools_menu.end + ruby + + # +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# DESCRIPTION: List all layers under a ruler +# +# Run the script with +# klayout -rm list_layers.lym ... +# or put the script as "list_layers.lym" into the installation path (on Unix for version <=0.21: +# set $KLAYOUTPATH to the installation folder). +# +# This script will install a new entry in the "Tools" menu called "List Layers". Before this +# function can be used, a single ruler must be drawn. The script looks for +# shapes that are crossed by this ruler and reports the layers of those shapes. The script can operate +# on multiple layouts as well. +# + +require 'stringio' + +# locate the layout and the (single) ruler +app = RBA::Application.instance +view = app.main_window.current_view +if !view + raise "No view open for creating the cross section from" +end + +# fetch the ruler +ruler = nil +nrulers = 0 +view.each_annotation do |a| + # Use only rulers with "plain line" or ruler style + if a.style == RBA::Annotation::style_line || a.style == RBA::Annotation::style_ruler + ruler = a + nrulers += 1 + end +end + +if nrulers == 0 + raise "No ruler present (these must have 'plain line' or 'ruler' style)" +end +if nrulers > 1 + raise "More than one ruler present (with 'plain line' or 'ruler' style)" +end + +cv = view.cellview(view.active_cellview_index) +if ! cv.is_valid? + raise "The selected layout is not valid" +end + +# get all layers from the layer list +layers = [] +layer_titles = [] +cellviews = [] +layout_indices = [] + +i = view.begin_layers +while !i.at_end? + + lyi = i.current.source_cellview(true) + if lyi >= 0 && lyi < view.cellviews + + layout = view.cellview(lyi).layout + if layout.is_valid_layer?(i.current.layer_index) + + layout_indices.push(lyi) + cellviews.push(view.cellview(lyi)) + layers.push(i.current.layer_index) + + d = i.current.name + if d == "" + d = i.current.source(true).sub(/@\d+$/, "") + end + layer_titles.push(d) + + end + + end + + i.next + +end + +founds = {} + +layers.each_with_index do |layer_index,i| + + cv = cellviews[i] + layout = cv.layout + cell = cv.cell_index + dbu = layout.dbu + + # get the start and end points in database units and micron + p1_dbu = RBA::Point::from_dpoint(ruler.p1 * (1.0 / dbu)) + p2_dbu = RBA::Point::from_dpoint(ruler.p2 * (1.0 / dbu)) + line_dbu = RBA::Edge.new(p1_dbu, p2_dbu) + + # detect all touching shapes and all edges of those which cross the measurement line + shape_iter = layout.begin_shapes_touching(cell, layer_index, line_dbu.bbox) + while !shape_iter.at_end + + found = false + + shape = shape_iter.shape + if shape.is_polygon? || shape.is_path? || shape.is_box? + + polygon = shape.polygon.transformed_cplx(shape_iter.itrans) + polygon.each_edge do |edge_dbu| + + if line_dbu.crossed_by?(edge_dbu) && (line_dbu.side_of(edge_dbu.p1) > 0 || line_dbu.side_of(edge_dbu.p2) > 0) + layout_index = layout_indices[i] + founds[layout_index] ||= {} + founds[layout_index][layer_index] = i + found = true + break + end + + end + + end + + shape_iter.next + + if found + break + end + + end + +end + +# produce the output +output = StringIO.new("", "w") +output.write "<html><body>" + +output.write "<h2>Layer report</h2>" +x1 = (0.5 + ruler.p1.x * 1e5).floor * 1e-5 +y1 = (0.5 + ruler.p1.y * 1e5).floor * 1e-5 +x2 = (0.5 + ruler.p2.x * 1e5).floor * 1e-5 +y2 = (0.5 + ruler.p2.y * 1e5).floor * 1e-5 +output.write "<p>Position #{x1},#{y1} to #{x2},#{y2}</p>" + +founds.each do |lyi,f| + output.write "<h4>Layout #{view.cellview(lyi).name} (@#{lyi+1})</h4>" + ii = [] + f.each do |li,i| + ii.push(i) + end + ii.sort.each do |i| + output.write "Layer #{layer_titles[i]}<br/>" + end +end + +output.write "</body></html>" + +bs = RBA::BrowserSource::new_html(output.string) +bd = RBA::BrowserDialog::new +bd.set_source(bs) +bd.set_home("int:index.html") +bd.exec + + + diff --git a/images/foss-asic-tools/addons/sak/klayout/macros/new_macro.lym b/images/foss-asic-tools/addons/sak/klayout/macros/new_macro.lym new file mode 100755 index 00000000..c822bb45 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/macros/new_macro.lym @@ -0,0 +1,31 @@ + + + + + + + + + false + false + + false + + + ruby + + include RBA +ly = RBA::CellView::active.layout + +tracer = RBA::NetTracer::new + +tech = RBA::NetTracerTechnology::new +tech.connection("1/0", "2/0", "3/0") + +tracer.trace(tech, ly, ly.top_cell, RBA::Point::new(7000, 1500), ly.find_layer(1, 0)) + +tracer.each_element do |e| + puts e.shape.polygon.transformed(e.trans) +end + + diff --git a/images/foss-asic-tools/addons/sak/klayout/macros/replace_cells.lym b/images/foss-asic-tools/addons/sak/klayout/macros/replace_cells.lym new file mode 100755 index 00000000..553e8d9e --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/macros/replace_cells.lym @@ -0,0 +1,211 @@ + + + Replace Cells With Others + + + + + + false + false + + true + + @hcp_context_menu.end + ruby + + # +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# DESCRIPTION: Replace cells with other cells from another layout +# +# Install the script with +# klayout -rm replace_cells.lym ... +# or put the script as "replace_cells.lym" into the installation path +# (on Unix for version <=0.21: set $KLAYOUTPATH to the installation folder). +# +# The script installs a new menu entry at the end of the cell list context +# menu: "Replace Cells With Others". This function asks for a file containing +# a couple of other (top) cells, even with their own hierarchy. It will copy +# these cells into the existing layout and replace the corresponding cells in +# the current layout with the ones from the replacement library. + +# A utility function which copies one layout into another +def copy_cells(lsrc, ltarget, lmap, pmap) + + citarget = nil + + # a map for the cell indices + cmap = {} + + lsrc.each_cell_bottom_up do |cisrc| + + # create a new cell in the target layout and add to the cell index map + csrc = lsrc.cell(cisrc) + citarget = ltarget.add_cell(lsrc.cell_name(cisrc)) + ctarget = ltarget.cell(citarget) + cmap[cisrc] = citarget + + # copy the shapes + lsrc.layer_indices.each do |lisrc| + shtarget = ctarget.shapes(lmap[lisrc]) + csrc.shapes(lisrc).each do |shape| + + # property mapping + newpid = 0 # =no properties + if shape.has_prop_id? + newpid = pmap[shape.prop_id] + if !newpid + newpid = ltarget.properties_id(lsrc.properties(shape.prop_id)) + pmap[shape.prop_id] = newpid + end + end + + newshape = shtarget.insert(shape) + shtarget.replace_prop_id(newshape, newpid) + end + end + + # translate and copy the instances + csrc.each_inst do |inst| + + # property mapping + newpid = 0 # =no properties + if inst.has_prop_id? + newpid = pmap[inst.prop_id] + if !newpid + newpid = ltarget.properties_id(lsrc.properties(inst.prop_id)) + pmap[inst.prop_id] = newpid + end + end + + # get the instance object and create a new one with the new cell index + i = inst.cell_inst + trans = i.is_complex? ? i.cplx_trans : i.trans + cinew = cmap[i.cell_index] + if i.is_regular_array? + newinst = ctarget.insert(RBA::CellInstArray.new(cinew, trans, i.a, i.b, i.na, i.nb)) + else + newinst = ctarget.insert(RBA::CellInstArray.new(cinew, trans)) + end + + # apply the new property id + ctarget.replace_prop_id(newinst, newpid) + + end + + end + + return cmap + +end + +# Main functionality + +app = RBA::Application.instance +mw = app.main_window + +# get the current layout view +lv = mw.current_view +if lv == nil + raise "No view selected" +end + +# get the current cell view (the one selected in the hierarchy browser) +cv = lv.cellview(lv.active_cellview_index) +if !cv.is_valid? + raise "No layout selected" +end + +# fetch the name of the layout with the replacement cells +fn = RBA::FileDialog::get_open_file_name("Select replacement library", ".", "All files (*)") +if fn.has_value? + + lib = RBA::Layout::new + lmap = lib.read(fn.value) + + if ((lib.dbu - cv.layout.dbu).abs > 1e-6) + raise "Database units of the layouts must be identical" + end + + org_layers = {} + new_layers = {} + + cv.layout.layer_indices.each do |l| + info = cv.layout.get_info(l) + if lmap.is_mapped?(info) + ll = lmap.logical(info) + org_layers[l] = ll + new_layers[ll] = l + end + end + + has_new_layers = false + + lib.layer_indices.each do |l| + if ! new_layers[l] + ll = cv.layout.insert_layer(lib.get_info(l)) + new_layers[l] = ll + org_layers[ll] = l + has_new_layers = true + end + end + + tmap = {} + + lib.each_top_cell do |t| + tn = lib.cell_name(t) + if cv.layout.has_cell?(tn) + tt = cv.layout.cell_by_name(tn) + tmap[tt] = t + cv.layout.rename_cell(tt, "") + cv.layout.prune_subcells(tt, -1) + end + end + + pmap = {} + cmap = copy_cells(lib, cv.layout, new_layers, pmap) + + cv.layout.each_cell do |c| + + # change and the instances + c.each_inst do |inst| + + if tmap[inst.cell_index] + + # get the instance object and create a new one with the new cell index + i = inst.cell_inst + trans = i.is_complex? ? i.cplx_trans : i.trans + cinew = cmap[tmap[i.cell_index]] + if i.is_regular_array? + c.replace(inst, RBA::CellInstArray.new(cinew, trans, i.a, i.b, i.na, i.nb)) + else + c.replace(inst, RBA::CellInstArray.new(cinew, trans)) + end + + end + + end + + end + + # delete old cells + tmap.each do |k,v| + cv.layout.prune_cell(k, -1) + end + + if has_new_layers + mw.cm_lv_add_missing + end + +end + + diff --git a/images/foss-asic-tools/addons/sak/klayout/macros/scale_anisotropic.lym b/images/foss-asic-tools/addons/sak/klayout/macros/scale_anisotropic.lym new file mode 100755 index 00000000..b97eca49 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/macros/scale_anisotropic.lym @@ -0,0 +1,112 @@ + + + Anisotropic Scaling + + + + + general + false + false + + true + + edit_menu.selection_menu.sel_scale + ruby + # This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# DESCRIPTION: Anisotropic scaling macro for KLayout + +module AnisotropicScaling + + app = RBA::Application::instance + app.is_editable? || raise("KLayout must be run in editable mode to use this macro") + + mw = app.main_window + view = mw.current_view + view || raise("No view open") + + # check whether the selection does not contain any instances and whether there + # is any selection at all + anything = false + view.each_object_selected do |obj| + if obj.is_cell_inst? + raise("At least one instance was encountered as part of the selection.\nThese instances are not scaled. It is suggested to flatten the selection before using the anisotropic scaling function.") + end + anything = true + end + if !anything + raise("Nothing selected to scale") + end + + # ask for the scaling factors + text = RBA::InputDialog::ask_string("Enter Scaling Factor", "Scaling factor (x,y)", "1.0,1.0") + if text + + f = text.split(",") + f.size > 1 || f.push(f[0]) + f = f.collect { |n| n.to_f } + + fx = f[0] + fy = f[1] + + # begin the transaction (undo/redo support) + view.transaction("Anisotropic scaling") + begin + + # perform the scaling on every object + view.each_object_selected do |obj| + + if !obj.is_cell_inst? + + if obj.shape.is_polygon? || obj.shape.is_simple_polygon? || obj.shape.is_path? + + # Anisotropic scaling of polygon (paths are converted as polygons + # because in the general case the width cannot be maintained) + poly = obj.shape.polygon + new_hull = [] + poly.each_point_hull do |p| + new_hull.push(RBA::Point::new((p.x * fx + 0.5).floor, (p.y * fy + 0.5).floor)) + end + poly.assign_hull(new_hull) + poly.holes.times do |hi| + new_hole = [] + poly.each_point_hole(hi) do |p| + new_hole.push(RBA::Point::new((p.x * fx + 0.5).floor, (p.y * fy + 0.5).floor)) + end + poly.assign_hole(hi, new_hole) + end + obj.shape.polygon = poly + + elsif obj.shape.is_box? + + # Anisotropic scaling of box + box = obj.shape.box + p1 = RBA::Point::new((box.p1.x * fx + 0.5).floor, (box.p1.y * fy + 0.5).floor) + p2 = RBA::Point::new((box.p2.x * fx + 0.5).floor, (box.p2.y * fy + 0.5).floor) + obj.shape.box = RBA::Box::new(p1, p2) + + end + + end + + end + + ensure + view.commit + view.cancel + end + + end + +end + + diff --git a/images/foss-asic-tools/addons/sak/klayout/macros/screenshot.lym b/images/foss-asic-tools/addons/sak/klayout/macros/screenshot.lym new file mode 100755 index 00000000..c36fa315 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/macros/screenshot.lym @@ -0,0 +1,131 @@ + + + Screenshot With Options + + + + + general + false + false + + true + + file_menu.screenshot + ruby + module MyMacro + + include RBA + + # This class implements a dialog with a screenshot display area and a + # screenshot button + class ScreenshotDialog < QDialog + + include RBA + + def initialize(parent = nil) + + super + + setWindowTitle("Screenshot Saver") + + layout = QGridLayout.new(self) + setLayout(layout) + + l = QLabel.new(self) + l.text = "Width" + layout.addWidget(l, 0, 0, 1, 1) + + l = QLabel.new(self) + l.text = "Height" + layout.addWidget(l, 1, 0, 1, 1) + + width_edit = QLineEdit.new(self) + width_edit.text = "1000" + layout.addWidget(width_edit, 0, 1, 1, 1) + + height_edit = QLineEdit.new(self) + height_edit.text = "1000" + layout.addWidget(height_edit, 1, 1, 1, 1) + + l = QLabel.new(self) + l.text = "or use resolution (um/pixel):" + layout.addWidget(l, 0, 2, 1, 1) + + res_edit = QLineEdit.new(self) + res_edit.text = "1.0" + layout.addWidget(res_edit, 0, 3, 1, 1) + + res_compute = QPushButton.new(self) + res_compute.text = "Set Size" + res_compute.clicked do + begin + r = res_edit.text.to_f + r > 1.0e-6 || raise("Invalid value for resolution") + view = Application::instance.main_window.current_view + view || raise("No view open") + f = 1.0 / (r * view.viewport_trans.mag) + width_edit.text = (view.viewport_width * f + 0.5).floor.to_s + height_edit.text = (view.viewport_height * f + 0.5).floor.to_s + rescue => ex + QMessageBox::critical(self, "Error", ex.to_s, QMessageBox::Ok.to_i) + end + end + layout.addWidget(res_compute, 0, 4, 1, 1) + + l = QLabel.new(self) + l.text = "To File" + layout.addWidget(l, 2, 0, 1, 1) + + file_edit = QLineEdit.new(self) + file_edit.text = "file.png" + layout.addWidget(file_edit, 2, 1, 1, 3) + + browse = QPushButton.new(self) + browse.text = "..." + layout.addWidget(browse, 2, 4, 1, 1) + browse.clicked do + begin + file = QFileDialog::getSaveFileName(self, "Choose file to save screenshot") + !file.empty? && file_edit.text = file + rescue + end + end + + do_cancel = QPushButton.new(self) + do_cancel.text = "Cancel" + layout.addWidget(do_cancel, 4, 4, 1, 1) + do_cancel.clicked do + self.reject + end + + do_save = QPushButton.new(self) + do_save.text = "Save" + layout.addWidget(do_save, 4, 0, 1, 1) + do_save.clicked do + begin + w = width_edit.text.to_i + h = height_edit.text.to_i + f = file_edit.text + view = Application::instance.main_window.current_view + view || raise("No view open") + view.save_image(f, w, h) + self.accept + rescue => ex + QMessageBox::critical(self, "Error", ex.to_s, QMessageBox::Ok.to_i) + end + end + + layout.setRowStretch(3, 1) + + end + + end + + # Instantiate the dialog and show it. + $dialog || $dialog = ScreenshotDialog.new(Application::instance.main_window) + $dialog.exec + +end + + diff --git a/images/foss-asic-tools/addons/sak/klayout/macros/search_odd_width_paths.lym b/images/foss-asic-tools/addons/sak/klayout/macros/search_odd_width_paths.lym new file mode 100755 index 00000000..1642dcc2 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/macros/search_odd_width_paths.lym @@ -0,0 +1,70 @@ + + + Find Paths With Odd Width + + + + + + false + false + + true + + tools_menu.end + ruby + + # +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# DESCRIPTION: Search paths with odd width in KLayout +# +# Run the script with +# klayout -rm search_odd_path_widths.lym ... +# or put the script as "search_odd_path_widths.lym" into the installation path (on Unix for version <=0.21: +# set $KLAYOUTPATH to the installation folder). +# + +app = RBA::Application.instance +mw = app.main_window + +lv = mw.current_view +if lv == nil + raise "No view selected" +end + +cv = lv.active_cellview +if !cv.is_valid? + raise "No cell or no layout found" +end + +cv.layout.each_cell do |cell| + (0..(cv.layout.layers-1)).each do |l| + if cv.layout.is_valid_layer?(l) + cell.shapes(l).each do |s| + if s.is_path? && (s.path_width % 2) == 1 + if RBA::MessageBox::info("Path with odd width", + "Cell: #{cv.layout.cell_name(cell.cell_index)}\n" + + "Layer: #{cv.layout.get_info(l).to_s}\n" + + "Path: #{s.path.to_s}\n" + + "\n" + + "Press 'Ok' to continue, 'Cancel' to stop.", + RBA::MessageBox::b_ok + RBA::MessageBox::b_cancel) == RBA::MessageBox::b_cancel + raise "Operation aborted" + end + end + end + end + end +end + + + diff --git a/images/foss-asic-tools/addons/sak/klayout/macros/write_childcells.lym b/images/foss-asic-tools/addons/sak/klayout/macros/write_childcells.lym new file mode 100755 index 00000000..568507de --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/macros/write_childcells.lym @@ -0,0 +1,100 @@ + + + Write Child Cells + + + + + + false + false + + true + write_child_cells + @hcp_context_menu.end + ruby + + # +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# DESCRIPTION: Write all child cells of the current cell to individual files +# +# Install the script with +# klayout -rm write_childcells.lym ... +# or put the script as "write_childcells.lym" into the installation path +# (on Unix for version <=0.21: set $KLAYOUTPATH to the installation folder). +# +# The script installs a new menu entry at the end of the cell list context +# menu: "Write Child Cells". This function asks for the hierarchy level and +# writes all cells at this level (below the current cell) to files called +# "{cellname}.gds". + +# Collect all cells at hiearchy level "level" below the cell "from_cell" +# into the array "cells" which is used as a set. +# The keys of "cells" will be the cell indexes of the cells collected. +def get_cells_at_hierarchy_level(layout, from_cell, level, cells) + from_cell.each_child_cell do |cc| + if level == 1 + cells[cc] = 1 + else + get_cells_at_hierarchy_level(layout, layout.cell(cc), level - 1, cells) + end + end +end + + +# Main functionality + +app = RBA::Application.instance +mw = app.main_window + +# get the current layout view +lv = mw.current_view +if lv == nil + raise "No view selected" +end + +# get the current cell view (the one selected in the hierarchy browser) +cv = lv.cellview(lv.active_cellview_index) +if !cv.is_valid? + raise "No layout selected" +end + +# fetch the hierarchy level from which to write the cells +level = RBA::InputDialog.get_int_ex("Hierachy Level", "Specify the hierarchy level below cell #{cv.layout.cell_name(cv.cell_index)}, layout @#{lv.active_cellview_index+1} from which to write the cells", 1, 1, 1000, 1) +if level.has_value? + + # gather the cells to write + cells_to_write = {} + get_cells_at_hierarchy_level(cv.layout, cv.cell, level.value, cells_to_write) + + # loop over all child cells of the current cell + cells_to_write.each do |cc,dummy| + + # make a cell object reference from the cell index + child_cell = cv.layout.cell(cc) + + # get the cell's name + cell_name = cv.layout.cell_name(cc) + + # write the cell as "{cellname}.gds" + file_name = "#{cell_name}.gds" + options = RBA::SaveLayoutOptions.new + options.add_cell(cc) # select this cell for writing + puts "Writing #{file_name} .." + cv.layout.write(file_name, false, options) + + end + +end + + + diff --git a/images/foss-asic-tools/addons/sak/klayout/merge.rb b/images/foss-asic-tools/addons/sak/klayout/merge.rb new file mode 100755 index 00000000..9f2ad9b5 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/merge.rb @@ -0,0 +1,20 @@ +# merge.rb +# +# Merges two files into one +# +# Run this script with +# klayout -rd file1=first_file.gds -rd file2=second_file.gds -rd output=output_file.gds -z -r merge_files.rb +# +# (Note: -z puts KLayout into non-GUI mode) +# +# Read the first layout +layout = RBA::Layout.new +lmap = layout.read($file1) + +# read the second file which basically performs the merge +load_layout_options = RBA::LoadLayoutOptions.new +load_layout_options.set_layer_map(lmap, true) +layout.read($file2, load_layout_options) + + +layout.write($output) \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/klayout/merge2.rb b/images/foss-asic-tools/addons/sak/klayout/merge2.rb new file mode 100755 index 00000000..d8a361f5 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/merge2.rb @@ -0,0 +1,67 @@ +# merge2.rb +# +# Merges two files into one +# +# Run this script with +# klayout -rd file1=first_file.gds -rd file2=second_file.gds -rd output=output_file.gds -z -r merge_files.rb +# +# (Note: -z puts KLayout into non-GUI mode) +# +# Read the first layout +layout = RBA::Layout.new +lmap = layout.read($file1) + +# store and take away the cell names of all cells read so far +# (by setting the cell name to "" the cells basically become invisible for +# the following read) +cell_names = { } +(0..(layout.cells-1)).each do |ci| + cell_names[ci] = layout.cell_name(ci) + layout.rename_cell(ci, "") # this prevents a name clash on the next read +end + +# read the second file which basically performs the merge +load_layout_options = RBA::LoadLayoutOptions.new +load_layout_options.set_layer_map(lmap, true) +layout.read($file2, load_layout_options) + +# rename the cells by using prefix "A" for layout 1 and "B" for layout 2 +(0..(layout.cells-1)).each do |ci| + if cell_names[ci] + layout.rename_cell(ci, cell_names[ci]) + else + layout.rename_cell(ci, "B" + layout.cell_name(ci)) + end +end + +ind = 0 +ind2 = 0 + +layout.each_cell do |c| + # change and the instances + + if c.name == "user_project_wrapper" + ind = Integer(c.cell_index) + puts ind + elsif c.name == "Buser_project_wrapper" + ind2 = Integer(c.cell_index) + puts ind2 + end +end + +layout.each_cell do |c| + c.each_inst do |inst| + if inst.cell_index.equal? ind + # get the instance object and create a new one with the new cell index + i = inst.cell_inst + trans = i.is_complex? ? i.cplx_trans : i.trans + c.replace(inst, RBA::CellInstArray.new(ind2, trans)) + end + + end + +end + +layout.delete_cell(ind) +layout.rename_cell(ind2, "user_project_wrapper") +layout.write($output) \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/klayout/merge_kl.py b/images/foss-asic-tools/addons/sak/klayout/merge_kl.py new file mode 100755 index 00000000..8c190226 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/merge_kl.py @@ -0,0 +1,57 @@ +# SPDX-FileCopyrightText: 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +# klayout -rd file1=caravel_xxxxyyyy.oas -rd file2=user_project_wrapper.oas,caravel__fill_pattern.oas -rd user_id="" -z -r merge_kl.py + +# Use caravel_xxxxyyyy as the golden caravel +import pya + +def merge(): + files = file2.split(",") + opt = pya.LoadLayoutOptions() + opt_oas = pya.SaveLayoutOptions() + ly = pya.Layout() + + for file in files: + lmap = ly.read(file1) + + ly = change_uid(ly) + + opt.set_layer_map(lmap, True) + ly.read(file, opt) + + ly.write(output) + + for cells in ly.each_cell(): + ci = cells.cell_index() + if "$" in cells.name: + ly.delete_cell_rec(ci) + + opt_oas.set_format_from_filename(output) + opt_oas.oasis_substitution_char='' + ly.write(output, opt_oas) + +def change_uid(lib): + for cells in lib.each_cell(): + ci = cells.cell_index() + if "xxxxyyyy" in cells.name: + name = cells.name.replace("xxxxyyyy", user_id) + lib.rename_cell(ci, name) + return lib + +if __name__ == "__main__": + output = "caravel_" + user_id + ".oas" + merge() \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/klayout/mv_shapes.py b/images/foss-asic-tools/addons/sak/klayout/mv_shapes.py new file mode 100755 index 00000000..b5d7a709 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/mv_shapes.py @@ -0,0 +1,51 @@ +import pya +from time import sleep + +try: + if output_layout == "": + raise NameError + _output_layout = output_layout +except NameError: + _output_layout = input_layout + print("Warning: output_layout was not provided; will do the modifications in place!") + print("Hit CTRL-C to cancel...") + sleep(3) + +print("Starting...") +app = pya.Application.instance() +win = app.main_window() + +# Load technology file +tech = pya.Technology() +tech.load(tech_file) +layoutOptions = tech.load_layout_options + +# Load def/gds file in the main window +cell_view = win.load_layout(input_layout, layoutOptions, 0) +layout_view = cell_view.view() +layout_view.max_hier() + +# gets the corresponding layout object +layout = cell_view.layout() + +# gets the cell to change is "INV2X" +# cell = layout.cell("Active_area") +cell = cell_view.cell + +# finds source layer +layer, purpose = source_layer.split('/') +assert layer and purpose +_source_layer = layout.layer(int(layer), int(purpose)) + +# finds (or creates) target layer +layer, purpose = target_layer.split('/') +assert layer and purpose +_target_layer = layout.layer(int(layer), int(purpose)) + +layout.move_layer(_source_layer, _target_layer) + +layout.write(_output_layout) + +print("Successfully wrote", _output_layout) + +app.exit(0) diff --git a/images/foss-asic-tools/addons/sak/klayout/mv_shapes.sh b/images/foss-asic-tools/addons/sak/klayout/mv_shapes.sh new file mode 100755 index 00000000..2f8446e4 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/mv_shapes.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +: ${1?"Usage: $0 file.gds src_layer/src_purpose targ_layer/targ_purpose [output.gds]"} +: ${2?"Usage: $0 file.gds src_layer/src_purpose targ_layer/targ_purpose [output.gds]"} +: ${3?"Usage: $0 file.gds src_layer/src_purpose targ_layer/targ_purpose [output.gds]"} +: ${PDK_ROOT?"You need to export PDK_ROOT"} +TECH=${TECH:-sky130A} + +xvfb-run klayout -z -rd input_layout=$1 -rd tech_file=$PDK_ROOT/$TECH/libs.tech/klayout/$TECH.lyt -rd source_layer=$2 -rd target_layer=$3 -rd output_layout=$4 -rm $(dirname $0)/mv_shapes.py diff --git a/images/foss-asic-tools/addons/sak/klayout/parse_klayout_xor_log.py b/images/foss-asic-tools/addons/sak/klayout/parse_klayout_xor_log.py new file mode 100755 index 00000000..f5bbff29 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/parse_klayout_xor_log.py @@ -0,0 +1,51 @@ +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import re + +parser = argparse.ArgumentParser( + description='extracts the total xor differnces from an xor log') + +parser.add_argument('--log_file', '-l', required=True, + help='log file') + +parser.add_argument('--output', '-o', required=True, + help='output file to store results') + +args = parser.parse_args() +log_file_name = args.log_file +out_file_name = args.output + +string = "XOR differences:" +pattern = re.compile(r'\s*%s\s*([\d+]+)' % string) +tot_cnt = 0 +with open(log_file_name, "r") as f: + for line in f: + m = pattern.match(line) + if m: + tot_cnt += int(m.group(1)) + +string = "Issue with layer:" +pattern = re.compile(r'\s*%s\s*([\d+]+)' % string) +with open(log_file_name, "r") as f: + for line in f: + m = pattern.match(line) + if m: + outFileOpener = open(out_file_name, "a") + outFileOpener.write(line + '\n') + +outFileOpener = open(out_file_name, "a") +outFileOpener.write("Total XOR differences = " + str(tot_cnt) + '\n') +outFileOpener.close() diff --git a/images/foss-asic-tools/addons/sak/klayout/parse_xor_log.py b/images/foss-asic-tools/addons/sak/klayout/parse_xor_log.py new file mode 100755 index 00000000..ea4b90e3 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/parse_xor_log.py @@ -0,0 +1,55 @@ +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import re + +parser = argparse.ArgumentParser( + description='extracts the total xor differnces from an xor log') + +parser.add_argument('--log_file', '-l', required=True, + help='log file') + +parser.add_argument('--output', '-o', required=True, + help='output file to store results') + +parser.add_argument('--cell_name', '-c', required=True, + help='cell name') + +args = parser.parse_args() +log_file_name = args.log_file +out_file_name = args.output +cell_name = args.cell_name + +string = "XOR differences:" +pattern = re.compile(r'\s*%s\s*([\d+]+)' % string) +tot_cnt = 0 +with open(log_file_name, "r") as f: + for line in f: + m = pattern.match(line) + if m: + tot_cnt += int(m.group(1)) + +string = "Issue with layer:" +pattern = re.compile(r'\s*%s\s*([\d+]+)' % string) +with open(log_file_name, "r") as f: + for line in f: + m = pattern.match(line) + if m: + outFileOpener = open(out_file_name, "a") + outFileOpener.write(line + '\n') + +outFileOpener = open(out_file_name, "a") +outFileOpener.write("Total XOR differences of " + cell_name + " = " + str(tot_cnt) + '\n') +outFileOpener.close() diff --git a/images/foss-asic-tools/addons/sak/klayout/precheck_klayout.rb b/images/foss-asic-tools/addons/sak/klayout/precheck_klayout.rb new file mode 100755 index 00000000..8f56895f --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/precheck_klayout.rb @@ -0,0 +1,308 @@ +# SPDX-FileCopyrightText: 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +# Precheck that checks: +# 1. origin of the user_project_wrapper +# 2. Bounry layer is in user_project_wrapper +# 3. erase everything on the boundry layer for xor check +# +# To Run the script: +# klayout -rd file1= -rd file2= -z -r precheck_klayout.rb + +# class BoolProcessor + +# def initialize(layout, cell) + +# @layout = layout +# @cell = cell + +# @proc = RBA::ShapeProcessor.new + +# @temp_layers = [] + +# end + +# # Locate a layer for input. +# # The layer is specified by a RBA::LayerInfo object which identifies the layer by +# # a layer and datatype for example. If the layer does not exist, it is created. +# # This method returns a layer index which can be used as input for other functions. +# def input(lp) + +# layer_index = nil + +# # locate the layer if it already exists +# (0..(@layout.layers-1)).each do |i| +# if @layout.is_valid_layer?(i) && @layout.get_info(i).is_equivalent?(lp) +# layer_index = i +# break +# end +# end + +# # create a new layer if it does not exist +# return layer_index || @layout.insert_layer(lp) + +# end + +# # Create a new temporary layer and remember for removal on "cleanup". +# # This method returns a layer index which can be used as input for other functions. +# def tmp +# lp = RBA::LayerInfo.new +# layer_index = @layout.insert_layer(lp) +# @temp_layers.push(layer_index) +# return layer_index +# end + +# # Assign a layer as output. +# # Change the layer given by the layer index to the output layer specified +# # by a RBA::LayerInfo object. If the layer already exists, it is deleted. +# def output(lp, layer_index) + +# li = nil + +# # locate the layer if it already exists +# (0..(@layout.layers-1)).each do |i| +# if @layout.is_valid_layer?(i) && @layout.get_info(i).is_equivalent?(lp) +# li = i +# break +# end +# end + +# # clear the layer if it already exists +# if li != layer_index +# if li +# @layout.delete_layer(li) +# end +# @layout.set_info(layer_index, lp) +# end + +# # remove the layer from the list of temporary layers +# new_temp = [] +# @temp_layers.each do |i| +# if i != layer_index +# new_temp.push(i) +# end +# end +# @temp_layers = new_temp + +# end + +# # Clean up all temporary layers +# def cleanup +# @temp_layers.each do |i| +# @layout.delete_layer(i) +# end +# @temp_layers = [] +# end + +# # Size a layer by the given value (in micron). +# # "input" is the input layer, given by a layer index. +# def size(input, d) +# res = tmp() +# @proc.size(@layout, @cell, input, @cell.shapes(res), to_dbu(d), +# 2, true, true, true) +# return res +# end + +# # Size a layer by the given values anisotropically (in micron) +# # "input" is the input layer, given by a layer index. +# def size2(input, dx, dy) +# res = tmp() +# @proc.size(@layout, @cell, input, @cell.shapes(res), to_dbu(dx), to_dbu(dy), +# 2, true, true, true) +# return res +# end + +# # OR two layers +# # "a" and "b" are the input layers, given by a layer index. +# def or(a, b) +# res = tmp() +# @proc.boolean(@layout, @cell, a, @layout, @cell, b, @cell.shapes(res), +# RBA::EdgeProcessor::mode_or, true, true, true) +# return res +# end + +# # XOR two layers +# # "a" and "b" are the input layers, given by a layer index. +# def xor(a, b) +# res = tmp() +# @proc.boolean(@layout, @cell, a, @layout, @cell, b, @cell.shapes(res), +# RBA::EdgeProcessor::mode_xor, true, true, true) +# return res +# end + +# # AND two layers +# # "a" and "b" are the input layers, given by a layer index. +# def and(a, b) +# res = tmp() +# @proc.boolean(@layout, @cell, a, @layout, @cell, b, @cell.shapes(res), +# RBA::EdgeProcessor::mode_and, true, true, true) +# return res +# end + +# # NOT two layers +# # "a" and "b" are the input layers, given by a layer index. +# def not(a, b) +# res = tmp() +# @proc.boolean(@layout, @cell, a, @layout, @cell, b, @cell.shapes(res), +# RBA::EdgeProcessor::mode_anotb, true, true, true) +# return res +# end + +# # Convert a value from micron to database units +# # "a" and "b" are the input layers, given by a layer index. +# def to_dbu(micron) +# return (0.5 + micron / @layout.dbu).floor() +# end + +# # Run a procedure in the context of this object +# def run(&action) +# action.call(self) +# cleanup +# end + +# private +# @layout +# @cell +# @proc + +# end + +layout = RBA::Layout.new +lmap = layout.read($file1) + + +origin = Struct.new( :instx, :insty, :instrot) +originx = Array.new +originy = Array.new +originr = Array.new + +lmap2 = layout.read($file2) + +ind = 0 + +# define which cell to select +check_cell = layout.cell($cell_name) +if check_cell == nil + raise "user_project_wrapper is not in layout" +else + puts "[INFO] Found user_project_wrapper" +end + +ind = check_cell.cell_index + + +layout.each_cell do |c| + c.each_inst do |inst| + if inst.cell_index == ind + iindex = inst.cell_index + name = layout.cell_name(iindex) + itrans = inst.trans.to_s.gsub(",", "\s").split("\s") + instrot = itrans[0] + instx = (itrans[1].to_i * layout.dbu).round(6) + insty = (itrans[2].to_i * layout.dbu).round(6) + origin.new(instx, insty, instrot) + originx.append(instx) + originy.append(insty) + originr.append(instrot) + # puts("#{name},#{instx},#{insty},#{instrot}") + end + end +end + +# Checks if the origins are the same +if originx.uniq.size > 1 || originy.uniq.size > 1 || originr.uniq.size > 1 + raise "Origin of the user_project_wrapper is wrong" +else + puts "[INFO] Origin test passed successfully" +end + +# define which layer to select +boundry_layer = layout.layer(235, 4) + +# define a box on the layer and erase anything on that box +region = check_cell.bbox_per_layer(boundry_layer) + +# Checks if there's a boundry layer +if region.area == 0 + raise "There is no boundry layer in user_project_wrapper" +else + puts "[INFO] Boundry Layer test passed successfully" +end + +# Erase all layers on boundry layer +# cell_to_change = layout.cell($cell_name) +# cell_to_change.shapes(layout.layer(104, 0)).insert(RBA::Box::new(-42880, -1600, 2962500, 3521290)) +# cell_to_change.shapes(layout.layer(106, 0)).insert(RBA::Box::new(-6980, -37520, 2926600, 3557210)) + +# BoolProcessor.new(layout, layout.cell($cell_name)).run do |p| +# boundry = p.input(RBA::LayerInfo.new(235, 4)) +# bbox = p.input(RBA::LayerInfo.new(104, 0)) +# bbox2 = p.input(RBA::LayerInfo.new(106, 0)) +# tap = p.input(RBA::LayerInfo.new(81, 14)) +# met5_pin = p.input(RBA::LayerInfo.new(72, 16)) +# met5 = p.input(RBA::LayerInfo.new(72, 20)) +# met4_pin = p.input(RBA::LayerInfo.new(71, 16)) +# met4 = p.input(RBA::LayerInfo.new(71, 20)) +# via = p.input(RBA::LayerInfo.new(71, 44)) + +# layout.layer_indices.each do |li| +# # if li != bbox +# if li == met5 || li == met5_pin +# active = p.input(RBA::LayerInfo.new(layout.get_info(li).layer, layout.get_info(li).datatype)) +# gates = p.and(active, bbox) +# p.output(RBA::LayerInfo.new(10, 0), gates) +# active = p.xor(gates, active) +# p.output(RBA::LayerInfo.new(layout.get_info(li).layer, layout.get_info(li).datatype), active) +# end +# # end +# # if li != bbox2 +# if li == met4 || li == met4_pin +# active = p.input(RBA::LayerInfo.new(layout.get_info(li).layer, layout.get_info(li).datatype)) +# gates = p.and(active, bbox2) +# p.output(RBA::LayerInfo.new(10, 0), gates) +# active = p.xor(gates, active) +# p.output(RBA::LayerInfo.new(layout.get_info(li).layer, layout.get_info(li).datatype), active) +# end +# if li == via +# active = p.input(RBA::LayerInfo.new(layout.get_info(li).layer, layout.get_info(li).datatype)) +# gates = p.and(active, bbox2) +# gates2 = p.and(active, bbox) +# p.output(RBA::LayerInfo.new(10, 0), gates) +# p.output(RBA::LayerInfo.new(11, 0), gates2) +# act = p.xor(gates, active) +# act2 = p.xor(gates2, active) +# actt = p.and(act, act2) +# p.output(RBA::LayerInfo.new(layout.get_info(li).layer, layout.get_info(li).datatype), actt) +# end +# # end +# if li != boundry && li != tap +# active = p.input(RBA::LayerInfo.new(layout.get_info(li).layer, layout.get_info(li).datatype)) +# gates = p.and(active, boundry) +# p.output(RBA::LayerInfo.new(10, 0), gates) +# active = p.xor(gates, active) +# p.output(RBA::LayerInfo.new(layout.get_info(li).layer, layout.get_info(li).datatype), active) +# end +# end +# layout.delete_layer(layout.layer(10,0)) +# layout.delete_layer(layout.layer(11,0)) +# layout.delete_layer(layout.layer(104,0)) +# layout.delete_layer(layout.layer(106,0)) +# end + +#write to output file +# puts "[INFO] Writing empty gds file to temp_erase.gds" +# layout.write("temp_erase.gds") + diff --git a/images/foss-asic-tools/addons/sak/klayout/precheck_klayout.sh b/images/foss-asic-tools/addons/sak/klayout/precheck_klayout.sh new file mode 100755 index 00000000..15036dfc --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/precheck_klayout.sh @@ -0,0 +1,37 @@ +#!/bin/sh +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +: ${1?"Usage: $0 golden user_project_wrapper.gds/user_analog_project_wrapper.gds"} +: ${2?"Usage: $0 modified user_project_wrapper.gds/user_analog_project_wrapper.gds"} +: ${3?"Usage: $0 cell name"} +: ${4?"Usage: $0 output file for xoring .gds"} + + +echo "First Layout: $1" +echo "Second Layout: $2" +echo "cell: $3" +echo "output from xor Layout: $4" + +klayout -rd file1=$1 -rd file2=$2 -rd cell_name=$3 -z -r $(dirname $0)/precheck_klayout.rb + +klayout -rd file1=$1 -rd output=golden_erased.gds -rd cell_name=$3 -z -r $(dirname $0)/erase.rb + +klayout -rd file1=$2 -rd output=modified_erased.gds -rd cell_name=$3 -z -r $(dirname $0)/erase.rb + +$SAK/klayout/run_xor.sh modified_erased.gds golden_erased.gds $3 $4 + +rm golden_erase.gds +rm modified_erased.gds + diff --git a/images/foss-asic-tools/addons/sak/klayout/replace_some_cells.py b/images/foss-asic-tools/addons/sak/klayout/replace_some_cells.py new file mode 100755 index 00000000..ef0df5a8 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/replace_some_cells.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python3 +import subprocess +import argparse +import os + +parser = argparse.ArgumentParser( + description='Replaces a portion of the cells with others from the library.') + +parser.add_argument('--probability', '-p', type=float, required=True, + default=1.0, + help='') + +parser.add_argument('--design-name', '-name', required=True) + +parser.add_argument('--from-cell-prefix', '-from', required=True, nargs='+') +parser.add_argument('--to-cell-prefix', '-to', required=True, nargs='+') + +parser.add_argument('--user-gds', '-design', required=True) +parser.add_argument('--library-gds', '-library', required=True, nargs='+') + +parser.add_argument('--output-gds', '-o', required=True) + +parser.add_argument('--xor', action='store_true', + default=False, + help='Produce an XOR GDS of the output_gds vs the original user_gds.' + 'In the same output directory as output_gds') + +args = parser.parse_args() + +probability = args.probability + +design_name = args.design_name + +from_cell_prefix = args.from_cell_prefix +to_cell_prefix = args.to_cell_prefix + +user_gds = args.user_gds +library_gds = args.library_gds +output_gds = args.output_gds + +xor_flag = args.xor + +klayout_cmd = f"klayout -zz \ + -rd design_name={design_name} \ + -rd from_cell_prefix={','.join(from_cell_prefix)} \ + -rd to_cell_prefix={','.join(to_cell_prefix)} \ + -rd library_gds={','.join(library_gds)} \ + -rd user_gds={user_gds} \ + -rd output_gds={output_gds} \ + -rd probability={probability} \ + -rm tmp.py" + +klayout_code=r""" +import pya +from random import random, seed + +seed(a=0) + +app = pya.Application.instance() +win = app.main_window() + +# design_name = 'manual_macro_placement_test' + +# from_cell_prefix = 'sky130_fd_sc_hd__decap' +# to_cell_prefix = 'sky130_fd_sc_hd__fill' + +# library_gds = '/home/xrex/usr/devel/pdks/sky130A/libs.ref/sky130_fd_sc_hd/gds/sky130_fd_sc_hd.gds' +# user_gds = '/home/xrex/usr/devel/openlane_develop/designs/manual_macro_placement_test/runs/test/results/magic/manual_macro_placement_test.gds' +# output_gds = '/home/xrex/usr/devel/openlane_develop/designs/manual_macro_placement_test/runs/test/results/magic/out.gds' + +# probability = 1.0 + +####### + +library_gds = library_gds.split(',') +from_cell_prefix = from_cell_prefix.split(',') +to_cell_prefix = to_cell_prefix.split(',') + +from_cells = [] +to_cells = [] + +user_layout = pya.Layout() + +for gds in library_gds: + print("Reading", gds) + user_layout.read(gds) + +# find the cells we're interested in (flat cell list) +for cell in user_layout.each_cell(): + cell_name = cell.name + + for prefix in from_cell_prefix: + if cell_name.startswith(prefix): + assert cell not in from_cells + from_cells.append(cell) + + for prefix in to_cell_prefix: + if cell_name.startswith(prefix): + assert cell not in to_cells + to_cells.append(cell) + +print("From:", [c.name for c in from_cells]) +print("To:", [c.name for c in to_cells]) + +subst_dict = {} +for cell_from in from_cells: + cell_from_width = cell_from.bbox().width() + for cell_to in to_cells: + cell_to_width = cell_to.bbox().width() + if cell_to_width == cell_from_width: + subst_dict[cell_from.name] = cell_to + break + + subst_dict.setdefault(cell_from.name, None) + +print('-'*10) + +for k, v in subst_dict.items(): + if v: + print("Found a substitution", k, "->", v.name) + +print('-'*10) + +############################## + +matching_insts = [] + +def add_if_matching_cell(inst): + cell_name = inst.cell.name + # print("DBUG: Checking", cell_name) + for prefix in from_cell_prefix: + if cell_name.startswith(prefix): + matching_insts.append(inst) + +def print_cell_name(inst): + pass + +def substitute_matching_cell(inst): + cell_name = inst.cell.name + assert cell_name in subst_dict + if subst_dict[cell_name] is not None: + # print("DBUG: Replacing", cell_name, end=' ') + # print("with", subst_dict[cell_name].name) + inst.cell = subst_dict[cell_name] + +def exec_for_each_inst(cell, func): + # print("DBUG_CELL:", cell.name) + for inst in cell.each_inst(): + # print(" DBUG_INST:", inst.cell.name) + assert inst is not None + + # for cells that have no hierarchy beneath (standard cells in this case) + if inst.cell.hierarchy_levels() == 0: + func(inst) + + # for macros + for child_idx in cell.each_child_cell(): + cell = user_layout.cell(child_idx) + if cell.hierarchy_levels() > 0: + # print("DBUG_CHILD:", cell.name) + exec_for_each_inst(cell, func) + +user_layout.read(user_gds) + +top_cell = user_layout.cell(design_name) + +print("Top-cell name:", top_cell.name) + +exec_for_each_inst(top_cell, add_if_matching_cell) + +subst_cnt = 0 +tot = len(matching_insts) +for inst in matching_insts: + if random() <= float(probability): + subst_cnt += 1 + substitute_matching_cell(inst) + +print("Substituted", subst_cnt, "out of", tot, "substitutable cells") + +# delete the rest of the top-level cells +####### revise this: +for cell in user_layout.top_cells(): + if cell.name != design_name: + cell.delete() + +for cell in user_layout.top_cells(): + if cell.name != design_name: + cell.delete() + +user_layout.write(output_gds) + +print("Successfully wrote", output_gds) +""" + +with open("tmp.py", "w") as f: + f.write(klayout_code) + +try: + print("Executing:") + print(klayout_cmd) + output = subprocess.call(klayout_cmd.split()) +except: + print("KLayout script failed") +finally: + pass + os.remove('tmp.py') + +if xor_flag: + print("Running XOR on the result against the original user GDS.") + output_xor_file_name = os.path.splitext(output_gds)[0] + '.xor.gds' + xor_cmd = f"sh {os.path.dirname(os.path.realpath(__file__))}/xor.sh {output_gds} {user_gds} {design_name} {output_xor_file_name}" + try: + print("Executing:") + print(xor_cmd) + output = subprocess.call(xor_cmd.split()) + except: + print("XOR script failed") diff --git a/images/foss-asic-tools/addons/sak/klayout/run_gds2oas.sh b/images/foss-asic-tools/addons/sak/klayout/run_gds2oas.sh new file mode 100755 index 00000000..96c411cc --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/run_gds2oas.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -e + +echo "converting all gds files to oasis files" + +for filename in *.gds; do + out="${filename%%.*}" + out=$out".oas" + xvfb-run -a klayout -z \ + -rd input_layout=$filename \ + -rd output=$out \ + -rm $(dirname $0)/gds2oas.py; done + +echo 'Done converting all gds files to oasis files' +exit 0 \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/klayout/run_xor.sh b/images/foss-asic-tools/addons/sak/klayout/run_xor.sh new file mode 100755 index 00000000..2e18d2a9 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/run_xor.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# script for running the xor script and then running the parsing script + +: ${1?"Usage: $0 file1.gds file2.gds output.gds|markers.xml"} +: ${2?"Usage: $0 file1.gds file2.gds output.gds|markers.xml"} +: ${3?"Usage: $0 file1.gds file2.gds output.gds|markers.xml"} +: ${4?"Usage: $0 file1.gds file2.gds output.gds|markers.xml"} + +./xor.sh $1 $2 $3 $4 | tee xor.log + +rm xor_total.txt + +python3 parse_xor_log.py \ + -l "xor.log" \ + -o "xor_total.txt" \ + -c $3 + +cat xor_total.txt diff --git a/images/foss-asic-tools/addons/sak/klayout/scrotLayout.py b/images/foss-asic-tools/addons/sak/klayout/scrotLayout.py new file mode 100755 index 00000000..473fdb9a --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/scrotLayout.py @@ -0,0 +1,40 @@ +import pya +import re +import os + +WIDTH = 2048 +HEIGHT = 2048 + +app = pya.Application.instance() +win = app.main_window() + +# Load technology file +tech = pya.Technology() +tech.load(tech_file) +layoutOptions = tech.load_layout_options +layoutOptions.text_enabled = False + +# Load def file in the main window +cell_view = win.load_layout(input_layout, layoutOptions, 0) +layout_view = cell_view.view() +layout_view.grid_visible = False + +layout_view.max_hier() +# layout_view.clear_layers() + +# Hide layers with these purposes +hidden_purposes = [0, 4, 5] + +li = layout_view.begin_layers() +while not li.at_end(): + lp = li.current() + if lp.source_datatype in hidden_purposes: + new_lp = lp.dup() + new_lp.visible = False + layout_view.set_layer_properties(li, new_lp) + + li.next() + +layout_view.save_image(os.path.splitext(input_layout)[0]+'.png', WIDTH, HEIGHT) + +app.exit(0) diff --git a/images/foss-asic-tools/addons/sak/klayout/scrotLayout.sh b/images/foss-asic-tools/addons/sak/klayout/scrotLayout.sh new file mode 100755 index 00000000..d8337839 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/scrotLayout.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +: ${1?"Usage: $0 tech_file input"} +: ${2?"Usage: $0 tech_file input"} + +echo "Using Techfile: $1" +echo "Using layout file: $2" + +# The -a here is necessary to handle race conditions. +# This limits the max number of possible jobs to 100. +xvfb-run -a klayout -z \ + -rd input_layout=$2 \ + -rd tech_file=$1 \ + -rm $(dirname $0)/scrotLayout.py + +exit 0 diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/DRC_ciic.sh b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/DRC_ciic.sh new file mode 100755 index 00000000..358efa90 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/DRC_ciic.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +: ${1?"Usage: $0 gds input file"} +: ${2?"Usage: $0 report name"} +: ${3?"Usage: $0 number of threads"} +: ${4?"Usage: $0 size of tiles"} + +start=$(date +"%r") +/ciic/tools/bin/klayout -rd input=$1 -rd report=$2 -rd thr=$3 -rd tiles=$4 -rd beol=1 -rd feol=1 -zz -r sky130A_mr_opt.drc +end=$(date +"%r") +echo "start: $start \nend: $end" diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/do-not-use-sky130_2_jeffdi.lydrc b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/do-not-use-sky130_2_jeffdi.lydrc new file mode 100755 index 00000000..cb80e644 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/do-not-use-sky130_2_jeffdi.lydrc @@ -0,0 +1,868 @@ + + + + + drc + + + + false + false + + true + drc_scripts + tools_menu.drc.end + dsl + drc-dsl-xml + # +# DRC for SKY130 according to : +# https://skywater-pdk.readthedocs.io/en/latest/rules/periphery.html +# https://skywater-pdk.readthedocs.io/en/latest/rules/layers.html +# +# Distributed under GNU GPLv3: https://www.gnu.org/licenses/ +# +# History : +# 2020-10-04 : v1.0 : initial release +# +########################################################################################## + +# optionnal for a batch launch : klayout -b -rd input=my_layout.gds -rd report=sky130_drc.txt -r drc_sky130.drc +if $input + source($input) +end + +if $report + report("SKY130 DRC runset", $report) +else + report("SKY130 DRC runset", File.join(File.dirname(RBA::CellView::active.filename), "sky130_drc.txt")) +end + +AL = true # do not change +CU = false # do not change +# choose betwen only one of AL or CU back-end flow here : +backend_flow = AL + +# enable / disable rule groups +FEOL = false # front-end-of-line checks +BEOL = true # back-end-of-line checks +OFFGRID = false # manufacturing grid/angle checks + +# klayout setup +######################## +# use a tile size of 1mm - not used in deep mode- +tiles(1000.um) +# use a tile border of 10 micron: +tile_borders(1.um) +#no_borders + +# hierachical +deep + +# use 4 cpu cores +threads(16) +# if more inof is needed, set true +verbose(true) + +# layers definitions +######################## +diff = input(65, 20) +tap = polygons(65, 44) +nwell = polygons(64, 20) +dnwell = polygons(64, 18) +pwbm = polygons(19, 44) +pwde = polygons(124, 20) +natfet = polygons(124, 21) +hvtr = polygons(18, 20) +hvtp = polygons(78, 44) +ldntm = polygons(11, 44) +hvi = polygons(75, 20) +tunm = polygons(80, 20) +lvtn = polygons(125, 44) +poly = polygons(66, 20) +hvntm = polygons(125, 20) +nsdm = polygons(93, 44) +psdm = polygons(94, 20) +rpm = polygons(86, 20) +urpm = polygons(79, 20) +npc = polygons(95, 20) +licon = polygons(66, 44) +li = input(67, 20) +mcon = polygons(67, 44) +m1 = polygons(68, 20) +via = polygons(68, 44) +m2 = polygons(69, 20) +via2 = polygons(69, 44) +m3 = polygons(70, 20) +via3 = polygons(70, 44) +m4 = polygons(71, 20) +via4 = polygons(71, 44) +m5 = polygons(72, 20) +pad = polygons(76, 20) +nsm = polygons(61, 20) +capm = polygons(89, 44) +cap2m = polygons(97, 44) +vhvi = polygons(74, 21) +uhvi = polygons(74, 22) +npn = polygons(82, 20) +inductor = polygons(82, 24) +vpp = polygons(82, 64) +pnp = polygons(82, 44) +lvs_prune = polygons(84, 44) +ncm = polygons(92, 44) +padcenter = polygons(81, 20) +mf = polygons(76, 44) +areaid_sl = polygons(81, 1) +areaid_ce = polygons(81, 2) +areaid_fe = polygons(81, 3) +areaid_sc = polygons(81, 4) +areaid_sf = polygons(81, 6) +areaid_sw = polygons(81, 7) +areaid_sr = polygons(81, 8) +areaid_mt = polygons(81, 10) +areaid_dt = polygons(81, 11) +areaid_ft = polygons(81, 12) +areaid_ww = polygons(81, 13) +areaid_ld = polygons(81, 14) +areaid_ns = polygons(81, 15) +areaid_ij = polygons(81, 17) +areaid_zr = polygons(81, 18) +areaid_ed = polygons(81, 19) +areaid_de = polygons(81, 23) +areaid_rd = polygons(81, 24) +areaid_dn = polygons(81, 50) +areaid_cr = polygons(81, 51) +areaid_cd = polygons(81, 52) +areaid_st = polygons(81, 53) +areaid_op = polygons(81, 54) +areaid_en = polygons(81, 57) +areaid_en20 = polygons(81, 58) +areaid_le = polygons(81, 60) +areaid_hl = polygons(81, 63) +areaid_sd = polygons(81, 70) +areaid_po = polygons(81, 81) +areaid_it = polygons(81, 84) +areaid_et = polygons(81, 101) +areaid_lvt = polygons(81, 108) +areaid_re = polygons(81, 125) +areaid_ag = polygons(81, 79) +poly_rs = polygons(66, 13) +diff_rs = polygons(65, 13) +pwell_rs = polygons(64, 13) +li_rs = polygons(67, 13) +cfom = polygons(22, 20) + + +# Define a new custom function that selects polygons by their number of holes: +# It will return a new layer containing those polygons with min to max holes. +# max can be nil to omit the upper limit. +class DRC::DRCLayer + def with_holes(min, max) + new_data = RBA::Region::new + self.data.each do |p| + if p.holes >= (min || 0) && (!max || p.holes <= max) + new_data.insert(p) + end + end + DRC::DRCLayer::new(@engine, new_data) + end +end + +# DRC section +######################## +info("DRC section") + +if FEOL +info("FEOL section") +gate = diff & poly + +# dnwell +dnwell.width(3.0, euclidian).output("dnwell.2", "dnwell.2 : min. dnwell width : 3.0um") +dnwell.not(uhvi).not(areaid_po).isolated(6.3, euclidian).output("dnwell.3", "dnwell.3 : min. dnwell spacing : 6.3um") +dnwell.and(pnp).output("dnwell.4", "dnwell.4 : dnwell must not overlap pnp") +dnwell.and(psdm).edges.not(psdm.edges).output("dnwell.5", "p+ must not straddle dnwell") +# dnwell.6 rue not coded + +# nwell +nwell.width(0.84, euclidian).output("nwell.1", "nwell.1 : min. nwell width : 0.84um") +nwell.isolated(1.27, euclidian).output("nwell.2a", "nwell.2a : min. nwell spacing (merged if less) : 1.27um") +# rule nwell.4 is suitable for digital cells +#nwell.not(uhvi).not(areaid_en20).not_interacting(tap.and(licon).and(li)).output("nwell.4", "nwell4 : all nwell exempt inside uhvi must contain a n+tap") +nwell.enclosing(dnwell.not(uhvi).not(areaid_po), 0.4, euclidian).output("nwell.5", "nwell.5 : min. nwell enclosing dnwell exempt unside uhvi : 0.4um") +dnwell.enclosing(nwell.not(uhvi), 1.03, euclidian).output("nwell.6", "nwell.6 : min. dnwell enclosing nwell exempt unside uhvi : 1.03um") +dnwell.separation(nwell, 4.5, euclidian).output("nwell.7", "nwell.7 : min. dnwell separation nwell : 4.5um") + +# pwbm +pwbm.not(uhvi).output("pwbm", "pwbm must be inside uhvi") +dnwell.and(uhvi).edges.not(pwbm).output("pwbm.4", "pwbm.4 : dnwell inside uhvi must be enclosed by pwbm") + +# pwde +pwde.not(pwbm).output("pwdem.3", "pwdem.3 : pwde must be inside pwbm") +pwde.not(uhvi).output("pwdem.4", "pwdem.4 : pwde must be inside uhvi") +pwde.not(dnwell).output("pwdem.5", "pwdem.5 : pwde must be inside dnwell") + +# hvtp +#hvtp.not(nwell).output("hvtp", "hvtp must inside nwell") +hvtp.width(0.38, euclidian).output("hvtp.1", "hvtp.1 : min. hvtp width : 0.38um") +hvtp.isolated(0.38, euclidian).output("hvtp.2", "hvtp.2 : min. hvtp spacing : 0.38um") +hvtp.enclosing(gate.and(psdm), 0.18, euclidian).output("hvtp.3", "hvtp.3 : min. hvtp enclosure of pfet gate : 0.18um") +hvtp.separation(gate.and(psdm), 0.18, euclidian).output("hvtp.4", "hvtp.4 : min. hvtp spacing pfet gate: 0.18um") +hvtp.with_area(0..0.265).output("hvtp.5", "hvtp.5 : min. hvtp area : 0.265um²") + +# hvtr +hvtr.width(0.38, euclidian).output("hvtr.1", "hvtr.1 : min. hvtr width : 0.38um") +hvtr.isolated(0.38, euclidian).output("hvtr.2", "hvtr.2 : min. hvtr spacing : 0.38um") + +# lvtn +lvtn.width(0.38, euclidian).output("lvtn.1", "lvtn.1 : min. lvtn width : 0.38um") +lvtn.isolated(0.38, euclidian).output("lvtn.2", "lvtn.2 : min. lvtn spacing : 0.38um") +lvtn.separation(diff.and(poly).not(uhvi), 0.18, euclidian).output("lvtn.3a", "lvtn.3a : min. lvtn spacing to gate : 0.18um") +lvtn.separation(diff.and(nwell).not(poly), 0.235, projection).output("lvtn.3b", "lvtn.3b : min. lvtn spacing to pfet s/d : 0.18um") +lvtn.enclosing(gate.not(uhvi), 0.18, euclidian).output("lvtn.4b", "lvtn.4b : min. lvtn enclosing to gate : 0.18um") +lvtn.separation(hvtp, 0.38, euclidian).output("lvtn.9", "lvtn.9 : min. lvtn spacing hvtp : 0.38um") +nwell.not_interacting(gate.and(nwell.not(hvi).not(areaid_ce))).enclosing(lvtn.not(uhvi), 0.18, euclidian).polygons.without_area(0).output("lvtn.4b", "lvtn.4b : min. lvtn enclosure of gate : 0.18um") +lvtn.separation(nwell.inside(areaid_ce), 0.38, euclidian).output("lvtn.12", "lvtn.12 : min. lvtn spacing nwell inside areaid.ce : 0.38um") +lvtn.with_area(0..0.265).output("lvtn.13", "lvtn.13 : min. lvtn area : 0.265um²") + +# ncm +ncm.and(tap.and(nwell).or(diff.not(nwell))).output("ncm.x.3", "ncm.x.3 : ncm must not overlap n+diff") +ncm.width(0.38, euclidian).output("ncm.1", "ncm.1 : min. ncm width : 0.38um") +ncm.isolated(0.38, euclidian).output("ncm.2", "ncm.2 : min. ncm spacing manual merge if smaller : 0.38um") +ncm.enclosing(diff.and(nwell), 0.18, euclidian).output("ncm.3", "ncm.3 : min. ncm enclosure of p+diff : 0.18um") +ncm.separation(lvtn.and(diff), 0.23, euclidian).output("ncm.5", "ncm.5 : min. ncm spacing lvtn diff : 0.23um") +ncm.separation(diff.not(nwell), 0.2, euclidian).output("ncm.6", "ncm.6 : min. ncm spacing nfet : 0.2um") +ncm.with_area(0..0.265).output("ncm.7", "ncm.13 : min. ncm area : 0.265um²") + +# diff-tap +difftap = diff + tap +difftap.width(0.15, euclidian).output("difftap.1", "difftap.1 : min. difftap width : 0.15um") +not_in_cell1 = layout(source.cell_obj).select("s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b" , "-s8fpls_pl8", "-s8fpls_rdrv4" , "-s8fpls_rdrv4f", "-s8fpls_rdrv8") +not_in_cell1_diff = not_in_cell1.input(65, 20) +not_in_cell1_diff.not(areaid_sc).not(poly).edges.and(gate.edges).with_length(0,0.42).output("difftap.2", "difftap.2: min. gate (exempt areaid.sc) width : 0.42um") +diff.and(areaid_sc).not(poly).edges.and(gate.edges).with_length(0,0.36).output("difftap.2", "difftap.2: min. gate inside areaid.sc width : 0.36um") +difftap.isolated(0.27, euclidian).output("difftap.3", "difftap.3 : min. difftap spacing : 0.27um") +tap.edges.and(diff.edges).with_length(0,0.29).output("difftap.4", "difftap.4 : min. tap bound by diffusion : 0.29um") +tap.edges.and(diff.edges).space(0.4, projection).output("difftap.5", "difftap.5 : min. tap bound by 2 diffusions : 0.4um") +(tap.edges.and(diff.edges)).extended(0.01, 0.01, 0, 0, false).not(tap.and(diff)).and(diff.or(tap)).output("difftap.6", "difftap.6 : diff and tap not allowed to extend beyong their abutting ege") +tap.edges.not_interacting(diff.edges).separation(diff.edges, 0.13, euclidian).output("difftap.7", "difftap.7 : min. diff/tap spacing to non-coincident diff edge : 0.13um") +diff.edges.not_interacting(tap.edges).separation(tap.edges, 0.13, euclidian).output("difftap.7", "difftap.7 : min. diff/tap spacing to non-coincident tap edge : 0.13um") +nwell.enclosing(diff.not(uhvi).and(psdm), 0.18, euclidian).output("difftap.8", "difftap.8 : min. p+diff enclosure by nwell : 0.18um") +diff.not(uhvi).and(nsdm).separation(nwell, 0.34, euclidian).output("difftap.9", "difftap.9 : min. n+diff spacing to nwell : 0.34um") +nwell.enclosing(tap.not(uhvi).and(nsdm), 0.18, euclidian).output("difftap.10", "difftap.10 : min. n+tap enclosure by nwell : 0.18um") +tap.not(uhvi).and(psdm).separation(nwell, 0.13, euclidian).output("difftap.11", "difftap.11 : min. p+tap spacing to nwell : 0.13um") + +# tunm +tunm.width(0.41, euclidian).output("tunm.1", "tunm.1 : min. tunm width : 0.41um") +tunm.isolated(0.5, euclidian).output("tunm.2", "tunm.2 : min. tunm spacing : 0.5um") +tunm.enclosing(gate, 0.095, euclidian).output("tunm.3", "tunm.3 : min. tunm beyond gate : 0.095um") +tunm.separation(gate.not_interacting(tunm), 0.095, euclidian).output("tunm.4", "tunm.4 : min. tunm spacing to gate outside tunm: 0.095um") +gate.and(tunm).edges.not(gate.edges).output("tunm.5", "tunm.5 : gate must not straddle tunm") +tunm.not(dnwell).output("tunm.6a", "tunm.6a : tunm not allowed outside dnwell") +tunm.with_area(0..0.672).output("tunm.7", "tunm.7 : min. tunm area : 0.672um²") + +# poly +poly.width(0.15, euclidian).output("poly.1a", "poly.1a : min. poly width : 0.15um") +poly.not(diff).edges.and(gate.and(lvtn).edges).space(0.35, euclidian).output("poly.1b", "poly.1b: min. lvtn gate width : 0.35um") +poly.isolated(0.21, euclidian).output("poly.2", "poly.2 : min. poly spacing : 0.21um") +poly.and(rpm.or(urpm).or(poly_rs)).width(0.33, euclidian).output("poly.3", "poly.3 : min. poly resistor width : 0.33um") +poly.not(gate).separation(diff, 0.075, projection).polygons.without_area(0).output("poly.4", "poly.4 : min. poly on field spacing to diff : 0.075um") +poly.not(gate).separation(tap, 0.055, euclidian).output("poly.5", "poly.5 : min. poly on field spacing to tap : 0.055um") +gate.separation(tap, 0.3, projection).polygons.and(diff).output("poly.6", "poly.6 : min. gate spacing to tap : 0.3um") +diff.enclosing(gate, 0.25, projection).polygons.without_area(0).output("poly.7", "poly.7 : min. source/drain length : 0.25um") +poly.enclosing(gate, 0.13, projection).polygons.without_area(0).output("poly.8", "poly.8 : min. poly extention gate (endcap) : 0.13um") +poly.and(rpm.or(urpm).or(poly_rs)).separation(poly.or(difftap), 0.48, euclidian).polygons.without_area(0).output("poly.9", "poly.9 : min. poly resistor space to poly or diff/tap : 0.48um") +diff.merged.edges.end_segments(0.01).and(poly).output("poly.10", "poly.10 : poly must not overlap diff corner") +gate.with_angle(0 .. 90).output("poly.11", "poly.11 : non 90 degree angle gate") +not_in_cell3 = layout(source.cell_obj).select("s8fgvr_n_fg2") +not_in_cell3_poly = not_in_cell3.input(66, 20) +not_in_cell3_poly.not(hvi).not(nwell.not(hvi)).and(tap).output("poly.12", "poly.12 : poly must not overlap tap") +poly.and(diff_rs).output("poly.15", "poly.15 : poly must not overlap diff resistor") + +# rpm +rpm.width(1.27, euclidian).output("rpm.1a", "rpm.1a : min. rpm width : 1.27um") +rpm.isolated(0.84, euclidian).output("rpm.2", "rpm.2 : min. rpm spacing : 0.84um") +rpm.enclosing(poly.and(poly_rs).and(psdm), 0.2, euclidian).output("rpm.3", "rpm.3 : min. rpm enclosure of poly resistor : 0.2um") +psdm.enclosing(poly.and(poly_rs).and(rpm), 0.11, euclidian).output("rpm.4", "rpm.4 : min. psdm enclosure of poly resistor : 0.11um") +npc.enclosing(poly.and(poly_rs).and(rpm), 0.095, euclidian).output("rpm.5", "rpm.5 : min. npc enclosure of poly resistor : 0.095um") +rpm.separation(nsdm, 0.2, euclidian).output("rpm.6", "rpm.6 : min. rpm spacing nsdm: 0.2um") +rpm.separation(poly, 0.2, euclidian).output("rpm.7", "rpm.7 : min. rpm spacing poly: 0.2um") +rpm.and(poly).edges.not(poly.edges).output("rpm.8", "rpm.8 : poly must not straddle rpm") +poly.and(poly_rs).and(rpm).separation(hvntm, 0.185, euclidian).output("rpm.9", "rpm.9 : min. poly resistor spacing hvntm: 0.185um") +rpm.and(pwbm).output("rpm.10", "rpm.107 : min. rpm spacing pwbm: na") + +# varac +varac = poly & tap & (nwell - hvi) - areaid_ce +tap.not(poly).edges.and(varac.edges).space(0.18, euclidian).output("varac.1", "varac.1: min. varac channel length : 0.18um") +tap.and(poly).edges.and(varac.edges).space(1.0, euclidian).output("varac.2", "varac.2: min. varac channel wdth : 1.0um") +varac.separation(hvtp, 0.18, euclidian).output("varac.3", "varac.3: min. varac channel space to hvtp : 0.18um") +varac.separation(licon.and(tap), 0.25, euclidian).output("varac.4", "varac.4: min. varac channel space to licon on tap : 0.25um") +nwell.enclosing(poly.overlapping(varac), 0.15, euclidian).output("varac.5", "varac.5: min. nwell enclosure of poly overlapping varac channel : 0.15um") +tap.overlapping(varac).separation(difftap, 0.27, euclidian).polygons.without_area(0).output("varac.6", "varac.6: min. varac channel tap space to difftap : 0.27um") +nwell.overlapping(varac).and(diff.and(nwell)).output("varac.7", "varac.7: nwell overlapping varac channel must not overlap p+diff") + +# photo +photodiode = dnwell & areaid_po +photodiode.edges.without_length(3.0).output("photo.2", "photo.2 : minimum/maximum width of photodiode : 3.0um") +photodiode.isolated(5.0, euclidian).output("photo.3", "photo.3 : mini. photodiode spacing : 5.0um") +photodiode.separation(dnwell, 5.3, euclidian).output("photo.4", "photo.4 : mini. photodiode spacing to dnwell : 5.3um") +areaid_po.not(dnwell).output("photo.5.6", "photo.5.6 : photodiode edges must coincide areaid.po and enclosed by dnwell") +photodiode.not(tap.not(nwell).holes).output("photo.7", "photo.7 : photodiode must be enclosed by p+tap ring") +photodiode.and(nwell).edges.without_length(0.84).output("photo.8", "photo.8 : minimum/maximum width of nwell inside photodiode : 0.84um") +areaid_po.edges.and(photodiode.and(nwell).sized(1.08)).without_length(12.0).output("photo.9", "photo.9 : minimum/maximum enclosure of nwell by photodiode : 1.08um") +photodiode.and(tap).edges.without_length(0.41).output("photo.10", "photo.10 : minimum/maximum width of tap inside photodiode : 0.41um") + +# npc +npc.width(0.27, euclidian).output("npc.1", "npc.1 : min. npc width : 0.27um") +npc.isolated(0.27, euclidian).output("npc.2", "npc.2 : min. npc spacing, should be mnually merge if less : 0.27um") +npc.separation(gate, 0.09, euclidian).output("npc.4", "npc.4 : min. npc spacing to gate : 0.09um") + +# nsdm/psdm +npsdm = nsdm + psdm +nsdm.width(0.38, euclidian).output("nsdm.1", "nsdm.1 : min. nsdm width : 0.38um") +psdm.width(0.38, euclidian).output("psdm.1", "psdm.1 : min. psdm width : 0.38um") +nsdm.isolated(0.38, euclidian).output("n/psdm.1", "n/psdm.1 : min. nsdm spacing, should be mnually merge if less : 0.38um") +psdm.isolated(0.38, euclidian).output("n/psdm.1", "n/psdm.1 : min. psdm spacing, should be mnually merge if less : 0.38um") +npsdm.enclosing(diff, 0.125, euclidian).polygons.not(tap.sized(0.125)).output("n/psdm.5a", "n/psdm.5a : min. n/psdm enclosure diff except butting edge : 0.125um") +npsdm.enclosing(tap, 0.125, euclidian).polygons.not(diff.sized(0.125)).output("n/psdm.5b", "n/psdm.5b : min. n/psdm enclosure tap except butting edge : 0.125um") +tap.edges.and(diff.edges).not(npsdm).output("n/psdm.6", "n/psdm.6 : min. n/psdm enclosure of butting edge : 0.0um") +nsdm.and(difftap).separation(psdm.and(difftap), 0.13, euclidian).polygons.without_area(0).output("n/psdm.7", "n/psdm.7 : min. nsdm diff spacing to psdm diff except butting edge : 0.13um") +diff.and((nsdm.and(nwell)).or(psdm.not(nwell))).output("n/psdm.8", "n/psdm.8 : diff should be the opposite type of well/substrate underneath") +tap.and((nsdm.not(nwell)).or(psdm.and(nwell))).output("n/psdm.8", "n/psdm.8 : tap should be the same type of well/substrate underneath") +tap.and(diff).without_area(0).output("tap and diff", "tap and diff must not overlap") +nsdm.with_area(0..0.265).output("n/psdm.10a", "n/psdm.10a : min. nsdm area : 0.265um²") +psdm.with_area(0..0.265).output("n/psdm.10b", "n/psdm.10b : min. psdm area : 0.265um²") + +# licon +licon.not(poly.interacting(poly_rs)).edges.without_length(0.17).output("licon.1", "licon.1 : minimum/maximum width of licon : 0.17um") +licon.and(poly.interacting(poly_rs)).not_interacting((licon.and(poly.interacting(poly_rs)).edges.with_length(0.19)).or(licon.and(poly.interacting(poly_rs)).edges.with_length(2.0))).output("licon.1b/c", "licon.1b/c : minimum/maximum width/length of licon inside poly resistor : 2.0/0.19um") +licon.isolated(0.17, euclidian).output("licon.2", "licon.2 : min. licon spacing : 0.17um") +licon.and(poly.interacting(poly_rs)).edges.with_length(0.19).space(0.35, euclidian).output("licon.2b", "licon.2b : min. licon 0.19um edge on resistor spacing : 0.35um") +licon.interacting(licon.and(poly.interacting(poly_rs)).edges.with_length(2.0)).separation(licon.and(poly.interacting(poly_rs)), 0.51, euclidian).output("licon.2c", "licon.2c : min. licon 2.0um edge on resistor spacing : 0.51um") +licon.and(poly.interacting(poly_rs)).separation(licon.not(poly.interacting(poly_rs)), 0.51, euclidian).output("licon.2d", "licon.2d : min. licon on resistor spacing other licon : 0.51um") +# rule licon.3 not coded +licon.not(li).not(poly.or(diff).or(tap)).output("licon.4", "licon.4 : min. licon must overlap li and (poly or tap or diff) ") +diff.enclosing(licon, 0.04, euclidian).output("licon.5", "licon.5 : min. diff enclosure of licon : 0.04um") +tap.edges.and(diff.edges).separation(licon.and(tap).edges, 0.06, euclidian).output("licon.6", "licon.6 : min. abutting edge spacing to licon tap : 0.06um") +licon_edges_with_less_enclosure_tap = tap.enclosing(licon, 0.12, projection).second_edges +opposite1 = (licon.edges - licon_edges_with_less_enclosure_tap).width(0.17 + 1.dbu, projection).polygons +licon.not_interacting(opposite1).output("licon.7", "licon.7 : min. tap enclosure of licon by one of 2 opposite edges : 0.12um") +poly.enclosing(licon, 0.05, euclidian).output("licon.8", "licon.8 : min. poly enclosure of licon : 0.05um") +licon008 = licon.interacting(poly.enclosing(licon, 0.08, euclidian).polygons) +licon_edges_with_less_enclosure_poly = poly.enclosing(licon, 0.08, projection).second_edges +opposite2 = (licon.edges - licon_edges_with_less_enclosure_poly).width(0.17 + 1.dbu, projection).polygons +licon008.not_interacting(opposite2).output("licon.8a", "licon.8a : min. poly enclosure of licon by one of 2 opposite edges : 0.08um") +# rule licon.9 not coded +licon.and(tap.and(nwell.not(hvi))).separation(varac, 0.25, euclidian).output("licon.10", "licon.10 : min. licon spacing to varac channel : 0.25um") +not_in_cell4 = layout(source.cell_obj).select("-s8fs_gwdlvx4", "-s8fs_gwdlvx8", "-s8fs_hvrsw_x4", "-s8fs_hvrsw8", "-s8fs_hvrsw264", "-s8fs_hvrsw520", "-s8fs_rdecdrv", "-s8fs_rdec8”, “s8fs_rdec32", "-s8fs_rdec264", "-s8fs_rdec520") +not_in_cell4_licon = not_in_cell4.input(66, 44) +not_in_cell4_licon.and(diff.or(tap)).separation(gate.not(areaid_sc), 0.055, euclidian).output("licon.11", "licon.11 : min. licon spacing to gate : 0.055um") +licon.and(diff.or(tap)).separation(gate.and(areaid_sc), 0.05, euclidian).output("licon.11a", "licon.11a : min. licon spacing to gate inside areaid.sc : 0.05um") +in_cell4 = layout(source.cell_obj).select("+s8fs_gwdlvx4", "+s8fs_gwdlvx8", "+s8fs_hvrsw_x4", "+s8fs_hvrsw8", "+s8fs_hvrsw264", "+s8fs_hvrsw520") +in_cell4_licon = in_cell4.input(66, 44) +in_cell4_licon.and(diff.or(tap)).separation(gate, 0.04, euclidian).output("licon.11c", "licon.11c : min. licon spacing to gate for specific cells: 0.04um") +# rules 11.b , 11.d not coded +diff.interacting(gate).not(diff.interacting(gate).width(5.7, euclidian).polygons).output("licon.12", "licon.12 : max. sd width without licon : 5.7um") +licon.and(diff.or(tap)).separation(npc, 0.09, euclidian).output("licon.13", "licon.13 : min. difftap licon spacing to npc : 0.09um") +licon.and(poly).separation(diff.or(tap), 0.19, euclidian).output("licon.14", "licon.14 : min. poly licon spacing to difftap : 0.19um") +npc.enclosing(licon.and(poly), 0.1, euclidian).output("licon.15", "licon.15 : min. npc enclosure of poly-licon : 0.1um") +# rule licon.16 not applicable for the diff for the nmos of a nand gates or the pmos of a nor gates +#diff.not(gate).not_interacting(licon).output("licon.16", "licon.16 : diff must enclose one licon") +tap.not(uhvi).not_interacting(licon).output("licon.16", "licon.16 : tap must enclose one licon") +poly.and(tap).edges.not(tap.edges).output("licon.17", "licon.17 : tap must not straddle poly") +npc.not_interacting(licon.and(poly)).output("licon.18", "licon.18 : npc mut enclosed one poly-licon") + +# li +not_in_cell5 = layout(source.cell_obj).select("-s8rf2_xcmvpp_hd5_*") +not_in_cell5_li = not_in_cell5.input(67, 20) +not_in_cell5_li.width(0.17, euclidian).output("li.1", "li.1 : min. li width : 0.17um") +in_cell5 = layout(source.cell_obj).select("+s8rf2_xcmvpp_hd5_*") +in_cell5_li = in_cell5.input(67, 20) +in_cell5_li.width(0.14, euclidian).output("li.1a", "li.1a : min. li width for the cells s8rf2_xcmvpp_hd5_* : 0.14um") +# rule li.2 not coded +not_in_cell5_li.isolated(0.17, euclidian).output("li.3", "li.3 : min. li spacing : 0.17um") +in_cell5_li.isolated(0.14, euclidian).output("li.3a", "li.3a : min. li spacing for the cells s8rf2_xcmvpp_hd5_* : 0.14um") +licon08 = licon.interacting(li.enclosing(licon, 0.08, euclidian).polygons) +licon_edges_with_less_enclosure_li = li.enclosing(licon, 0.08, projection).second_edges +opposite3 = (licon.edges - licon_edges_with_less_enclosure_li).width(0.17 + 1.dbu, projection).polygons +licon08.not_interacting(opposite3).output("li.5", "li.5 : min. li enclosure of licon of 2 opposite edges : 0.08um") +li.with_area(0..0.0561).output("li.6", "li.6 : min. li area : 0.0561um²") + +# vpp +vpp.width(1.43, euclidian).output("vpp.1", "vpp.1 : min. vpp width : 1.43um") +# rules 1.b, 1.c not coded +vpp.and(poly.or(difftap)).output("vpp.3", "vpp.3 : vpp must not overlapp poly or diff or tap") +vpp.and(nwell).edges.not(vpp.edges).output("vpp.4", "vpp.4 : vpp must not straddle nwell") +vpp.and(dnwell).edges.not(vpp.edges).output("vpp.4", "vpp.4 : vpp must not straddle dnwell") +vpp.and(poly.or(li).or(m1).or(m2)).separation(poly.or(li).or(m1).or(m2), 1.5, euclidian).polygons.with_area(2.25,nil).output("vpp.5", "vpp.5 : min. vpp spacing to poly or li or m1 or m2 : 1.5um") +vpp.with_area(0..area(vpp.and(m3))*0.25).output("vpp.5a", "vpp.5a : max. m3 density in vpp : 0.25") +vpp.with_area(0..area(vpp.and(m4))*0.3).output("vpp.5b", "vpp.5b : max. m4 density in vpp : 0.3") +vpp.with_area(0..area(vpp.and(m5))*0.4).output("vpp.5c", "vpp.5c : max. m5 density in vpp : 0.4") +nwell.enclosing(vpp, 1.5, euclidian).output("vpp.8", "vpp.8 : nwell enclosure of vpp : 1.5") +vpp.separation(nwell, 1.5, euclidian).polygons.without_area(0).output("vpp.9", "vpp.9 : vpp spacing to nwell : 1.5") +# rule vpp.10 not coded +# rule vpp.11 not coded because moscap is not defined properly by any gds layer +# rules vpp.12a, 12b, 12c not coded because specific to one cell +if backend_flow = CU + m1.separation(vpp.and(m1), 0.16, euclidian).polygons.without_area(0).output("vpp.13", "vpp.13 : m1 spacing to m1inside vpp : 0.16") +end + +# CAPM +capm.width(1.0, euclidian).output("capm.1", "capm.1 : min. capm width : 1.0um") +capm.isolated(0.84, euclidian).output("capm.2a", "capm.2a : min. capm spacing : 0.84um") +m2.interacting(capm).isolated(1.2, euclidian).output("capm.2b", "capm.2b : min. capm spacing : 1.2um") +m2.enclosing(capm, 0.14, euclidian).output("capm.3", "capm.3 : min. m2 enclosure of capm : 0.14um") +capm.enclosing(via2, 0.14, euclidian).output("capm.4", "capm.4 : min. capm enclosure of via2 : 0.14um") +capm.separation(via2, 0.14, euclidian).output("capm.5", "capm.5 : min. capm spacing to via2 : 0.14um") +capm.sized(-20.0).sized(20.0).output("capm.6", "capm.6 : max. capm lenght/width : 20um") +capm.with_angle(0 .. 90).output("capm.7", "capm.7 : capm not rectangle") +capm.separation(via, 0.14, euclidian).polygons.without_area(0).output("capm.8", "capm.8 : min. capm spacing to via : 0.14um") +capm.and(nwell).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle nwell") +capm.and(diff).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle diff") +capm.and(tap).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle tap") +capm.and(poly).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle poly") +capm.and(li).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle li") +capm.and(m1).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle m1") +capm.separation(m2.not_interacting(capm), 0.14, euclidian).output("capm.11", "capm.11 : min. capm spacing to m2 not overlapping capm : 0.5um") + +end #FEOL + +if BEOL +info("BEOL section") + +# ct +mcon.edges.without_length(0.17).output("ct.1", "ct.1 : minimum/maximum width of mcon : 0.17um") +mcon.isolated(0.19, euclidian).output("ct.2", "ct.2 : min. mcon spacing : 0.19um") +# rule ct.3 not coded +mcon.not(li).output("ct.4", "ct.4 : mcon should covered by li") +if backend_flow = CU + li.interacting(li.and(m1).not(mcon).with_holes(1,10)).enclosing(mcon, 0.2, euclidian).output("ct.irdrop.1", "ct.irdrop.1 : min. li enclsoure of 1..10 mcon : 0.2um") + li.interacting(li.and(m1).not(mcon).with_holes(11,100)).enclosing(mcon, 0.3, euclidian).output("ct.irdrop.2", "ct.irdrop.2 : min. li enclsoure of 11..100 mcon : 0.3um") +end + +# m1 +huge_m1 = m1.sized(-1.5).sized(1.5) +m1.width(0.14, euclidian).output("m1.1", "m1.1 : min. m1 width : 0.14um") +m1.isolated(0.14, euclidian).output("m1.2", "m1.2 : min. m1 spacing : 0.14um") +huge_m1.separation(m1, 0.28, euclidian).output("m1.3ab", "m1.3ab : min. 3um.m1 spacing m1 : 0.28um") +not_in_cell6 = layout(source.cell_obj).select("-s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b", "-s8fpls_pl8", "-s8fs_cmux4_fm") +not_in_cell6_m1 = not_in_cell6.input(68, 20) +not_in_cell6_m1.enclosing(mcon, 0.03, euclidian).output("m1.4", "m1.4 : min. m1 enclosure of mcon : 0.03um") +in_cell6 = layout(source.cell_obj).select("+s8cell_ee_plus_sseln_a", "+s8cell_ee_plus_sseln_b", "+s8cell_ee_plus_sselp_a", "+s8cell_ee_plus_sselp_b", "+s8fpls_pl8", "+s8fs_cmux4_fm") +in_cell6_m1 = in_cell6.input(68, 20) +in_cell6_m1.enclosing(mcon, 0.005, euclidian).output("m1.4a", "m1.4a : min. m1 enclosure of mcon for specific cells : 0.005um") +m1.with_area(0..0.083).output("m1.6", "m1.6 : min. m1 area : 0.083um²") +m1.holes.with_area(0..0.14).output("m1.7", "m1.7 : min. m1 holes area : 0.14um²") +if backend_flow = AL + mcon06 = mcon.interacting(poly.enclosing(m1, 0.06, euclidian).polygons) + mcon_edges_with_less_enclosure_m1 = m1.enclosing(mcon, 0.06, projection).second_edges + opposite4 = (mcon.edges - mcon_edges_with_less_enclosure_m1).width(0.17 + 1.dbu, projection).polygons + mcon06.not_interacting(opposite4).output("m1.5", "m1.5 : min. m1 enclosure of mcon of 2 opposite edges : 0.06um") + # rule m1.pd.1, rule m1.pd.2a, rule m1.pd.2b not coded +end +if bakend_flow = CU + m1.sized(-2.0).sized(2.0).output("m1.11", "m1.11 : max. m1 width after slotting : 4.0um") + # rule m1.12 not coded because inconsistent with m1.11 + # rule m1.13, m1.14, m1.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +end + +# via +#rule via.3 not coded +via.not(m1).output("via.4c.5c", "via.4c.5c : m1 must enclose all via") +if backend_flow = AL + via.not(areaid_mt).edges.without_length(0.15).output("via.1a", "via.1a : minimum/maximum width of via : 0.15um") + via.and(areaid_mt).not_interacting((via.and(areaid_mt).edges.without_length(0.15)).or(via.and(areaid_mt).edges.without_length(0.23)).or(via.and(areaid_mt).edges.without_length(0.28))).output("via.1b", "via.1b : minimum/maximum width of via in areaid.mt: 0.15um or 0.23um or 0.28um") + via.isolated(0.17, euclidian).output("via.2", "via.2 : min. via spacing : 0.17um") + m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.055, euclidian).output("via.4a", "via.4a : min. m1 enclosure of 0.15um via : 0.055um") + m1.enclosing(via.not_interacting(via.edges.without_length(0.23)), 0.03, euclidian).output("via.4b", "via.4b : min. m1 enclosure of 0.23um via : 0.03um") + via1_edges_with_less_enclosure_m1 = m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.085, projection).second_edges + opposite5 = (via.not_interacting(via.edges.without_length(0.15)).edges - via1_edges_with_less_enclosure_m1).width(0.15 + 1.dbu, projection).polygons + via.not_interacting(via.edges.without_length(0.15)).not_interacting(opposite5).output("via1.5a", "via1.5a : min. m1 enclosure of 0.15um via of 2 opposite edges : 0.085um") + via2_edges_with_less_enclosure_m1 = m1.enclosing(via.not_interacting(via.edges.without_length(0.23)), 0.06, projection).second_edges + opposite6 = (via.not_interacting(via.edges.without_length(0.23)).edges - via2_edges_with_less_enclosure_m1).width(0.23 + 1.dbu, projection).polygons + via.not_interacting(via.edges.without_length(0.23)).not_interacting(opposite6).output("via1.5b", "via1.5b : min. m1 enclosure of 0.23um via of 2 opposite edges : 0.06um") +end +if backend_flow = CU + via.not(areaid_mt).edges.without_length(0.18).output("via.11", "via.11 : minimum/maximum width of via : 0.18um") + via.isolated(0.13, euclidian).output("via.12", "via.12 : min. via spacing : 0.13um") + # rule via.13 not coded because not understandable + via1_edges_with_less_enclosure_m1 = m1.enclosing(via, 0.04, projection).second_edges + opposite5 = (via.edges - via1_edges_with_less_enclosure_m1).width(0.18 + 1.dbu, projection).polygons + via.not_interacting(opposite5).output("via1.14", "via1.14 : min. m1 enclosure of 0.04um via of 2 opposite edges : 0.04um") + # rules via.irdrop.1, via.irdrop.2, via.irdrop.3, via.irdrop.4 not coded because not understandable +end + +# m2 +huge_m2 = m2.sized(-1.5).sized(1.5) +m2.width(0.14, euclidian).output("m2.1", "m2.1 : min. m2 width : 0.14um") +m2.isolated(0.14, euclidian).output("m2.2", "m2.2 : min. m2 spacing : 0.14um") +huge_m2.separation(m2, 0.28, euclidian).output("m2.3ab", "m2.3ab : min. 3um.m2 spacing m2 : 0.28um") +# rule m2.3c not coded +m2.with_area(0..0.0676).output("m2.6", "m2.6 : min. m2 area : 0.0676um²") +m2.holes.with_area(0..0.14).output("m2.7", "m2.7 : min. m2 holes area : 0.14um²") +via.not(m2).output("m2.via", "m2.via : m2 must enclose via") +if backend_flow = AL + m2.enclosing(via, 0.055, euclidian).output("m2.4", "m2.4 : min. m2 enclosure of via : 0.055um") + via_edges_with_less_enclosure_m2 = m2.enclosing(via, 0.085, projection).second_edges + opposite7 = (via.edges - via_edges_with_less_enclosure_m2).width(0.2 + 1.dbu, projection).polygons + via.not_interacting(opposite7).output("m2.5", "m2.5 : min. m2 enclosure of via of 2 opposite edges : 0.085um") + # rule m2.pd.1, rule m2.pd.2a, rule m2.pd.2b not coded +end +if bakend_flow = CU + m2.sized(-2.0).sized(2.0).output("m2.11", "m2.11 : max. m2 width after slotting : 4.0um") + # rule m2.12 not coded because inconsistent with m2.11 + # rule m2.13, m2.14, m2.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +end + +# via2 +#rule via233 not coded +via2.not(m2).output("via2", "via2 : m2 must enclose all via2") +if backend_flow = AL + via2.not(areaid_mt).edges.without_length(0.2).output("via2.1a", "via2.1a : minimum/maximum width of via2 : 0.2um") + via2.and(areaid_mt).not_interacting((via2.and(areaid_mt).edges.without_length(0.2)).or(via2.and(areaid_mt).edges.without_length(1.2)).or(via2.and(areaid_mt).edges.without_length(1.5))).output("via2.1b", "via2.1b : minimum/maximum width of via2 in areaid.mt: 0.2um or 1.2um or 1.5um") + via2.isolated(0.2, euclidian).output("via2.2", "via2.2 : min. via2 spacing : 0.2um") + m2.enclosing(via2, 0.04, euclidian).output("via2.4", "via2.4 : min. m2 enclosure of via2 : 0.04um") + m2.enclosing(via2.not_interacting(via2.edges.without_length(1.5)), 0.14, euclidian).output("via2.4a", "via2.4a : min. m2 enclosure of 1.5um via2 : 0.14um") + via2_edges_with_less_enclosure_m2 = m2.enclosing(via2, 0.085, projection).second_edges + opposite8 = (via2.edges - via2_edges_with_less_enclosure_m2).width(0.2 + 1.dbu, projection).polygons + via2.not_interacting(opposite8).output("via2.5", "via2.5 : min. m2 enclosure of via2 of 2 opposite edges : 0.085um") +end +if backend_flow = CU + via2.edges.without_length(0.21).output("via2.11", "via2.11 : minimum/maximum width of via2 : 0.21um") + via2.isolated(0.18, euclidian).output("via2.12", "via2.12 : min. via2 spacing : 0.18um") + # rule via2.13 not coded because not understandable, or not clear + m2.enclosing(via2, 0.035, euclidian).output("via2.14", "via2.14 : min. m2 enclosure of via2 : 0.035um") + # rules via2.irdrop.1, via2.irdrop.2, via2.irdrop.3, via2.irdrop.4 not coded because not understandable +end + +# m3 +huge_m3 = m3 - m3.width(3.0, projection).polygons +m3.width(0.3, euclidian).output("m3.1", "m3.1 : min. m3 width : 0.3um") +m3.isolated(0.3, euclidian).output("m3.2", "m3.2 : min. m3 spacing : 0.3um") +huge_m3.separation(m3, 0.4, euclidian).output("m3.3ab", "m3.3ab : min. 3um.m3 spacing m3 : 0.4um") +# rule m3.3c not coded +m3.with_area(0..0.24).output("m3.6", "m3.6 : min. m2 area : 0.24um²") +via2.not(m3).output("m3.via2", "m3.via2 : m3 must enclose via2") +if backend_flow = AL + m3.enclosing(via2, 0.065, euclidian).output("m3.4", "m3.4 : min. m3 enclosure of via2 : 0.065um") + via2_edges_with_less_enclosure_m3 = m3.enclosing(via2, 0.085, projection).second_edges + # m3.5 N/A + # opposite9 = (via2.edges - via2_edges_with_less_enclosure_m3).width(0.3 + 1.dbu, projection).polygons + # via2.not_interacting(opposite9).output("m3.5", "m3.5 : min. m3 enclosure of via2 of 2 opposite edges : 0.085um") + # rule m3.pd.1, rule m3.pd.2a, rule m3.pd.2b not coded +end +if bakend_flow = CU + m3.holes.with_area(0..0.2).output("m3.7", "m3.7 : min. m2 holes area : 0.2um²") + m3.sized(-2.0).sized(2.0).output("m3.11", "m3.11 : max. m3 width after slotting : 4.0um") + # rule m3.12 not coded because inconsistent with m3.11 + # rule m3.13, m3.14, m3.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +end + +# via3 +#rule via3.3 not coded +via3.not(m3).output("via3", "via3 : m3 must enclose all via3") +if backend_flow = AL + via3.not(areaid_mt).edges.without_length(0.2).output("via3.1a", "via3.1a : minimum/maximum width of via3 : 0.2um") + via3.and(areaid_mt).not_interacting((via3.and(areaid_mt).edges.without_length(0.2)).or(via3.and(areaid_mt).edges.without_length(0.8))).output("via3.1a", "via3.1a : minimum/maximum width of via3 in areaid.mt: 0.2um or 0.8um") + via3.isolated(0.2, euclidian).output("via3.2", "via3.2 : min. via3 spacing : 0.2um") + m3.enclosing(via3, 0.06, euclidian).output("via3.4", "via3.4 : min. m3 enclosure of via3 : 0.06um") + via3_edges_with_less_enclosure_m3 = m3.enclosing(via3, 0.09, projection).second_edges + opposite10 = (via3.edges - via3_edges_with_less_enclosure_m3).width(0.2 + 1.dbu, projection).polygons + via3.not_interacting(opposite10).output("via3.5", "via3.5 : min. m2 enclosure of via3 of 2 opposite edges : 0.09um") +end +if backend_flow = CU + via3.edges.without_length(0.21).output("via3.11", "via3.11 : minimum/maximum width of via3 : 0.21um") + via3.isolated(0.18, euclidian).output("via3.12", "via3.12 : min. via3 spacing : 0.18um") + m3.enclosing(via3, 0.055, euclidian).output("via3.13", "via3.13 : min. m3 enclosure of via3 : 0.055um") + # rule via3.14 not coded because not understandable, or not clear + # rules via3.irdrop.1, via3.irdrop.2, via3.irdrop.3, via3.irdrop.4 not coded because not understandable +end + +# nsm +nsm.width(3.0, euclidian).output("nsm.1", "nsm.1 : min. nsm width : 3.0um") +nsm.isolated(4.0, euclidian).output("nsm.2", "nsm.2 : min. nsm spacing : 4.0um") +nsm.enclosing(diff, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of diff : 3.0um") +nsm.enclosing(tap, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of tap : 3.0um") +nsm.enclosing(poly, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of poly : 3.0um") +nsm.enclosing(li, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of li : 3.0um") +nsm.enclosing(m1, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m1 : 3.0um") +nsm.enclosing(m2, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m2 : 3.0um") +nsm.enclosing(m3, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m3 : 3.0um") +nsm.enclosing(m4, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m4 : 3.0um") +nsm.enclosing(m5, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m5 : 3.0um") +nsm.enclosing(cfom, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of cfom : 3.0um") +if backend_flow = AL + nsm.separation(diff, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to diff : 1.0um") + nsm.separation(tap, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to tap : 1.0um") + nsm.separation(poly, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to poly : 1.0um") + nsm.separation(li, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to li : 1.0um") + nsm.separation(m1, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m1 : 1.0um") + nsm.separation(m2, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m2 : 1.0um") + nsm.separation(m3, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m3 : 1.0um") + nsm.separation(m4, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m4 : 1.0um") + nsm.separation(m5, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m5 : 1.0um") + nsm.separation(cfom, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to cfom : 1.0um") +end + +# m4 +huge_m4 = m4.sized(-1.5).sized(1.5) +m4.width(0.3, euclidian).output("m4.1", "m4.1 : min. m4 width : 0.3um") +m4.isolated(0.3, euclidian).output("m4.2", "m4.2 : min. m4 spacing : 0.3um") +m4.with_area(0..0.24).output("m4.4", "m4.4 : min. m2 area : 0.24um²") +huge_m4.separation(m4, 0.4, euclidian).output("m4.5ab", "m4.5ab : min. 3um.m4 spacing m4 : 0.4um") +via3.not(m4).output("m4.via3", "m4.via3 : m4 must enclose via3") +if backend_flow = AL + m4.enclosing(via3, 0.065, euclidian).output("m4.3", "m4.3 : min. m4 enclosure of via3 : 0.065um") + # m4.5 doesn't exist + # via3_edges_with_less_enclosure_m4 = m4.enclosing(via2, 0.085, projection).second_edges + # opposite9 = (via3.edges - via3_edges_with_less_enclosure_m4).width(0.3 + 1.dbu, projection).polygons + # via3.not_interacting(opposite9).output("m4.5", "m4.5 : min. m4 enclosure of via3 of 2 opposite edges : 0.085um") + # rule m4.pd.1, rule m4.pd.2a, rule m4.pd.2b not coded +end +if bakend_flow = CU + m4.holes.with_area(0..0.2).output("m4.7", "m4.7 : min. m2 holes area : 0.2um²") + m4.sized(-5.0).sized(5.0).output("m4.11", "m4.11 : max. m4 width after slotting : 10.0um") + # rule m4.12 not coded because inconsistent with m4.11 + # rule m4.13, m4.14, m4.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 + m4.enclosing(via3, 0.06, euclidian).output("m4.15", "m4.15 : min. m4 enclosure of via3 : 0.06um") +end + +# via4 +via4.edges.without_length(0.8).output("via4.1a", "via4.1a : minimum/maximum width of via4 : 0.8um") +via4.isolated(0.8, euclidian).output("via4.2", "via4.2 : min. via4 spacing : 0.8um") +#rule via4.3 not coded +m4.enclosing(via4, 0.19, euclidian).output("via4.4", "via4.4 : min. m4 enclosure of via4 : 0.19um") +via4.not(m4).output("via4", "via4 : m4 must enclose all via4") +if backend_flow = CU + # rules via4.irdrop.1, via4.irdrop.2, via4.irdrop.3, via4.irdrop.4 not coded because not understandable +end + +# m5 +m5.width(1.6, euclidian).output("m5.1", "m5.1 : min. m5 width : 1.6um") +m5.isolated(1.6, euclidian).output("m5.2", "m5.2 : min. m5 spacing : 1.6um") +via4.not(m5).output("m5.via4", "m5.via4 : m5 must enclose via4") +m5.enclosing(via4, 0.31, euclidian).output("m5.3", "m4.3 : min. m5 enclosure of via4 : 0.31um") + +# pad +pad.isolated(1.27, euclidian).output("pad.2", "pad.2 : min. pad spacing : 1.27um") + +end #BEOL + +if FEOL +info("FEOL section") + +# mf +mf.not_interacting(mf.edges.without_length(0.8)).output("mf.1", "mf.1 : minimum/maximum width of fuse : 0.8um") +mf.not_interacting(mf.edges.without_length(7.2)).output("mf.2", "mf.2 : minimum/maximum length of fuse : 7.2um") +mf.isolated(1.96, euclidian).output("mf.3", "mf.3 : min. fuse center spacing : 2.76um") +# fuses need more clarification on fuse_shield, fuse layers ... + +# hvi +hvi.width(0.6, euclidian).output("hvi.1", "hvi.1 : min. hvi width : 0.6um") +hvi.isolated(0.7, euclidian).output("hvi.2", "hvi.2 : min. hvi spacing, merge if less : 0.7um") +hvi.and(tunm).output("hvi.4", "hvi.4 : hvi must not overlapp tunm") +hvi.and(nwell).separation(nwell, 2.0, euclidian).output("hvnwell.8", "hvnwelli.8 : min. hvnwel spacing to nwell : 2.0") +areaid_hl.not(hvi).output("hvnwel.9", "hvnwell.9 : hvi must overlapp hvnwell") +# rule hvnell.10 not coded +diff.not(psdm.and(diff_rs)).and(hvi).width(0.29, euclidian).output("hvdifftap.14", "hvdifftap.14 : min. diff inside hvi width : 0.29um") +diff.and(psdm.and(diff_rs)).and(hvi).width(0.15, euclidian).output("hvdifftap.14a", "hvdifftap.14a : min. p+diff resistor inside hvi width : 0.15um") +diff.and(hvi).isolated(0.3, euclidian).output("hvdifftap.15a", "hvdifftap.15a : min. diff inside hvi spacing : 0.3um") +diff.and(hvi).and(nsdm).separation(diff.and(hvi).and(psdm), 0.37, euclidian).polygons.without_area(0).output("hvdifftap.15b", "hvdifftap.15b : min. n+diff inside hvi spacing to p+diff inside hvi except abutting: 0.37um") +tap.and(hvi).edges.and(diff).without_length(0.7).output("hvdifftap.16", "hvdifftap.16 : min. tap inside hvi abuttng diff : 0.7um") +hvi.and(nwell).enclosing(diff, 0.33, euclidian).output("hvdifftap.17", "hvdifftap.17 : min. hvnwell enclosure of p+diff : 0.33um") +hvi.and(nwell).separation(diff, 0.43, euclidian).output("hvdifftap.18", "hvdifftap.18 : min. hvnwell spacing to n+diff : 0.43um") +hvi.and(nwell).enclosing(tap, 0.33, euclidian).output("hvdifftap.19", "hvdifftap.19 : min. hvnwell enclosure of n+tap : 0.33um") +hvi.and(nwell).separation(tap, 0.43, euclidian).output("hvdifftap.20", "hvdifftap.20 : min. hvnwell spacing to p+tap : 0.43um") +hvi.and(diff).edges.not(diff.edges).output("hvdifftap.21", "hvdifftap.21 : diff must not straddle hvi") +hvi.and(tap).edges.not(tap.edges).output("hvdifftap.21", "hvdifftap.21 : tap must not straddle hvi") +hvi.enclosing(difftap, 0.18, euclidian).output("hvdifftap.22", "hvdifftap.22 : min. hvi enclosure of diff or tap : 0.18um") +hvi.separation(difftap, 0.18, euclidian).output("hvdifftap.23", "hvdifftap.23 : min. hvi spacing to diff or tap : 0.18um") +hvi.and(diff).not(nwell).separation(nwell, 0.43, euclidian).output("hvdifftap.24", "hvdifftap.24 : min. hv n+diff spacing to nwell : 0.43um") +diff.and(hvi).not(nwell).isolated(1.07, euclidian).polygons.and(tap).output("hvdifftap.25", "hvdifftap.25 : min. n+diff inside hvi spacing accros p+tap : 1.07um") +diff.not(poly).edges.and(gate.and(hvi).edges).space(0.35, euclidian).output("hvpoly.13", "hvpoly.13: min. hvi gate length : 0.5um") +hvi.and(poly).edges.not(poly.edges).output("hvpoly.14", "hvpoly.14 : poly must not straddle hvi") + +# hvntm +hvntm.width(0.7, euclidian).output("hvntm.1", "hvntm.1 : min. hvntm width : 0.7um") +hvntm.isolated(0.7, euclidian).output("hvntm.2", "hvntm.2 : min. hvntm spacing : 0.7um") +hvntm.enclosing(diff.and(nwell).and(hvi), 0.185, euclidian).output("hvntm.3", "hvntm.3 : min. hvntm enclosure of hv n+diff : 0.185um") +hvntm.separation(diff.not(nwell).not(hvi), 0.185, euclidian).output("hvntm.4", "hvntm.4 : min. hvntm spacing to n+diff : 0.185um") +hvntm.separation(diff.and(nwell).not(hvi), 0.185, euclidian).output("hvntm.5", "hvntm.5 : min. hvntm spacing to p+diff : 0.185um") +hvntm.separation(tap.not(nwell).not(hvi), 0.185, euclidian).polygons.without_area(0).output("hvntm.6a", "hvntm.6a : min. hvntm spacing to p+tap : 0.185um") +hvntm.and(areaid_ce).output("hvntm.9", "hvntm.9 : hvntm must not overlapp areaid.ce") + +# denmos +poly.not_interacting(pwde).interacting(areaid_en).width(1.055, projection).output("denmos.1", "denmos.1 : min. de_nfet gate width : 1.055um") +diff.not_interacting(pwde).enclosing(poly.interacting(areaid_en), 0.28, projection).polygons.without_area(0).output("denmos.2", "denmos.2 : min. de_nfet source ouside poly width : 0.28um") +diff.not_interacting(pwde).and(poly.interacting(areaid_en)).width(0.925, projection).output("denmos.3", "denmos.3 : min. de_nfet source inside poly width : 0.925um") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).width(0.17, euclidian).output("denmos.4", "denmos.4 : min. de_nfet drain width : 0.17um") +nwell.not_interacting(pwde).and(poly.interacting(areaid_en)).width(0.225, projection).polygons.or(nwell.and(poly.interacting(areaid_en)).sized(-0.1125).sized(0.1125)).output("denmos.5", "denmos.5 : min. de_nfet source inside nwell width : 0.225m") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).separation(diff.interacting(poly.interacting(areaid_en)), 1.585, projection).output("denmos.6", "denmos.6 : min. de_nfet source spacing to drain : 1.585um") +nwell.not_interacting(pwde).and(poly.and(diff).interacting(areaid_en)).edges.without_length(5.0, nil).output("denmos.7", "denmos.7 : min. de_nfet channel width : 5.0um") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("denmos.8", "denmos.8 : 90deg. not allowed for de_nfet drain") +nwell.not_interacting(pwde).interacting(areaid_en).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("denmos.9a", "denmos.9a : 90deg. not allowed for de_nfet nwell") +nwell.not_interacting(pwde).interacting(areaid_en).edges.with_angle(45).without_length(0.607..0.609).output("denmos.9a", "denmos.9a : 45deg. bevels of de_nfet nwell should be 0.43um from corners") +nwell.not_interacting(pwde).interacting(areaid_en).edges.with_angle(135).without_length(0.607..0.609).output("denmos.9a", "denmos.9a : 45deg. bevels of de_nfet nwell should be 0.43um from corners") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(45).without_length(0.7..0.71).output("denmos.9b", "denmos.9b : 45deg. bevels of de_nfet drain should be 0.05um from corners") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(135).without_length(0.7..0.71).output("denmos.9b", "denmos.9b : 45deg. bevels of de_nfet drain should be 0.05um from corners") +nwell.not_interacting(pwde).enclosing(diff.interacting(areaid_en).not_interacting(poly), 0.66, euclidian).output("denmos.10", "denmos.10 : min. nwell enclosure of de_nfet drain : 0.66um") +nwell.not_interacting(pwde).interacting(areaid_en).separation(tap.not(nwell), 0.86, euclidian).output("denmos.11", "denmos.11 : min. de_nfet nwell spacing to tap : 0.86um") +nwell.not_interacting(pwde).interacting(areaid_en).isolated(2.4, euclidian).output("denmos.12", "denmos.12 : min. de_nfet nwell : 2.4um") +nsdm.not_interacting(pwde).enclosing(diff.interacting(areaid_en).interacting(poly), 0.13, euclidian).output("denmos.13", "denmos.13 : min. nsdm enclosure of de_nfet source : 0.13um") + +# depmos +poly.interacting(pwde).interacting(areaid_en).width(1.05, projection).output("depmos.1", "depmos.1 : min. de_pfet gate width : 1.05um") +diff.interacting(pwde).enclosing(poly.interacting(areaid_en), 0.28, projection).polygons.without_area(0).output("depmos.2", "depmos.2 : min. de_pfet source ouside poly width : 0.28um") +diff.interacting(pwde).and(poly.interacting(areaid_en)).width(0.92, projection).output("depmos.3", "depmos.3 : min. de_pfet source inside poly width : 0.92um") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).width(0.17, euclidian).output("depmos.4", "depmos.4 : min. de_pfet drain width : 0.17um") +pwde.not(nwell).and(poly.interacting(areaid_en)).width(0.26, projection).polygons.or(pwde.not(nwell).and(poly.interacting(areaid_en)).sized(-0.13).sized(0.13)).output("depmos.5", "depmos.5 : min. de_pfet source inside nwell width : 0.26m") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).separation(diff.interacting(poly.interacting(areaid_en)), 1.19, projection).output("depmos.6", "depmos.6 : min. de_pfet source spacing to drain : 1.19um") +nwell.interacting(pwde).and(poly.and(diff).interacting(areaid_en)).edges.without_length(5.0, nil).output("depmos.7", "depmos.7 : min. de_pfet channel width : 5.0um") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("depmos.8", "depmos.8 : 90deg. not allowed for de_pfet drain") +pwde.not(nwell).interacting(areaid_en).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("depmos.9a", "depmos.9a : 90deg. not allowed for de_pfet pwell") +pwde.not(nwell).interacting(areaid_en).edges.with_angle(45).without_length(0.607..0.609).output("depmos.9a", "depmos.9a : 45deg. bevels of de_pfet pwell should be 0.43um from corners") +pwde.not(nwell).interacting(areaid_en).edges.with_angle(135).without_length(0.607..0.609).output("depmos.9a", "depmos.9a : 45deg. bevels of de_pfet pwell should be 0.43um from corners") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(45).without_length(0.7..0.71).output("depmos.9b", "depmos.9b : 45deg. bevels of de_pfet drain should be 0.05um from corners") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(135).without_length(0.7..0.71).output("depmos.9b", "depmos.9b : 45deg. bevels of de_pfet drain should be 0.05um from corners") +nwell.interacting(pwde).separation(diff.interacting(areaid_en).not_interacting(poly), 0.86, euclidian).output("depmos.10", "depmos.10 : min. pwell enclosure of de_pfet drain : 0.86um") +pwde.not(nwell).interacting(areaid_en).separation(tap.and(nwell), 0.66, euclidian).output("depmos.11", "depmos.11 : min. de_pfet pwell spacing to tap : 0.66um") +psdm.interacting(pwde).enclosing(diff.interacting(areaid_en).interacting(poly), 0.13, euclidian).output("depmos.12", "depmos.12 : min. psdm enclosure of de_pfet source : 0.13um") + +# extd +areaid_en.and(difftap).edges.not(difftap.edges).output("extd.1", "extd.1 : difftap must not straddle areaid.en") +difftap.interacting(areaid_en).not(poly).with_area(0).output("extd.2", "extd.2 : poly must not overlapp entirely difftap in areaid.en") +# rules extd.4, extd.5, extd.6, extd.7 not coded because specific to some cells + +# vhvi +# rules vhvi.vhv.1, vhvi.vhv.2, vhvi.vhv.3, vhvi.vhv.4, vhvi.vhv.5, vhvi.vhv.6 not coded +vhvi.width(0.02, euclidian).output("vhvi.1", "vhvi.1 : min. vhvi width : 0.02um") +vhvi.and(areaid_ce).output("vhvi.2", "vhvi.2 : vhvi must not overlap areaid.ce") +vhvi.and(hvi).output("vhvi.3", "vhvi.3 : vhvi must not overlap hvi") +# rules vhvi.4, vhvi.6 not coded +vhvi.and(diff).edges.not(diff.edges).output("vhvi.5", "vhvi.5 : vhvi must not straddle diff") +vhvi.and(tap).edges.not(tap.edges).output("vhvi.5", "vhvi.5 : vhvi must not straddle tap") +vhvi.and(poly).edges.not(poly.edges).output("vhvi.7", "vhvi.7 : vhvi must not straddle poly") + +nwell.and(vhvi).separation(nwell, 2.5, euclidian).output("hv.nwell.1", "hv.nwell.1 : min. vhvi nwell spacing to nwell : 2.5um") +diff.and(vhvi).isolated(0.3, euclidian).output("hv.diff.1", "hv.diff.1 : min. vhvi diff spacing : 0.3um") +nwell.interacting(diff.and(vhvi)).separation(diff.not(nwell), 0.43, euclidian).output("hv.diff.2", "hv.diff.2 : min. vhvi nwell spacing n+diff : 0.43um") +diff.and(vhvi).not(nwell).separation(nwell, 0.55, euclidian).output("hv.diff.3a", "hv.diff.3a : min. vhvi n+diff spacing nwell : 0.55um") +# rule hv.diff.3b not coded +poly.and(vhvi).not(diff).separation(diff, 0.3, euclidian).polygons.without_area(0).output("hv.poly.2", "hv.poly.2 : min. vhvi poly spacing to diff : 0.3um") +poly.and(vhvi).not(diff).separation(nwell, 0.55, euclidian).polygons.without_area(0).output("hv.poly.3", "hv.poly.3 : min. vhvi poly spacing to nwell : 0.55um") +nwell.enclosing(poly.and(vhvi).not(diff), 0.3, euclidian).polygons.without_area(0).output("hv.poly.4", "hv.poly.4 : min. nwell enclosure of vhvi poly : 0.3um") +#poly.and(vhvi).enclosing(diff.interacting(areaid_en), 0.16, projection).polygons.without_area(0).output("hv.poly.6", "hv.poly.6 : min. poly enclosure of hvfet gate : 0.16um") +# rule hv.poly.7 not coded + +# uhvi +uhvi.and(diff).edges.not(diff.edges).output("uhvi.1", "uhvi.1 : diff must not straddle uhvi") +uhvi.and(tap).edges.not(tap.edges).output("uhvi.1", "uhvi.1 : tap must not straddle uhvi") +uhvi.and(poly).edges.not(poly.edges).output("uhvi.2", "uhvi.2 : poly must not straddle uhvi") +pwbm.not(uhvi).output("uhvi.3", "uhvi.3 : uhvi must not enclose pwbm") +uhvi.and(dnwell).edges.not(dnwell.edges).output("uhvi.4", "uhvi.4 : dnwell must not straddle uhvi") +areaid_en20.not(uhvi).output("uhvi.5", "uhvi.5 : uhvi must not enclose areaid.en20") +#dnwell.not(uhvi).output("uhvi.6", "uhvi.6 : uhvi must not enclose dnwell") +natfet.not(uhvi).output("uhvi.7", "uhvi.7 : uhvi must not enclose natfet") + +# pwell_res +pwell_rs.width(2.65).output("pwres.2", "pwres.2 : min. pwell resistor width : 2.65um") +pwell_rs.sized(-2.65).sized(2.65).output("pwres.2", "pwres.2 : max. pwell resistor width : 2.65um") +pwell_rs.interacting(pwell_rs.edges.with_length(2.651,26.499)).output("pwres.3", "pwres.3 : min. pwell resistor length : 26.5um") +pwell_rs.interacting(pwell_rs.edges.with_length(265.0, nil)).output("pwres.4", "pwres.4 : max. pwell resistor length : 265um") +tap.interacting(pwell_rs).separation(nwell, 0.22, euclidian).output("pwres.5", "pwres.5 : min. pwell resistor tap spacing to nwell : 0.22um") +tap.interacting(pwell_rs).and(tap.sized(0.22).and(nwell)).output("pwres.5", "pwres.5 : max. pwell resistor tap spacing to nwell : 0.22um") +tap.interacting(pwell_rs).width(0.53).output("pwres.6", "pwres.6 : min. width of tap inside pwell resistor : 0.53um") +tap.interacting(pwell_rs).sized(-0.265).sized(0.265).output("pwres.6", "pwres.6 : max. width of tap inside pwell resistor : 0.53um") +# rules pwres.7a, pwres.7b not coded +pwell_rs.and(diff).output("pwres.8", "pwres.8 : diff not allowed inside pwell resistor") +pwell_rs.and(poly).output("pwres.8", "pwres.8 : poly not allowed inside pwell resistor") +# rules pwres.9, pwres.10 not coded + +# rf_diode +areaid_re.with_angle(0 .. 90).output("rfdiode.1", "rfdiode.1 : non 90 degree angle areaid.re") +areaid_re.not(nwell).or(nwell.interacting(areaid_re).not(areaid_re)).output("rfdiode.2", "rfdiode.2 : areaid.re must coincide rf nwell diode") +# rule rfdiode.3 not coded + +end #FEOL + +if OFFGRID +info("OFFGRID-ANGLES section") + +dnwell.ongrid(0.005).output("dnwell_OFFGRID", "x.1b : OFFGRID vertex on dnwell") +dnwell.with_angle(0 .. 45).output("dnwell_angle", "x.3a : non 45 degree angle dnwell") +nwell.ongrid(0.005).output("nwell_OFFGRID", "x.1b : OFFGRID vertex on nwell") +nwell.with_angle(0 .. 45).output("nwell_angle", "x.3a : non 45 degree angle nwell") +pwbm.ongrid(0.005).output("pwbm_OFFGRID", "x.1b : OFFGRID vertex on pwbm") +pwbm.with_angle(0 .. 45).output("pwbm_angle", "x.3a : non 45 degree angle pwbm") +pwde.ongrid(0.005).output("pwde_OFFGRID", "x.1b : OFFGRID vertex on pwde") +pwde.with_angle(0 .. 45).output("pwde_angle", "x.3a : non 45 degree angle pwde") +hvtp.ongrid(0.005).output("hvtp_OFFGRID", "x.1b : OFFGRID vertex on hvtp") +hvtp.with_angle(0 .. 45).output("hvtp_angle", "x.3a : non 45 degree angle hvtp") +hvtr.ongrid(0.005).output("hvtr_OFFGRID", "x.1b : OFFGRID vertex on hvtr") +hvtr.with_angle(0 .. 45).output("hvtr_angle", "x.3a : non 45 degree angle hvtr") +lvtn.ongrid(0.005).output("lvtn_OFFGRID", "x.1b : OFFGRID vertex on lvtn") +lvtn.with_angle(0 .. 45).output("lvtn_angle", "x.3a : non 45 degree angle lvtn") +ncm.ongrid(0.005).output("ncm_OFFGRID", "x.1b : OFFGRID vertex on ncm") +ncm.with_angle(0 .. 45).output("ncm_angle", "x.3a : non 45 degree angle ncm") +diff.ongrid(0.005).output("diff_OFFGRID", "x.1b : OFFGRID vertex on diff") +tap.ongrid(0.005).output("tap_OFFGRID", "x.1b : OFFGRID vertex on tap") +diff.not(areaid_en.and(uhvi)).with_angle(0 .. 90).output("diff_angle", "x.2 : non 90 degree angle diff") +diff.and(areaid_en.and(uhvi)).with_angle(0 .. 45).output("diff_angle", "x.2c : non 45 degree angle diff") +tap.not(areaid_en.and(uhvi)).with_angle(0 .. 90).output("tap_angle", "x.2 : non 90 degree angle tap") +tap.and(areaid_en.and(uhvi)).with_angle(0 .. 45).output("tap_angle", "x.2c : non 45 degree angle tap") +tunm.ongrid(0.005).output("tunm_OFFGRID", "x.1b : OFFGRID vertex on tunm") +tunm.with_angle(0 .. 45).output("tunm_angle", "x.3a : non 45 degree angle tunm") +poly.ongrid(0.005).output("poly_OFFGRID", "x.1b : OFFGRID vertex on poly") +poly.with_angle(0 .. 90).output("poly_angle", "x.2 : non 90 degree angle poly") +rpm.ongrid(0.005).output("rpm_OFFGRID", "x.1b : OFFGRID vertex on rpm") +rpm.with_angle(0 .. 45).output("rpm_angle", "x.3a : non 45 degree angle rpm") +npc.ongrid(0.005).output("npc_OFFGRID", "x.1b : OFFGRID vertex on npc") +npc.with_angle(0 .. 45).output("npc_angle", "x.3a : non 45 degree angle npc") +nsdm.ongrid(0.005).output("nsdm_OFFGRID", "x.1b : OFFGRID vertex on nsdm") +nsdm.with_angle(0 .. 45).output("nsdm_angle", "x.3a : non 45 degree angle nsdm") +psdm.ongrid(0.005).output("psdm_OFFGRID", "x.1b : OFFGRID vertex on psdm") +psdm.with_angle(0 .. 45).output("psdm_angle", "x.3a : non 45 degree angle psdm") +licon.ongrid(0.005).output("licon_OFFGRID", "x.1b : OFFGRID vertex on licon") +licon.with_angle(0 .. 90).output("licon_angle", "x.2 : non 90 degree angle licon") +li.ongrid(0.005).output("li_OFFGRID", "x.1b : OFFGRID vertex on li") +li.with_angle(0 .. 45).output("li_angle", "x.3a : non 45 degree angle li") +mcon.ongrid(0.005).output("ct_OFFGRID", "x.1b : OFFGRID vertex on mcon") +mcon.with_angle(0 .. 90).output("ct_angle", "x.2 : non 90 degree angle mcon") +vpp.ongrid(0.005).output("vpp_OFFGRID", "x.1b : OFFGRID vertex on vpp") +vpp.with_angle(0 .. 45).output("vpp_angle", "x.3a : non 45 degree angle vpp") +m1.ongrid(0.005).output("m1_OFFGRID", "x.1b : OFFGRID vertex on m1") +m1.with_angle(0 .. 45).output("m1_angle", "x.3a : non 45 degree angle m1") +via.ongrid(0.005).output("via_OFFGRID", "x.1b : OFFGRID vertex on via") +via.with_angle(0 .. 90).output("via_angle", "x.2 : non 90 degree angle via") +m2.ongrid(0.005).output("m2_OFFGRID", "x.1b : OFFGRID vertex on m2") +m2.with_angle(0 .. 45).output("m2_angle", "x.3a : non 45 degree angle m2") +via2.ongrid(0.005).output("via2_OFFGRID", "x.1b : OFFGRID vertex on via2") +via2.with_angle(0 .. 90).output("via2_angle", "x.2 : non 90 degree angle via2") +m3.ongrid(0.005).output("m3_OFFGRID", "x.1b : OFFGRID vertex on m3") +m3.with_angle(0 .. 45).output("m3_angle", "x.3a : non 45 degree angle m3") +via3.ongrid(0.005).output("via3_OFFGRID", "x.1b : OFFGRID vertex on via3") +via3.with_angle(0 .. 90).output("via3_angle", "x.2 : non 90 degree angle via3") +nsm.ongrid(0.005).output("nsm_OFFGRID", "x.1b : OFFGRID vertex on nsm") +nsm.with_angle(0 .. 45).output("nsm_angle", "x.3a : non 45 degree angle nsm") +m4.ongrid(0.005).output("m4_OFFGRID", "x.1b : OFFGRID vertex on m4") +m4.with_angle(0 .. 45).output("m4_angle", "x.3a : non 45 degree angle m4") +via4.ongrid(0.005).output("via4_OFFGRID", "x.1b : OFFGRID vertex on via4") +via4.with_angle(0 .. 90).output("via4_angle", "x.2 : non 90 degree angle via4") +m5.ongrid(0.005).output("m5_OFFGRID", "x.1b : OFFGRID vertex on m5") +m5.with_angle(0 .. 45).output("m5_angle", "x.3a : non 45 degree angle m5") +pad.ongrid(0.005).output("pad_OFFGRID", "x.1b : OFFGRID vertex on pad") +pad.with_angle(0 .. 45).output("pad_angle", "x.3a : non 45 degree angle pad") +mf.ongrid(0.005).output("mf_OFFGRID", "x.1b : OFFGRID vertex on mf") +mf.with_angle(0 .. 90).output("mf_angle", "x.2 : non 90 degree angle mf") +hvi.ongrid(0.005).output("hvi_OFFGRID", "x.1b : OFFGRID vertex on hvi") +hvi.with_angle(0 .. 45).output("hvi_angle", "x.3a : non 45 degree angle hvi") +hvntm.ongrid(0.005).output("hvntm_OFFGRID", "x.1b : OFFGRID vertex on hvntm") +hvntm.with_angle(0 .. 45).output("hvntm_angle", "x.3a : non 45 degree angle hvntm") +vhvi.ongrid(0.005).output("vhvi_OFFGRID", "x.1b : OFFGRID vertex on vhvi") +vhvi.with_angle(0 .. 45).output("vhvi_angle", "x.3a : non 45 degree angle vhvi") +uhvi.ongrid(0.005).output("uhvi_OFFGRID", "x.1b : OFFGRID vertex on uhvi") +uhvi.with_angle(0 .. 45).output("uhvi_angle", "x.3a : non 45 degree angle uhvi") +pwell_rs.ongrid(0.005).output("pwell_rs_OFFGRID", "x.1b : OFFGRID vertex on pwell_rs") +pwell_rs.with_angle(0 .. 45).output("pwell_rs_angle", "x.3a : non 45 degree angle pwell_rs") +areaid_re.ongrid(0.005).output("areaid_re_OFFGRID", "x.1b : OFFGRID vertex on areaid.re") + +end #OFFGRID + diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/fom_density.drc b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/fom_density.drc new file mode 100755 index 00000000..2439f292 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/fom_density.drc @@ -0,0 +1,162 @@ + +errs = 0 +log("fom_density.drc:: sourcing design file=#{$gds_input} topcell=#{$top_cell} ...") +src = source($gds_input, $top_cell) +layout = src.layout +log("done.") + + +report("Density Checks", $report_file) + +verbose(false) + +diff_wildcard = "65/20" +tap_wildcard = "65/44" +fomfill_wildcard = "65,23/28" +fommk_wildcard = "23/0" + +#$chip_boundary = input(235,4) +log("flattening chip boundary...") +$chip_boundary = input(235,4).flatten +log("done.") + +$bbox = $chip_boundary.bbox + +window_size = 700 + +if $step + step_size = $step.to_f +else + step_size = 70 +end +log("step size = #{step_size}") + +llx, lly, urx, ury = $bbox.left, $bbox.bottom, $bbox.right, $bbox.top +log("llx=#{llx} lly=#{lly} urx=#{urx} ury=#{ury}") +if urx-llx <= 0 || ury-lly <= 0 + STDERR.puts "ERROR: fom_density.drc: fatal error, chip_boundary bbox empty or malformed" + errs += 1 +end + +cnt = 0 +x_cnt = ((urx-step_size-llx) / step_size).ceil() +y_cnt = ((ury-step_size-lly) / step_size ).ceil() +tot = x_cnt * y_cnt +$fom_area_map = array = Array.new(x_cnt+1) { Array.new(y_cnt+1) { 0.0 } } +$tile_area_map = array = Array.new(x_cnt+1) { Array.new(y_cnt+1) { 0.0 } } + +log("x_cnt = #{x_cnt}") +log("y_cnt = #{y_cnt}") + +if x_cnt < 1 || y_cnt < 1 + STDERR.puts "ERROR: fom_density.drc: fatal error, x-count or y-count < 1: #{x_cnt} #{y_cnt}" + errs += 1 +end + +# any errors till now?: abort. +if errs > 0 + exit 1 +end + +class FomArea < RBA::TileOutputReceiver + def put(ix, iy, tile, obj, dbu, clip) + if tile + fom_area_scaled = obj.to_f * dbu * dbu + #tile_area_scaled = tile.area * dbu * dbu + tile_area_scaled = (tile & ($bbox * (1.0 / dbu))).area * dbu * dbu + #puts "got area for tile #{ix+1},#{iy+1}: #{fom_area_scaled.to_s} #{tile_area_scaled.to_s}" + $fom_area_map[ix][iy] += fom_area_scaled + $tile_area_map[ix][iy] = tile_area_scaled + else + puts "empty tile #{ix+1},#{iy+1}" + end + end + def finish(success) + puts "finish received: success = #{success}" + end + +end + +tp = RBA::TilingProcessor::new + +# register the custom receiver +tp.output("my_receiver", FomArea::new) + +tp.input("diff", layout.top_cell().begin_shapes_rec(layout.layer(65,20) ) ) +tp.input("tap", layout.top_cell().begin_shapes_rec(layout.layer(65,44) ) ) +tp.input("fomfill", layout.top_cell().begin_shapes_rec(layout.layer(23,28) ) ) + +tp.frame=$bbox +tp.tile_size(step_size, step_size) # 70x70 um tile size +log("dbu = #{layout.dbu}") +log("bbox_area = #{$bbox.area}") +tp.dbu = layout.dbu +tp.threads = $thr.to_i +# tp.scale_to_dbu = false + +# The script clips the input at the tile and computes the (merged) area: +tp.queue("_output(my_receiver, _tile && ((diff | tap | fomfill) & _tile).area)") + +log("calculating subtile areas (= #{tot})...") +tp.execute("Job description") + +cnt = 0 +big_x_cnt = ((urx-window_size-llx) / step_size).ceil() +big_y_cnt = ((ury-window_size-lly) / step_size).ceil() +big_tot = big_x_cnt * big_y_cnt +tiles_per_step = (window_size / step_size).ceil() +log("tiles per step = #{tiles_per_step}") +log("calculating window step densities (= #{big_tot})...") +markers_min = polygon_layer +markers_max = polygon_layer +min_err = 0 +max_err = 0 +min_density = 1 +max_density = 0 +for x in (0 ... big_x_cnt) + log("{{ CHECK }} #{cnt}/#{big_tot.round}") + for y in (0 ... big_y_cnt) + fom_area = 0 + tile_area = 0 + fom_density = 0 + #$fom_area_map.slice(x, tiles_per_step).each { |a| a.slice(y, tiles_per_step).each { |b| puts "#{x},#{y} = #{b}" } } + $fom_area_map.slice(x, tiles_per_step).each { |a| a.slice(y, tiles_per_step).each { |b| fom_area+=b } } + $tile_area_map.slice(x, tiles_per_step).each { |a| a.slice(y, tiles_per_step).each { |b| tile_area+=b } } + marker_box = box(x * step_size, y* step_size, (x+tiles_per_step)*step_size, (y+tiles_per_step)*step_size) + if tile_area > 0 + fom_density = fom_area / tile_area + #log("fom density #{cnt}/#{big_tot.round} is #{fom_density} for area #{tile_area}") + if fom_density < min_density + min_density = fom_density + end + if fom_density > max_density + max_density = fom_density + end + if fom_density < 0.33 + min_err += 1 + markers_min.insert(marker_box) + log("fom density below 0.33 : #{cnt}/#{big_tot.round} is #{"%.4f" % fom_density} for tile (#{marker_box.to_s}), area = #{tile_area.round}") + elsif fom_density > 0.57 + max_err += 1 + markers_max.insert(marker_box) + log("fom density above 0.57 : #{cnt}/#{big_tot.round} is #{"%.4f" % fom_density} for tile (#{marker_box.to_s}), area = #{tile_area.round}") + end + end + cnt += 1 + end +end + +log("minimum fom density = #{"%.4f" % min_density}") +log("maximum fom density = #{"%.4f" % max_density}") + +if min_err > 0 + log("cfom.pd.1d violations = #{min_err}") + markers_min.output("cfom.pd.1d", "0.33 min fom pattern density") +end + +if max_err > 0 + log("cfom.pd.1e violations = #{max_err}") + markers_max.output("cfom.pd.1e", "0.57 max fom pattern density") +end + + diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/fom_density_old.lydrc b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/fom_density_old.lydrc new file mode 100755 index 00000000..c95182a7 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/fom_density_old.lydrc @@ -0,0 +1,96 @@ + + + + + drc + + + + false + false + + true + drc_scripts + tools_menu.drc.end + dsl + drc-dsl-xml + + +log("sourcing design file...") +source($gds_input, $top_cell) +log("done.") + +report("Density Checks", $report_file) + +verbose(false) + +diff_wildcard = "65/20" +tap_wildcard = "65/44" +fomfill_wildcard = "65,23/28" +fommk_wildcard = "23/0" + +#chip_boundary = input(235,4) +log("flattening chip boundary...") +chip_boundary = input(235,4).flatten +log("done.") + +#pl = polygon_layer +#pl.insert(box(0, 0, 700, 700)) +#pl & chip_boundary + +if $thr + threads($thr) +else + threads(4) +end + +bbox = chip_boundary.bbox + +window_size = 700 + +if $step + step_size = $step.to_f +else + step_size = 70 +end +log("step size = #{step_size}") + +llx, lly, urx, ury = bbox.left, bbox.bottom, bbox.right, bbox.top + +log("merging fom layers...") +#fom = polygons(diff_wildcard, tap_wildcard, fomfill_wildcard, fommk_wildcard).merged() +log("done.") + +cnt = 0 +tot = ((urx-window_size-llx) / step_size).ceil() * ((ury-window_size-lly) / step_size ).ceil() +for x in (llx..urx-window_size).step(step_size) + log("{{ CHECK }} #{cnt}/#{tot.round}") + for y in (lly..ury-window_size).step(step_size) + pl = polygon_layer + pl.insert(box(x, y, x+window_size, y+window_size)) + box_within_boundary = pl & chip_boundary + m_area_within_seal = (box_within_boundary & source.touching(box_within_boundary.bbox).polygons(diff_wildcard, tap_wildcard, fomfill_wildcard, fommk_wildcard)).area + #m_area_within_seal = (box_within_boundary & fom).area + m_density = m_area_within_seal / box_within_boundary.area + + cnt = cnt + 1 + # Needed for interfacing with other scripts + # puts does not print to stdout but rather to tty + # which can not be captured in python + #system 'echo %d/%d'%[cnt, tot.round] + log("fom density #{cnt}/#{tot.round} is #{m_density}") + if m_density < 0.33 + #box_within_boundary.output("cfom.pd.1d", "0.33 min fom pattern density, fom density is #{m_density}") + box_within_boundary.output("cfom.pd.1d", "0.33 min fom pattern density") + end + if m_density > 0.57 + #box_within_boundary.output("cfom.pd.1e", "0.57 max fom pattern density, fom density is #{m_density}") + box_within_boundary.output("cfom.pd.1e", "0.57 max fom pattern density") + end + # m_density < 0.33 && box_within_boundary.output("cfom.pd.1d", "0.33 min FOM pattern density") + # m_density > 0.57 && box_within_boundary.output("cfom.pd.1e", "0.57 max FOM pattern density") + end +end + + + diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/met_density.lydrc b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/met_density.lydrc new file mode 100755 index 00000000..c71a9d62 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/met_density.lydrc @@ -0,0 +1,163 @@ + + + + + drc + + + + false + false + + true + drc_scripts + tools_menu.drc.end + dsl + drc-dsl-xml + + +source($gds_input, $top_cell) +report("Density Checks", $report_file) + +verbose(false) + +li1_wildcard = "67/0-4,6-43,45-*" +mcon_wildcard = "67/44" +li1fill_wildcard = "56/28" + +m1_wildcard = "68/0-4,6-43,45-*" +via_wildcard = "68/44" +m1fill_wildcard = "36/28" + +m2_wildcard = "69/0-4,6-43,45-*" +via2_wildcard = "69/44" +m2fill_wildcard = "41/28" + +m3_wildcard = "70/0-4,6-43,45-*" +via3_wildcard = "70/44" +m3fill_wildcard = "34/28" + +m4_wildcard = "71/0-4,6-43,45-*" +via4_wildcard = "71/44" +m4fill_wildcard = "51/28" + +m5_wildcard = "72/0-4,6-43,45-*" +m5fill_wildcard = "59/28" + +seal_wildcard = "61/20" + +# --------------- + +li1 = polygons(li1_wildcard) +mcon = polygons(mcon_wildcard) + +m1 = polygons(m1_wildcard) +via = polygons(via_wildcard) + +m2 = polygons(m2_wildcard) +via2 = polygons(via2_wildcard) + +m3 = polygons(m3_wildcard) +via3 = polygons(via3_wildcard) + +m4 = polygons(m4_wildcard) +m4fill = polygons(m4fill_wildcard) +via4 = polygons(via4_wildcard) + +m5 = polygons(m5_wildcard) + +seal_layer = input(seal_wildcard) +chip_boundary = input(235,4) +#area = (m4+m4fill).area +bbox_area = seal_layer.bbox.area +area_within_seal = bbox_area - seal_layer.area + +marker_box = polygon_layer +marker_box.insert(chip_boundary.bbox) + +#li1_wildcard = "67/20" +#li1fill_wildcard = "56/28" +li1_density = polygons(li1_wildcard, li1fill_wildcard).area / area_within_seal +li1_ca_density = 1 - li1_density +log("li1_ca_density is #{li1_ca_density}") +if li1_ca_density < 0.4 + #chip_boundary.output("li1.pd.1d", "0.4 min li1 ca pattern density, li1 ca density is #{li1_ca_density}") + marker_box.output("li1.pd.1d", "0.4 min li1 ca pattern density") +end +if li1_ca_density > 0.65 + #chip_boundary.output("li1.pd.1e", "0.65 max li1 ca pattern density, li1 ca density is #{li1_ca_density}") + marker_box.output("li1.pd.1e", "0.65 max li1 ca pattern density") +end + +#m1_wildcard = "68/20" +#m1fill_wildcard = "36/28" +m1_density = polygons(m1_wildcard, m1fill_wildcard).area / area_within_seal +m1_ca_density = 1 - m1_density +log("m1_ca_density is #{m1_ca_density}") +if m1_ca_density < 0.4 + #chip_boundary.output("m1.pd.1d", "0.4 min m1 ca pattern density, m1 ca density is #{m1_ca_density}") + marker_box.output("m1.pd.1d", "0.4 min m1 ca pattern density") +end +if m1_ca_density > 0.65 + #chip_boundary.output("m1.pd.1e", "0.65 max m1 ca pattern density, m1 ca density is #{m1_ca_density}") + marker_box.output("m1.pd.1e", "0.65 max m1 ca pattern density") +end + +#m2_wildcard = "69/20" +#m2_fill_wildcard = "41/28" +m2_density = polygons(m2_wildcard, m2fill_wildcard).area / area_within_seal +m2_ca_density = 1 - m2_density +log("m2_ca_density is #{m2_ca_density}") +if m2_ca_density < 0.4 + #chip_boundary.output("m2.pd.1d", "0.4 min m2 ca pattern density, m2 ca density is #{m2_ca_density}") + marker_box.output("m2.pd.1d", "0.4 min m2 ca pattern density") +end +if m2_ca_density > 0.65 + #chip_boundary.output("m2.pd.1e", "0.65 max m2 ca pattern density, m2 ca density is #{m2_ca_density}") + marker_box.output("m2.pd.1e", "0.65 max m2 ca pattern density") +end + +#m3_wildcard = "70/20" +#m3_fill_wildcard = "34/28" +m3_density = polygons(m3_wildcard, m3fill_wildcard).area / area_within_seal +m3_ca_density = 1 - m3_density +log("m3_ca_density is #{m3_ca_density}") +if m3_ca_density < 0.4 + #chip_boundary.output("m3.pd.1d", "0.4 min m3 ca pattern density, m3 ca density is #{m3_ca_density}") + marker_box.output("m3.pd.1d", "0.4 min m3 ca pattern density") +end +if m3_ca_density > 0.65 + #chip_boundary.output("m3.pd.1e", "0.65 max m3 ca pattern density, m3 ca density is #{m3_ca_density}") + marker_box.output("m3.pd.1e", "0.65 max m3 ca pattern density") +end + +#m4_wildcard = "71/20" +#m4fill_wildcard = "51/28" +m4_density = polygons(m4_wildcard, m4fill_wildcard).area / area_within_seal +m4_ca_density = 1 - m4_density +log("m4_ca_density is #{m4_ca_density}") +if m4_ca_density < 0.4 + #chip_boundary.output("m4.pd.1d", "0.4 min m4 ca pattern density, m4 ca density is #{m4_ca_density}") + marker_box.output("m4.pd.1d", "0.4 min m4 ca pattern density, m4 ca density is #{m4_ca_density}") +end +if m4_ca_density > 0.65 + #chip_boundary.output("m4.pd.1e", "0.65 max m4 ca pattern density") + marker_box.output("m4.pd.1e", "0.65 max m4 ca pattern density") +end + +#m5_wildcard = "72/20" +#m5fill_wildcard = "59/28" +m5_density = polygons(m5_wildcard, m5fill_wildcard).area / area_within_seal +m5_ca_density = 1 - m5_density +log("m5_ca_density is #{m5_ca_density}") +if m5_ca_density < 0.24 + #chip_boundary.output("m5.pd.1d", "0.24 min m5 ca pattern density, m5 ca density is #{m5_ca_density}") + marker_box.output("m5.pd.1d", "0.24 min m5 ca pattern density") +end +if m5_ca_density > 0.55 + #chip_boundary.output("m5.pd.1e", "0.55 max m5 ca pattern density, m5 ca density is #{m5_ca_density}") + marker_box.output("m5.pd.1e", "0.55 max m5 ca pattern density") +end + + + diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-drc-wip.lydrc b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-drc-wip.lydrc new file mode 100755 index 00000000..73c716e6 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-drc-wip.lydrc @@ -0,0 +1,868 @@ + + + + + drc + + + + false + false + + true + drc_scripts + tools_menu.drc.end + dsl + drc-dsl-xml + # +# DRC for SKY130 according to : +# https://skywater-pdk.readthedocs.io/en/latest/rules/periphery.html +# https://skywater-pdk.readthedocs.io/en/latest/rules/layers.html +# +# Distributed under GNU GPLv3: https://www.gnu.org/licenses/ +# +# History : +# 2020-10-04 : v1.0 : initial release +# +########################################################################################## + +# optionnal for a batch launch : klayout -b -rd input=my_layout.gds -rd report=sky130_drc.txt -r drc_sky130.drc +if $input + source($input) +end + +if $report + report($report) +else + report("SKY130 DRC runset", File.join(File.dirname(RBA::CellView::active.filename), "sky130_drc.txt")) +end + +AL = true # do not change +CU = false # do not change +# choose betwen only one of AL or CU back-end flow here : +backend_flow = AL + +# enable / disable rule groups +FEOL = false # front-end-of-line checks +BEOL = true # back-end-of-line checks +OFFGRID = false # manufacturing grid/angle checks + +# klayout setup +######################## +# use a tile size of 1mm - not used in deep mode- +tiles(1000.um) +# use a tile border of 10 micron: +tile_borders(1.um) +#no_borders + +# hierachical +deep + +# use 4 cpu cores +threads(4) +# if more inof is needed, set true +verbose(true) + +# layers definitions +######################## +diff = input(65, 20) +tap = polygons(65, 44) +nwell = polygons(64, 20) +dnwell = polygons(64, 18) +pwbm = polygons(19, 44) +pwde = polygons(124, 20) +natfet = polygons(124, 21) +hvtr = polygons(18, 20) +hvtp = polygons(78, 44) +ldntm = polygons(11, 44) +hvi = polygons(75, 20) +tunm = polygons(80, 20) +lvtn = polygons(125, 44) +poly = polygons(66, 20) +hvntm = polygons(125, 20) +nsdm = polygons(93, 44) +psdm = polygons(94, 20) +rpm = polygons(86, 20) +urpm = polygons(79, 20) +npc = polygons(95, 20) +licon = polygons(66, 44) +li = input(67, 20) +mcon = polygons(67, 44) +m1 = polygons(68, 20) +via = polygons(68, 44) +m2 = polygons(69, 20) +via2 = polygons(69, 44) +m3 = polygons(70, 20) +via3 = polygons(70, 44) +m4 = polygons(71, 20) +via4 = polygons(71, 44) +m5 = polygons(72, 20) +pad = polygons(76, 20) +nsm = polygons(61, 20) +capm = polygons(89, 44) +cap2m = polygons(97, 44) +vhvi = polygons(74, 21) +uhvi = polygons(74, 22) +npn = polygons(82, 20) +inductor = polygons(82, 24) +vpp = polygons(82, 64) +pnp = polygons(82, 44) +lvs_prune = polygons(84, 44) +ncm = polygons(92, 44) +padcenter = polygons(81, 20) +mf = polygons(76, 44) +areaid_sl = polygons(81, 1) +areaid_ce = polygons(81, 2) +areaid_fe = polygons(81, 3) +areaid_sc = polygons(81, 4) +areaid_sf = polygons(81, 6) +areaid_sw = polygons(81, 7) +areaid_sr = polygons(81, 8) +areaid_mt = polygons(81, 10) +areaid_dt = polygons(81, 11) +areaid_ft = polygons(81, 12) +areaid_ww = polygons(81, 13) +areaid_ld = polygons(81, 14) +areaid_ns = polygons(81, 15) +areaid_ij = polygons(81, 17) +areaid_zr = polygons(81, 18) +areaid_ed = polygons(81, 19) +areaid_de = polygons(81, 23) +areaid_rd = polygons(81, 24) +areaid_dn = polygons(81, 50) +areaid_cr = polygons(81, 51) +areaid_cd = polygons(81, 52) +areaid_st = polygons(81, 53) +areaid_op = polygons(81, 54) +areaid_en = polygons(81, 57) +areaid_en20 = polygons(81, 58) +areaid_le = polygons(81, 60) +areaid_hl = polygons(81, 63) +areaid_sd = polygons(81, 70) +areaid_po = polygons(81, 81) +areaid_it = polygons(81, 84) +areaid_et = polygons(81, 101) +areaid_lvt = polygons(81, 108) +areaid_re = polygons(81, 125) +areaid_ag = polygons(81, 79) +poly_rs = polygons(66, 13) +diff_rs = polygons(65, 13) +pwell_rs = polygons(64, 13) +li_rs = polygons(67, 13) +cfom = polygons(22, 20) + + +# Define a new custom function that selects polygons by their number of holes: +# It will return a new layer containing those polygons with min to max holes. +# max can be nil to omit the upper limit. +class DRC::DRCLayer + def with_holes(min, max) + new_data = RBA::Region::new + self.data.each do |p| + if p.holes >= (min || 0) && (!max || p.holes <= max) + new_data.insert(p) + end + end + DRC::DRCLayer::new(@engine, new_data) + end +end + +# DRC section +######################## +info("DRC section") + +if FEOL +info("FEOL section") +gate = diff & poly + +# dnwell +dnwell.width(3.0, euclidian).output("dnwell.2", "dnwell.2 : min. dnwell width : 3.0um") +dnwell.not(uhvi).not(areaid_po).isolated(6.3, euclidian).output("dnwell.3", "dnwell.3 : min. dnwell spacing : 6.3um") +dnwell.and(pnp).output("dnwell.4", "dnwell.4 : dnwell must not overlap pnp") +dnwell.and(psdm).edges.not(psdm.edges).output("dnwell.5", "p+ must not straddle dnwell") +# dnwell.6 rue not coded + +# nwell +nwell.width(0.84, euclidian).output("nwell.1", "nwell.1 : min. nwell width : 0.84um") +nwell.isolated(1.27, euclidian).output("nwell.2a", "nwell.2a : min. nwell spacing (merged if less) : 1.27um") +# rule nwell.4 is suitable for digital cells +#nwell.not(uhvi).not(areaid_en20).not_interacting(tap.and(licon).and(li)).output("nwell.4", "nwell4 : all nwell exempt inside uhvi must contain a n+tap") +nwell.enclosing(dnwell.not(uhvi).not(areaid_po), 0.4, euclidian).output("nwell.5", "nwell.5 : min. nwell enclosing dnwell exempt unside uhvi : 0.4um") +dnwell.enclosing(nwell.not(uhvi), 1.03, euclidian).output("nwell.6", "nwell.6 : min. dnwell enclosing nwell exempt unside uhvi : 1.03um") +dnwell.separation(nwell, 4.5, euclidian).output("nwell.7", "nwell.7 : min. dnwell separation nwell : 4.5um") + +# pwbm +pwbm.not(uhvi).output("pwbm", "pwbm must be inside uhvi") +dnwell.and(uhvi).edges.not(pwbm).output("pwbm.4", "pwbm.4 : dnwell inside uhvi must be enclosed by pwbm") + +# pwde +pwde.not(pwbm).output("pwdem.3", "pwdem.3 : pwde must be inside pwbm") +pwde.not(uhvi).output("pwdem.4", "pwdem.4 : pwde must be inside uhvi") +pwde.not(dnwell).output("pwdem.5", "pwdem.5 : pwde must be inside dnwell") + +# hvtp +#hvtp.not(nwell).output("hvtp", "hvtp must inside nwell") +hvtp.width(0.38, euclidian).output("hvtp.1", "hvtp.1 : min. hvtp width : 0.38um") +hvtp.isolated(0.38, euclidian).output("hvtp.2", "hvtp.2 : min. hvtp spacing : 0.38um") +hvtp.enclosing(gate.and(psdm), 0.18, euclidian).output("hvtp.3", "hvtp.3 : min. hvtp enclosure of pfet gate : 0.18um") +hvtp.separation(gate.and(psdm), 0.18, euclidian).output("hvtp.4", "hvtp.4 : min. hvtp spacing pfet gate: 0.18um") +hvtp.with_area(0..0.265).output("hvtp.5", "hvtp.5 : min. hvtp area : 0.265um²") + +# hvtr +hvtr.width(0.38, euclidian).output("hvtr.1", "hvtr.1 : min. hvtr width : 0.38um") +hvtr.isolated(0.38, euclidian).output("hvtr.2", "hvtr.2 : min. hvtr spacing : 0.38um") + +# lvtn +lvtn.width(0.38, euclidian).output("lvtn.1", "lvtn.1 : min. lvtn width : 0.38um") +lvtn.isolated(0.38, euclidian).output("lvtn.2", "lvtn.2 : min. lvtn spacing : 0.38um") +lvtn.separation(diff.and(poly).not(uhvi), 0.18, euclidian).output("lvtn.3a", "lvtn.3a : min. lvtn spacing to gate : 0.18um") +lvtn.separation(diff.and(nwell).not(poly), 0.235, projection).output("lvtn.3b", "lvtn.3b : min. lvtn spacing to pfet s/d : 0.18um") +lvtn.enclosing(gate.not(uhvi), 0.18, euclidian).output("lvtn.4b", "lvtn.4b : min. lvtn enclosing to gate : 0.18um") +lvtn.separation(hvtp, 0.38, euclidian).output("lvtn.9", "lvtn.9 : min. lvtn spacing hvtp : 0.38um") +nwell.not_interacting(gate.and(nwell.not(hvi).not(areaid_ce))).enclosing(lvtn.not(uhvi), 0.18, euclidian).polygons.without_area(0).output("lvtn.4b", "lvtn.4b : min. lvtn enclosure of gate : 0.18um") +lvtn.separation(nwell.inside(areaid_ce), 0.38, euclidian).output("lvtn.12", "lvtn.12 : min. lvtn spacing nwell inside areaid.ce : 0.38um") +lvtn.with_area(0..0.265).output("lvtn.13", "lvtn.13 : min. lvtn area : 0.265um²") + +# ncm +ncm.and(tap.and(nwell).or(diff.not(nwell))).output("ncm.x.3", "ncm.x.3 : ncm must not overlap n+diff") +ncm.width(0.38, euclidian).output("ncm.1", "ncm.1 : min. ncm width : 0.38um") +ncm.isolated(0.38, euclidian).output("ncm.2", "ncm.2 : min. ncm spacing manual merge if smaller : 0.38um") +ncm.enclosing(diff.and(nwell), 0.18, euclidian).output("ncm.3", "ncm.3 : min. ncm enclosure of p+diff : 0.18um") +ncm.separation(lvtn.and(diff), 0.23, euclidian).output("ncm.5", "ncm.5 : min. ncm spacing lvtn diff : 0.23um") +ncm.separation(diff.not(nwell), 0.2, euclidian).output("ncm.6", "ncm.6 : min. ncm spacing nfet : 0.2um") +ncm.with_area(0..0.265).output("ncm.7", "ncm.13 : min. ncm area : 0.265um²") + +# diff-tap +difftap = diff + tap +difftap.width(0.15, euclidian).output("difftap.1", "difftap.1 : min. difftap width : 0.15um") +not_in_cell1 = layout(source.cell_obj).select("s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b" , "-s8fpls_pl8", "-s8fpls_rdrv4" , "-s8fpls_rdrv4f", "-s8fpls_rdrv8") +not_in_cell1_diff = not_in_cell1.input(65, 20) +not_in_cell1_diff.not(areaid_sc).not(poly).edges.and(gate.edges).with_length(0,0.42).output("difftap.2", "difftap.2: min. gate (exempt areaid.sc) width : 0.42um") +diff.and(areaid_sc).not(poly).edges.and(gate.edges).with_length(0,0.36).output("difftap.2", "difftap.2: min. gate inside areaid.sc width : 0.36um") +difftap.isolated(0.27, euclidian).output("difftap.3", "difftap.3 : min. difftap spacing : 0.27um") +tap.edges.and(diff.edges).with_length(0,0.29).output("difftap.4", "difftap.4 : min. tap bound by diffusion : 0.29um") +tap.edges.and(diff.edges).space(0.4, projection).output("difftap.5", "difftap.5 : min. tap bound by 2 diffusions : 0.4um") +(tap.edges.and(diff.edges)).extended(0.01, 0.01, 0, 0, false).not(tap.and(diff)).and(diff.or(tap)).output("difftap.6", "difftap.6 : diff and tap not allowed to extend beyong their abutting ege") +tap.edges.not_interacting(diff.edges).separation(diff.edges, 0.13, euclidian).output("difftap.7", "difftap.7 : min. diff/tap spacing to non-coincident diff edge : 0.13um") +diff.edges.not_interacting(tap.edges).separation(tap.edges, 0.13, euclidian).output("difftap.7", "difftap.7 : min. diff/tap spacing to non-coincident tap edge : 0.13um") +nwell.enclosing(diff.not(uhvi).and(psdm), 0.18, euclidian).output("difftap.8", "difftap.8 : min. p+diff enclosure by nwell : 0.18um") +diff.not(uhvi).and(nsdm).separation(nwell, 0.34, euclidian).output("difftap.9", "difftap.9 : min. n+diff spacing to nwell : 0.34um") +nwell.enclosing(tap.not(uhvi).and(nsdm), 0.18, euclidian).output("difftap.10", "difftap.10 : min. n+tap enclosure by nwell : 0.18um") +tap.not(uhvi).and(psdm).separation(nwell, 0.13, euclidian).output("difftap.11", "difftap.11 : min. p+tap spacing to nwell : 0.13um") + +# tunm +tunm.width(0.41, euclidian).output("tunm.1", "tunm.1 : min. tunm width : 0.41um") +tunm.isolated(0.5, euclidian).output("tunm.2", "tunm.2 : min. tunm spacing : 0.5um") +tunm.enclosing(gate, 0.095, euclidian).output("tunm.3", "tunm.3 : min. tunm beyond gate : 0.095um") +tunm.separation(gate.not_interacting(tunm), 0.095, euclidian).output("tunm.4", "tunm.4 : min. tunm spacing to gate outside tunm: 0.095um") +gate.and(tunm).edges.not(gate.edges).output("tunm.5", "tunm.5 : gate must not straddle tunm") +tunm.not(dnwell).output("tunm.6a", "tunm.6a : tunm not allowed outside dnwell") +tunm.with_area(0..0.672).output("tunm.7", "tunm.7 : min. tunm area : 0.672um²") + +# poly +poly.width(0.15, euclidian).output("poly.1a", "poly.1a : min. poly width : 0.15um") +poly.not(diff).edges.and(gate.and(lvtn).edges).space(0.35, euclidian).output("poly.1b", "poly.1b: min. lvtn gate width : 0.35um") +poly.isolated(0.21, euclidian).output("poly.2", "poly.2 : min. poly spacing : 0.21um") +poly.and(rpm.or(urpm).or(poly_rs)).width(0.33, euclidian).output("poly.3", "poly.3 : min. poly resistor width : 0.33um") +poly.not(gate).separation(diff, 0.075, projection).polygons.without_area(0).output("poly.4", "poly.4 : min. poly on field spacing to diff : 0.075um") +poly.not(gate).separation(tap, 0.055, euclidian).output("poly.5", "poly.5 : min. poly on field spacing to tap : 0.055um") +gate.separation(tap, 0.3, projection).polygons.and(diff).output("poly.6", "poly.6 : min. gate spacing to tap : 0.3um") +diff.enclosing(gate, 0.25, projection).polygons.without_area(0).output("poly.7", "poly.7 : min. source/drain length : 0.25um") +poly.enclosing(gate, 0.13, projection).polygons.without_area(0).output("poly.8", "poly.8 : min. poly extention gate (endcap) : 0.13um") +poly.and(rpm.or(urpm).or(poly_rs)).separation(poly.or(difftap), 0.48, euclidian).polygons.without_area(0).output("poly.9", "poly.9 : min. poly resistor space to poly or diff/tap : 0.48um") +diff.merged.edges.end_segments(0.01).and(poly).output("poly.10", "poly.10 : poly must not overlap diff corner") +gate.with_angle(0 .. 90).output("poly.11", "poly.11 : non 90 degree angle gate") +not_in_cell3 = layout(source.cell_obj).select("s8fgvr_n_fg2") +not_in_cell3_poly = not_in_cell3.input(66, 20) +not_in_cell3_poly.not(hvi).not(nwell.not(hvi)).and(tap).output("poly.12", "poly.12 : poly must not overlap tap") +poly.and(diff_rs).output("poly.15", "poly.15 : poly must not overlap diff resistor") + +# rpm +rpm.width(1.27, euclidian).output("rpm.1a", "rpm.1a : min. rpm width : 1.27um") +rpm.isolated(0.84, euclidian).output("rpm.2", "rpm.2 : min. rpm spacing : 0.84um") +rpm.enclosing(poly.and(poly_rs).and(psdm), 0.2, euclidian).output("rpm.3", "rpm.3 : min. rpm enclosure of poly resistor : 0.2um") +psdm.enclosing(poly.and(poly_rs).and(rpm), 0.11, euclidian).output("rpm.4", "rpm.4 : min. psdm enclosure of poly resistor : 0.11um") +npc.enclosing(poly.and(poly_rs).and(rpm), 0.095, euclidian).output("rpm.5", "rpm.5 : min. npc enclosure of poly resistor : 0.095um") +rpm.separation(nsdm, 0.2, euclidian).output("rpm.6", "rpm.6 : min. rpm spacing nsdm: 0.2um") +rpm.separation(poly, 0.2, euclidian).output("rpm.7", "rpm.7 : min. rpm spacing poly: 0.2um") +rpm.and(poly).edges.not(poly.edges).output("rpm.8", "rpm.8 : poly must not straddle rpm") +poly.and(poly_rs).and(rpm).separation(hvntm, 0.185, euclidian).output("rpm.9", "rpm.9 : min. poly resistor spacing hvntm: 0.185um") +rpm.and(pwbm).output("rpm.10", "rpm.107 : min. rpm spacing pwbm: na") + +# varac +varac = poly & tap & (nwell - hvi) - areaid_ce +tap.not(poly).edges.and(varac.edges).space(0.18, euclidian).output("varac.1", "varac.1: min. varac channel length : 0.18um") +tap.and(poly).edges.and(varac.edges).space(1.0, euclidian).output("varac.2", "varac.2: min. varac channel wdth : 1.0um") +varac.separation(hvtp, 0.18, euclidian).output("varac.3", "varac.3: min. varac channel space to hvtp : 0.18um") +varac.separation(licon.and(tap), 0.25, euclidian).output("varac.4", "varac.4: min. varac channel space to licon on tap : 0.25um") +nwell.enclosing(poly.overlapping(varac), 0.15, euclidian).output("varac.5", "varac.5: min. nwell enclosure of poly overlapping varac channel : 0.15um") +tap.overlapping(varac).separation(difftap, 0.27, euclidian).polygons.without_area(0).output("varac.6", "varac.6: min. varac channel tap space to difftap : 0.27um") +nwell.overlapping(varac).and(diff.and(nwell)).output("varac.7", "varac.7: nwell overlapping varac channel must not overlap p+diff") + +# photo +photodiode = dnwell & areaid_po +photodiode.edges.without_length(3.0).output("photo.2", "photo.2 : minimum/maximum width of photodiode : 3.0um") +photodiode.isolated(5.0, euclidian).output("photo.3", "photo.3 : mini. photodiode spacing : 5.0um") +photodiode.separation(dnwell, 5.3, euclidian).output("photo.4", "photo.4 : mini. photodiode spacing to dnwell : 5.3um") +areaid_po.not(dnwell).output("photo.5.6", "photo.5.6 : photodiode edges must coincide areaid.po and enclosed by dnwell") +photodiode.not(tap.not(nwell).holes).output("photo.7", "photo.7 : photodiode must be enclosed by p+tap ring") +photodiode.and(nwell).edges.without_length(0.84).output("photo.8", "photo.8 : minimum/maximum width of nwell inside photodiode : 0.84um") +areaid_po.edges.and(photodiode.and(nwell).sized(1.08)).without_length(12.0).output("photo.9", "photo.9 : minimum/maximum enclosure of nwell by photodiode : 1.08um") +photodiode.and(tap).edges.without_length(0.41).output("photo.10", "photo.10 : minimum/maximum width of tap inside photodiode : 0.41um") + +# npc +npc.width(0.27, euclidian).output("npc.1", "npc.1 : min. npc width : 0.27um") +npc.isolated(0.27, euclidian).output("npc.2", "npc.2 : min. npc spacing, should be mnually merge if less : 0.27um") +npc.separation(gate, 0.09, euclidian).output("npc.4", "npc.4 : min. npc spacing to gate : 0.09um") + +# nsdm/psdm +npsdm = nsdm + psdm +nsdm.width(0.38, euclidian).output("nsdm.1", "nsdm.1 : min. nsdm width : 0.38um") +psdm.width(0.38, euclidian).output("psdm.1", "psdm.1 : min. psdm width : 0.38um") +nsdm.isolated(0.38, euclidian).output("n/psdm.1", "n/psdm.1 : min. nsdm spacing, should be mnually merge if less : 0.38um") +psdm.isolated(0.38, euclidian).output("n/psdm.1", "n/psdm.1 : min. psdm spacing, should be mnually merge if less : 0.38um") +npsdm.enclosing(diff, 0.125, euclidian).polygons.not(tap.sized(0.125)).output("n/psdm.5a", "n/psdm.5a : min. n/psdm enclosure diff except butting edge : 0.125um") +npsdm.enclosing(tap, 0.125, euclidian).polygons.not(diff.sized(0.125)).output("n/psdm.5b", "n/psdm.5b : min. n/psdm enclosure tap except butting edge : 0.125um") +tap.edges.and(diff.edges).not(npsdm).output("n/psdm.6", "n/psdm.6 : min. n/psdm enclosure of butting edge : 0.0um") +nsdm.and(difftap).separation(psdm.and(difftap), 0.13, euclidian).polygons.without_area(0).output("n/psdm.7", "n/psdm.7 : min. nsdm diff spacing to psdm diff except butting edge : 0.13um") +diff.and((nsdm.and(nwell)).or(psdm.not(nwell))).output("n/psdm.8", "n/psdm.8 : diff should be the opposite type of well/substrate underneath") +tap.and((nsdm.not(nwell)).or(psdm.and(nwell))).output("n/psdm.8", "n/psdm.8 : tap should be the same type of well/substrate underneath") +tap.and(diff).without_area(0).output("tap and diff", "tap and diff must not overlap") +nsdm.with_area(0..0.265).output("n/psdm.10a", "n/psdm.10a : min. nsdm area : 0.265um²") +psdm.with_area(0..0.265).output("n/psdm.10b", "n/psdm.10b : min. psdm area : 0.265um²") + +# licon +licon.not(poly.interacting(poly_rs)).edges.without_length(0.17).output("licon.1", "licon.1 : minimum/maximum width of licon : 0.17um") +licon.and(poly.interacting(poly_rs)).not_interacting((licon.and(poly.interacting(poly_rs)).edges.with_length(0.19)).or(licon.and(poly.interacting(poly_rs)).edges.with_length(2.0))).output("licon.1b/c", "licon.1b/c : minimum/maximum width/length of licon inside poly resistor : 2.0/0.19um") +licon.isolated(0.17, euclidian).output("licon.2", "licon.2 : min. licon spacing : 0.17um") +licon.and(poly.interacting(poly_rs)).edges.with_length(0.19).space(0.35, euclidian).output("licon.2b", "licon.2b : min. licon 0.19um edge on resistor spacing : 0.35um") +licon.interacting(licon.and(poly.interacting(poly_rs)).edges.with_length(2.0)).separation(licon.and(poly.interacting(poly_rs)), 0.51, euclidian).output("licon.2c", "licon.2c : min. licon 2.0um edge on resistor spacing : 0.51um") +licon.and(poly.interacting(poly_rs)).separation(licon.not(poly.interacting(poly_rs)), 0.51, euclidian).output("licon.2d", "licon.2d : min. licon on resistor spacing other licon : 0.51um") +# rule licon.3 not coded +licon.not(li).not(poly.or(diff).or(tap)).output("licon.4", "licon.4 : min. licon must overlap li and (poly or tap or diff) ") +diff.enclosing(licon, 0.04, euclidian).output("licon.5", "licon.5 : min. diff enclosure of licon : 0.04um") +tap.edges.and(diff.edges).separation(licon.and(tap).edges, 0.06, euclidian).output("licon.6", "licon.6 : min. abutting edge spacing to licon tap : 0.06um") +licon_edges_with_less_enclosure_tap = tap.enclosing(licon, 0.12, projection).second_edges +opposite1 = (licon.edges - licon_edges_with_less_enclosure_tap).width(0.17 + 1.dbu, projection).polygons +licon.not_interacting(opposite1).output("licon.7", "licon.7 : min. tap enclosure of licon by one of 2 opposite edges : 0.12um") +poly.enclosing(licon, 0.05, euclidian).output("licon.8", "licon.8 : min. poly enclosure of licon : 0.05um") +licon008 = licon.interacting(poly.enclosing(licon, 0.08, euclidian).polygons) +licon_edges_with_less_enclosure_poly = poly.enclosing(licon, 0.08, projection).second_edges +opposite2 = (licon.edges - licon_edges_with_less_enclosure_poly).width(0.17 + 1.dbu, projection).polygons +licon008.not_interacting(opposite2).output("licon.8a", "licon.8a : min. poly enclosure of licon by one of 2 opposite edges : 0.08um") +# rule licon.9 not coded +licon.and(tap.and(nwell.not(hvi))).separation(varac, 0.25, euclidian).output("licon.10", "licon.10 : min. licon spacing to varac channel : 0.25um") +not_in_cell4 = layout(source.cell_obj).select("-s8fs_gwdlvx4", "-s8fs_gwdlvx8", "-s8fs_hvrsw_x4", "-s8fs_hvrsw8", "-s8fs_hvrsw264", "-s8fs_hvrsw520", "-s8fs_rdecdrv", "-s8fs_rdec8”, “s8fs_rdec32", "-s8fs_rdec264", "-s8fs_rdec520") +not_in_cell4_licon = not_in_cell4.input(66, 44) +not_in_cell4_licon.and(diff.or(tap)).separation(gate.not(areaid_sc), 0.055, euclidian).output("licon.11", "licon.11 : min. licon spacing to gate : 0.055um") +licon.and(diff.or(tap)).separation(gate.and(areaid_sc), 0.05, euclidian).output("licon.11a", "licon.11a : min. licon spacing to gate inside areaid.sc : 0.05um") +in_cell4 = layout(source.cell_obj).select("+s8fs_gwdlvx4", "+s8fs_gwdlvx8", "+s8fs_hvrsw_x4", "+s8fs_hvrsw8", "+s8fs_hvrsw264", "+s8fs_hvrsw520") +in_cell4_licon = in_cell4.input(66, 44) +in_cell4_licon.and(diff.or(tap)).separation(gate, 0.04, euclidian).output("licon.11c", "licon.11c : min. licon spacing to gate for specific cells: 0.04um") +# rules 11.b , 11.d not coded +diff.interacting(gate).not(diff.interacting(gate).width(5.7, euclidian).polygons).output("licon.12", "licon.12 : max. sd width without licon : 5.7um") +licon.and(diff.or(tap)).separation(npc, 0.09, euclidian).output("licon.13", "licon.13 : min. difftap licon spacing to npc : 0.09um") +licon.and(poly).separation(diff.or(tap), 0.19, euclidian).output("licon.14", "licon.14 : min. poly licon spacing to difftap : 0.19um") +npc.enclosing(licon.and(poly), 0.1, euclidian).output("licon.15", "licon.15 : min. npc enclosure of poly-licon : 0.1um") +# rule licon.16 not applicable for the diff for the nmos of a nand gates or the pmos of a nor gates +#diff.not(gate).not_interacting(licon).output("licon.16", "licon.16 : diff must enclose one licon") +tap.not(uhvi).not_interacting(licon).output("licon.16", "licon.16 : tap must enclose one licon") +poly.and(tap).edges.not(tap.edges).output("licon.17", "licon.17 : tap must not straddle poly") +npc.not_interacting(licon.and(poly)).output("licon.18", "licon.18 : npc mut enclosed one poly-licon") + +# li +not_in_cell5 = layout(source.cell_obj).select("-s8rf2_xcmvpp_hd5_*") +not_in_cell5_li = not_in_cell5.input(67, 20) +not_in_cell5_li.width(0.17, euclidian).output("li.1", "li.1 : min. li width : 0.17um") +in_cell5 = layout(source.cell_obj).select("+s8rf2_xcmvpp_hd5_*") +in_cell5_li = in_cell5.input(67, 20) +in_cell5_li.width(0.14, euclidian).output("li.1a", "li.1a : min. li width for the cells s8rf2_xcmvpp_hd5_* : 0.14um") +# rule li.2 not coded +not_in_cell5_li.isolated(0.17, euclidian).output("li.3", "li.3 : min. li spacing : 0.17um") +in_cell5_li.isolated(0.14, euclidian).output("li.3a", "li.3a : min. li spacing for the cells s8rf2_xcmvpp_hd5_* : 0.14um") +licon08 = licon.interacting(li.enclosing(licon, 0.08, euclidian).polygons) +licon_edges_with_less_enclosure_li = li.enclosing(licon, 0.08, projection).second_edges +opposite3 = (licon.edges - licon_edges_with_less_enclosure_li).width(0.17 + 1.dbu, projection).polygons +licon08.not_interacting(opposite3).output("li.5", "li.5 : min. li enclosure of licon of 2 opposite edges : 0.08um") +li.with_area(0..0.0561).output("li.6", "li.6 : min. li area : 0.0561um²") + +# vpp +vpp.width(1.43, euclidian).output("vpp.1", "vpp.1 : min. vpp width : 1.43um") +# rules 1.b, 1.c not coded +vpp.and(poly.or(difftap)).output("vpp.3", "vpp.3 : vpp must not overlapp poly or diff or tap") +vpp.and(nwell).edges.not(vpp.edges).output("vpp.4", "vpp.4 : vpp must not straddle nwell") +vpp.and(dnwell).edges.not(vpp.edges).output("vpp.4", "vpp.4 : vpp must not straddle dnwell") +vpp.and(poly.or(li).or(m1).or(m2)).separation(poly.or(li).or(m1).or(m2), 1.5, euclidian).polygons.with_area(2.25,nil).output("vpp.5", "vpp.5 : min. vpp spacing to poly or li or m1 or m2 : 1.5um") +vpp.with_area(0..area(vpp.and(m3))*0.25).output("vpp.5a", "vpp.5a : max. m3 density in vpp : 0.25") +vpp.with_area(0..area(vpp.and(m4))*0.3).output("vpp.5b", "vpp.5b : max. m4 density in vpp : 0.3") +vpp.with_area(0..area(vpp.and(m5))*0.4).output("vpp.5c", "vpp.5c : max. m5 density in vpp : 0.4") +nwell.enclosing(vpp, 1.5, euclidian).output("vpp.8", "vpp.8 : nwell enclosure of vpp : 1.5") +vpp.separation(nwell, 1.5, euclidian).polygons.without_area(0).output("vpp.9", "vpp.9 : vpp spacing to nwell : 1.5") +# rule vpp.10 not coded +# rule vpp.11 not coded because moscap is not defined properly by any gds layer +# rules vpp.12a, 12b, 12c not coded because specific to one cell +if backend_flow = CU + m1.separation(vpp.and(m1), 0.16, euclidian).polygons.without_area(0).output("vpp.13", "vpp.13 : m1 spacing to m1inside vpp : 0.16") +end + +# CAPM +capm.width(1.0, euclidian).output("capm.1", "capm.1 : min. capm width : 1.0um") +capm.isolated(0.84, euclidian).output("capm.2a", "capm.2a : min. capm spacing : 0.84um") +m2.interacting(capm).isolated(1.2, euclidian).output("capm.2b", "capm.2b : min. capm spacing : 1.2um") +m2.enclosing(capm, 0.14, euclidian).output("capm.3", "capm.3 : min. m2 enclosure of capm : 0.14um") +capm.enclosing(via2, 0.14, euclidian).output("capm.4", "capm.4 : min. capm enclosure of via2 : 0.14um") +capm.separation(via2, 0.14, euclidian).output("capm.5", "capm.5 : min. capm spacing to via2 : 0.14um") +capm.sized(-20.0).sized(20.0).output("capm.6", "capm.6 : max. capm lenght/width : 20um") +capm.with_angle(0 .. 90).output("capm.7", "capm.7 : capm not rectangle") +capm.separation(via, 0.14, euclidian).polygons.without_area(0).output("capm.8", "capm.8 : min. capm spacing to via : 0.14um") +capm.and(nwell).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle nwell") +capm.and(diff).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle diff") +capm.and(tap).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle tap") +capm.and(poly).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle poly") +capm.and(li).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle li") +capm.and(m1).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle m1") +capm.separation(m2.not_interacting(capm), 0.14, euclidian).output("capm.11", "capm.11 : min. capm spacing to m2 not overlapping capm : 0.5um") + +end #FEOL + +if BEOL +info("BEOL section") + +# ct +mcon.edges.without_length(0.17).output("ct.1", "ct.1 : minimum/maximum width of mcon : 0.17um") +mcon.isolated(0.19, euclidian).output("ct.2", "ct.2 : min. mcon spacing : 0.19um") +# rule ct.3 not coded +mcon.not(li).output("ct.4", "ct.4 : mcon should covered by li") +if backend_flow = CU + li.interacting(li.and(m1).not(mcon).with_holes(1,10)).enclosing(mcon, 0.2, euclidian).output("ct.irdrop.1", "ct.irdrop.1 : min. li enclsoure of 1..10 mcon : 0.2um") + li.interacting(li.and(m1).not(mcon).with_holes(11,100)).enclosing(mcon, 0.3, euclidian).output("ct.irdrop.2", "ct.irdrop.2 : min. li enclsoure of 11..100 mcon : 0.3um") +end + +# m1 +huge_m1 = m1.sized(-1.5).sized(1.5) +m1.width(0.14, euclidian).output("m1.1", "m1.1 : min. m1 width : 0.14um") +m1.isolated(0.14, euclidian).output("m1.2", "m1.2 : min. m1 spacing : 0.14um") +huge_m1.separation(m1, 0.28, euclidian).output("m1.3ab", "m1.3ab : min. 3um.m1 spacing m1 : 0.28um") +not_in_cell6 = layout(source.cell_obj).select("-s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b", "-s8fpls_pl8", "-s8fs_cmux4_fm") +not_in_cell6_m1 = not_in_cell6.input(68, 20) +not_in_cell6_m1.enclosing(mcon, 0.03, euclidian).output("m1.4", "m1.4 : min. m1 enclosure of mcon : 0.03um") +in_cell6 = layout(source.cell_obj).select("+s8cell_ee_plus_sseln_a", "+s8cell_ee_plus_sseln_b", "+s8cell_ee_plus_sselp_a", "+s8cell_ee_plus_sselp_b", "+s8fpls_pl8", "+s8fs_cmux4_fm") +in_cell6_m1 = in_cell6.input(68, 20) +in_cell6_m1.enclosing(mcon, 0.005, euclidian).output("m1.4a", "m1.4a : min. m1 enclosure of mcon for specific cells : 0.005um") +m1.with_area(0..0.083).output("m1.6", "m1.6 : min. m1 area : 0.083um²") +m1.holes.with_area(0..0.14).output("m1.7", "m1.7 : min. m1 holes area : 0.14um²") +if backend_flow = AL + mcon06 = mcon.interacting(poly.enclosing(m1, 0.06, euclidian).polygons) + mcon_edges_with_less_enclosure_m1 = m1.enclosing(mcon, 0.06, projection).second_edges + opposite4 = (mcon.edges - mcon_edges_with_less_enclosure_m1).width(0.17 + 1.dbu, projection).polygons + mcon06.not_interacting(opposite4).output("m1.5", "m1.5 : min. m1 enclosure of mcon of 2 opposite edges : 0.06um") + # rule m1.pd.1, rule m1.pd.2a, rule m1.pd.2b not coded +end +if bakend_flow = CU + m1.sized(-2.0).sized(2.0).output("m1.11", "m1.11 : max. m1 width after slotting : 4.0um") + # rule m1.12 not coded because inconsistent with m1.11 + # rule m1.13, m1.14, m1.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +end + +# via +#rule via.3 not coded +via.not(m1).output("via.4c.5c", "via.4c.5c : m1 must enclose all via") +if backend_flow = AL + via.not(areaid_mt).edges.without_length(0.15).output("via.1a", "via.1a : minimum/maximum width of via : 0.15um") + via.and(areaid_mt).not_interacting((via.and(areaid_mt).edges.without_length(0.15)).or(via.and(areaid_mt).edges.without_length(0.23)).or(via.and(areaid_mt).edges.without_length(0.28))).output("via.1b", "via.1b : minimum/maximum width of via in areaid.mt: 0.15um or 0.23um or 0.28um") + via.isolated(0.17, euclidian).output("via.2", "via.2 : min. via spacing : 0.17um") + m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.055, euclidian).output("via.4a", "via.4a : min. m1 enclosure of 0.15um via : 0.055um") + m1.enclosing(via.not_interacting(via.edges.without_length(0.23)), 0.03, euclidian).output("via.4b", "via.4b : min. m1 enclosure of 0.23um via : 0.03um") + via1_edges_with_less_enclosure_m1 = m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.085, projection).second_edges + opposite5 = (via.not_interacting(via.edges.without_length(0.15)).edges - via1_edges_with_less_enclosure_m1).width(0.15 + 1.dbu, projection).polygons + via.not_interacting(via.edges.without_length(0.15)).not_interacting(opposite5).output("via1.5a", "via1.5a : min. m1 enclosure of 0.15um via of 2 opposite edges : 0.085um") + via2_edges_with_less_enclosure_m1 = m1.enclosing(via.not_interacting(via.edges.without_length(0.23)), 0.06, projection).second_edges + opposite6 = (via.not_interacting(via.edges.without_length(0.23)).edges - via2_edges_with_less_enclosure_m1).width(0.23 + 1.dbu, projection).polygons + via.not_interacting(via.edges.without_length(0.23)).not_interacting(opposite6).output("via1.5b", "via1.5b : min. m1 enclosure of 0.23um via of 2 opposite edges : 0.06um") +end +if backend_flow = CU + via.not(areaid_mt).edges.without_length(0.18).output("via.11", "via.11 : minimum/maximum width of via : 0.18um") + via.isolated(0.13, euclidian).output("via.12", "via.12 : min. via spacing : 0.13um") + # rule via.13 not coded because not understandable + via1_edges_with_less_enclosure_m1 = m1.enclosing(via, 0.04, projection).second_edges + opposite5 = (via.edges - via1_edges_with_less_enclosure_m1).width(0.18 + 1.dbu, projection).polygons + via.not_interacting(opposite5).output("via1.14", "via1.14 : min. m1 enclosure of 0.04um via of 2 opposite edges : 0.04um") + # rules via.irdrop.1, via.irdrop.2, via.irdrop.3, via.irdrop.4 not coded because not understandable +end + +# m2 +huge_m2 = m2.sized(-1.5).sized(1.5) +m2.width(0.14, euclidian).output("m2.1", "m2.1 : min. m2 width : 0.14um") +m2.isolated(0.14, euclidian).output("m2.2", "m2.2 : min. m2 spacing : 0.14um") +huge_m2.separation(m2, 0.28, euclidian).output("m2.3ab", "m2.3ab : min. 3um.m2 spacing m2 : 0.28um") +# rule m2.3c not coded +m2.with_area(0..0.0676).output("m2.6", "m2.6 : min. m2 area : 0.0676um²") +m2.holes.with_area(0..0.14).output("m2.7", "m2.7 : min. m2 holes area : 0.14um²") +via.not(m2).output("m2.via", "m2.via : m2 must enclose via") +if backend_flow = AL + m2.enclosing(via, 0.055, euclidian).output("m2.4", "m2.4 : min. m2 enclosure of via : 0.055um") + via_edges_with_less_enclosure_m2 = m2.enclosing(via, 0.085, projection).second_edges + opposite7 = (via.edges - via_edges_with_less_enclosure_m2).width(0.2 + 1.dbu, projection).polygons + via.not_interacting(opposite7).output("m2.5", "m2.5 : min. m2 enclosure of via of 2 opposite edges : 0.085um") + # rule m2.pd.1, rule m2.pd.2a, rule m2.pd.2b not coded +end +if bakend_flow = CU + m2.sized(-2.0).sized(2.0).output("m2.11", "m2.11 : max. m2 width after slotting : 4.0um") + # rule m2.12 not coded because inconsistent with m2.11 + # rule m2.13, m2.14, m2.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +end + +# via2 +#rule via233 not coded +via2.not(m2).output("via2", "via2 : m2 must enclose all via2") +if backend_flow = AL + via2.not(areaid_mt).edges.without_length(0.2).output("via2.1a", "via2.1a : minimum/maximum width of via2 : 0.2um") + via2.and(areaid_mt).not_interacting((via2.and(areaid_mt).edges.without_length(0.2)).or(via2.and(areaid_mt).edges.without_length(1.2)).or(via2.and(areaid_mt).edges.without_length(1.5))).output("via2.1b", "via2.1b : minimum/maximum width of via2 in areaid.mt: 0.2um or 1.2um or 1.5um") + via2.isolated(0.2, euclidian).output("via2.2", "via2.2 : min. via2 spacing : 0.2um") + m2.enclosing(via2, 0.04, euclidian).output("via2.4", "via2.4 : min. m2 enclosure of via2 : 0.04um") + m2.enclosing(via2.not_interacting(via2.edges.without_length(1.5)), 0.14, euclidian).output("via2.4a", "via2.4a : min. m2 enclosure of 1.5um via2 : 0.14um") + via2_edges_with_less_enclosure_m2 = m2.enclosing(via2, 0.085, projection).second_edges + opposite8 = (via2.edges - via2_edges_with_less_enclosure_m2).width(0.2 + 1.dbu, projection).polygons + via2.not_interacting(opposite8).output("via2.5", "via2.5 : min. m2 enclosure of via2 of 2 opposite edges : 0.085um") +end +if backend_flow = CU + via2.edges.without_length(0.21).output("via2.11", "via2.11 : minimum/maximum width of via2 : 0.21um") + via2.isolated(0.18, euclidian).output("via2.12", "via2.12 : min. via2 spacing : 0.18um") + # rule via2.13 not coded because not understandable, or not clear + m2.enclosing(via2, 0.035, euclidian).output("via2.14", "via2.14 : min. m2 enclosure of via2 : 0.035um") + # rules via2.irdrop.1, via2.irdrop.2, via2.irdrop.3, via2.irdrop.4 not coded because not understandable +end + +# m3 +huge_m3 = m3 - m3.width(3.0, projection).polygons +m3.width(0.3, euclidian).output("m3.1", "m3.1 : min. m3 width : 0.3um") +m3.isolated(0.3, euclidian).output("m3.2", "m3.2 : min. m3 spacing : 0.3um") +huge_m3.separation(m3, 0.4, euclidian).output("m3.3ab", "m3.3ab : min. 3um.m3 spacing m3 : 0.4um") +# rule m3.3c not coded +m3.with_area(0..0.24).output("m3.6", "m3.6 : min. m2 area : 0.24um²") +via2.not(m3).output("m3.via2", "m3.via2 : m3 must enclose via2") +if backend_flow = AL + m3.enclosing(via2, 0.065, euclidian).output("m3.4", "m3.4 : min. m3 enclosure of via2 : 0.065um") + via2_edges_with_less_enclosure_m3 = m3.enclosing(via2, 0.085, projection).second_edges + # m3.5 N/A + # opposite9 = (via2.edges - via2_edges_with_less_enclosure_m3).width(0.3 + 1.dbu, projection).polygons + # via2.not_interacting(opposite9).output("m3.5", "m3.5 : min. m3 enclosure of via2 of 2 opposite edges : 0.085um") + # rule m3.pd.1, rule m3.pd.2a, rule m3.pd.2b not coded +end +if bakend_flow = CU + m3.holes.with_area(0..0.2).output("m3.7", "m3.7 : min. m2 holes area : 0.2um²") + m3.sized(-2.0).sized(2.0).output("m3.11", "m3.11 : max. m3 width after slotting : 4.0um") + # rule m3.12 not coded because inconsistent with m3.11 + # rule m3.13, m3.14, m3.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +end + +# via3 +#rule via3.3 not coded +via3.not(m3).output("via3", "via3 : m3 must enclose all via3") +if backend_flow = AL + via3.not(areaid_mt).edges.without_length(0.2).output("via3.1a", "via3.1a : minimum/maximum width of via3 : 0.2um") + via3.and(areaid_mt).not_interacting((via3.and(areaid_mt).edges.without_length(0.2)).or(via3.and(areaid_mt).edges.without_length(0.8))).output("via3.1a", "via3.1a : minimum/maximum width of via3 in areaid.mt: 0.2um or 0.8um") + via3.isolated(0.2, euclidian).output("via3.2", "via3.2 : min. via3 spacing : 0.2um") + m3.enclosing(via3, 0.06, euclidian).output("via3.4", "via3.4 : min. m3 enclosure of via3 : 0.06um") + via3_edges_with_less_enclosure_m3 = m3.enclosing(via3, 0.09, projection).second_edges + opposite10 = (via3.edges - via3_edges_with_less_enclosure_m3).width(0.2 + 1.dbu, projection).polygons + via3.not_interacting(opposite10).output("via3.5", "via3.5 : min. m2 enclosure of via3 of 2 opposite edges : 0.09um") +end +if backend_flow = CU + via3.edges.without_length(0.21).output("via3.11", "via3.11 : minimum/maximum width of via3 : 0.21um") + via3.isolated(0.18, euclidian).output("via3.12", "via3.12 : min. via3 spacing : 0.18um") + m3.enclosing(via3, 0.055, euclidian).output("via3.13", "via3.13 : min. m3 enclosure of via3 : 0.055um") + # rule via3.14 not coded because not understandable, or not clear + # rules via3.irdrop.1, via3.irdrop.2, via3.irdrop.3, via3.irdrop.4 not coded because not understandable +end + +# nsm +nsm.width(3.0, euclidian).output("nsm.1", "nsm.1 : min. nsm width : 3.0um") +nsm.isolated(4.0, euclidian).output("nsm.2", "nsm.2 : min. nsm spacing : 4.0um") +nsm.enclosing(diff, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of diff : 3.0um") +nsm.enclosing(tap, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of tap : 3.0um") +nsm.enclosing(poly, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of poly : 3.0um") +nsm.enclosing(li, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of li : 3.0um") +nsm.enclosing(m1, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m1 : 3.0um") +nsm.enclosing(m2, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m2 : 3.0um") +nsm.enclosing(m3, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m3 : 3.0um") +nsm.enclosing(m4, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m4 : 3.0um") +nsm.enclosing(m5, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m5 : 3.0um") +nsm.enclosing(cfom, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of cfom : 3.0um") +if backend_flow = AL + nsm.separation(diff, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to diff : 1.0um") + nsm.separation(tap, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to tap : 1.0um") + nsm.separation(poly, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to poly : 1.0um") + nsm.separation(li, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to li : 1.0um") + nsm.separation(m1, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m1 : 1.0um") + nsm.separation(m2, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m2 : 1.0um") + nsm.separation(m3, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m3 : 1.0um") + nsm.separation(m4, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m4 : 1.0um") + nsm.separation(m5, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m5 : 1.0um") + nsm.separation(cfom, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to cfom : 1.0um") +end + +# m4 +huge_m4 = m4.sized(-1.5).sized(1.5) +m4.width(0.3, euclidian).output("m4.1", "m4.1 : min. m4 width : 0.3um") +m4.isolated(0.3, euclidian).output("m4.2", "m4.2 : min. m4 spacing : 0.3um") +m4.with_area(0..0.24).output("m4.4", "m4.4 : min. m2 area : 0.24um²") +huge_m4.separation(m4, 0.4, euclidian).output("m4.5ab", "m4.5ab : min. 3um.m4 spacing m4 : 0.4um") +via3.not(m4).output("m4.via3", "m4.via3 : m4 must enclose via3") +if backend_flow = AL + m4.enclosing(via3, 0.065, euclidian).output("m4.3", "m4.3 : min. m4 enclosure of via3 : 0.065um") + # m4.5 doesn't exist + # via3_edges_with_less_enclosure_m4 = m4.enclosing(via2, 0.085, projection).second_edges + # opposite9 = (via3.edges - via3_edges_with_less_enclosure_m4).width(0.3 + 1.dbu, projection).polygons + # via3.not_interacting(opposite9).output("m4.5", "m4.5 : min. m4 enclosure of via3 of 2 opposite edges : 0.085um") + # rule m4.pd.1, rule m4.pd.2a, rule m4.pd.2b not coded +end +if bakend_flow = CU + m4.holes.with_area(0..0.2).output("m4.7", "m4.7 : min. m2 holes area : 0.2um²") + m4.sized(-5.0).sized(5.0).output("m4.11", "m4.11 : max. m4 width after slotting : 10.0um") + # rule m4.12 not coded because inconsistent with m4.11 + # rule m4.13, m4.14, m4.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 + m4.enclosing(via3, 0.06, euclidian).output("m4.15", "m4.15 : min. m4 enclosure of via3 : 0.06um") +end + +# via4 +via4.edges.without_length(0.8).output("via4.1a", "via4.1a : minimum/maximum width of via4 : 0.8um") +via4.isolated(0.8, euclidian).output("via4.2", "via4.2 : min. via4 spacing : 0.8um") +#rule via4.3 not coded +m4.enclosing(via4, 0.19, euclidian).output("via4.4", "via4.4 : min. m4 enclosure of via4 : 0.19um") +via4.not(m4).output("via4", "via4 : m4 must enclose all via4") +if backend_flow = CU + # rules via4.irdrop.1, via4.irdrop.2, via4.irdrop.3, via4.irdrop.4 not coded because not understandable +end + +# m5 +m5.width(1.6, euclidian).output("m5.1", "m5.1 : min. m5 width : 1.6um") +m5.isolated(1.6, euclidian).output("m5.2", "m5.2 : min. m5 spacing : 1.6um") +via4.not(m5).output("m5.via4", "m5.via4 : m5 must enclose via4") +m5.enclosing(via4, 0.31, euclidian).output("m5.3", "m4.3 : min. m5 enclosure of via4 : 0.31um") + +# pad +pad.isolated(1.27, euclidian).output("pad.2", "pad.2 : min. pad spacing : 1.27um") + +end #BEOL + +if FEOL +info("FEOL section") + +# mf +mf.not_interacting(mf.edges.without_length(0.8)).output("mf.1", "mf.1 : minimum/maximum width of fuse : 0.8um") +mf.not_interacting(mf.edges.without_length(7.2)).output("mf.2", "mf.2 : minimum/maximum length of fuse : 7.2um") +mf.isolated(1.96, euclidian).output("mf.3", "mf.3 : min. fuse center spacing : 2.76um") +# fuses need more clarification on fuse_shield, fuse layers ... + +# hvi +hvi.width(0.6, euclidian).output("hvi.1", "hvi.1 : min. hvi width : 0.6um") +hvi.isolated(0.7, euclidian).output("hvi.2", "hvi.2 : min. hvi spacing, merge if less : 0.7um") +hvi.and(tunm).output("hvi.4", "hvi.4 : hvi must not overlapp tunm") +hvi.and(nwell).separation(nwell, 2.0, euclidian).output("hvnwell.8", "hvnwelli.8 : min. hvnwel spacing to nwell : 2.0") +areaid_hl.not(hvi).output("hvnwel.9", "hvnwell.9 : hvi must overlapp hvnwell") +# rule hvnell.10 not coded +diff.not(psdm.and(diff_rs)).and(hvi).width(0.29, euclidian).output("hvdifftap.14", "hvdifftap.14 : min. diff inside hvi width : 0.29um") +diff.and(psdm.and(diff_rs)).and(hvi).width(0.15, euclidian).output("hvdifftap.14a", "hvdifftap.14a : min. p+diff resistor inside hvi width : 0.15um") +diff.and(hvi).isolated(0.3, euclidian).output("hvdifftap.15a", "hvdifftap.15a : min. diff inside hvi spacing : 0.3um") +diff.and(hvi).and(nsdm).separation(diff.and(hvi).and(psdm), 0.37, euclidian).polygons.without_area(0).output("hvdifftap.15b", "hvdifftap.15b : min. n+diff inside hvi spacing to p+diff inside hvi except abutting: 0.37um") +tap.and(hvi).edges.and(diff).without_length(0.7).output("hvdifftap.16", "hvdifftap.16 : min. tap inside hvi abuttng diff : 0.7um") +hvi.and(nwell).enclosing(diff, 0.33, euclidian).output("hvdifftap.17", "hvdifftap.17 : min. hvnwell enclosure of p+diff : 0.33um") +hvi.and(nwell).separation(diff, 0.43, euclidian).output("hvdifftap.18", "hvdifftap.18 : min. hvnwell spacing to n+diff : 0.43um") +hvi.and(nwell).enclosing(tap, 0.33, euclidian).output("hvdifftap.19", "hvdifftap.19 : min. hvnwell enclosure of n+tap : 0.33um") +hvi.and(nwell).separation(tap, 0.43, euclidian).output("hvdifftap.20", "hvdifftap.20 : min. hvnwell spacing to p+tap : 0.43um") +hvi.and(diff).edges.not(diff.edges).output("hvdifftap.21", "hvdifftap.21 : diff must not straddle hvi") +hvi.and(tap).edges.not(tap.edges).output("hvdifftap.21", "hvdifftap.21 : tap must not straddle hvi") +hvi.enclosing(difftap, 0.18, euclidian).output("hvdifftap.22", "hvdifftap.22 : min. hvi enclosure of diff or tap : 0.18um") +hvi.separation(difftap, 0.18, euclidian).output("hvdifftap.23", "hvdifftap.23 : min. hvi spacing to diff or tap : 0.18um") +hvi.and(diff).not(nwell).separation(nwell, 0.43, euclidian).output("hvdifftap.24", "hvdifftap.24 : min. hv n+diff spacing to nwell : 0.43um") +diff.and(hvi).not(nwell).isolated(1.07, euclidian).polygons.and(tap).output("hvdifftap.25", "hvdifftap.25 : min. n+diff inside hvi spacing accros p+tap : 1.07um") +diff.not(poly).edges.and(gate.and(hvi).edges).space(0.35, euclidian).output("hvpoly.13", "hvpoly.13: min. hvi gate length : 0.5um") +hvi.and(poly).edges.not(poly.edges).output("hvpoly.14", "hvpoly.14 : poly must not straddle hvi") + +# hvntm +hvntm.width(0.7, euclidian).output("hvntm.1", "hvntm.1 : min. hvntm width : 0.7um") +hvntm.isolated(0.7, euclidian).output("hvntm.2", "hvntm.2 : min. hvntm spacing : 0.7um") +hvntm.enclosing(diff.and(nwell).and(hvi), 0.185, euclidian).output("hvntm.3", "hvntm.3 : min. hvntm enclosure of hv n+diff : 0.185um") +hvntm.separation(diff.not(nwell).not(hvi), 0.185, euclidian).output("hvntm.4", "hvntm.4 : min. hvntm spacing to n+diff : 0.185um") +hvntm.separation(diff.and(nwell).not(hvi), 0.185, euclidian).output("hvntm.5", "hvntm.5 : min. hvntm spacing to p+diff : 0.185um") +hvntm.separation(tap.not(nwell).not(hvi), 0.185, euclidian).polygons.without_area(0).output("hvntm.6a", "hvntm.6a : min. hvntm spacing to p+tap : 0.185um") +hvntm.and(areaid_ce).output("hvntm.9", "hvntm.9 : hvntm must not overlapp areaid.ce") + +# denmos +poly.not_interacting(pwde).interacting(areaid_en).width(1.055, projection).output("denmos.1", "denmos.1 : min. de_nfet gate width : 1.055um") +diff.not_interacting(pwde).enclosing(poly.interacting(areaid_en), 0.28, projection).polygons.without_area(0).output("denmos.2", "denmos.2 : min. de_nfet source ouside poly width : 0.28um") +diff.not_interacting(pwde).and(poly.interacting(areaid_en)).width(0.925, projection).output("denmos.3", "denmos.3 : min. de_nfet source inside poly width : 0.925um") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).width(0.17, euclidian).output("denmos.4", "denmos.4 : min. de_nfet drain width : 0.17um") +nwell.not_interacting(pwde).and(poly.interacting(areaid_en)).width(0.225, projection).polygons.or(nwell.and(poly.interacting(areaid_en)).sized(-0.1125).sized(0.1125)).output("denmos.5", "denmos.5 : min. de_nfet source inside nwell width : 0.225m") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).separation(diff.interacting(poly.interacting(areaid_en)), 1.585, projection).output("denmos.6", "denmos.6 : min. de_nfet source spacing to drain : 1.585um") +nwell.not_interacting(pwde).and(poly.and(diff).interacting(areaid_en)).edges.without_length(5.0, nil).output("denmos.7", "denmos.7 : min. de_nfet channel width : 5.0um") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("denmos.8", "denmos.8 : 90deg. not allowed for de_nfet drain") +nwell.not_interacting(pwde).interacting(areaid_en).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("denmos.9a", "denmos.9a : 90deg. not allowed for de_nfet nwell") +nwell.not_interacting(pwde).interacting(areaid_en).edges.with_angle(45).without_length(0.607..0.609).output("denmos.9a", "denmos.9a : 45deg. bevels of de_nfet nwell should be 0.43um from corners") +nwell.not_interacting(pwde).interacting(areaid_en).edges.with_angle(135).without_length(0.607..0.609).output("denmos.9a", "denmos.9a : 45deg. bevels of de_nfet nwell should be 0.43um from corners") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(45).without_length(0.7..0.71).output("denmos.9b", "denmos.9b : 45deg. bevels of de_nfet drain should be 0.05um from corners") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(135).without_length(0.7..0.71).output("denmos.9b", "denmos.9b : 45deg. bevels of de_nfet drain should be 0.05um from corners") +nwell.not_interacting(pwde).enclosing(diff.interacting(areaid_en).not_interacting(poly), 0.66, euclidian).output("denmos.10", "denmos.10 : min. nwell enclosure of de_nfet drain : 0.66um") +nwell.not_interacting(pwde).interacting(areaid_en).separation(tap.not(nwell), 0.86, euclidian).output("denmos.11", "denmos.11 : min. de_nfet nwell spacing to tap : 0.86um") +nwell.not_interacting(pwde).interacting(areaid_en).isolated(2.4, euclidian).output("denmos.12", "denmos.12 : min. de_nfet nwell : 2.4um") +nsdm.not_interacting(pwde).enclosing(diff.interacting(areaid_en).interacting(poly), 0.13, euclidian).output("denmos.13", "denmos.13 : min. nsdm enclosure of de_nfet source : 0.13um") + +# depmos +poly.interacting(pwde).interacting(areaid_en).width(1.05, projection).output("depmos.1", "depmos.1 : min. de_pfet gate width : 1.05um") +diff.interacting(pwde).enclosing(poly.interacting(areaid_en), 0.28, projection).polygons.without_area(0).output("depmos.2", "depmos.2 : min. de_pfet source ouside poly width : 0.28um") +diff.interacting(pwde).and(poly.interacting(areaid_en)).width(0.92, projection).output("depmos.3", "depmos.3 : min. de_pfet source inside poly width : 0.92um") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).width(0.17, euclidian).output("depmos.4", "depmos.4 : min. de_pfet drain width : 0.17um") +pwde.not(nwell).and(poly.interacting(areaid_en)).width(0.26, projection).polygons.or(pwde.not(nwell).and(poly.interacting(areaid_en)).sized(-0.13).sized(0.13)).output("depmos.5", "depmos.5 : min. de_pfet source inside nwell width : 0.26m") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).separation(diff.interacting(poly.interacting(areaid_en)), 1.19, projection).output("depmos.6", "depmos.6 : min. de_pfet source spacing to drain : 1.19um") +nwell.interacting(pwde).and(poly.and(diff).interacting(areaid_en)).edges.without_length(5.0, nil).output("depmos.7", "depmos.7 : min. de_pfet channel width : 5.0um") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("depmos.8", "depmos.8 : 90deg. not allowed for de_pfet drain") +pwde.not(nwell).interacting(areaid_en).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("depmos.9a", "depmos.9a : 90deg. not allowed for de_pfet pwell") +pwde.not(nwell).interacting(areaid_en).edges.with_angle(45).without_length(0.607..0.609).output("depmos.9a", "depmos.9a : 45deg. bevels of de_pfet pwell should be 0.43um from corners") +pwde.not(nwell).interacting(areaid_en).edges.with_angle(135).without_length(0.607..0.609).output("depmos.9a", "depmos.9a : 45deg. bevels of de_pfet pwell should be 0.43um from corners") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(45).without_length(0.7..0.71).output("depmos.9b", "depmos.9b : 45deg. bevels of de_pfet drain should be 0.05um from corners") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(135).without_length(0.7..0.71).output("depmos.9b", "depmos.9b : 45deg. bevels of de_pfet drain should be 0.05um from corners") +nwell.interacting(pwde).separation(diff.interacting(areaid_en).not_interacting(poly), 0.86, euclidian).output("depmos.10", "depmos.10 : min. pwell enclosure of de_pfet drain : 0.86um") +pwde.not(nwell).interacting(areaid_en).separation(tap.and(nwell), 0.66, euclidian).output("depmos.11", "depmos.11 : min. de_pfet pwell spacing to tap : 0.66um") +psdm.interacting(pwde).enclosing(diff.interacting(areaid_en).interacting(poly), 0.13, euclidian).output("depmos.12", "depmos.12 : min. psdm enclosure of de_pfet source : 0.13um") + +# extd +areaid_en.and(difftap).edges.not(difftap.edges).output("extd.1", "extd.1 : difftap must not straddle areaid.en") +difftap.interacting(areaid_en).not(poly).with_area(0).output("extd.2", "extd.2 : poly must not overlapp entirely difftap in areaid.en") +# rules extd.4, extd.5, extd.6, extd.7 not coded because specific to some cells + +# vhvi +# rules vhvi.vhv.1, vhvi.vhv.2, vhvi.vhv.3, vhvi.vhv.4, vhvi.vhv.5, vhvi.vhv.6 not coded +vhvi.width(0.02, euclidian).output("vhvi.1", "vhvi.1 : min. vhvi width : 0.02um") +vhvi.and(areaid_ce).output("vhvi.2", "vhvi.2 : vhvi must not overlap areaid.ce") +vhvi.and(hvi).output("vhvi.3", "vhvi.3 : vhvi must not overlap hvi") +# rules vhvi.4, vhvi.6 not coded +vhvi.and(diff).edges.not(diff.edges).output("vhvi.5", "vhvi.5 : vhvi must not straddle diff") +vhvi.and(tap).edges.not(tap.edges).output("vhvi.5", "vhvi.5 : vhvi must not straddle tap") +vhvi.and(poly).edges.not(poly.edges).output("vhvi.7", "vhvi.7 : vhvi must not straddle poly") + +nwell.and(vhvi).separation(nwell, 2.5, euclidian).output("hv.nwell.1", "hv.nwell.1 : min. vhvi nwell spacing to nwell : 2.5um") +diff.and(vhvi).isolated(0.3, euclidian).output("hv.diff.1", "hv.diff.1 : min. vhvi diff spacing : 0.3um") +nwell.interacting(diff.and(vhvi)).separation(diff.not(nwell), 0.43, euclidian).output("hv.diff.2", "hv.diff.2 : min. vhvi nwell spacing n+diff : 0.43um") +diff.and(vhvi).not(nwell).separation(nwell, 0.55, euclidian).output("hv.diff.3a", "hv.diff.3a : min. vhvi n+diff spacing nwell : 0.55um") +# rule hv.diff.3b not coded +poly.and(vhvi).not(diff).separation(diff, 0.3, euclidian).polygons.without_area(0).output("hv.poly.2", "hv.poly.2 : min. vhvi poly spacing to diff : 0.3um") +poly.and(vhvi).not(diff).separation(nwell, 0.55, euclidian).polygons.without_area(0).output("hv.poly.3", "hv.poly.3 : min. vhvi poly spacing to nwell : 0.55um") +nwell.enclosing(poly.and(vhvi).not(diff), 0.3, euclidian).polygons.without_area(0).output("hv.poly.4", "hv.poly.4 : min. nwell enclosure of vhvi poly : 0.3um") +#poly.and(vhvi).enclosing(diff.interacting(areaid_en), 0.16, projection).polygons.without_area(0).output("hv.poly.6", "hv.poly.6 : min. poly enclosure of hvfet gate : 0.16um") +# rule hv.poly.7 not coded + +# uhvi +uhvi.and(diff).edges.not(diff.edges).output("uhvi.1", "uhvi.1 : diff must not straddle uhvi") +uhvi.and(tap).edges.not(tap.edges).output("uhvi.1", "uhvi.1 : tap must not straddle uhvi") +uhvi.and(poly).edges.not(poly.edges).output("uhvi.2", "uhvi.2 : poly must not straddle uhvi") +pwbm.not(uhvi).output("uhvi.3", "uhvi.3 : uhvi must not enclose pwbm") +uhvi.and(dnwell).edges.not(dnwell.edges).output("uhvi.4", "uhvi.4 : dnwell must not straddle uhvi") +areaid_en20.not(uhvi).output("uhvi.5", "uhvi.5 : uhvi must not enclose areaid.en20") +#dnwell.not(uhvi).output("uhvi.6", "uhvi.6 : uhvi must not enclose dnwell") +natfet.not(uhvi).output("uhvi.7", "uhvi.7 : uhvi must not enclose natfet") + +# pwell_res +pwell_rs.width(2.65).output("pwres.2", "pwres.2 : min. pwell resistor width : 2.65um") +pwell_rs.sized(-2.65).sized(2.65).output("pwres.2", "pwres.2 : max. pwell resistor width : 2.65um") +pwell_rs.interacting(pwell_rs.edges.with_length(2.651,26.499)).output("pwres.3", "pwres.3 : min. pwell resistor length : 26.5um") +pwell_rs.interacting(pwell_rs.edges.with_length(265.0, nil)).output("pwres.4", "pwres.4 : max. pwell resistor length : 265um") +tap.interacting(pwell_rs).separation(nwell, 0.22, euclidian).output("pwres.5", "pwres.5 : min. pwell resistor tap spacing to nwell : 0.22um") +tap.interacting(pwell_rs).and(tap.sized(0.22).and(nwell)).output("pwres.5", "pwres.5 : max. pwell resistor tap spacing to nwell : 0.22um") +tap.interacting(pwell_rs).width(0.53).output("pwres.6", "pwres.6 : min. width of tap inside pwell resistor : 0.53um") +tap.interacting(pwell_rs).sized(-0.265).sized(0.265).output("pwres.6", "pwres.6 : max. width of tap inside pwell resistor : 0.53um") +# rules pwres.7a, pwres.7b not coded +pwell_rs.and(diff).output("pwres.8", "pwres.8 : diff not allowed inside pwell resistor") +pwell_rs.and(poly).output("pwres.8", "pwres.8 : poly not allowed inside pwell resistor") +# rules pwres.9, pwres.10 not coded + +# rf_diode +areaid_re.with_angle(0 .. 90).output("rfdiode.1", "rfdiode.1 : non 90 degree angle areaid.re") +areaid_re.not(nwell).or(nwell.interacting(areaid_re).not(areaid_re)).output("rfdiode.2", "rfdiode.2 : areaid.re must coincide rf nwell diode") +# rule rfdiode.3 not coded + +end #FEOL + +if OFFGRID +info("OFFGRID-ANGLES section") + +dnwell.ongrid(0.005).output("dnwell_OFFGRID", "x.1b : OFFGRID vertex on dnwell") +dnwell.with_angle(0 .. 45).output("dnwell_angle", "x.3a : non 45 degree angle dnwell") +nwell.ongrid(0.005).output("nwell_OFFGRID", "x.1b : OFFGRID vertex on nwell") +nwell.with_angle(0 .. 45).output("nwell_angle", "x.3a : non 45 degree angle nwell") +pwbm.ongrid(0.005).output("pwbm_OFFGRID", "x.1b : OFFGRID vertex on pwbm") +pwbm.with_angle(0 .. 45).output("pwbm_angle", "x.3a : non 45 degree angle pwbm") +pwde.ongrid(0.005).output("pwde_OFFGRID", "x.1b : OFFGRID vertex on pwde") +pwde.with_angle(0 .. 45).output("pwde_angle", "x.3a : non 45 degree angle pwde") +hvtp.ongrid(0.005).output("hvtp_OFFGRID", "x.1b : OFFGRID vertex on hvtp") +hvtp.with_angle(0 .. 45).output("hvtp_angle", "x.3a : non 45 degree angle hvtp") +hvtr.ongrid(0.005).output("hvtr_OFFGRID", "x.1b : OFFGRID vertex on hvtr") +hvtr.with_angle(0 .. 45).output("hvtr_angle", "x.3a : non 45 degree angle hvtr") +lvtn.ongrid(0.005).output("lvtn_OFFGRID", "x.1b : OFFGRID vertex on lvtn") +lvtn.with_angle(0 .. 45).output("lvtn_angle", "x.3a : non 45 degree angle lvtn") +ncm.ongrid(0.005).output("ncm_OFFGRID", "x.1b : OFFGRID vertex on ncm") +ncm.with_angle(0 .. 45).output("ncm_angle", "x.3a : non 45 degree angle ncm") +diff.ongrid(0.005).output("diff_OFFGRID", "x.1b : OFFGRID vertex on diff") +tap.ongrid(0.005).output("tap_OFFGRID", "x.1b : OFFGRID vertex on tap") +diff.not(areaid_en.and(uhvi)).with_angle(0 .. 90).output("diff_angle", "x.2 : non 90 degree angle diff") +diff.and(areaid_en.and(uhvi)).with_angle(0 .. 45).output("diff_angle", "x.2c : non 45 degree angle diff") +tap.not(areaid_en.and(uhvi)).with_angle(0 .. 90).output("tap_angle", "x.2 : non 90 degree angle tap") +tap.and(areaid_en.and(uhvi)).with_angle(0 .. 45).output("tap_angle", "x.2c : non 45 degree angle tap") +tunm.ongrid(0.005).output("tunm_OFFGRID", "x.1b : OFFGRID vertex on tunm") +tunm.with_angle(0 .. 45).output("tunm_angle", "x.3a : non 45 degree angle tunm") +poly.ongrid(0.005).output("poly_OFFGRID", "x.1b : OFFGRID vertex on poly") +poly.with_angle(0 .. 90).output("poly_angle", "x.2 : non 90 degree angle poly") +rpm.ongrid(0.005).output("rpm_OFFGRID", "x.1b : OFFGRID vertex on rpm") +rpm.with_angle(0 .. 45).output("rpm_angle", "x.3a : non 45 degree angle rpm") +npc.ongrid(0.005).output("npc_OFFGRID", "x.1b : OFFGRID vertex on npc") +npc.with_angle(0 .. 45).output("npc_angle", "x.3a : non 45 degree angle npc") +nsdm.ongrid(0.005).output("nsdm_OFFGRID", "x.1b : OFFGRID vertex on nsdm") +nsdm.with_angle(0 .. 45).output("nsdm_angle", "x.3a : non 45 degree angle nsdm") +psdm.ongrid(0.005).output("psdm_OFFGRID", "x.1b : OFFGRID vertex on psdm") +psdm.with_angle(0 .. 45).output("psdm_angle", "x.3a : non 45 degree angle psdm") +licon.ongrid(0.005).output("licon_OFFGRID", "x.1b : OFFGRID vertex on licon") +licon.with_angle(0 .. 90).output("licon_angle", "x.2 : non 90 degree angle licon") +li.ongrid(0.005).output("li_OFFGRID", "x.1b : OFFGRID vertex on li") +li.with_angle(0 .. 45).output("li_angle", "x.3a : non 45 degree angle li") +mcon.ongrid(0.005).output("ct_OFFGRID", "x.1b : OFFGRID vertex on mcon") +mcon.with_angle(0 .. 90).output("ct_angle", "x.2 : non 90 degree angle mcon") +vpp.ongrid(0.005).output("vpp_OFFGRID", "x.1b : OFFGRID vertex on vpp") +vpp.with_angle(0 .. 45).output("vpp_angle", "x.3a : non 45 degree angle vpp") +m1.ongrid(0.005).output("m1_OFFGRID", "x.1b : OFFGRID vertex on m1") +m1.with_angle(0 .. 45).output("m1_angle", "x.3a : non 45 degree angle m1") +via.ongrid(0.005).output("via_OFFGRID", "x.1b : OFFGRID vertex on via") +via.with_angle(0 .. 90).output("via_angle", "x.2 : non 90 degree angle via") +m2.ongrid(0.005).output("m2_OFFGRID", "x.1b : OFFGRID vertex on m2") +m2.with_angle(0 .. 45).output("m2_angle", "x.3a : non 45 degree angle m2") +via2.ongrid(0.005).output("via2_OFFGRID", "x.1b : OFFGRID vertex on via2") +via2.with_angle(0 .. 90).output("via2_angle", "x.2 : non 90 degree angle via2") +m3.ongrid(0.005).output("m3_OFFGRID", "x.1b : OFFGRID vertex on m3") +m3.with_angle(0 .. 45).output("m3_angle", "x.3a : non 45 degree angle m3") +via3.ongrid(0.005).output("via3_OFFGRID", "x.1b : OFFGRID vertex on via3") +via3.with_angle(0 .. 90).output("via3_angle", "x.2 : non 90 degree angle via3") +nsm.ongrid(0.005).output("nsm_OFFGRID", "x.1b : OFFGRID vertex on nsm") +nsm.with_angle(0 .. 45).output("nsm_angle", "x.3a : non 45 degree angle nsm") +m4.ongrid(0.005).output("m4_OFFGRID", "x.1b : OFFGRID vertex on m4") +m4.with_angle(0 .. 45).output("m4_angle", "x.3a : non 45 degree angle m4") +via4.ongrid(0.005).output("via4_OFFGRID", "x.1b : OFFGRID vertex on via4") +via4.with_angle(0 .. 90).output("via4_angle", "x.2 : non 90 degree angle via4") +m5.ongrid(0.005).output("m5_OFFGRID", "x.1b : OFFGRID vertex on m5") +m5.with_angle(0 .. 45).output("m5_angle", "x.3a : non 45 degree angle m5") +pad.ongrid(0.005).output("pad_OFFGRID", "x.1b : OFFGRID vertex on pad") +pad.with_angle(0 .. 45).output("pad_angle", "x.3a : non 45 degree angle pad") +mf.ongrid(0.005).output("mf_OFFGRID", "x.1b : OFFGRID vertex on mf") +mf.with_angle(0 .. 90).output("mf_angle", "x.2 : non 90 degree angle mf") +hvi.ongrid(0.005).output("hvi_OFFGRID", "x.1b : OFFGRID vertex on hvi") +hvi.with_angle(0 .. 45).output("hvi_angle", "x.3a : non 45 degree angle hvi") +hvntm.ongrid(0.005).output("hvntm_OFFGRID", "x.1b : OFFGRID vertex on hvntm") +hvntm.with_angle(0 .. 45).output("hvntm_angle", "x.3a : non 45 degree angle hvntm") +vhvi.ongrid(0.005).output("vhvi_OFFGRID", "x.1b : OFFGRID vertex on vhvi") +vhvi.with_angle(0 .. 45).output("vhvi_angle", "x.3a : non 45 degree angle vhvi") +uhvi.ongrid(0.005).output("uhvi_OFFGRID", "x.1b : OFFGRID vertex on uhvi") +uhvi.with_angle(0 .. 45).output("uhvi_angle", "x.3a : non 45 degree angle uhvi") +pwell_rs.ongrid(0.005).output("pwell_rs_OFFGRID", "x.1b : OFFGRID vertex on pwell_rs") +pwell_rs.with_angle(0 .. 45).output("pwell_rs_angle", "x.3a : non 45 degree angle pwell_rs") +areaid_re.ongrid(0.005).output("areaid_re_OFFGRID", "x.1b : OFFGRID vertex on areaid.re") + +end #OFFGRID + diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-eft.lyp b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-eft.lyp new file mode 100755 index 00000000..a2eb105d --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-eft.lyp @@ -0,0 +1,8649 @@ + + + + #ccccd9 + #ccccd9 + 0 + 0 + C7 + C0 + true + true + false + 1 + false + false + 0 + prBoundary.boundary - 235/4 + 235/4@1 + + + #00ffff + #00ffff + 0 + 0 + C21 + C0 + true + true + false + 1 + false + false + 0 + pwell.drawing - 64/44 + 64/44@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C39 + C0 + true + true + false + 1 + false + false + 0 + pwell.pin - 122/16 + 122/16@1 + + + #9900e6 + #9900e6 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + pwell.label - 64/59 + 64/59@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + pwell.res - 64/13 + 64/13@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + pwell.cut - 64/14 + 64/14@1 + + + #ffffff + #96c8ff + 0 + 0 + C39 + C0 + true + true + false + 1 + false + false + 0 + pwelliso.pin - 44/16 + 44/16@1 + + + #9900e6 + #9900e6 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + pwelliso.label - 44/5 + 44/5@1 + + + #00cc66 + #00cc66 + 0 + 0 + C21 + C0 + true + true + false + 1 + false + false + 0 + nwell.drawing - 64/20 + 64/20@1 + + + #ff00ff + #ff00ff + 0 + 0 + C2 + C0 + true + true + false + 1 + false + false + 0 + nwell.net - 84/23 + 84/23@1 + + + #268c6b + #268c6b + 0 + 0 + C37 + C0 + true + true + false + 1 + false + false + 0 + nwell.pin - 64/16 + 64/16@1 + + + #333399 + #333399 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + nwell.label - 64/5 + 64/5@1 + + + #c8ffc8 + #c8ffc8 + 0 + 0 + C48 + C0 + true + true + false + 1 + false + false + 0 + dnwell.drawing - 64/18 + 64/18@1 + + + #00ffff + #00ffff + 0 + 0 + C6 + C0 + true + true + false + 1 + false + false + 0 + vhvi.drawing - 74/21 + 74/21@1 + + + #00ff00 + #00ff00 + 0 + 0 + C35 + C0 + true + true + false + 1 + false + false + 0 + diff.drawing - 65/20 + 65/20@1 + + + #00ff00 + #00ff00 + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + diff.res - 65/13 + 65/13@1 + + + #00ff00 + #00ff00 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + diff.cut - 65/14 + 65/14@1 + + + #268c6b + #268c6b + 0 + 0 + C37 + C0 + false + true + false + 1 + false + false + 0 + diff.pin - 65/16 + 65/16@1 + + + #c8ffc8 + #c8ffc8 + 0 + 0 + C1 + C0 + false + true + false + 1 + false + false + 0 + diff.label - 65/6 + 65/6@1 + + + #00ff00 + #00ff00 + 0 + 0 + C5 + C0 + false + true + false + 1 + false + false + 0 + diff.net - 65/23 + 65/23@1 + + + #00ff00 + #00ff00 + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + diff.boundary - 65/4 + 65/4@1 + + + #9900e6 + #9900e6 + 0 + 0 + C37 + C0 + true + true + false + 1 + false + false + 0 + diff.hv - 65/8 + 65/8@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C35 + C0 + true + true + false + 1 + false + false + 0 + tap.drawing - 65/44 + 65/44@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C6 + C0 + false + true + false + 1 + false + false + 0 + tap.pin - 65/48 + 65/48@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C5 + C0 + false + true + false + 1 + false + false + 0 + tap.net - 65/41 + 65/41@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + tap.boundary - 65/60 + 65/60@1 + + + #fff464 + #fff464 + 0 + 0 + C1 + C0 + false + true + false + 1 + false + false + 0 + tap.label - 65/5 + 65/5@1 + + + #9900e6 + #9900e6 + 0 + 0 + C23 + C0 + true + true + false + 1 + false + false + 0 + psdm.drawing - 94/20 + 94/20@1 + + + #e61f0d + #e61f0d + 0 + 0 + C22 + C0 + true + true + false + 1 + false + false + 0 + nsdm.drawing - 93/44 + 93/44@1 + + + #ff0000 + #ff0000 + 0 + 0 + C42 + C0 + true + true + false + 1 + false + false + 0 + poly.drawing - 66/20 + 66/20@1 + + + #ff8000 + #ff8000 + 0 + 0 + C39 + C0 + true + true + false + 1 + false + false + 0 + poly.pin - 66/16 + 66/16@1 + + + #ff0000 + #ff0000 + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + poly.res - 66/13 + 66/13@1 + + + #ff0000 + #ff0000 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + poly.cut - 66/14 + 66/14@1 + + + #ff0000 + #ff0000 + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + poly.gate - 66/9 + 66/9@1 + + + #ffafaf + #ffafaf + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + poly.label - 66/5 + 66/5@1 + + + #ff0000 + #ff0000 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + poly.boundary - 66/4 + 66/4@1 + + + #ff0000 + #ff0000 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + poly.probe - 66/25 + 66/25@1 + + + #ff0000 + #ff0000 + 0 + 0 + C37 + C0 + true + true + false + 1 + false + false + 0 + poly.short - 66/15 + 66/15@1 + + + #ff0000 + #ff0000 + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + poly.net - 66/23 + 66/23@1 + + + #ff0000 + #ff0000 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + poly.model - 66/83 + 66/83@1 + + + #00cc66 + #00cc66 + 0 + 0 + C51 + C0 + true + true + false + 1 + false + false + 0 + ldntm.drawing - 11/44 + 11/44@1 + + + #96c8ff + #ffffff + 0 + 0 + C15 + C0 + true + true + false + 1 + false + false + 0 + lvtn.drawing - 125/44 + 125/44@1 + + + #ff8000 + #ffffff + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + hvtp.drawing - 78/44 + 78/44@1 + + + #ff0000 + #e61f0d + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + hvtr.drawing - 18/20 + 18/20@1 + + + #9900e6 + #9900e6 + 0 + 0 + C42 + C0 + true + true + false + 1 + false + false + 0 + tunm.drawing - 80/20 + 80/20@1 + + + #ffffcc + #ffffcc + 0 + 0 + C24 + C0 + true + true + false + 1 + false + false + 0 + licon1.drawing - 66/44 + 66/44@1 + + + #ffffcc + #ffffcc + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + licon1.boundary - 66/60 + 66/60@1 + + + #ffe6bf + #c8ffff + 0 + 0 + C6 + C0 + false + true + false + 1 + false + false + 0 + licon1.pin - 66/58 + 66/58@1 + + + #ffffcc + #ffffcc + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + licon1.net - 66/41 + 66/41@1 + + + #bf4026 + #bf4026 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + npc.drawing - 95/20 + 95/20@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + li1.drawing - 67/20 + 67/20@1 + + + #bf4026 + #bf4026 + 0 + 0 + C47 + C0 + true + true + false + 1 + false + false + 0 + li1.pin - 67/16 + 67/16@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + I1 + C0 + false + true + false + 1 + false + false + 0 + li1.res - 67/13 + 67/13@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C1 + C0 + false + true + false + 1 + false + false + 0 + li1.cut - 67/14 + 67/14@1 + + + #bf4026 + #bf4026 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + li1.label - 67/5 + 67/5@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C54 + C0 + true + true + false + 1 + false + false + 0 + li1.net - 67/23 + 67/23@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + li1.boundary - 67/4 + 67/4@1 + + + #bf4026 + #bf4026 + 0 + 0 + C54 + C0 + true + true + false + 1 + false + false + 0 + li1.blockage - 67/10 + 67/10@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C37 + C0 + true + true + false + 1 + false + false + 0 + li1.short - 67/15 + 67/15@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + li1.probe - 67/25 + 67/25@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + mcon.drawing - 67/44 + 67/44@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + mcon.boundary - 67/60 + 67/60@1 + + + #ffffcc + #d9e6ff + 0 + 0 + C6 + C0 + false + true + false + 1 + false + false + 0 + mcon.pin - 67/48 + 67/48@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + mcon.net - 67/41 + 67/41@1 + + + #0000ff + #0000ff + 0 + 0 + C7 + C0 + true + true + false + 1 + false + false + 0 + met1.drawing - 68/20 + 68/20@1 + + + #0000ff + #0000ff + 0 + 0 + I1 + C0 + false + true + false + 1 + false + false + 0 + met1.res - 68/13 + 68/13@1 + + + #0000ff + #0000ff + 0 + 0 + C1 + C0 + false + true + false + 1 + false + false + 0 + met1.cut - 68/14 + 68/14@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C6 + C0 + true + true + false + 1 + false + false + 0 + met1.pin - 68/16 + 68/16@1 + + + #96c8ff + #96c8ff + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + met1.label - 68/5 + 68/5@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + met1.net - 68/23 + 68/23@1 + + + #0000ff + #0000ff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + met1.boundary - 68/4 + 68/4@1 + + + #0000ff + #0000ff + 0 + 0 + C54 + C0 + true + true + false + 1 + false + false + 0 + met1.blockage - 68/10 + 68/10@1 + + + #0000ff + #0000ff + 0 + 0 + C37 + C0 + true + true + false + 1 + false + false + 0 + met1.short - 68/15 + 68/15@1 + + + #0000ff + #0000ff + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + met1.probe - 68/25 + 68/25@1 + + + #0000ff + #0000ff + 0 + 0 + C26 + C0 + false + true + false + 1 + false + false + 0 + met1.option1 - 68/32 + 68/32@1 + + + #0000ff + #0000ff + 0 + 0 + C27 + C0 + false + true + false + 1 + false + false + 0 + met1.option2 - 68/33 + 68/33@1 + + + #0000ff + #0000ff + 0 + 0 + C28 + C0 + false + true + false + 1 + false + false + 0 + met1.option3 - 68/34 + 68/34@1 + + + #0000ff + #0000ff + 0 + 0 + C29 + C0 + false + true + false + 1 + false + false + 0 + met1.option4 - 68/35 + 68/35@1 + + + #0000ff + #0000ff + 0 + 0 + C30 + C0 + false + true + false + 1 + false + false + 0 + met1.option5 - 68/36 + 68/36@1 + + + #0000ff + #0000ff + 0 + 0 + C31 + C0 + false + true + false + 1 + false + false + 0 + met1.option6 - 68/37 + 68/37@1 + + + #0000ff + #0000ff + 0 + 0 + C32 + C0 + false + true + false + 1 + false + false + 0 + met1.option7 - 68/38 + 68/38@1 + + + #0000ff + #0000ff + 0 + 0 + C33 + C0 + false + true + false + 1 + false + false + 0 + met1.option8 - 68/39 + 68/39@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + via.drawing - 68/44 + 68/44@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + via.boundary - 68/60 + 68/60@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + via.net - 68/41 + 68/41@1 + + + #ae7dff + #ae7dff + 0 + 0 + C6 + C0 + false + true + false + 1 + false + false + 0 + via.pin - 68/58 + 68/58@1 + + + #ff00ff + #ff00ff + 0 + 0 + C38 + C0 + true + true + false + 1 + false + false + 0 + met2.drawing - 69/20 + 69/20@1 + + + #ff00ff + #ff00ff + 0 + 0 + I1 + C0 + false + true + false + 1 + false + false + 0 + met2.res - 69/13 + 69/13@1 + + + #ff00ff + #ff00ff + 0 + 0 + C1 + C0 + false + true + false + 1 + false + false + 0 + met2.cut - 69/14 + 69/14@1 + + + #ff00ff + #ff00ff + 0 + 0 + C46 + C0 + true + true + false + 1 + false + false + 0 + met2.pin - 69/16 + 69/16@1 + + + #ffc8ff + #ffc8ff + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + met2.label - 69/5 + 69/5@1 + + + #ff00ff + #ff00ff + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + met2.net - 69/23 + 69/23@1 + + + #ff00ff + #ff00ff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + met2.boundary - 69/4 + 69/4@1 + + + #ff00ff + #ff00ff + 0 + 0 + C54 + C0 + true + true + false + 1 + false + false + 0 + met2.blockage - 69/10 + 69/10@1 + + + #ff00ff + #ff00ff + 0 + 0 + C37 + C0 + true + true + false + 1 + false + false + 0 + met2.short - 69/15 + 69/15@1 + + + #ff00ff + #ff00ff + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + met2.probe - 69/25 + 69/25@1 + + + #ff00ff + #ff00ff + 0 + 0 + C26 + C0 + false + true + false + 1 + false + false + 0 + met2.option1 - 69/32 + 69/32@1 + + + #ff00ff + #ff00ff + 0 + 0 + C27 + C0 + false + true + false + 1 + false + false + 0 + met2.option2 - 69/33 + 69/33@1 + + + #ff00ff + #ff00ff + 0 + 0 + C28 + C0 + false + true + false + 1 + false + false + 0 + met2.option3 - 69/34 + 69/34@1 + + + #ff00ff + #ff00ff + 0 + 0 + C29 + C0 + false + true + false + 1 + false + false + 0 + met2.option4 - 69/35 + 69/35@1 + + + #ff00ff + #ff00ff + 0 + 0 + C30 + C0 + false + true + false + 1 + false + false + 0 + met2.option5 - 69/36 + 69/36@1 + + + #ff00ff + #ff00ff + 0 + 0 + C31 + C0 + false + true + false + 1 + false + false + 0 + met2.option6 - 69/37 + 69/37@1 + + + #ff00ff + #ff00ff + 0 + 0 + C32 + C0 + false + true + false + 1 + false + false + 0 + met2.option7 - 69/38 + 69/38@1 + + + #ff00ff + #ff00ff + 0 + 0 + C33 + C0 + false + true + false + 1 + false + false + 0 + met2.option8 - 69/39 + 69/39@1 + + + #ff8000 + #ff8000 + 0 + 0 + I1 + C7 + true + true + false + 3 + false + false + 0 + via2.drawing - 69/44 + 69/44@1 + + + #ff8000 + #ff8000 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + via2.boundary - 69/60 + 69/60@1 + + + #ff8000 + #ff8000 + 0 + 0 + C6 + C0 + false + true + false + 1 + false + false + 0 + via2.pin - 69/58 + 69/58@1 + + + #ff8000 + #ff8000 + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + via2.net - 69/41 + 69/41@1 + + + #00ffff + #00ffff + 0 + 0 + C50 + C0 + true + true + false + 1 + false + false + 0 + met3.drawing - 70/20 + 70/20@1 + + + #00ffff + #00ffff + 0 + 0 + I1 + C0 + false + true + false + 1 + false + false + 0 + met3.res - 70/13 + 70/13@1 + + + #00ffff + #00ffff + 0 + 0 + C1 + C0 + false + true + false + 1 + false + false + 0 + met3.cut - 70/14 + 70/14@1 + + + #00ffff + #00ffff + 0 + 0 + C35 + C0 + true + true + false + 1 + false + false + 0 + met3.pin - 70/16 + 70/16@1 + + + #c8ffff + #c8ffff + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + met3.label - 70/5 + 70/5@1 + + + #00ffff + #00ffff + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + met3.net - 70/23 + 70/23@1 + + + #00ffff + #00ffff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + met3.boundary - 70/4 + 70/4@1 + + + #00ffff + #00ffff + 0 + 0 + C54 + C0 + true + true + false + 1 + false + false + 0 + met3.blockage - 70/10 + 70/10@1 + + + #00ffff + #00ffff + 0 + 0 + C37 + C0 + true + true + false + 1 + false + false + 0 + met3.short - 70/15 + 70/15@1 + + + #00ffff + #00ffff + 0 + 0 + I1 + C0 + false + true + false + 1 + false + false + 0 + met3.fuse - 70/17 + 70/17@1 + + + #00ffff + #00ffff + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + met3.probe - 70/25 + 70/25@1 + + + #00ffff + #00ffff + 0 + 0 + C26 + C0 + false + true + false + 1 + false + false + 0 + met3.option1 - 70/32 + 70/32@1 + + + #00ffff + #00ffff + 0 + 0 + C27 + C0 + false + true + false + 1 + false + false + 0 + met3.option2 - 70/33 + 70/33@1 + + + #00ffff + #00ffff + 0 + 0 + C28 + C0 + false + true + false + 1 + false + false + 0 + met3.option3 - 70/34 + 70/34@1 + + + #00ffff + #00ffff + 0 + 0 + C29 + C0 + false + true + false + 1 + false + false + 0 + met3.option4 - 70/35 + 70/35@1 + + + #00ffff + #00ffff + 0 + 0 + C30 + C0 + false + true + false + 1 + false + false + 0 + met3.option5 - 70/36 + 70/36@1 + + + #00ffff + #00ffff + 0 + 0 + C31 + C0 + false + true + false + 1 + false + false + 0 + met3.option6 - 70/37 + 70/37@1 + + + #00ffff + #00ffff + 0 + 0 + C32 + C0 + false + true + false + 1 + false + false + 0 + met3.option7 - 70/38 + 70/38@1 + + + #00ffff + #00ffff + 0 + 0 + C33 + C0 + false + true + false + 1 + false + false + 0 + met3.option8 - 70/39 + 70/39@1 + + + #268c6b + #268c6b + 0 + 0 + I1 + C7 + true + true + false + 3 + false + false + 0 + via3.drawing - 70/44 + 70/44@1 + + + #268c6b + #268c6b + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + via3.boundary - 70/60 + 70/60@1 + + + #268c6b + #268c6b + 0 + 0 + C6 + C0 + false + true + false + 1 + false + false + 0 + via3.pin - 70/48 + 70/48@1 + + + #268c6b + #268c6b + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + via3.net - 70/41 + 70/41@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C15 + C0 + true + true + false + 1 + false + false + 0 + met4.drawing - 71/20 + 71/20@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + I1 + C0 + false + true + false + 1 + false + false + 0 + met4.res - 71/13 + 71/13@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C1 + C0 + false + true + false + 1 + false + false + 0 + met4.cut - 71/14 + 71/14@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C35 + C0 + true + true + false + 1 + false + false + 0 + met4.pin - 71/16 + 71/16@1 + + + #ae7dff + #ae7dff + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + met4.label - 71/5 + 71/5@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + met4.net - 71/23 + 71/23@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + met4.boundary - 71/4 + 71/4@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C54 + C0 + true + true + false + 1 + false + false + 0 + met4.blockage - 71/10 + 71/10@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C37 + C0 + true + true + false + 1 + false + false + 0 + met4.short - 71/15 + 71/15@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + I1 + C0 + false + true + false + 1 + false + false + 0 + met4.fuse - 71/17 + 71/17@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + met4.probe - 71/25 + 71/25@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C26 + C0 + false + true + false + 1 + false + false + 0 + met4.option1 - 71/32 + 71/32@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C27 + C0 + false + true + false + 1 + false + false + 0 + met4.option2 - 71/33 + 71/33@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C28 + C0 + false + true + false + 1 + false + false + 0 + met4.option3 - 71/34 + 71/34@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C29 + C0 + false + true + false + 1 + false + false + 0 + met4.option4 - 71/35 + 71/35@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C30 + C0 + false + true + false + 1 + false + false + 0 + met4.option5 - 71/36 + 71/36@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C31 + C0 + false + true + false + 1 + false + false + 0 + met4.option6 - 71/37 + 71/37@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C32 + C0 + false + true + false + 1 + false + false + 0 + met4.option7 - 71/38 + 71/38@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C33 + C0 + false + true + false + 1 + false + false + 0 + met4.option8 - 71/39 + 71/39@1 + + + #ffff00 + #ffff00 + 0 + 0 + I1 + C7 + true + true + false + 3 + false + false + 0 + via4.drawing - 71/44 + 71/44@1 + + + #ffff00 + #ffff00 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + via4.boundary - 71/60 + 71/60@1 + + + #ffff00 + #ffff00 + 0 + 0 + C6 + C0 + false + true + false + 1 + false + false + 0 + via4.pin - 71/48 + 71/48@1 + + + #ffff00 + #ffff00 + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + via4.net - 71/41 + 71/41@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C43 + C0 + true + true + false + 1 + false + false + 0 + met5.drawing - 72/20 + 72/20@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + I1 + C0 + false + true + false + 1 + false + false + 0 + met5.res - 72/13 + 72/13@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C1 + C0 + false + true + false + 1 + false + false + 0 + met5.cut - 72/14 + 72/14@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C35 + C0 + true + true + false + 1 + false + false + 0 + met5.pin - 72/16 + 72/16@1 + + + #fff464 + #fff464 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + met5.label - 72/5 + 72/5@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + met5.net - 72/23 + 72/23@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + met5.boundary - 72/4 + 72/4@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C54 + C0 + true + true + false + 1 + false + false + 0 + met5.blockage - 72/10 + 72/10@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C37 + C0 + true + true + false + 1 + false + false + 0 + met5.short - 72/15 + 72/15@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + I1 + C0 + false + true + false + 1 + false + false + 0 + met5.fuse - 72/17 + 72/17@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + met5.probe - 72/25 + 72/25@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C26 + C0 + false + true + false + 1 + false + false + 0 + met5.option1 - 72/32 + 72/32@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C27 + C0 + false + true + false + 1 + false + false + 0 + met5.option2 - 72/33 + 72/33@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C28 + C0 + false + true + false + 1 + false + false + 0 + met5.option3 - 72/34 + 72/34@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C29 + C0 + false + true + false + 1 + false + false + 0 + met5.option4 - 72/35 + 72/35@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C30 + C0 + false + true + false + 1 + false + false + 0 + met5.option5 - 72/36 + 72/36@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C31 + C0 + false + true + false + 1 + false + false + 0 + met5.option6 - 72/37 + 72/37@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C32 + C0 + false + true + false + 1 + false + false + 0 + met5.option7 - 72/38 + 72/38@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C33 + C0 + false + true + false + 1 + false + false + 0 + met5.option8 - 72/39 + 72/39@1 + + + #00cc66 + #00cc66 + 0 + 0 + C51 + C0 + true + true + false + 1 + false + false + 0 + nsm.drawing - 61/20 + 61/20@1 + + + #ffffcc + #ffffcc + 0 + 0 + C21 + C0 + true + true + false + 1 + false + false + 0 + pad.drawing - 76/20 + 76/20@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + pad.label - 76/5 + 76/5@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C35 + C0 + true + true + false + 1 + false + false + 0 + pad.pin - 76/16 + 76/16@1 + + + #ff00ff + #ff00ff + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + pnp.drawing - 82/44 + 82/44@1 + + + #ffc8ff + #ffc8ff + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + pnp.label - 82/59 + 82/59@1 + + + #00ffff + #00ffff + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + npn.drawing - 82/20 + 82/20@1 + + + #c8ffff + #c8ffff + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + npn.label - 82/5 + 82/5@1 + + + #ffffff + #96c8ff + 0 + 0 + C39 + C0 + true + true + false + 1 + false + false + 0 + rpm.drawing - 86/20 + 86/20@1 + + + #ffffff + #c896ff + 0 + 0 + C38 + C0 + true + true + false + 1 + false + false + 0 + urpm.drawing - 79/20 + 79/20@1 + + + #9900e6 + #9900e6 + 0 + 0 + C4 + C0 + true + true + false + 1 + false + false + 0 + hvi.drawing - 75/20 + 75/20@1 + + + #ffb232 + #ffb232 + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + capacitor.drawing - 82/64 + 82/64@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + ncm.drawing - 92/44 + 92/44@1 + + + #ff8000 + #ff8000 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + cncm.drawing - 96/44 + 96/44@1 + + + #ff0000 + #ff0000 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + cncm.mask - 17/0 + 17/0@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C21 + C1 + true + true + false + 1 + false + false + 0 + pmm.drawing - 85/44 + 85/44@1 + + + #bf4026 + #bf4026 + 0 + 0 + C41 + C0 + true + true + false + 1 + false + false + 0 + pmm2.drawing - 77/20 + 77/20@1 + + + #e61f0d + #e61f0d + 0 + 0 + C48 + C0 + true + true + false + 1 + false + false + 0 + rdl.drawing - 74/20 + 74/20@1 + + + #e61f0d + #e61f0d + 0 + 0 + C35 + C0 + true + true + false + 1 + false + false + 0 + rdl.pin - 74/16 + 74/16@1 + + + #ff6464 + #ff6464 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + rdl.label - 74/5 + 74/5@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + rdl.res - 74/13 + 74/13@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + rdl.cut - 74/14 + 74/14@1 + + + #e61f0d + #e61f0d + 0 + 0 + C37 + C0 + false + true + false + 1 + false + false + 0 + rdl.short - 74/15 + 74/15@1 + + + #e61f0d + #e61f0d + 0 + 0 + C26 + C0 + false + true + false + 1 + false + false + 0 + rdl.option1 - 89/32 + 89/32@1 + + + #e61f0d + #e61f0d + 0 + 0 + C27 + C0 + false + true + false + 1 + false + false + 0 + rdl.option2 - 89/33 + 89/33@1 + + + #e61f0d + #e61f0d + 0 + 0 + C28 + C0 + false + true + false + 1 + false + false + 0 + rdl.option3 - 89/34 + 89/34@1 + + + #e61f0d + #e61f0d + 0 + 0 + C29 + C0 + false + true + false + 1 + false + false + 0 + rdl.option4 - 89/35 + 89/35@1 + + + #e61f0d + #e61f0d + 0 + 0 + C30 + C0 + false + true + false + 1 + false + false + 0 + rdl.option5 - 89/36 + 89/36@1 + + + #e61f0d + #e61f0d + 0 + 0 + C31 + C0 + false + true + false + 1 + false + false + 0 + rdl.option6 - 89/37 + 89/37@1 + + + #e61f0d + #e61f0d + 0 + 0 + C32 + C0 + false + true + false + 1 + false + false + 0 + rdl.option7 - 89/38 + 89/38@1 + + + #e61f0d + #e61f0d + 0 + 0 + C33 + C0 + false + true + false + 1 + false + false + 0 + rdl.option8 - 89/39 + 89/39@1 + + + #ccccd9 + #333399 + 0 + 0 + C7 + C0 + true + true + false + 1 + false + false + 0 + ubm.drawing - 127/21 + 127/21@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C21 + C0 + true + true + false + 1 + false + false + 0 + bump.drawing - 127/22 + 127/22@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + inductor.drawing - 82/24 + 82/24@1 + + + #fff464 + #fff464 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + inductor.label - 82/25 + 82/25@1 + + + #333399 + #ffffff + 0 + 0 + C26 + C0 + true + true + false + 1 + false + false + 0 + inductor.term1 - 82/26 + 82/26@1 + + + #333399 + #ffffff + 0 + 0 + C27 + C0 + true + true + false + 1 + false + false + 0 + inductor.term2 - 82/27 + 82/27@1 + + + #333399 + #ffffff + 0 + 0 + C28 + C0 + true + true + false + 1 + false + false + 0 + inductor.term3 - 82/28 + 82/28@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C21 + C0 + true + true + false + 1 + false + false + 0 + cfom.drawing - 22/20 + 22/20@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cfom.mask - 23/0 + 23/0@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cfom.fill - 23/28 + 23/28@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + cfom.maskAdd - 22/21 + 22/21@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cfom.maskDrop - 22/22 + 22/22@1 + + + #268c6b + #268c6b + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + cfom.waffleDrop - 22/24 + 22/24@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C21 + C0 + false + true + false + 1 + false + false + 0 + fom.dummy - 22/23 + 22/23@1 + + + #268c6b + #268c6b + 0 + 0 + C21 + C0 + false + true + false + 1 + false + false + 0 + cnwm.drawing - 109/44 + 109/44@1 + + + #268c6b + #268c6b + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cnwm.mask - 21/0 + 21/0@1 + + + #268c6b + #268c6b + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cnwm.maskAdd - 109/43 + 109/43@1 + + + #268c6b + #268c6b + 0 + 0 + C11 + C0 + false + true + false + 1 + false + false + 0 + cnwm.maskDrop - 109/42 + 109/42@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + cdnm.drawing - 110/20 + 110/20@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C17 + C0 + true + true + false + 1 + false + false + 0 + cdnm.mask - 48/0 + 48/0@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + cdnm.maskAdd - 110/21 + 110/21@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C3 + C0 + true + true + false + 1 + false + false + 0 + cdnm.maskDrop - 110/22 + 110/22@1 + + + #96c8ff + #ffffcc + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + clvtnm.drawing - 25/44 + 25/44@1 + + + #96c8ff + #ffffff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + clvtnm.mask - 25/0 + 25/0@1 + + + #96c8ff + #ffffff + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + clvtnm.maskAdd - 25/43 + 25/43@1 + + + #96c8ff + #0000ff + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + clvtnm.maskDrop - 25/42 + 25/42@1 + + + #ff8000 + #ffffcc + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + chvtpm.drawing - 88/44 + 88/44@1 + + + #ff8000 + #ffffff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + chvtpm.mask - 97/0 + 97/0@1 + + + #ff8000 + #ffffff + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + chvtpm.maskAdd - 97/43 + 97/43@1 + + + #ff8000 + #0000ff + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + chvtpm.maskDrop - 97/42 + 97/42@1 + + + #ff0000 + #d9e6ff + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + chvtrm.drawing - 98/44 + 98/44@1 + + + #ff0000 + #e61f0d + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + chvtrm.mask - 98/0 + 98/0@1 + + + #ff0000 + #e61f0d + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + chvtrm.maskAdd - 98/43 + 98/43@1 + + + #ff0000 + #d9e6ff + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + chvtrm.maskDrop - 98/42 + 98/42@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + ctunm.drawing - 96/20 + 96/20@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + ctunm.mask - 20/0 + 20/0@1 + + + #ffffff + #ffffff + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + ctunm.maskAdd - 96/21 + 96/21@1 + + + #ffffff + #ffffff + 0 + 0 + C3 + C0 + true + true + false + 1 + false + false + 0 + ctunm.maskDrop - 96/22 + 96/22@1 + + + #ff0000 + #ff0000 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + conom.drawing - 87/44 + 87/44@1 + + + #ff0000 + #ff0000 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + conom.mask - 88/0 + 88/0@1 + + + #ff0000 + #ff0000 + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + conom.maskAdd - 87/43 + 87/43@1 + + + #ff0000 + #ff0000 + 0 + 0 + C3 + C0 + true + true + false + 1 + false + false + 0 + conom.maskDrop - 87/42 + 87/42@1 + + + #00cc66 + #00cc66 + 0 + 0 + C21 + C0 + true + true + false + 1 + false + false + 0 + cnsdm.drawing - 29/20 + 29/20@1 + + + #00cc66 + #00cc66 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cnsdm.mask - 30/0 + 30/0@1 + + + #00cc66 + #00cc66 + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + cnsdm.maskAdd - 29/21 + 29/21@1 + + + #00cc66 + #00cc66 + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cnsdm.maskDrop - 29/22 + 29/22@1 + + + #ffff00 + #ffff00 + 0 + 0 + C21 + C0 + true + true + false + 1 + false + false + 0 + cpsdm.drawing - 31/20 + 31/20@1 + + + #ffff00 + #ffff00 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cpsdm.mask - 32/0 + 32/0@1 + + + #ffff00 + #ffff00 + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + cpsdm.maskAdd - 31/21 + 31/21@1 + + + #ffff00 + #ffff00 + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cpsdm.maskDrop - 31/22 + 31/22@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C21 + C0 + true + true + false + 1 + false + false + 0 + cntm.drawing - 26/20 + 26/20@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cntm.mask - 27/0 + 27/0@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cntm.maskAdd - 26/21 + 26/21@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C11 + C0 + false + true + false + 1 + false + false + 0 + cntm.maskDrop - 26/22 + 26/22@1 + + + #ffff00 + #ffff00 + 0 + 0 + C21 + C0 + true + true + false + 1 + false + false + 0 + hvntm.drawing - 125/20 + 125/20@1 + + + #fff5e6 + #fff5e6 + 0 + 0 + C21 + C0 + true + true + false + 1 + false + false + 0 + chvntm.drawing - 38/20 + 38/20@1 + + + #fff5e6 + #fff5e6 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + chvntm.mask - 39/0 + 39/0@1 + + + #fff5e6 + #fff5e6 + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + chvntm.maskAdd - 38/21 + 38/21@1 + + + #fff5e6 + #fff5e6 + 0 + 0 + C11 + C0 + false + true + false + 1 + false + false + 0 + chvntm.maskDrop - 38/22 + 38/22@1 + + + #00cc66 + #00cc66 + 0 + 0 + C21 + C0 + false + true + false + 1 + false + false + 0 + cldntm.drawing - 11/20 + 11/20@1 + + + #00cc66 + #00cc66 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cldntm.mask - 11/0 + 11/0@1 + + + #ff8000 + #ff8000 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + clvom.drawing - 45/20 + 45/20@1 + + + #268c6b + #268c6b + 0 + 0 + C17 + C0 + true + true + false + 1 + false + false + 0 + clvom.mask - 46/0 + 46/0@1 + + + #268c6b + #268c6b + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + clvom.maskAdd - 45/21 + 45/21@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + clvom.maskDrop - 45/22 + 45/22@1 + + + #ff8000 + #ff8000 + 0 + 0 + C21 + C0 + false + true + false + 1 + false + false + 0 + cp1m.drawing - 33/44 + 33/44@1 + + + #ff8000 + #ff8000 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cp1m.mask - 28/0 + 28/0@1 + + + #ff8000 + #ff8000 + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cp1m.fill - 28/28 + 28/28@1 + + + #ff8000 + #ff8000 + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + cp1m.maskAdd - 33/43 + 33/43@1 + + + #9900e6 + #9900e6 + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + cp1m.waffleDrop - 33/24 + 33/24@1 + + + #ff8000 + #ff8000 + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cp1m.maskDrop - 33/42 + 33/42@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + cli1m.drawing - 115/44 + 115/44@1 + + + #00ffff + #00ffff + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cli1m.mask - 56/0 + 56/0@1 + + + #00ffff + #00ffff + 0 + 0 + C12 + C0 + true + true + false + 1 + false + false + 0 + cli1m.fill - 56/28 + 56/28@1 + + + #00ffff + #00ffff + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + cli1m.maskAdd - 115/43 + 115/43@1 + + + #00ffff + #00ffff + 0 + 0 + C3 + C0 + true + true + false + 1 + false + false + 0 + cli1m.maskDrop - 115/42 + 115/42@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + clicm1.drawing - 106/44 + 106/44@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + clicm1.mask - 43/0 + 43/0@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + clicm1.maskAdd - 106/43 + 106/43@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C3 + C0 + true + true + false + 1 + false + false + 0 + clicm1.maskDrop - 106/42 + 106/42@1 + + + #0000ff + #0000ff + 0 + 0 + C21 + C0 + false + true + false + 1 + false + false + 0 + cmm1.drawing - 62/20 + 62/20@1 + + + #0000ff + #0000ff + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cmm1.mask - 36/0 + 36/0@1 + + + #0000ff + #0000ff + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cmm1.fill - 36/28 + 36/28@1 + + + #0000ff + #0000ff + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cmm1.maskAdd - 62/21 + 62/21@1 + + + #0000ff + #0000ff + 0 + 0 + C11 + C0 + false + true + false + 1 + false + false + 0 + cmm1.maskDrop - 62/22 + 62/22@1 + + + #0000ff + #0000ff + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + cmm1.waffleDrop - 62/24 + 62/24@1 + + + #ffffcc + #ffffcc + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + cviam.drawing - 105/20 + 105/20@1 + + + #ffffcc + #ffffcc + 0 + 0 + C17 + C0 + true + true + false + 1 + false + false + 0 + cviam.mask - 40/0 + 40/0@1 + + + #ffffcc + #ffffcc + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cviam.maskAdd - 105/21 + 105/21@1 + + + #ffffcc + #ffffcc + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + cviam.maskDrop - 105/22 + 105/22@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C21 + C0 + false + true + false + 1 + false + false + 0 + cmm2.drawing - 105/44 + 105/44@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cmm2.mask - 41/0 + 41/0@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cmm2.fill - 41/28 + 41/28@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cmm2.maskAdd - 105/43 + 105/43@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C11 + C0 + false + true + false + 1 + false + false + 0 + cmm2.maskDrop - 105/42 + 105/42@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + cmm2.waffleDrop - 105/52 + 105/52@1 + + + #333399 + #333399 + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + cviam2.drawing - 108/20 + 108/20@1 + + + #333399 + #333399 + 0 + 0 + C17 + C0 + true + true + false + 1 + false + false + 0 + cviam2.mask - 44/0 + 44/0@1 + + + #333399 + #333399 + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cviam2.maskAdd - 108/21 + 108/21@1 + + + #333399 + #333399 + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + cviam2.maskDrop - 108/22 + 108/22@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C21 + C0 + false + true + false + 1 + false + false + 0 + cmm3.drawing - 107/20 + 107/20@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cmm3.mask - 34/0 + 34/0@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cmm3.fill - 34/28 + 34/28@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cmm3.maskAdd - 107/21 + 107/21@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C11 + C0 + false + true + false + 1 + false + false + 0 + cmm3.maskDrop - 107/22 + 107/22@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + cmm3.waffleDrop - 107/24 + 107/24@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + cnpc.drawing - 44/20 + 44/20@1 + + + #e61f0d + #e61f0d + 0 + 0 + C40 + C0 + true + true + false + 1 + false + false + 0 + cnpc.mask - 49/0 + 49/0@1 + + + #e61f0d + #e61f0d + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cnpc.maskAdd - 44/43 + 44/43@1 + + + #e61f0d + #e61f0d + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + cnpc.maskDrop - 44/42 + 44/42@1 + + + #268c6b + #268c6b + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + cviam3.drawing - 112/20 + 112/20@1 + + + #268c6b + #268c6b + 0 + 0 + C17 + C0 + true + true + false + 1 + false + false + 0 + cviam3.mask - 50/0 + 50/0@1 + + + #268c6b + #268c6b + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cviam3.maskAdd - 112/21 + 112/21@1 + + + #268c6b + #268c6b + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + cviam3.maskDrop - 112/22 + 112/22@1 + + + #00cc66 + #00cc66 + 0 + 0 + C21 + C0 + true + true + false + 1 + false + false + 0 + cnsm.mask - 22/0 + 22/0@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C21 + C0 + false + true + false + 1 + false + false + 0 + cpdm.drawing - 104/44 + 104/44@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cpdm.mask - 37/0 + 37/0@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cpdm.maskAdd - 104/43 + 104/43@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C11 + C0 + false + true + false + 1 + false + false + 0 + cpdm.maskDrop - 104/42 + 104/42@1 + + + #8c8ca6 + #0000ff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + cpmm.drawing - 91/44 + 91/44@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cpbo.mask - 99/0 + 99/0@1 + + + #00cc66 + #00cc66 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cmm4.mask - 51/0 + 51/0@1 + + + #00cc66 + #00cc66 + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cmm4.fill - 51/28 + 51/28@1 + + + #00cc66 + #00cc66 + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + cmm4.maskAdd - 112/43 + 112/43@1 + + + #00cc66 + #00cc66 + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cmm4.maskDrop - 112/42 + 112/42@1 + + + #00cc66 + #00cc66 + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + cmm4.waffleDrop - 112/4 + 112/4@1 + + + #00ffff + #00ffff + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + cviam4.drawing - 117/20 + 117/20@1 + + + #00ffff + #00ffff + 0 + 0 + C17 + C0 + true + true + false + 1 + false + false + 0 + cviam4.mask - 58/0 + 58/0@1 + + + #00ffff + #00ffff + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cviam4.maskAdd - 117/21 + 117/21@1 + + + #00ffff + #00ffff + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + cviam4.maskDrop - 117/22 + 117/22@1 + + + #ff8000 + #ff8000 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cmm5.mask - 59/0 + 59/0@1 + + + #ff8000 + #ff8000 + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cmm5.fill - 59/28 + 59/28@1 + + + #ff8000 + #ff8000 + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + cmm5.waffleDrop - 117/4 + 117/4@1 + + + #0000ff + #0000ff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + target.drawing - 76/44 + 76/44@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + cctm1.drawing - 101/44 + 101/44@1 + + + #ffffff + #ffffff + 0 + 0 + C17 + C0 + true + true + false + 1 + false + false + 0 + cctm1.mask - 35/0 + 35/0@1 + + + #ffffff + #ffffff + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cctm1.maskAdd - 101/43 + 101/43@1 + + + #ffffff + #ffffff + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + cctm1.maskDrop - 101/42 + 101/42@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + crpm.drawing - 53/44 + 53/44@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + crpm.mask - 96/0 + 96/0@1 + + + #ffffff + #ffffff + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + crpm.maskAdd - 53/43 + 53/43@1 + + + #ffffff + #ffffff + 0 + 0 + C3 + C0 + true + true + false + 1 + false + false + 0 + crpm.maskDrop - 53/42 + 53/42@1 + + + #e61f0d + #e61f0d + 0 + 0 + C48 + C0 + false + true + false + 1 + false + false + 0 + ccu1m.mask - 93/0 + 93/0@1 + + + #bf4026 + #bf4026 + 0 + 0 + C41 + C0 + false + true + false + 1 + false + false + 0 + cpmm2.mask - 94/0 + 94/0@1 + + + #ccccd9 + #333399 + 0 + 0 + C7 + C0 + false + true + false + 1 + false + false + 0 + cubm.mask - 100/0 + 100/0@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C21 + C0 + false + true + false + 1 + false + false + 0 + cbump.mask - 101/0 + 101/0@1 + + + #00bfff + #00bfff + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + overlap.drawing - 90/20 + 90/20@1 + + + #ff7f50 + #ff7f50 + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + overlap.boundary - 90/4 + 90/4@1 + + + #ff8000 + #ff8000 + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.lowTapDensity - 81/14 + 81/14@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.notCritSide - 81/15 + 81/15@1 + + + #adff2f + #adff2f + 0 + 0 + C2 + C7 + true + true + false + 3 + false + false + 0 + areaid.injection - 81/17 + 81/17@1 + + + #bebed8 + #bebed8 + 0 + 0 + C2 + C7 + true + true + false + 3 + false + false + 0 + areaid.rfdiode - 81/125 + 81/125@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.seal - 81/1 + 81/1@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.core - 81/2 + 81/2@1 + + + #ffffcc + #ffffcc + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.frame - 81/3 + 81/3@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.esd - 81/19 + 81/19@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.dieCut - 81/11 + 81/11@1 + + + #00ff00 + #00ff00 + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.moduleCut - 81/10 + 81/10@1 + + + #00ffff + #00ffff + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.frameRect - 81/12 + 81/12@1 + + + #333399 + #ccccd9 + 0 + 0 + C23 + C0 + true + true + false + 1 + false + false + 0 + areaid.substrateCut - 81/53 + 81/53@1 + + + #ffff00 + #ffff00 + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.diode - 81/23 + 81/23@1 + + + #ff00ff + #ff00ff + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.standardc - 81/4 + 81/4@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C0 + C5 + true + true + false + 1 + false + false + 0 + areaid.deadZon - 81/50 + 81/50@1 + + + #ff8000 + #ff8000 + 0 + 0 + C0 + C5 + true + true + false + 1 + false + false + 0 + areaid.critCorner - 81/51 + 81/51@1 + + + #ffffcc + #ffffcc + 0 + 0 + C0 + C5 + true + true + false + 1 + false + false + 0 + areaid.critSid - 81/52 + 81/52@1 + + + #8c8ca6 + #c8ffc8 + 0 + 0 + C21 + C7 + true + true + false + 3 + false + false + 0 + areaid.opcDrop - 81/54 + 81/54@1 + + + #00bfff + #00ffe7 + 0 + 0 + C1 + C7 + true + true + false + 3 + false + false + 0 + areaid.waffleWindow - 81/13 + 81/13@1 + + + #daa520 + #daa520 + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.extendedDrain - 81/57 + 81/57@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.lvNative - 81/60 + 81/60@1 + + + #9900e6 + #9900e6 + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.photo - 81/81 + 81/81@1 + + + #ff00ff + #00ff00 + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.etest - 81/101 + 81/101@1 + + + #ff0000 + #ff0000 + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.hvnwell - 81/63 + 81/63@1 + + + #9900e6 + #9900e6 + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.rdlprobepad - 81/27 + 81/27@1 + + + #00bfff + #00bfff + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.sigPadDiff - 81/6 + 81/6@1 + + + #c8ffc8 + #c8ffc8 + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.sigPadWell - 81/7 + 81/7@1 + + + #ff7f50 + #ff7f50 + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.sigPadMetNtr - 81/8 + 81/8@1 + + + #ff6464 + #ff6464 + 0 + 0 + C0 + C7 + true + true + false + 3 + false + false + 0 + areaid.analog - 81/79 + 81/79@1 + + + #0080ff + #0080ff + 0 + 0 + C0 + + true + true + false + + false + false + 0 + text.drawing 83/44@1 + 83/44@1 + + + #008080 + #008080 + 0 + 0 + I9 + + true + true + false + + false + false + 0 + crrpm.mask 102/0@1 + 102/0@1 + + + #ffff00 + #ffffff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + prune.drawing - 84/44 + 84/44@1 + + + #0000ff + #0000ff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + padCenter.drawing - 81/20 + 81/20@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C7 + C0 + true + true + false + 1 + false + false + 0 + met1.psa1 - 68/88 + 68/88@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C38 + C0 + true + true + false + 1 + false + false + 0 + met2.psa1 - 69/88 + 69/88@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C50 + C0 + true + true + false + 1 + false + false + 0 + met3.psa1 - 70/88 + 70/88@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C15 + C0 + true + true + false + 1 + false + false + 0 + met4.psa1 - 71/88 + 71/88@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C43 + C0 + true + true + false + 1 + false + false + 0 + met5.psa1 - 72/88 + 72/88@1 + + + #00ffe7 + #00ffe7 + 0 + 0 + C7 + C0 + true + true + false + 1 + false + false + 0 + met1.psa2 - 68/89 + 68/89@1 + + + #00ffe7 + #00ffe7 + 0 + 0 + C38 + C0 + true + true + false + 1 + false + false + 0 + met2.psa2 - 69/89 + 69/89@1 + + + #00ffe7 + #00ffe7 + 0 + 0 + C50 + C0 + true + true + false + 1 + false + false + 0 + met3.psa2 - 70/89 + 70/89@1 + + + #00ffe7 + #00ffe7 + 0 + 0 + C15 + C0 + true + true + false + 1 + false + false + 0 + met4.psa2 - 71/89 + 71/89@1 + + + #00ffe7 + #00ffe7 + 0 + 0 + C43 + C0 + true + true + false + 1 + false + false + 0 + met5.psa2 - 72/89 + 72/89@1 + + + #ffffcc + #ffffcc + 0 + 0 + C7 + C0 + true + true + false + 1 + false + false + 0 + met1.psa3 - 68/90 + 68/90@1 + + + #ffffcc + #ffffcc + 0 + 0 + C38 + C0 + true + true + false + 1 + false + false + 0 + met2.psa3 - 69/90 + 69/90@1 + + + #ffffcc + #ffffcc + 0 + 0 + C50 + C0 + true + true + false + 1 + false + false + 0 + met3.psa3 - 70/90 + 70/90@1 + + + #ffffcc + #ffffcc + 0 + 0 + C15 + C0 + true + true + false + 1 + false + false + 0 + met4.psa3 - 71/90 + 71/90@1 + + + #ffffcc + #ffffcc + 0 + 0 + C43 + C0 + true + true + false + 1 + false + false + 0 + met5.psa3 - 72/90 + 72/90@1 + + + #802626 + #802626 + 0 + 0 + C7 + C0 + true + true + false + 1 + false + false + 0 + met1.psa4 - 68/91 + 68/91@1 + + + #802626 + #802626 + 0 + 0 + C38 + C0 + true + true + false + 1 + false + false + 0 + met2.psa4 - 69/91 + 69/91@1 + + + #802626 + #802626 + 0 + 0 + C50 + C0 + true + true + false + 1 + false + false + 0 + met3.psa4 - 70/91 + 70/91@1 + + + #802626 + #802626 + 0 + 0 + C15 + C0 + true + true + false + 1 + false + false + 0 + met4.psa4 - 71/91 + 71/91@1 + + + #802626 + #802626 + 0 + 0 + C43 + C0 + true + true + false + 1 + false + false + 0 + met5.psa4 - 72/91 + 72/91@1 + + + #333399 + #333399 + 0 + 0 + C7 + C0 + true + true + false + 1 + false + false + 0 + met1.psa5 - 68/92 + 68/92@1 + + + #333399 + #333399 + 0 + 0 + C38 + C0 + true + true + false + 1 + false + false + 0 + met2.psa5 - 69/92 + 69/92@1 + + + #333399 + #333399 + 0 + 0 + C50 + C0 + true + true + false + 1 + false + false + 0 + met3.psa5 - 70/92 + 70/92@1 + + + #333399 + #333399 + 0 + 0 + C15 + C0 + true + true + false + 1 + false + false + 0 + met4.psa5 - 71/92 + 71/92@1 + + + #333399 + #333399 + 0 + 0 + C43 + C0 + true + true + false + 1 + false + false + 0 + met5.psa5 - 72/92 + 72/92@1 + + + #fa8072 + #fa8072 + 0 + 0 + C7 + C0 + true + true + false + 1 + false + false + 0 + met1.psa6 - 68/93 + 68/93@1 + + + #fa8072 + #fa8072 + 0 + 0 + C38 + C0 + true + true + false + 1 + false + false + 0 + met2.psa6 - 69/93 + 69/93@1 + + + #fa8072 + #fa8072 + 0 + 0 + C50 + C0 + true + true + false + 1 + false + false + 0 + met3.psa6 - 70/93 + 70/93@1 + + + #fa8072 + #fa8072 + 0 + 0 + C15 + C0 + true + true + false + 1 + false + false + 0 + met4.psa6 - 71/93 + 71/93@1 + + + #fa8072 + #fa8072 + 0 + 0 + C43 + C0 + true + true + false + 1 + false + false + 0 + met5.psa6 - 72/93 + 72/93@1 + + + #ff0000 + #ff0000 + 0 + 0 + C10 + C0 + true + true + false + 1 + false + false + 0 + rdl.psa1 - 74/88 + 74/88@1 + + + #0000ff + #0000ff + 0 + 0 + C10 + C0 + true + true + false + 1 + false + false + 0 + rdl.psa2 - 74/89 + 74/89@1 + + + #00cc66 + #00cc66 + 0 + 0 + C10 + C0 + true + true + false + 1 + false + false + 0 + rdl.psa3 - 74/90 + 74/90@1 + + + #ffffff + #ffffff + 0 + 0 + C10 + C0 + true + true + false + 1 + false + false + 0 + rdl.psa4 - 74/91 + 74/91@1 + + + #ffff00 + #ffff00 + 0 + 0 + C10 + C0 + true + true + false + 1 + false + false + 0 + rdl.psa5 - 74/92 + 74/92@1 + + + #bf4026 + #bf4026 + 0 + 0 + C10 + C0 + true + true + false + 1 + false + false + 0 + rdl.psa6 - 74/93 + 74/93@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C21 + C1 + false + true + false + 1 + false + false + 0 + blanking.drawing - 124/40 + 124/40@1 + + + #80a8ff + #80a8ff + 0 + 0 + I5 + + true + true + false + + false + false + 0 + via.label 5/1@1 + 5/1@1 + + + #80a8ff + #80a8ff + 0 + 0 + I9 + + true + true + false + + false + false + 0 + via.blockage 5/3@1 + 5/3@1 + + + #ff0080 + #ff0080 + 0 + 0 + I5 + + true + true + false + + false + false + 0 + via2.blockage 7/3@1 + 7/3@1 + + + #8000ff + #8000ff + 0 + 0 + I9 + + true + true + false + + false + false + 0 + via3.label 9/1@1 + 9/1@1 + + + #8000ff + #8000ff + 0 + 0 + I5 + + true + true + false + + false + false + 0 + via3.blockage 9/3@1 + 9/3@1 + + + #0080ff + #0080ff + 0 + 0 + I9 + + true + true + false + + false + false + 0 + via4.label 11/1@1 + 11/1@1 + + + #0080ff + #0080ff + 0 + 0 + I5 + + true + true + false + + false + false + 0 + via4.blockage 11/3@1 + 11/3@1 + + + #800057 + #800057 + 0 + 0 + I9 + + true + true + false + + false + false + 0 + rdlcon.drawing 13/0@1 + 13/0@1 + + + #0080ff + #0080ff + 0 + 0 + I5 + + true + true + false + + false + false + 0 + marker.error 83/6@1 + 83/6@1 + + + #0080ff + #0080ff + 0 + 0 + I9 + + true + true + false + + false + false + 0 + marker.warning 83/7@1 + 83/7@1 + + + #008080 + #008080 + 0 + 0 + I5 + + true + true + false + + false + false + 0 + rrpm.drawing 102/20@1 + 102/20@1 + + + #80ff8d + #80ff8d + 0 + 0 + C0 + + true + true + false + + false + false + 0 + prBoundary.drawing 235/0@1 + 235/0@1 + + + #ffae00 + #ffae00 + 0 + 0 + C0 + + true + true + false + + false + false + 0 + OUTLINE 236/0@1 + 236/0@1 + + + + + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + + 1 + blank + + + + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + + 2 + solid + + + + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + + 3 + dots + + + + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + + 4 + hLine + + + + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + + 5 + vLine + + + + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + + 6 + cross + + + + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + + 7 + grid + + + + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + + 8 + slash + + + + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + + 9 + backSlash + + + + **......**...... + ..*.......*..... + ...**......**... + .....*.......*.. + ......**......** + *.......*....... + .**......**..... + ...*.......*.... + ....**......**.. + ......*.......*. + *......**......* + .*.......*...... + ..**......**.... + ....*.......*... + .....**......**. + .......*.......* + + 10 + hZigZag + + + + *....*....*..... + *.....*....*.... + .*....*.....*... + ..*....*....*... + ..*.....*....*.. + ...*....*.....*. + ....*....*....*. + ....*.....*....* + *....*....*..... + *.....*....*.... + .*....*.....*... + ..*....*....*... + ..*.....*....*.. + ...*....*.....*. + ....*....*....*. + ....*.....*....* + + 11 + vZigZag + + + + ................ + ................ + ...*****...***** + ...*...*...*...* + ...*...*...*...* + ****...*****...* + ................ + ................ + ................ + ................ + ...*****...***** + ...*...*...*...* + ...*...*...*...* + ****...*****...* + ................ + ................ + + 12 + hCurb + + + + .....*.......*.. + .....*.......*.. + .....*.......*.. + ..****....****.. + ..*.......*..... + ..*.......*..... + ..*.......*..... + ..****....****.. + .....*.......*.. + .....*.......*.. + .....*.......*.. + ..****....****.. + ..*.......*..... + ..*.......*..... + ..*.......*..... + ..****....****.. + + 13 + vCurb + + + + **************** + ..*.......*..... + ..*.......*..... + ..*.......*..... + **************** + ......*.......*. + ......*.......*. + ......*.......*. + **************** + ..*.......*..... + ..*.......*..... + ..*.......*..... + **************** + ......*.......*. + ......*.......*. + ......*.......*. + + 14 + brick + + + + ................ + ..*.......*..... + ..*.......*..... + ..*.......*..... + *****...*****... + ..*.......*..... + ..*.......*..... + ..*.......*..... + ................ + .....*.......*.. + .....*.......*.. + .....*.......*.. + ...*****...***** + .....*.......*.. + .....*.......*.. + .....*.......*.. + + 15 + dagger + + + + ................ + ..*............. + ..*............. + ..*............. + *****........... + ..*............. + ..*............. + ..*............. + ................ + .............*.. + .............*.. + .............*.. + ...........***** + .............*.. + .............*.. + .............*.. + + 16 + sparseDagger + + + + ................ + ..........*..... + ..........*..... + ..........*..... + ........*****... + ..........*..... + ..........*..... + ..........*..... + ................ + .....*.......... + .....*.......... + .....*.......... + ...*****........ + .....*.......... + .....*.......... + .....*.......... + + 17 + sparseDagger2 + + + + ................ + ....*........... + ...*.*.......... + ..*...*......... + .*.....*........ + *********....... + ................ + ................ + ................ + ...........*.... + ..........*.*... + .........*...*.. + ........*.....*. + .......********* + ................ + ................ + + 18 + triangle + + + + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + + 19 + x + + + + ................ + .*.....*.....*.. + ..*...**....*... + ...*.*.*...*.... + ....*..*..*..... + .....*.*.*...... + ......***....... + .......*........ + ......***....... + .....*.*.*...... + ....*..*..*..... + ...*...*...*.... + ..*....*....*... + .*..*******..*.. + ................ + ................ + + 20 + Xone + + + + ................ + .*....**.....*.. + ..*..*..*...*... + ...**....*.*.... + ....*....**..... + .....*...*...... + ......*.*....... + .......*........ + ......*.*....... + .....*...*...... + ....*.....*..... + ...**......*.... + ..*.*.......*... + .*..******...*.. + ................ + ................ + + 21 + Xtwo + + + + ................ + ................ + ......*.......*. + ................ + ................ + ................ + ..*.......*..... + ................ + ................ + ................ + ......*.......*. + ................ + ................ + ................ + ..*.......*..... + ................ + + 22 + spareDots + + + + ................ + ................ + ................ + ................ + ................ + ......*.......*. + ................ + ................ + ................ + ................ + ................ + ................ + ..*.......*..... + ................ + ................ + ................ + + 23 + spareDots21 + + + + ................ + ................ + ......*.......*. + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ..*.......*..... + ................ + ................ + ................ + ................ + ................ + + 24 + spareDots22 + + + + ****....****.... + ****....****.... + ****....****.... + ****....****.... + ....****....**** + ....****....**** + ....****....**** + ....****....**** + ****....****.... + ****....****.... + ****....****.... + ****....****.... + ....****....**** + ....****....**** + ....****....**** + ....****....**** + + 25 + checker + + + + ....****....**** + ....****....**** + ....****....**** + ....****....**** + ****....****.... + ****....****.... + ****....****.... + ****....****.... + ....****....**** + ....****....**** + ....****....**** + ....****....**** + ****....****.... + ****....****.... + ****....****.... + ****....****.... + + 26 + checker2 + + + + ................ + ................ + ................ + ................ + .......*........ + ......**........ + .......*........ + .......*........ + .......*........ + .......*........ + ......***....... + ................ + ................ + ................ + ................ + ................ + + 27 + one + + + + ................ + ................ + ................ + ................ + ................ + .......**....... + ......*..*...... + .........*...... + ........*....... + .......*........ + ......*......... + ......****...... + ................ + ................ + ................ + ................ + + 28 + two + + + + ................ + ................ + ................ + ................ + ................ + ......***....... + .....*...*...... + .........*...... + .......**....... + .........*...... + .....*...*...... + ......***....... + ................ + ................ + ................ + ................ + + 29 + three + + + + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + .............*.. + ............**.. + ...........*.*.. + ..........*..*.. + .........******. + .............*.. + .............*.. + ................ + + 30 + four + + + + ................ + ................ + ................ + ......***....... + .....*.......... + .....*.......... + .....***........ + ........*....... + ........*....... + .....***........ + ................ + ................ + ................ + ................ + ................ + ................ + + 31 + five + + + + ................ + ................ + ................ + ................ + .......***...... + ......*......... + ......*......... + ......****...... + ......*...*..... + ......*...*..... + .......***...... + ................ + ................ + ................ + ................ + ................ + + 32 + six + + + + ................ + ................ + ................ + .....******..... + ..........*..... + .........*...... + .........*...... + ........*....... + ........*....... + .......*........ + ......*......... + .....*.......... + ................ + ................ + ................ + ................ + + 33 + seven + + + + ................ + ................ + ................ + ................ + ......***....... + .....*...*...... + .....*...*...... + ......***....... + .....*...*...... + .....*...*...... + ......***....... + ................ + ................ + ................ + ................ + ................ + + 34 + eight + + + + *..............* + .*............*. + ..*..........*.. + ...*........*... + ....*......*.... + .....*....*..... + ......*..*...... + .......**....... + .......**....... + ......*..*...... + .....*....*..... + ....*......*.... + ...*........*... + ..*..........*.. + .*............*. + *..............* + + 35 + box45 + + + + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + + 36 + gray50 + + + + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + + 37 + gray25 + + + + .*.*.*...*.*.*.. + ................ + ...*...*...*...* + ................ + .*...*.*.*...*.* + ................ + ...*...*...*...* + ................ + .*.*.*...*.*.*.. + ................ + ...*...*...*...* + ................ + .*...*.*.*...*.* + ................ + ...*...*...*...* + ................ + + 38 + snow + + + + ..*.......*..... + ...*.......*.... + ....*.......*... + .....*.......*.. + ......*.......*. + .......*.......* + *.......*....... + .*.......*...... + ..*.......*..... + ...*.......*.... + ....*.......*... + .....*.......*.. + ......*.......*. + .......*.......* + *.......*....... + .*.......*...... + + 39 + backSlash2 + + + + *.....*.*.....*. + .*...*...*...*.. + ..*.*.....*.*... + ...*...*...*...* + ..*.*.....*.*... + .*...*...*...*.. + *.....*.*.....*. + ...*...*...*...* + *.....*.*.....*. + .*...*...*...*.. + ..*.*.....*.*... + ...*...*...*...* + ..*.*.....*.*... + .*...*...*...*.. + *.....*.*.....*. + ...*...*...*...* + + 40 + lattice + + + + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + + 41 + smallChecker + + + + ....*........... + ...*.*.......... + ..*...*......... + .*.....*........ + *.......*....... + .*.......*...... + ..*.......*..... + ...*.......*.... + ....*.......*... + .....*.......*.. + ......*.......*. + .......*.......* + ........*.....*. + .........*...*.. + ..........*.*... + ...........*.... + + 42 + slantBox + + + + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + + 43 + slash2 + + + + ...*.......*.... + ..*.......*..... + .*.......*...... + *.......*....... + .......*.......* + ......*.......*. + .....*.......*.. + ....*.......*... + ...*.......*.... + ..*.......*..... + .*.......*...... + *.......*....... + .......*.......* + ......*.......*. + .....*.......*.. + ....*.......*... + + 44 + bigSlash + + + + ****....****.... + *..*....*..*.... + *..*....*..*.... + ****....****.... + ................ + ................ + ................ + ................ + ****....****.... + *..*....*..*.... + *..*....*..*.... + ****....****.... + ................ + ................ + ................ + ................ + + 45 + boxes + + + + ..**......**.... + .*..*....*..*... + *....*..*....*.. + *....*..*....*.. + .*..*....*..*... + ..**......**.... + ................ + ................ + ..**......**.... + .*..*....*..*... + *....*..*....*.. + *....*..*....*.. + .*..*....*..*... + ..**......**.... + ................ + ................ + + 46 + circles + + + + .**..**..**..**. + ...*...*...*...* + *...*...*...*... + .**..**..**..**. + .**..**..**..**. + *...*...*...*... + ...*...*...*...* + .**..**..**..**. + .**..**..**..**. + ...*...*...*...* + *...*...*...*... + .**..**..**..**. + .**..**..**..**. + *...*...*...*... + ...*...*...*...* + .**..**..**..**. + + 47 + zigzag + + + + ................ + *.*.*.*.*.*.*.*. + ................ + ...*....*....*.. + ................ + *.*.*.*.*.*.*.*. + ................ + ...*....*....*.. + ................ + *.*.*.*.*.*.*.*. + ................ + ...*....*....*.. + ................ + *.*.*.*.*.*.*.*. + ................ + ...*....*....*.. + + 48 + lightMesh + + + + ...............* + ..............*. + .............*.. + ............*... + ...........*.... + ..........*..... + .........*...... + ........*....... + .......*........ + ......*......... + .....*.......... + ....*........... + ...*............ + ..*............. + .*.............. + *............... + + 49 + hugeSlash + + + + *............... + .*.............. + ..*............. + ...*............ + ....*........... + .....*.......... + ......*......... + .......*........ + ........*....... + .........*...... + ..........*..... + ...........*.... + ............*... + .............*.. + ..............*. + ...............* + + 50 + hugeSlash2 + + + + *.........*..... + .....*.......... + ..*.........*... + .......*........ + ....*.........*. + .*.......*...... + ......*......... + ...*.......*.... + ........*....... + .....*.......*.. + *.........*..... + .......*........ + ..*.........*... + .........*...... + ....*.........*. + ...........*.... + + 51 + curve + + + + ....*....*....*. + ..*............. + *.......*....... + .............*.. + .......*........ + ............*... + .....*.......... + ...*.......*.... + *............... + ................ + .........*...... + ................ + ......*........* + ...*............ + *............*.. + ..........*..... + + 52 + curve2 + + + + ...........*.... + ..........*.*... + .........*...*.. + ........*.....*. + .........*...*.. + ..........*.*... + ...........*.... + ................ + ................ + ...*............ + ..*.*........... + .*...*.......... + *.....*......... + .*...*.......... + ..*.*........... + ...*............ + + 53 + diams + + + + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ...*............ + ..*.*........... + .*...*.......... + *.....*......... + .*...*.......... + ..*.*........... + ...*............ + + 54 + sparsediam + + + + .......*.......* + ......*......... + .....*.......... + ................ + ................ + ................ + .*.............. + *............... + .......*.......* + ..............*. + .............*.. + ................ + ................ + ................ + .........*...... + ........*....... + + 55 + rain + + + *** + 1 + solid + + + ****.. + 2 + dashed + + + *.. + 3 + dots + + + ***..*.. + 4 + dashDot + + + **.. + 5 + shortDash + + + ****..**.. + 6 + doubleDash + + + *... + 7 + hidden + + + *** + 8 + thickLine + + diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-fom.lydrc b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-fom.lydrc new file mode 100755 index 00000000..0aee42df --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-fom.lydrc @@ -0,0 +1,78 @@ + + + + + drc + + + + false + false + + true + drc_scripts + tools_menu.drc.end + dsl + drc-dsl-xml + + +source($input) +report("Density Checks", $report) + +verbose(true) + +diff_wildcard = "65/20" +tap_wildcard = "65/44" +fomfill_wildcard = "65,23/28" +fommk_wildcard = "23/0" + +chip_boundary = input(235,4) +pl = polygon_layer +pl.insert(box(0, 0, 700, 700)) +pl & chip_boundary + +if $thr + threads($thr) +else + threads(4) +end + +verbose(true) + +bbox = chip_boundary.bbox + +window_size = 700 + +step_size = 70 + +llx, lly, urx, ury = bbox.left, bbox.bottom, bbox.right, bbox.top + +cnt = 0 +tot = ((urx-window_size-llx) / step_size).ceil() * ((ury-window_size-lly) / step_size ).ceil() +for x in (llx..urx-window_size).step(step_size) + for y in (lly..ury-window_size).step(step_size) + pl = polygon_layer + pl.insert(box(x, y, x+window_size, y+window_size)) + box_within_boundary = pl & chip_boundary + m_area_within_seal = (box_within_boundary & source.touching(box_within_boundary.bbox).polygons(diff_wildcard, tap_wildcard, fomfill_wildcard, fommk_wildcard)).area + m_density = m_area_within_seal / box_within_boundary.area + + cnt = cnt + 1 + # Needed for interfacing with other scripts + # puts does not print to stdout but rather to tty + # which can not be captured in python + system 'echo %d/%d'%[cnt, tot.round] + if m_density < 0.33 + box_within_boundary.output("cfom.pd.1d", "0.33 min FOM pattern density #{box_within_boundary.bbox}") + end + if m_density > 0.57 + box_within_boundary.output("cfom.pd.1e", "0.57 max FOM pattern density #{box_within_boundary.bbox}") + + end + # m_density < 0.33 && box_within_boundary.output("cfom.pd.1d", "0.33 min FOM pattern density") + # m_density > 0.57 && box_within_boundary.output("cfom.pd.1e", "0.57 max FOM pattern density") + end +end + + + diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-fom.lyp b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-fom.lyp new file mode 100755 index 00000000..fd62ac4c --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-fom.lyp @@ -0,0 +1,8377 @@ + + + + #ccccd9 + #ccccd9 + 0 + 0 + C7 + C0 + true + false + false + 1 + false + false + 0 + prBoundary.boundary - 235/4 + 235/4@1 + + + #00ffff + #00ffff + 0 + 0 + C20 + C0 + true + false + false + 1 + false + false + 0 + pwell.drawing - 64/44 + 64/44@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C38 + C0 + true + false + false + 1 + false + false + 0 + pwell.pin - 122/16 + 122/16@1 + + + #9900e6 + #9900e6 + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + pwell.label - 64/59 + 64/59@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + I1 + C0 + true + false + false + 1 + false + false + 0 + pwell.res - 64/13 + 64/13@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + pwell.cut - 64/14 + 64/14@1 + + + #ffffff + #96c8ff + 0 + 0 + C38 + C0 + true + false + false + 1 + false + false + 0 + pwelliso.pin - 44/16 + 44/16@1 + + + #9900e6 + #9900e6 + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + pwelliso.label - 44/5 + 44/5@1 + + + #00cc66 + #00cc66 + 0 + 0 + C20 + C0 + true + false + false + 1 + false + false + 0 + nwell.drawing - 64/20 + 64/20@1 + + + #ff00ff + #ff00ff + 0 + 0 + C2 + C0 + true + false + false + 1 + false + false + 0 + nwell.net - 84/23 + 84/23@1 + + + #268c6b + #268c6b + 0 + 0 + C36 + C0 + true + false + false + 1 + false + false + 0 + nwell.pin - 64/16 + 64/16@1 + + + #333399 + #333399 + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + nwell.label - 64/5 + 64/5@1 + + + #c8ffc8 + #c8ffc8 + 0 + 0 + C47 + C0 + true + false + false + 1 + false + false + 0 + dnwell.drawing - 64/18 + 64/18@1 + + + #00ffff + #00ffff + 0 + 0 + C6 + C0 + true + false + false + 1 + false + false + 0 + vhvi.drawing - 74/21 + 74/21@1 + + + #00ff00 + #00ff00 + 0 + 0 + C34 + C0 + true + true + false + 1 + false + false + 0 + diff.drawing - 65/20 + 65/20@1 + + + #00ff00 + #00ff00 + 0 + 0 + I1 + C0 + true + false + false + 1 + false + false + 0 + diff.res - 65/13 + 65/13@1 + + + #00ff00 + #00ff00 + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + diff.cut - 65/14 + 65/14@1 + + + #268c6b + #268c6b + 0 + 0 + C36 + C0 + false + false + false + 1 + false + false + 0 + diff.pin - 65/16 + 65/16@1 + + + #c8ffc8 + #c8ffc8 + 0 + 0 + C1 + C0 + false + false + false + 1 + false + false + 0 + diff.label - 65/6 + 65/6@1 + + + #00ff00 + #00ff00 + 0 + 0 + C5 + C0 + false + false + false + 1 + false + false + 0 + diff.net - 65/23 + 65/23@1 + + + #00ff00 + #00ff00 + 0 + 0 + C0 + C0 + false + false + false + 1 + false + false + 0 + diff.boundary - 65/4 + 65/4@1 + + + #9900e6 + #9900e6 + 0 + 0 + C36 + C0 + true + false + false + 1 + false + false + 0 + diff.hv - 65/8 + 65/8@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C34 + C0 + true + true + false + 1 + false + false + 0 + tap.drawing - 65/44 + 65/44@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C6 + C0 + false + false + false + 1 + false + false + 0 + tap.pin - 65/48 + 65/48@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C5 + C0 + false + false + false + 1 + false + false + 0 + tap.net - 65/41 + 65/41@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C0 + C0 + false + false + false + 1 + false + false + 0 + tap.boundary - 65/60 + 65/60@1 + + + #fff464 + #fff464 + 0 + 0 + C1 + C0 + false + false + false + 1 + false + false + 0 + tap.label - 65/5 + 65/5@1 + + + #9900e6 + #9900e6 + 0 + 0 + C22 + C0 + true + false + false + 1 + false + false + 0 + psdm.drawing - 94/20 + 94/20@1 + + + #e61f0d + #e61f0d + 0 + 0 + C21 + C0 + true + false + false + 1 + false + false + 0 + nsdm.drawing - 93/44 + 93/44@1 + + + #ff0000 + #ff0000 + 0 + 0 + C41 + C0 + true + false + false + 1 + false + false + 0 + poly.drawing - 66/20 + 66/20@1 + + + #ff8000 + #ff8000 + 0 + 0 + C38 + C0 + true + false + false + 1 + false + false + 0 + poly.pin - 66/16 + 66/16@1 + + + #ff0000 + #ff0000 + 0 + 0 + I1 + C0 + true + false + false + 1 + false + false + 0 + poly.res - 66/13 + 66/13@1 + + + #ff0000 + #ff0000 + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + poly.cut - 66/14 + 66/14@1 + + + #ff0000 + #ff0000 + 0 + 0 + I1 + C0 + true + false + false + 1 + false + false + 0 + poly.gate - 66/9 + 66/9@1 + + + #ffafaf + #ffafaf + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + poly.label - 66/5 + 66/5@1 + + + #ff0000 + #ff0000 + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + poly.boundary - 66/4 + 66/4@1 + + + #ff0000 + #ff0000 + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + poly.probe - 66/25 + 66/25@1 + + + #ff0000 + #ff0000 + 0 + 0 + C36 + C0 + true + false + false + 1 + false + false + 0 + poly.short - 66/15 + 66/15@1 + + + #ff0000 + #ff0000 + 0 + 0 + C5 + C0 + true + false + false + 1 + false + false + 0 + poly.net - 66/23 + 66/23@1 + + + #ff0000 + #ff0000 + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + poly.model - 66/83 + 66/83@1 + + + #00cc66 + #00cc66 + 0 + 0 + C50 + C0 + true + false + false + 1 + false + false + 0 + ldntm.drawing - 11/44 + 11/44@1 + + + #96c8ff + #ffffff + 0 + 0 + C15 + C0 + true + false + false + 1 + false + false + 0 + lvtn.drawing - 125/44 + 125/44@1 + + + #ff8000 + #ffffff + 0 + 0 + C14 + C0 + true + false + false + 1 + false + false + 0 + hvtp.drawing - 78/44 + 78/44@1 + + + #ff0000 + #e61f0d + 0 + 0 + C14 + C0 + false + false + false + 1 + false + false + 0 + hvtr.drawing - 18/20 + 18/20@1 + + + #9900e6 + #9900e6 + 0 + 0 + C41 + C0 + true + false + false + 1 + false + false + 0 + tunm.drawing - 80/20 + 80/20@1 + + + #ffffcc + #ffffcc + 0 + 0 + C23 + C0 + true + false + false + 1 + false + false + 0 + licon1.drawing - 66/44 + 66/44@1 + + + #ffffcc + #ffffcc + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + licon1.boundary - 66/60 + 66/60@1 + + + #ffe6bf + #c8ffff + 0 + 0 + C6 + C0 + false + false + false + 1 + false + false + 0 + licon1.pin - 66/58 + 66/58@1 + + + #ffffcc + #ffffcc + 0 + 0 + C5 + C0 + true + false + false + 1 + false + false + 0 + licon1.net - 66/41 + 66/41@1 + + + #bf4026 + #bf4026 + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + npc.drawing - 95/20 + 95/20@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C5 + C0 + true + false + false + 1 + false + false + 0 + li1.drawing - 67/20 + 67/20@1 + + + #bf4026 + #bf4026 + 0 + 0 + C46 + C0 + true + false + false + 1 + false + false + 0 + li1.pin - 67/16 + 67/16@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + I1 + C0 + false + false + false + 1 + false + false + 0 + li1.res - 67/13 + 67/13@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C1 + C0 + false + false + false + 1 + false + false + 0 + li1.cut - 67/14 + 67/14@1 + + + #bf4026 + #bf4026 + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + li1.label - 67/5 + 67/5@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C53 + C0 + true + false + false + 1 + false + false + 0 + li1.net - 67/23 + 67/23@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + li1.boundary - 67/4 + 67/4@1 + + + #bf4026 + #bf4026 + 0 + 0 + C53 + C0 + true + false + false + 1 + false + false + 0 + li1.blockage - 67/10 + 67/10@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C36 + C0 + true + false + false + 1 + false + false + 0 + li1.short - 67/15 + 67/15@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + li1.probe - 67/25 + 67/25@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + mcon.drawing - 67/44 + 67/44@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + mcon.boundary - 67/60 + 67/60@1 + + + #ffffcc + #d9e6ff + 0 + 0 + C6 + C0 + false + false + false + 1 + false + false + 0 + mcon.pin - 67/48 + 67/48@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C5 + C0 + true + false + false + 1 + false + false + 0 + mcon.net - 67/41 + 67/41@1 + + + #0000ff + #0000ff + 0 + 0 + C7 + C0 + true + false + false + 1 + false + false + 0 + met1.drawing - 68/20 + 68/20@1 + + + #0000ff + #0000ff + 0 + 0 + I1 + C0 + false + false + false + 1 + false + false + 0 + met1.res - 68/13 + 68/13@1 + + + #0000ff + #0000ff + 0 + 0 + C1 + C0 + false + false + false + 1 + false + false + 0 + met1.cut - 68/14 + 68/14@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C6 + C0 + true + false + false + 1 + false + false + 0 + met1.pin - 68/16 + 68/16@1 + + + #96c8ff + #96c8ff + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + met1.label - 68/5 + 68/5@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C5 + C0 + true + false + false + 1 + false + false + 0 + met1.net - 68/23 + 68/23@1 + + + #0000ff + #0000ff + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + met1.boundary - 68/4 + 68/4@1 + + + #0000ff + #0000ff + 0 + 0 + C53 + C0 + true + false + false + 1 + false + false + 0 + met1.blockage - 68/10 + 68/10@1 + + + #0000ff + #0000ff + 0 + 0 + C36 + C0 + true + false + false + 1 + false + false + 0 + met1.short - 68/15 + 68/15@1 + + + #0000ff + #0000ff + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + met1.probe - 68/25 + 68/25@1 + + + #0000ff + #0000ff + 0 + 0 + C25 + C0 + false + false + false + 1 + false + false + 0 + met1.option1 - 68/32 + 68/32@1 + + + #0000ff + #0000ff + 0 + 0 + C26 + C0 + false + false + false + 1 + false + false + 0 + met1.option2 - 68/33 + 68/33@1 + + + #0000ff + #0000ff + 0 + 0 + C27 + C0 + false + false + false + 1 + false + false + 0 + met1.option3 - 68/34 + 68/34@1 + + + #0000ff + #0000ff + 0 + 0 + C28 + C0 + false + false + false + 1 + false + false + 0 + met1.option4 - 68/35 + 68/35@1 + + + #0000ff + #0000ff + 0 + 0 + C29 + C0 + false + false + false + 1 + false + false + 0 + met1.option5 - 68/36 + 68/36@1 + + + #0000ff + #0000ff + 0 + 0 + C30 + C0 + false + false + false + 1 + false + false + 0 + met1.option6 - 68/37 + 68/37@1 + + + #0000ff + #0000ff + 0 + 0 + C31 + C0 + false + false + false + 1 + false + false + 0 + met1.option7 - 68/38 + 68/38@1 + + + #0000ff + #0000ff + 0 + 0 + C32 + C0 + false + false + false + 1 + false + false + 0 + met1.option8 - 68/39 + 68/39@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + via.drawing - 68/44 + 68/44@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + via.boundary - 68/60 + 68/60@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C5 + C0 + true + false + false + 1 + false + false + 0 + via.net - 68/41 + 68/41@1 + + + #ae7dff + #ae7dff + 0 + 0 + C6 + C0 + false + false + false + 1 + false + false + 0 + via.pin - 68/58 + 68/58@1 + + + #ff00ff + #ff00ff + 0 + 0 + C37 + C0 + true + false + false + 1 + false + false + 0 + met2.drawing - 69/20 + 69/20@1 + + + #ff00ff + #ff00ff + 0 + 0 + I1 + C0 + false + false + false + 1 + false + false + 0 + met2.res - 69/13 + 69/13@1 + + + #ff00ff + #ff00ff + 0 + 0 + C1 + C0 + false + false + false + 1 + false + false + 0 + met2.cut - 69/14 + 69/14@1 + + + #ff00ff + #ff00ff + 0 + 0 + C45 + C0 + true + false + false + 1 + false + false + 0 + met2.pin - 69/16 + 69/16@1 + + + #ffc8ff + #ffc8ff + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + met2.label - 69/5 + 69/5@1 + + + #ff00ff + #ff00ff + 0 + 0 + C5 + C0 + true + false + false + 1 + false + false + 0 + met2.net - 69/23 + 69/23@1 + + + #ff00ff + #ff00ff + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + met2.boundary - 69/4 + 69/4@1 + + + #ff00ff + #ff00ff + 0 + 0 + C53 + C0 + true + false + false + 1 + false + false + 0 + met2.blockage - 69/10 + 69/10@1 + + + #ff00ff + #ff00ff + 0 + 0 + C36 + C0 + true + false + false + 1 + false + false + 0 + met2.short - 69/15 + 69/15@1 + + + #ff00ff + #ff00ff + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + met2.probe - 69/25 + 69/25@1 + + + #ff00ff + #ff00ff + 0 + 0 + C25 + C0 + false + false + false + 1 + false + false + 0 + met2.option1 - 69/32 + 69/32@1 + + + #ff00ff + #ff00ff + 0 + 0 + C26 + C0 + false + false + false + 1 + false + false + 0 + met2.option2 - 69/33 + 69/33@1 + + + #ff00ff + #ff00ff + 0 + 0 + C27 + C0 + false + false + false + 1 + false + false + 0 + met2.option3 - 69/34 + 69/34@1 + + + #ff00ff + #ff00ff + 0 + 0 + C28 + C0 + false + false + false + 1 + false + false + 0 + met2.option4 - 69/35 + 69/35@1 + + + #ff00ff + #ff00ff + 0 + 0 + C29 + C0 + false + false + false + 1 + false + false + 0 + met2.option5 - 69/36 + 69/36@1 + + + #ff00ff + #ff00ff + 0 + 0 + C30 + C0 + false + false + false + 1 + false + false + 0 + met2.option6 - 69/37 + 69/37@1 + + + #ff00ff + #ff00ff + 0 + 0 + C31 + C0 + false + false + false + 1 + false + false + 0 + met2.option7 - 69/38 + 69/38@1 + + + #ff00ff + #ff00ff + 0 + 0 + C32 + C0 + false + false + false + 1 + false + false + 0 + met2.option8 - 69/39 + 69/39@1 + + + #ff8000 + #ff8000 + 0 + 0 + I1 + C0 + true + false + false + 3 + false + false + 0 + via2.drawing - 69/44 + 69/44@1 + + + #ff8000 + #ff8000 + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + via2.boundary - 69/60 + 69/60@1 + + + #ff8000 + #ff8000 + 0 + 0 + C6 + C0 + false + false + false + 1 + false + false + 0 + via2.pin - 69/58 + 69/58@1 + + + #ff8000 + #ff8000 + 0 + 0 + C5 + C0 + true + false + false + 1 + false + false + 0 + via2.net - 69/41 + 69/41@1 + + + #00ffff + #00ffff + 0 + 0 + C49 + C0 + true + false + false + 1 + false + false + 0 + met3.drawing - 70/20 + 70/20@1 + + + #00ffff + #00ffff + 0 + 0 + I1 + C0 + false + false + false + 1 + false + false + 0 + met3.res - 70/13 + 70/13@1 + + + #00ffff + #00ffff + 0 + 0 + C1 + C0 + false + false + false + 1 + false + false + 0 + met3.cut - 70/14 + 70/14@1 + + + #00ffff + #00ffff + 0 + 0 + C34 + C0 + true + false + false + 1 + false + false + 0 + met3.pin - 70/16 + 70/16@1 + + + #c8ffff + #c8ffff + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + met3.label - 70/5 + 70/5@1 + + + #00ffff + #00ffff + 0 + 0 + C5 + C0 + true + false + false + 1 + false + false + 0 + met3.net - 70/23 + 70/23@1 + + + #00ffff + #00ffff + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + met3.boundary - 70/4 + 70/4@1 + + + #00ffff + #00ffff + 0 + 0 + C53 + C0 + true + false + false + 1 + false + false + 0 + met3.blockage - 70/10 + 70/10@1 + + + #00ffff + #00ffff + 0 + 0 + C36 + C0 + true + false + false + 1 + false + false + 0 + met3.short - 70/15 + 70/15@1 + + + #00ffff + #00ffff + 0 + 0 + I1 + C0 + false + false + false + 1 + false + false + 0 + met3.fuse - 70/17 + 70/17@1 + + + #00ffff + #00ffff + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + met3.probe - 70/25 + 70/25@1 + + + #00ffff + #00ffff + 0 + 0 + C25 + C0 + false + false + false + 1 + false + false + 0 + met3.option1 - 70/32 + 70/32@1 + + + #00ffff + #00ffff + 0 + 0 + C26 + C0 + false + false + false + 1 + false + false + 0 + met3.option2 - 70/33 + 70/33@1 + + + #00ffff + #00ffff + 0 + 0 + C27 + C0 + false + false + false + 1 + false + false + 0 + met3.option3 - 70/34 + 70/34@1 + + + #00ffff + #00ffff + 0 + 0 + C28 + C0 + false + false + false + 1 + false + false + 0 + met3.option4 - 70/35 + 70/35@1 + + + #00ffff + #00ffff + 0 + 0 + C29 + C0 + false + false + false + 1 + false + false + 0 + met3.option5 - 70/36 + 70/36@1 + + + #00ffff + #00ffff + 0 + 0 + C30 + C0 + false + false + false + 1 + false + false + 0 + met3.option6 - 70/37 + 70/37@1 + + + #00ffff + #00ffff + 0 + 0 + C31 + C0 + false + false + false + 1 + false + false + 0 + met3.option7 - 70/38 + 70/38@1 + + + #00ffff + #00ffff + 0 + 0 + C32 + C0 + false + false + false + 1 + false + false + 0 + met3.option8 - 70/39 + 70/39@1 + + + #268c6b + #268c6b + 0 + 0 + I1 + C0 + true + false + false + 3 + false + false + 0 + via3.drawing - 70/44 + 70/44@1 + + + #268c6b + #268c6b + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + via3.boundary - 70/60 + 70/60@1 + + + #268c6b + #268c6b + 0 + 0 + C6 + C0 + false + false + false + 1 + false + false + 0 + via3.pin - 70/48 + 70/48@1 + + + #268c6b + #268c6b + 0 + 0 + C5 + C0 + true + false + false + 1 + false + false + 0 + via3.net - 70/41 + 70/41@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C15 + C0 + true + false + false + 1 + false + false + 0 + met4.drawing - 71/20 + 71/20@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + I1 + C0 + false + false + false + 1 + false + false + 0 + met4.res - 71/13 + 71/13@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C1 + C0 + false + false + false + 1 + false + false + 0 + met4.cut - 71/14 + 71/14@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C34 + C0 + true + false + false + 1 + false + false + 0 + met4.pin - 71/16 + 71/16@1 + + + #ae7dff + #ae7dff + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + met4.label - 71/5 + 71/5@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C5 + C0 + true + false + false + 1 + false + false + 0 + met4.net - 71/23 + 71/23@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + met4.boundary - 71/4 + 71/4@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C53 + C0 + true + false + false + 1 + false + false + 0 + met4.blockage - 71/10 + 71/10@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C36 + C0 + true + false + false + 1 + false + false + 0 + met4.short - 71/15 + 71/15@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + I1 + C0 + false + false + false + 1 + false + false + 0 + met4.fuse - 71/17 + 71/17@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + met4.probe - 71/25 + 71/25@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C25 + C0 + false + false + false + 1 + false + false + 0 + met4.option1 - 71/32 + 71/32@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C26 + C0 + false + false + false + 1 + false + false + 0 + met4.option2 - 71/33 + 71/33@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C27 + C0 + false + false + false + 1 + false + false + 0 + met4.option3 - 71/34 + 71/34@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C28 + C0 + false + false + false + 1 + false + false + 0 + met4.option4 - 71/35 + 71/35@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C29 + C0 + false + false + false + 1 + false + false + 0 + met4.option5 - 71/36 + 71/36@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C30 + C0 + false + false + false + 1 + false + false + 0 + met4.option6 - 71/37 + 71/37@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C31 + C0 + false + false + false + 1 + false + false + 0 + met4.option7 - 71/38 + 71/38@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C32 + C0 + false + false + false + 1 + false + false + 0 + met4.option8 - 71/39 + 71/39@1 + + + #ffff00 + #ffff00 + 0 + 0 + I1 + C0 + true + false + false + 3 + false + false + 0 + via4.drawing - 71/44 + 71/44@1 + + + #ffff00 + #ffff00 + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + via4.boundary - 71/60 + 71/60@1 + + + #ffff00 + #ffff00 + 0 + 0 + C6 + C0 + false + false + false + 1 + false + false + 0 + via4.pin - 71/48 + 71/48@1 + + + #ffff00 + #ffff00 + 0 + 0 + C5 + C0 + true + false + false + 1 + false + false + 0 + via4.net - 71/41 + 71/41@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C42 + C0 + true + false + false + 1 + false + false + 0 + met5.drawing - 72/20 + 72/20@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + I1 + C0 + false + false + false + 1 + false + false + 0 + met5.res - 72/13 + 72/13@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C1 + C0 + false + false + false + 1 + false + false + 0 + met5.cut - 72/14 + 72/14@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C34 + C0 + true + false + false + 1 + false + false + 0 + met5.pin - 72/16 + 72/16@1 + + + #fff464 + #fff464 + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + met5.label - 72/5 + 72/5@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C5 + C0 + true + false + false + 1 + false + false + 0 + met5.net - 72/23 + 72/23@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + met5.boundary - 72/4 + 72/4@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C53 + C0 + true + false + false + 1 + false + false + 0 + met5.blockage - 72/10 + 72/10@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C36 + C0 + true + false + false + 1 + false + false + 0 + met5.short - 72/15 + 72/15@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + I1 + C0 + false + false + false + 1 + false + false + 0 + met5.fuse - 72/17 + 72/17@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + met5.probe - 72/25 + 72/25@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C25 + C0 + false + false + false + 1 + false + false + 0 + met5.option1 - 72/32 + 72/32@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C26 + C0 + false + false + false + 1 + false + false + 0 + met5.option2 - 72/33 + 72/33@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C27 + C0 + false + false + false + 1 + false + false + 0 + met5.option3 - 72/34 + 72/34@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C28 + C0 + false + false + false + 1 + false + false + 0 + met5.option4 - 72/35 + 72/35@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C29 + C0 + false + false + false + 1 + false + false + 0 + met5.option5 - 72/36 + 72/36@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C30 + C0 + false + false + false + 1 + false + false + 0 + met5.option6 - 72/37 + 72/37@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C31 + C0 + false + false + false + 1 + false + false + 0 + met5.option7 - 72/38 + 72/38@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C32 + C0 + false + false + false + 1 + false + false + 0 + met5.option8 - 72/39 + 72/39@1 + + + #00cc66 + #00cc66 + 0 + 0 + C50 + C0 + true + false + false + 1 + false + false + 0 + nsm.drawing - 61/20 + 61/20@1 + + + #ffffcc + #ffffcc + 0 + 0 + C20 + C0 + true + false + false + 1 + false + false + 0 + pad.drawing - 76/20 + 76/20@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + pad.label - 76/5 + 76/5@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C34 + C0 + true + false + false + 1 + false + false + 0 + pad.pin - 76/16 + 76/16@1 + + + #ff00ff + #ff00ff + 0 + 0 + I1 + C0 + true + false + false + 1 + false + false + 0 + pnp.drawing - 82/44 + 82/44@1 + + + #ffc8ff + #ffc8ff + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + pnp.label - 82/59 + 82/59@1 + + + #00ffff + #00ffff + 0 + 0 + I1 + C0 + true + false + false + 1 + false + false + 0 + npn.drawing - 82/20 + 82/20@1 + + + #c8ffff + #c8ffff + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + npn.label - 82/5 + 82/5@1 + + + #ffffff + #96c8ff + 0 + 0 + C38 + C0 + true + false + false + 1 + false + false + 0 + rpm.drawing - 86/20 + 86/20@1 + + + #9900e6 + #9900e6 + 0 + 0 + C4 + C0 + true + false + false + 1 + false + false + 0 + hvi.drawing - 75/20 + 75/20@1 + + + #ffb232 + #ffb232 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + capacitor.drawing - 82/64 + 82/64@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C14 + C0 + true + false + false + 1 + false + false + 0 + ncm.drawing - 92/44 + 92/44@1 + + + #ff8000 + #ff8000 + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + cncm.drawing - 96/44 + 96/44@1 + + + #ff0000 + #ff0000 + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + cncm.mask - 17/0 + 17/0@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C20 + C1 + true + false + false + 1 + false + false + 0 + pmm.drawing - 85/44 + 85/44@1 + + + #bf4026 + #bf4026 + 0 + 0 + C40 + C0 + true + false + false + 1 + false + false + 0 + pmm2.drawing - 77/20 + 77/20@1 + + + #e61f0d + #e61f0d + 0 + 0 + C47 + C0 + true + false + false + 1 + false + false + 0 + rdl.drawing - 74/20 + 74/20@1 + + + #e61f0d + #e61f0d + 0 + 0 + C34 + C0 + true + false + false + 1 + false + false + 0 + rdl.pin - 74/16 + 74/16@1 + + + #ff6464 + #ff6464 + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + rdl.label - 74/5 + 74/5@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + I1 + C0 + true + false + false + 1 + false + false + 0 + rdl.res - 74/13 + 74/13@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + rdl.cut - 74/14 + 74/14@1 + + + #e61f0d + #e61f0d + 0 + 0 + C36 + C0 + false + false + false + 1 + false + false + 0 + rdl.short - 74/15 + 74/15@1 + + + #e61f0d + #e61f0d + 0 + 0 + C25 + C0 + false + false + false + 1 + false + false + 0 + rdl.option1 - 89/32 + 89/32@1 + + + #e61f0d + #e61f0d + 0 + 0 + C26 + C0 + false + false + false + 1 + false + false + 0 + rdl.option2 - 89/33 + 89/33@1 + + + #e61f0d + #e61f0d + 0 + 0 + C27 + C0 + false + false + false + 1 + false + false + 0 + rdl.option3 - 89/34 + 89/34@1 + + + #e61f0d + #e61f0d + 0 + 0 + C28 + C0 + false + false + false + 1 + false + false + 0 + rdl.option4 - 89/35 + 89/35@1 + + + #e61f0d + #e61f0d + 0 + 0 + C29 + C0 + false + false + false + 1 + false + false + 0 + rdl.option5 - 89/36 + 89/36@1 + + + #e61f0d + #e61f0d + 0 + 0 + C30 + C0 + false + false + false + 1 + false + false + 0 + rdl.option6 - 89/37 + 89/37@1 + + + #e61f0d + #e61f0d + 0 + 0 + C31 + C0 + false + false + false + 1 + false + false + 0 + rdl.option7 - 89/38 + 89/38@1 + + + #e61f0d + #e61f0d + 0 + 0 + C32 + C0 + false + false + false + 1 + false + false + 0 + rdl.option8 - 89/39 + 89/39@1 + + + #ccccd9 + #333399 + 0 + 0 + C7 + C0 + true + false + false + 1 + false + false + 0 + ubm.drawing - 127/21 + 127/21@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C20 + C0 + true + false + false + 1 + false + false + 0 + bump.drawing - 127/22 + 127/22@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + inductor.drawing - 82/24 + 82/24@1 + + + #fff464 + #fff464 + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + inductor.label - 82/25 + 82/25@1 + + + #333399 + #ffffff + 0 + 0 + C25 + C0 + true + false + false + 1 + false + false + 0 + inductor.term1 - 82/26 + 82/26@1 + + + #333399 + #ffffff + 0 + 0 + C26 + C0 + true + false + false + 1 + false + false + 0 + inductor.term2 - 82/27 + 82/27@1 + + + #333399 + #ffffff + 0 + 0 + C27 + C0 + true + false + false + 1 + false + false + 0 + inductor.term3 - 82/28 + 82/28@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C20 + C0 + true + false + false + 1 + false + false + 0 + cfom.drawing - 22/20 + 22/20@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C13 + C0 + true + false + false + 1 + false + false + 0 + cfom.mask - 23/0 + 23/0@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cfom.fill - 23/28 + 23/28@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C14 + C0 + true + false + false + 1 + false + false + 0 + cfom.maskAdd - 22/21 + 22/21@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C11 + C0 + true + false + false + 1 + false + false + 0 + cfom.maskDrop - 22/22 + 22/22@1 + + + #268c6b + #268c6b + 0 + 0 + I1 + C0 + true + false + false + 1 + false + false + 0 + cfom.waffleDrop - 22/24 + 22/24@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C20 + C0 + false + false + false + 1 + false + false + 0 + fom.dummy - 22/23 + 22/23@1 + + + #268c6b + #268c6b + 0 + 0 + C20 + C0 + false + false + false + 1 + false + false + 0 + cnwm.drawing - 109/44 + 109/44@1 + + + #268c6b + #268c6b + 0 + 0 + C13 + C0 + true + false + false + 1 + false + false + 0 + cnwm.mask - 21/0 + 21/0@1 + + + #268c6b + #268c6b + 0 + 0 + C14 + C0 + false + false + false + 1 + false + false + 0 + cnwm.maskAdd - 109/43 + 109/43@1 + + + #268c6b + #268c6b + 0 + 0 + C11 + C0 + false + false + false + 1 + false + false + 0 + cnwm.maskDrop - 109/42 + 109/42@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + cdnm.drawing - 110/20 + 110/20@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C17 + C0 + true + false + false + 1 + false + false + 0 + cdnm.mask - 48/0 + 48/0@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C14 + C0 + true + false + false + 1 + false + false + 0 + cdnm.maskAdd - 110/21 + 110/21@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C3 + C0 + true + false + false + 1 + false + false + 0 + cdnm.maskDrop - 110/22 + 110/22@1 + + + #96c8ff + #ffffcc + 0 + 0 + C0 + C0 + false + false + false + 1 + false + false + 0 + clvtnm.drawing - 25/44 + 25/44@1 + + + #96c8ff + #ffffff + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + clvtnm.mask - 25/0 + 25/0@1 + + + #96c8ff + #ffffff + 0 + 0 + C14 + C0 + false + false + false + 1 + false + false + 0 + clvtnm.maskAdd - 25/43 + 25/43@1 + + + #96c8ff + #0000ff + 0 + 0 + C3 + C0 + false + false + false + 1 + false + false + 0 + clvtnm.maskDrop - 25/42 + 25/42@1 + + + #ff8000 + #ffffcc + 0 + 0 + C0 + C0 + false + false + false + 1 + false + false + 0 + chvtpm.drawing - 88/44 + 88/44@1 + + + #ff8000 + #ffffff + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + chvtpm.mask - 97/0 + 97/0@1 + + + #ff8000 + #ffffff + 0 + 0 + C14 + C0 + false + false + false + 1 + false + false + 0 + chvtpm.maskAdd - 97/43 + 97/43@1 + + + #ff8000 + #0000ff + 0 + 0 + C3 + C0 + false + false + false + 1 + false + false + 0 + chvtpm.maskDrop - 97/42 + 97/42@1 + + + #ff0000 + #d9e6ff + 0 + 0 + C0 + C0 + false + false + false + 1 + false + false + 0 + chvtrm.drawing - 98/44 + 98/44@1 + + + #ff0000 + #e61f0d + 0 + 0 + C0 + C0 + false + false + false + 1 + false + false + 0 + chvtrm.mask - 98/0 + 98/0@1 + + + #ff0000 + #e61f0d + 0 + 0 + C14 + C0 + false + false + false + 1 + false + false + 0 + chvtrm.maskAdd - 98/43 + 98/43@1 + + + #ff0000 + #d9e6ff + 0 + 0 + C3 + C0 + false + false + false + 1 + false + false + 0 + chvtrm.maskDrop - 98/42 + 98/42@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + ctunm.drawing - 96/20 + 96/20@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + ctunm.mask - 20/0 + 20/0@1 + + + #ffffff + #ffffff + 0 + 0 + C14 + C0 + true + false + false + 1 + false + false + 0 + ctunm.maskAdd - 96/21 + 96/21@1 + + + #ffffff + #ffffff + 0 + 0 + C3 + C0 + true + false + false + 1 + false + false + 0 + ctunm.maskDrop - 96/22 + 96/22@1 + + + #ff0000 + #ff0000 + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + conom.drawing - 87/44 + 87/44@1 + + + #ff0000 + #ff0000 + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + conom.mask - 88/0 + 88/0@1 + + + #ff0000 + #ff0000 + 0 + 0 + C14 + C0 + true + false + false + 1 + false + false + 0 + conom.maskAdd - 87/43 + 87/43@1 + + + #ff0000 + #ff0000 + 0 + 0 + C3 + C0 + true + false + false + 1 + false + false + 0 + conom.maskDrop - 87/42 + 87/42@1 + + + #00cc66 + #00cc66 + 0 + 0 + C20 + C0 + true + false + false + 1 + false + false + 0 + cnsdm.drawing - 29/20 + 29/20@1 + + + #00cc66 + #00cc66 + 0 + 0 + C13 + C0 + true + false + false + 1 + false + false + 0 + cnsdm.mask - 30/0 + 30/0@1 + + + #00cc66 + #00cc66 + 0 + 0 + C14 + C0 + true + false + false + 1 + false + false + 0 + cnsdm.maskAdd - 29/21 + 29/21@1 + + + #00cc66 + #00cc66 + 0 + 0 + C11 + C0 + true + false + false + 1 + false + false + 0 + cnsdm.maskDrop - 29/22 + 29/22@1 + + + #ffff00 + #ffff00 + 0 + 0 + C20 + C0 + true + false + false + 1 + false + false + 0 + cpsdm.drawing - 31/20 + 31/20@1 + + + #ffff00 + #ffff00 + 0 + 0 + C13 + C0 + true + false + false + 1 + false + false + 0 + cpsdm.mask - 32/0 + 32/0@1 + + + #ffff00 + #ffff00 + 0 + 0 + C14 + C0 + true + false + false + 1 + false + false + 0 + cpsdm.maskAdd - 31/21 + 31/21@1 + + + #ffff00 + #ffff00 + 0 + 0 + C11 + C0 + true + false + false + 1 + false + false + 0 + cpsdm.maskDrop - 31/22 + 31/22@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C20 + C0 + true + false + false + 1 + false + false + 0 + cntm.drawing - 26/20 + 26/20@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C13 + C0 + true + false + false + 1 + false + false + 0 + cntm.mask - 27/0 + 27/0@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C14 + C0 + false + false + false + 1 + false + false + 0 + cntm.maskAdd - 26/21 + 26/21@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C11 + C0 + false + false + false + 1 + false + false + 0 + cntm.maskDrop - 26/22 + 26/22@1 + + + #ffff00 + #ffff00 + 0 + 0 + C20 + C0 + true + false + false + 1 + false + false + 0 + hvntm.drawing - 125/20 + 125/20@1 + + + #fff5e6 + #fff5e6 + 0 + 0 + C20 + C0 + true + false + false + 1 + false + false + 0 + chvntm.drawing - 38/20 + 38/20@1 + + + #fff5e6 + #fff5e6 + 0 + 0 + C13 + C0 + true + false + false + 1 + false + false + 0 + chvntm.mask - 39/0 + 39/0@1 + + + #fff5e6 + #fff5e6 + 0 + 0 + C14 + C0 + false + false + false + 1 + false + false + 0 + chvntm.maskAdd - 38/21 + 38/21@1 + + + #fff5e6 + #fff5e6 + 0 + 0 + C11 + C0 + false + false + false + 1 + false + false + 0 + chvntm.maskDrop - 38/22 + 38/22@1 + + + #00cc66 + #00cc66 + 0 + 0 + C20 + C0 + false + false + false + 1 + false + false + 0 + cldntm.drawing - 11/20 + 11/20@1 + + + #00cc66 + #00cc66 + 0 + 0 + C13 + C0 + true + false + false + 1 + false + false + 0 + cldntm.mask - 11/0 + 11/0@1 + + + #ff8000 + #ff8000 + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + clvom.drawing - 45/20 + 45/20@1 + + + #268c6b + #268c6b + 0 + 0 + C17 + C0 + true + false + false + 1 + false + false + 0 + clvom.mask - 46/0 + 46/0@1 + + + #268c6b + #268c6b + 0 + 0 + C14 + C0 + false + false + false + 1 + false + false + 0 + clvom.maskAdd - 45/21 + 45/21@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C3 + C0 + false + false + false + 1 + false + false + 0 + clvom.maskDrop - 45/22 + 45/22@1 + + + #ff8000 + #ff8000 + 0 + 0 + C20 + C0 + false + false + false + 1 + false + false + 0 + cp1m.drawing - 33/44 + 33/44@1 + + + #ff8000 + #ff8000 + 0 + 0 + C13 + C0 + true + false + false + 1 + false + false + 0 + cp1m.mask - 28/0 + 28/0@1 + + + #ff8000 + #ff8000 + 0 + 0 + C11 + C0 + true + false + false + 1 + false + false + 0 + cp1m.fill - 28/28 + 28/28@1 + + + #ff8000 + #ff8000 + 0 + 0 + C14 + C0 + true + false + false + 1 + false + false + 0 + cp1m.maskAdd - 33/43 + 33/43@1 + + + #9900e6 + #9900e6 + 0 + 0 + I1 + C0 + true + false + false + 1 + false + false + 0 + cp1m.waffleDrop - 33/24 + 33/24@1 + + + #ff8000 + #ff8000 + 0 + 0 + C11 + C0 + true + false + false + 1 + false + false + 0 + cp1m.maskDrop - 33/42 + 33/42@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + false + false + false + 1 + false + false + 0 + cli1m.drawing - 115/44 + 115/44@1 + + + #00ffff + #00ffff + 0 + 0 + C11 + C0 + true + false + false + 1 + false + false + 0 + cli1m.mask - 56/0 + 56/0@1 + + + #00ffff + #00ffff + 0 + 0 + C12 + C0 + true + false + false + 1 + false + false + 0 + cli1m.fill - 56/28 + 56/28@1 + + + #00ffff + #00ffff + 0 + 0 + C14 + C0 + true + false + false + 1 + false + false + 0 + cli1m.maskAdd - 115/43 + 115/43@1 + + + #00ffff + #00ffff + 0 + 0 + C3 + C0 + true + false + false + 1 + false + false + 0 + cli1m.maskDrop - 115/42 + 115/42@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + false + false + false + 1 + false + false + 0 + clicm1.drawing - 106/44 + 106/44@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + clicm1.mask - 43/0 + 43/0@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C14 + C0 + true + false + false + 1 + false + false + 0 + clicm1.maskAdd - 106/43 + 106/43@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C3 + C0 + true + false + false + 1 + false + false + 0 + clicm1.maskDrop - 106/42 + 106/42@1 + + + #0000ff + #0000ff + 0 + 0 + C20 + C0 + false + false + false + 1 + false + false + 0 + cmm1.drawing - 62/20 + 62/20@1 + + + #0000ff + #0000ff + 0 + 0 + C13 + C0 + true + false + false + 1 + false + false + 0 + cmm1.mask - 36/0 + 36/0@1 + + + #0000ff + #0000ff + 0 + 0 + C11 + C0 + true + false + false + 1 + false + false + 0 + cmm1.fill - 36/28 + 36/28@1 + + + #0000ff + #0000ff + 0 + 0 + C14 + C0 + false + false + false + 1 + false + false + 0 + cmm1.maskAdd - 62/21 + 62/21@1 + + + #0000ff + #0000ff + 0 + 0 + C11 + C0 + false + false + false + 1 + false + false + 0 + cmm1.maskDrop - 62/22 + 62/22@1 + + + #0000ff + #0000ff + 0 + 0 + I1 + C0 + true + false + false + 1 + false + false + 0 + cmm1.waffleDrop - 62/24 + 62/24@1 + + + #ffffcc + #ffffcc + 0 + 0 + C0 + C0 + false + false + false + 1 + false + false + 0 + cviam.drawing - 105/20 + 105/20@1 + + + #ffffcc + #ffffcc + 0 + 0 + C17 + C0 + true + false + false + 1 + false + false + 0 + cviam.mask - 40/0 + 40/0@1 + + + #ffffcc + #ffffcc + 0 + 0 + C14 + C0 + false + false + false + 1 + false + false + 0 + cviam.maskAdd - 105/21 + 105/21@1 + + + #ffffcc + #ffffcc + 0 + 0 + C3 + C0 + false + false + false + 1 + false + false + 0 + cviam.maskDrop - 105/22 + 105/22@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C20 + C0 + false + false + false + 1 + false + false + 0 + cmm2.drawing - 105/44 + 105/44@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C13 + C0 + true + false + false + 1 + false + false + 0 + cmm2.mask - 41/0 + 41/0@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C11 + C0 + true + false + false + 1 + false + false + 0 + cmm2.fill - 41/28 + 41/28@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C14 + C0 + false + false + false + 1 + false + false + 0 + cmm2.maskAdd - 105/43 + 105/43@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C11 + C0 + false + false + false + 1 + false + false + 0 + cmm2.maskDrop - 105/42 + 105/42@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + I1 + C0 + true + false + false + 1 + false + false + 0 + cmm2.waffleDrop - 105/52 + 105/52@1 + + + #333399 + #333399 + 0 + 0 + C0 + C0 + false + false + false + 1 + false + false + 0 + cviam2.drawing - 108/20 + 108/20@1 + + + #333399 + #333399 + 0 + 0 + C17 + C0 + true + false + false + 1 + false + false + 0 + cviam2.mask - 44/0 + 44/0@1 + + + #333399 + #333399 + 0 + 0 + C14 + C0 + false + false + false + 1 + false + false + 0 + cviam2.maskAdd - 108/21 + 108/21@1 + + + #333399 + #333399 + 0 + 0 + C3 + C0 + false + false + false + 1 + false + false + 0 + cviam2.maskDrop - 108/22 + 108/22@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C20 + C0 + false + false + false + 1 + false + false + 0 + cmm3.drawing - 107/20 + 107/20@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C13 + C0 + true + false + false + 1 + false + false + 0 + cmm3.mask - 34/0 + 34/0@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C11 + C0 + true + false + false + 1 + false + false + 0 + cmm3.fill - 34/28 + 34/28@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C14 + C0 + false + false + false + 1 + false + false + 0 + cmm3.maskAdd - 107/21 + 107/21@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C11 + C0 + false + false + false + 1 + false + false + 0 + cmm3.maskDrop - 107/22 + 107/22@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + I1 + C0 + true + false + false + 1 + false + false + 0 + cmm3.waffleDrop - 107/24 + 107/24@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + cnpc.drawing - 44/20 + 44/20@1 + + + #e61f0d + #e61f0d + 0 + 0 + C39 + C0 + true + false + false + 1 + false + false + 0 + cnpc.mask - 49/0 + 49/0@1 + + + #e61f0d + #e61f0d + 0 + 0 + C14 + C0 + false + false + false + 1 + false + false + 0 + cnpc.maskAdd - 44/43 + 44/43@1 + + + #e61f0d + #e61f0d + 0 + 0 + C3 + C0 + false + false + false + 1 + false + false + 0 + cnpc.maskDrop - 44/42 + 44/42@1 + + + #268c6b + #268c6b + 0 + 0 + C0 + C0 + false + false + false + 1 + false + false + 0 + cviam3.drawing - 112/20 + 112/20@1 + + + #268c6b + #268c6b + 0 + 0 + C17 + C0 + true + false + false + 1 + false + false + 0 + cviam3.mask - 50/0 + 50/0@1 + + + #268c6b + #268c6b + 0 + 0 + C14 + C0 + false + false + false + 1 + false + false + 0 + cviam3.maskAdd - 112/21 + 112/21@1 + + + #268c6b + #268c6b + 0 + 0 + C3 + C0 + false + false + false + 1 + false + false + 0 + cviam3.maskDrop - 112/22 + 112/22@1 + + + #00cc66 + #00cc66 + 0 + 0 + C20 + C0 + true + false + false + 1 + false + false + 0 + cnsm.mask - 22/0 + 22/0@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C20 + C0 + false + false + false + 1 + false + false + 0 + cpdm.drawing - 104/44 + 104/44@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C13 + C0 + true + false + false + 1 + false + false + 0 + cpdm.mask - 37/0 + 37/0@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C14 + C0 + false + false + false + 1 + false + false + 0 + cpdm.maskAdd - 104/43 + 104/43@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C11 + C0 + false + false + false + 1 + false + false + 0 + cpdm.maskDrop - 104/42 + 104/42@1 + + + #8c8ca6 + #0000ff + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + cpmm.drawing - 91/44 + 91/44@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C13 + C0 + true + false + false + 1 + false + false + 0 + cpbo.mask - 99/0 + 99/0@1 + + + #00cc66 + #00cc66 + 0 + 0 + C13 + C0 + true + false + false + 1 + false + false + 0 + cmm4.mask - 51/0 + 51/0@1 + + + #00cc66 + #00cc66 + 0 + 0 + C11 + C0 + true + false + false + 1 + false + false + 0 + cmm4.fill - 51/28 + 51/28@1 + + + #00cc66 + #00cc66 + 0 + 0 + C14 + C0 + true + false + false + 1 + false + false + 0 + cmm4.maskAdd - 112/43 + 112/43@1 + + + #00cc66 + #00cc66 + 0 + 0 + C11 + C0 + true + false + false + 1 + false + false + 0 + cmm4.maskDrop - 112/42 + 112/42@1 + + + #00cc66 + #00cc66 + 0 + 0 + I1 + C0 + true + false + false + 1 + false + false + 0 + cmm4.waffleDrop - 112/4 + 112/4@1 + + + #00ffff + #00ffff + 0 + 0 + C0 + C0 + false + false + false + 1 + false + false + 0 + cviam4.drawing - 117/20 + 117/20@1 + + + #00ffff + #00ffff + 0 + 0 + C17 + C0 + true + false + false + 1 + false + false + 0 + cviam4.mask - 58/0 + 58/0@1 + + + #00ffff + #00ffff + 0 + 0 + C14 + C0 + false + false + false + 1 + false + false + 0 + cviam4.maskAdd - 117/21 + 117/21@1 + + + #00ffff + #00ffff + 0 + 0 + C3 + C0 + false + false + false + 1 + false + false + 0 + cviam4.maskDrop - 117/22 + 117/22@1 + + + #ff8000 + #ff8000 + 0 + 0 + C13 + C0 + true + false + false + 1 + false + false + 0 + cmm5.mask - 59/0 + 59/0@1 + + + #ff8000 + #ff8000 + 0 + 0 + C11 + C0 + true + false + false + 1 + false + false + 0 + cmm5.fill - 59/28 + 59/28@1 + + + #ff8000 + #ff8000 + 0 + 0 + I1 + C0 + true + false + false + 1 + false + false + 0 + cmm5.waffleDrop - 117/4 + 117/4@1 + + + #0000ff + #0000ff + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + target.drawing - 76/44 + 76/44@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + false + false + false + 1 + false + false + 0 + cctm1.drawing - 101/44 + 101/44@1 + + + #ffffff + #ffffff + 0 + 0 + C17 + C0 + true + false + false + 1 + false + false + 0 + cctm1.mask - 35/0 + 35/0@1 + + + #ffffff + #ffffff + 0 + 0 + C14 + C0 + false + false + false + 1 + false + false + 0 + cctm1.maskAdd - 101/43 + 101/43@1 + + + #ffffff + #ffffff + 0 + 0 + C3 + C0 + false + false + false + 1 + false + false + 0 + cctm1.maskDrop - 101/42 + 101/42@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + crpm.drawing - 53/44 + 53/44@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + crpm.mask - 96/0 + 96/0@1 + + + #ffffff + #ffffff + 0 + 0 + C14 + C0 + true + false + false + 1 + false + false + 0 + crpm.maskAdd - 53/43 + 53/43@1 + + + #ffffff + #ffffff + 0 + 0 + C3 + C0 + true + false + false + 1 + false + false + 0 + crpm.maskDrop - 53/42 + 53/42@1 + + + #e61f0d + #e61f0d + 0 + 0 + C47 + C0 + false + false + false + 1 + false + false + 0 + ccu1m.mask - 93/0 + 93/0@1 + + + #bf4026 + #bf4026 + 0 + 0 + C40 + C0 + false + false + false + 1 + false + false + 0 + cpmm2.mask - 94/0 + 94/0@1 + + + #ccccd9 + #333399 + 0 + 0 + C7 + C0 + false + false + false + 1 + false + false + 0 + cubm.mask - 100/0 + 100/0@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C20 + C0 + false + false + false + 1 + false + false + 0 + cbump.mask - 101/0 + 101/0@1 + + + #00bfff + #00bfff + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + overlap.drawing - 90/20 + 90/20@1 + + + #ff7f50 + #ff7f50 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + overlap.boundary - 90/4 + 90/4@1 + + + #ff8000 + #ff8000 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.lowTapDensity - 81/14 + 81/14@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.notCritSide - 81/15 + 81/15@1 + + + #adff2f + #adff2f + 0 + 0 + C2 + C0 + true + false + false + 3 + false + false + 0 + areaid.injection - 81/17 + 81/17@1 + + + #bebed8 + #bebed8 + 0 + 0 + C2 + C0 + true + false + false + 3 + false + false + 0 + areaid.rfdiode - 81/125 + 81/125@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.seal - 81/1 + 81/1@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.core - 81/2 + 81/2@1 + + + #ffffcc + #ffffcc + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.frame - 81/3 + 81/3@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.esd - 81/19 + 81/19@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.dieCut - 81/11 + 81/11@1 + + + #00ff00 + #00ff00 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.moduleCut - 81/10 + 81/10@1 + + + #00ffff + #00ffff + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.frameRect - 81/12 + 81/12@1 + + + #333399 + #ccccd9 + 0 + 0 + C22 + C0 + true + false + false + 1 + false + false + 0 + areaid.substrateCut - 81/53 + 81/53@1 + + + #ffff00 + #ffff00 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.diode - 81/23 + 81/23@1 + + + #ff00ff + #ff00ff + 0 + 0 + C0 + C0 + true + true + false + 3 + false + false + 0 + areaid.standardc - 81/4 + 81/4@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C0 + C5 + true + false + false + 1 + false + false + 0 + areaid.deadZon - 81/50 + 81/50@1 + + + #ff8000 + #ff8000 + 0 + 0 + C0 + C5 + true + false + false + 1 + false + false + 0 + areaid.critCorner - 81/51 + 81/51@1 + + + #ffffcc + #ffffcc + 0 + 0 + C0 + C5 + true + false + false + 1 + false + false + 0 + areaid.critSid - 81/52 + 81/52@1 + + + #8c8ca6 + #c8ffc8 + 0 + 0 + C20 + C0 + true + false + false + 3 + false + false + 0 + areaid.opcDrop - 81/54 + 81/54@1 + + + #00bfff + #00ffe7 + 0 + 0 + C1 + C0 + true + false + false + 3 + false + false + 0 + areaid.waffleWindow - 81/13 + 81/13@1 + + + #daa520 + #daa520 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.extendedDrain - 81/57 + 81/57@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.lvNative - 81/60 + 81/60@1 + + + #9900e6 + #9900e6 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.photo - 81/81 + 81/81@1 + + + #ff00ff + #00ff00 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.etest - 81/101 + 81/101@1 + + + #ff0000 + #ff0000 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.hvnwell - 81/63 + 81/63@1 + + + #9900e6 + #9900e6 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.rdlprobepad - 81/27 + 81/27@1 + + + #00bfff + #00bfff + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.sigPadDiff - 81/6 + 81/6@1 + + + #c8ffc8 + #c8ffc8 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.sigPadWell - 81/7 + 81/7@1 + + + #ff7f50 + #ff7f50 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.sigPadMetNtr - 81/8 + 81/8@1 + + + #ff6464 + #ff6464 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.analog - 81/79 + 81/79@1 + + + #ffff00 + #ffffff + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + prune.drawing - 84/44 + 84/44@1 + + + #0000ff + #0000ff + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + padCenter.drawing - 81/20 + 81/20@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C7 + C0 + true + false + false + 1 + false + false + 0 + met1.psa1 - 68/88 + 68/88@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C37 + C0 + true + false + false + 1 + false + false + 0 + met2.psa1 - 69/88 + 69/88@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C49 + C0 + true + false + false + 1 + false + false + 0 + met3.psa1 - 70/88 + 70/88@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C15 + C0 + true + false + false + 1 + false + false + 0 + met4.psa1 - 71/88 + 71/88@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C42 + C0 + true + false + false + 1 + false + false + 0 + met5.psa1 - 72/88 + 72/88@1 + + + #00ffe7 + #00ffe7 + 0 + 0 + C7 + C0 + true + false + false + 1 + false + false + 0 + met1.psa2 - 68/89 + 68/89@1 + + + #00ffe7 + #00ffe7 + 0 + 0 + C37 + C0 + true + false + false + 1 + false + false + 0 + met2.psa2 - 69/89 + 69/89@1 + + + #00ffe7 + #00ffe7 + 0 + 0 + C49 + C0 + true + false + false + 1 + false + false + 0 + met3.psa2 - 70/89 + 70/89@1 + + + #00ffe7 + #00ffe7 + 0 + 0 + C15 + C0 + true + false + false + 1 + false + false + 0 + met4.psa2 - 71/89 + 71/89@1 + + + #00ffe7 + #00ffe7 + 0 + 0 + C42 + C0 + true + false + false + 1 + false + false + 0 + met5.psa2 - 72/89 + 72/89@1 + + + #ffffcc + #ffffcc + 0 + 0 + C7 + C0 + true + false + false + 1 + false + false + 0 + met1.psa3 - 68/90 + 68/90@1 + + + #ffffcc + #ffffcc + 0 + 0 + C37 + C0 + true + false + false + 1 + false + false + 0 + met2.psa3 - 69/90 + 69/90@1 + + + #ffffcc + #ffffcc + 0 + 0 + C49 + C0 + true + false + false + 1 + false + false + 0 + met3.psa3 - 70/90 + 70/90@1 + + + #ffffcc + #ffffcc + 0 + 0 + C15 + C0 + true + false + false + 1 + false + false + 0 + met4.psa3 - 71/90 + 71/90@1 + + + #ffffcc + #ffffcc + 0 + 0 + C42 + C0 + true + false + false + 1 + false + false + 0 + met5.psa3 - 72/90 + 72/90@1 + + + #802626 + #802626 + 0 + 0 + C7 + C0 + true + false + false + 1 + false + false + 0 + met1.psa4 - 68/91 + 68/91@1 + + + #802626 + #802626 + 0 + 0 + C37 + C0 + true + false + false + 1 + false + false + 0 + met2.psa4 - 69/91 + 69/91@1 + + + #802626 + #802626 + 0 + 0 + C49 + C0 + true + false + false + 1 + false + false + 0 + met3.psa4 - 70/91 + 70/91@1 + + + #802626 + #802626 + 0 + 0 + C15 + C0 + true + false + false + 1 + false + false + 0 + met4.psa4 - 71/91 + 71/91@1 + + + #802626 + #802626 + 0 + 0 + C42 + C0 + true + false + false + 1 + false + false + 0 + met5.psa4 - 72/91 + 72/91@1 + + + #333399 + #333399 + 0 + 0 + C7 + C0 + true + false + false + 1 + false + false + 0 + met1.psa5 - 68/92 + 68/92@1 + + + #333399 + #333399 + 0 + 0 + C37 + C0 + true + false + false + 1 + false + false + 0 + met2.psa5 - 69/92 + 69/92@1 + + + #333399 + #333399 + 0 + 0 + C49 + C0 + true + false + false + 1 + false + false + 0 + met3.psa5 - 70/92 + 70/92@1 + + + #333399 + #333399 + 0 + 0 + C15 + C0 + true + false + false + 1 + false + false + 0 + met4.psa5 - 71/92 + 71/92@1 + + + #333399 + #333399 + 0 + 0 + C42 + C0 + true + false + false + 1 + false + false + 0 + met5.psa5 - 72/92 + 72/92@1 + + + #fa8072 + #fa8072 + 0 + 0 + C7 + C0 + true + false + false + 1 + false + false + 0 + met1.psa6 - 68/93 + 68/93@1 + + + #fa8072 + #fa8072 + 0 + 0 + C37 + C0 + true + false + false + 1 + false + false + 0 + met2.psa6 - 69/93 + 69/93@1 + + + #fa8072 + #fa8072 + 0 + 0 + C49 + C0 + true + false + false + 1 + false + false + 0 + met3.psa6 - 70/93 + 70/93@1 + + + #fa8072 + #fa8072 + 0 + 0 + C15 + C0 + true + false + false + 1 + false + false + 0 + met4.psa6 - 71/93 + 71/93@1 + + + #fa8072 + #fa8072 + 0 + 0 + C42 + C0 + true + false + false + 1 + false + false + 0 + met5.psa6 - 72/93 + 72/93@1 + + + #ff0000 + #ff0000 + 0 + 0 + C10 + C0 + true + false + false + 1 + false + false + 0 + rdl.psa1 - 74/88 + 74/88@1 + + + #0000ff + #0000ff + 0 + 0 + C10 + C0 + true + false + false + 1 + false + false + 0 + rdl.psa2 - 74/89 + 74/89@1 + + + #00cc66 + #00cc66 + 0 + 0 + C10 + C0 + true + false + false + 1 + false + false + 0 + rdl.psa3 - 74/90 + 74/90@1 + + + #ffffff + #ffffff + 0 + 0 + C10 + C0 + true + false + false + 1 + false + false + 0 + rdl.psa4 - 74/91 + 74/91@1 + + + #ffff00 + #ffff00 + 0 + 0 + C10 + C0 + true + false + false + 1 + false + false + 0 + rdl.psa5 - 74/92 + 74/92@1 + + + #bf4026 + #bf4026 + 0 + 0 + C10 + C0 + true + false + false + 1 + false + false + 0 + rdl.psa6 - 74/93 + 74/93@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C20 + C1 + false + false + false + 1 + false + false + 0 + blanking.drawing - 124/40 + 124/40@1 + + + + + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + + 1 + blank + + + + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + + 2 + solid + + + + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + + 3 + dots + + + + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + + 4 + hLine + + + + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + + 5 + vLine + + + + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + + 6 + cross + + + + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + + 7 + grid + + + + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + + 8 + slash + + + + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + + 9 + backSlash + + + + **......**...... + ..*.......*..... + ...**......**... + .....*.......*.. + ......**......** + *.......*....... + .**......**..... + ...*.......*.... + ....**......**.. + ......*.......*. + *......**......* + .*.......*...... + ..**......**.... + ....*.......*... + .....**......**. + .......*.......* + + 10 + hZigZag + + + + *....*....*..... + *.....*....*.... + .*....*.....*... + ..*....*....*... + ..*.....*....*.. + ...*....*.....*. + ....*....*....*. + ....*.....*....* + *....*....*..... + *.....*....*.... + .*....*.....*... + ..*....*....*... + ..*.....*....*.. + ...*....*.....*. + ....*....*....*. + ....*.....*....* + + 11 + vZigZag + + + + ................ + ................ + ...*****...***** + ...*...*...*...* + ...*...*...*...* + ****...*****...* + ................ + ................ + ................ + ................ + ...*****...***** + ...*...*...*...* + ...*...*...*...* + ****...*****...* + ................ + ................ + + 12 + hCurb + + + + .....*.......*.. + .....*.......*.. + .....*.......*.. + ..****....****.. + ..*.......*..... + ..*.......*..... + ..*.......*..... + ..****....****.. + .....*.......*.. + .....*.......*.. + .....*.......*.. + ..****....****.. + ..*.......*..... + ..*.......*..... + ..*.......*..... + ..****....****.. + + 13 + vCurb + + + + **************** + ..*.......*..... + ..*.......*..... + ..*.......*..... + **************** + ......*.......*. + ......*.......*. + ......*.......*. + **************** + ..*.......*..... + ..*.......*..... + ..*.......*..... + **************** + ......*.......*. + ......*.......*. + ......*.......*. + + 14 + brick + + + + ................ + ..*.......*..... + ..*.......*..... + ..*.......*..... + *****...*****... + ..*.......*..... + ..*.......*..... + ..*.......*..... + ................ + .....*.......*.. + .....*.......*.. + .....*.......*.. + ...*****...***** + .....*.......*.. + .....*.......*.. + .....*.......*.. + + 15 + dagger + + + + ................ + ..*............. + ..*............. + ..*............. + *****........... + ..*............. + ..*............. + ..*............. + ................ + .............*.. + .............*.. + .............*.. + ...........***** + .............*.. + .............*.. + .............*.. + + 16 + sparseDagger + + + + ................ + ..........*..... + ..........*..... + ..........*..... + ........*****... + ..........*..... + ..........*..... + ..........*..... + ................ + .....*.......... + .....*.......... + .....*.......... + ...*****........ + .....*.......... + .....*.......... + .....*.......... + + 17 + sparseDagger2 + + + + ................ + ....*........... + ...*.*.......... + ..*...*......... + .*.....*........ + *********....... + ................ + ................ + ................ + ...........*.... + ..........*.*... + .........*...*.. + ........*.....*. + .......********* + ................ + ................ + + 18 + triangle + + + + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + + 19 + x + + + + ................ + .*.....*.....*.. + ..*...**....*... + ...*.*.*...*.... + ....*..*..*..... + .....*.*.*...... + ......***....... + .......*........ + ......***....... + .....*.*.*...... + ....*..*..*..... + ...*...*...*.... + ..*....*....*... + .*..*******..*.. + ................ + ................ + + 20 + Xone + + + + ................ + .*....**.....*.. + ..*..*..*...*... + ...**....*.*.... + ....*....**..... + .....*...*...... + ......*.*....... + .......*........ + ......*.*....... + .....*...*...... + ....*.....*..... + ...**......*.... + ..*.*.......*... + .*..******...*.. + ................ + ................ + + 21 + Xtwo + + + + ................ + ................ + ......*.......*. + ................ + ................ + ................ + ..*.......*..... + ................ + ................ + ................ + ......*.......*. + ................ + ................ + ................ + ..*.......*..... + ................ + + 22 + spareDots + + + + ................ + ................ + ................ + ................ + ................ + ......*.......*. + ................ + ................ + ................ + ................ + ................ + ................ + ..*.......*..... + ................ + ................ + ................ + + 23 + spareDots21 + + + + ................ + ................ + ......*.......*. + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ..*.......*..... + ................ + ................ + ................ + ................ + ................ + + 24 + spareDots22 + + + + ****....****.... + ****....****.... + ****....****.... + ****....****.... + ....****....**** + ....****....**** + ....****....**** + ....****....**** + ****....****.... + ****....****.... + ****....****.... + ****....****.... + ....****....**** + ....****....**** + ....****....**** + ....****....**** + + 25 + checker + + + + ....****....**** + ....****....**** + ....****....**** + ....****....**** + ****....****.... + ****....****.... + ****....****.... + ****....****.... + ....****....**** + ....****....**** + ....****....**** + ....****....**** + ****....****.... + ****....****.... + ****....****.... + ****....****.... + + 26 + checker2 + + + + ................ + ................ + ................ + ................ + .......*........ + ......**........ + .......*........ + .......*........ + .......*........ + .......*........ + ......***....... + ................ + ................ + ................ + ................ + ................ + + 27 + one + + + + ................ + ................ + ................ + ................ + ................ + .......**....... + ......*..*...... + .........*...... + ........*....... + .......*........ + ......*......... + ......****...... + ................ + ................ + ................ + ................ + + 28 + two + + + + ................ + ................ + ................ + ................ + ................ + ......***....... + .....*...*...... + .........*...... + .......**....... + .........*...... + .....*...*...... + ......***....... + ................ + ................ + ................ + ................ + + 29 + three + + + + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + .............*.. + ............**.. + ...........*.*.. + ..........*..*.. + .........******. + .............*.. + .............*.. + ................ + + 30 + four + + + + ................ + ................ + ................ + ......***....... + .....*.......... + .....*.......... + .....***........ + ........*....... + ........*....... + .....***........ + ................ + ................ + ................ + ................ + ................ + ................ + + 31 + five + + + + ................ + ................ + ................ + ................ + .......***...... + ......*......... + ......*......... + ......****...... + ......*...*..... + ......*...*..... + .......***...... + ................ + ................ + ................ + ................ + ................ + + 32 + six + + + + ................ + ................ + ................ + .....******..... + ..........*..... + .........*...... + .........*...... + ........*....... + ........*....... + .......*........ + ......*......... + .....*.......... + ................ + ................ + ................ + ................ + + 33 + seven + + + + ................ + ................ + ................ + ................ + ......***....... + .....*...*...... + .....*...*...... + ......***....... + .....*...*...... + .....*...*...... + ......***....... + ................ + ................ + ................ + ................ + ................ + + 34 + eight + + + + *..............* + .*............*. + ..*..........*.. + ...*........*... + ....*......*.... + .....*....*..... + ......*..*...... + .......**....... + .......**....... + ......*..*...... + .....*....*..... + ....*......*.... + ...*........*... + ..*..........*.. + .*............*. + *..............* + + 35 + box45 + + + + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + + 36 + gray50 + + + + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + + 37 + gray25 + + + + .*.*.*...*.*.*.. + ................ + ...*...*...*...* + ................ + .*...*.*.*...*.* + ................ + ...*...*...*...* + ................ + .*.*.*...*.*.*.. + ................ + ...*...*...*...* + ................ + .*...*.*.*...*.* + ................ + ...*...*...*...* + ................ + + 38 + snow + + + + ..*.......*..... + ...*.......*.... + ....*.......*... + .....*.......*.. + ......*.......*. + .......*.......* + *.......*....... + .*.......*...... + ..*.......*..... + ...*.......*.... + ....*.......*... + .....*.......*.. + ......*.......*. + .......*.......* + *.......*....... + .*.......*...... + + 39 + backSlash2 + + + + *.....*.*.....*. + .*...*...*...*.. + ..*.*.....*.*... + ...*...*...*...* + ..*.*.....*.*... + .*...*...*...*.. + *.....*.*.....*. + ...*...*...*...* + *.....*.*.....*. + .*...*...*...*.. + ..*.*.....*.*... + ...*...*...*...* + ..*.*.....*.*... + .*...*...*...*.. + *.....*.*.....*. + ...*...*...*...* + + 40 + lattice + + + + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + + 41 + smallChecker + + + + ....*........... + ...*.*.......... + ..*...*......... + .*.....*........ + *.......*....... + .*.......*...... + ..*.......*..... + ...*.......*.... + ....*.......*... + .....*.......*.. + ......*.......*. + .......*.......* + ........*.....*. + .........*...*.. + ..........*.*... + ...........*.... + + 42 + slantBox + + + + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + + 43 + slash2 + + + + ...*.......*.... + ..*.......*..... + .*.......*...... + *.......*....... + .......*.......* + ......*.......*. + .....*.......*.. + ....*.......*... + ...*.......*.... + ..*.......*..... + .*.......*...... + *.......*....... + .......*.......* + ......*.......*. + .....*.......*.. + ....*.......*... + + 44 + bigSlash + + + + ****....****.... + *..*....*..*.... + *..*....*..*.... + ****....****.... + ................ + ................ + ................ + ................ + ****....****.... + *..*....*..*.... + *..*....*..*.... + ****....****.... + ................ + ................ + ................ + ................ + + 45 + boxes + + + + ..**......**.... + .*..*....*..*... + *....*..*....*.. + *....*..*....*.. + .*..*....*..*... + ..**......**.... + ................ + ................ + ..**......**.... + .*..*....*..*... + *....*..*....*.. + *....*..*....*.. + .*..*....*..*... + ..**......**.... + ................ + ................ + + 46 + circles + + + + .**..**..**..**. + ...*...*...*...* + *...*...*...*... + .**..**..**..**. + .**..**..**..**. + *...*...*...*... + ...*...*...*...* + .**..**..**..**. + .**..**..**..**. + ...*...*...*...* + *...*...*...*... + .**..**..**..**. + .**..**..**..**. + *...*...*...*... + ...*...*...*...* + .**..**..**..**. + + 47 + zigzag + + + + ................ + *.*.*.*.*.*.*.*. + ................ + ...*....*....*.. + ................ + *.*.*.*.*.*.*.*. + ................ + ...*....*....*.. + ................ + *.*.*.*.*.*.*.*. + ................ + ...*....*....*.. + ................ + *.*.*.*.*.*.*.*. + ................ + ...*....*....*.. + + 48 + lightMesh + + + + ...............* + ..............*. + .............*.. + ............*... + ...........*.... + ..........*..... + .........*...... + ........*....... + .......*........ + ......*......... + .....*.......... + ....*........... + ...*............ + ..*............. + .*.............. + *............... + + 49 + hugeSlash + + + + *............... + .*.............. + ..*............. + ...*............ + ....*........... + .....*.......... + ......*......... + .......*........ + ........*....... + .........*...... + ..........*..... + ...........*.... + ............*... + .............*.. + ..............*. + ...............* + + 50 + hugeSlash2 + + + + *.........*..... + .....*.......... + ..*.........*... + .......*........ + ....*.........*. + .*.......*...... + ......*......... + ...*.......*.... + ........*....... + .....*.......*.. + *.........*..... + .......*........ + ..*.........*... + .........*...... + ....*.........*. + ...........*.... + + 51 + curve + + + + ....*....*....*. + ..*............. + *.......*....... + .............*.. + .......*........ + ............*... + .....*.......... + ...*.......*.... + *............... + ................ + .........*...... + ................ + ......*........* + ...*............ + *............*.. + ..........*..... + + 52 + curve2 + + + + ...........*.... + ..........*.*... + .........*...*.. + ........*.....*. + .........*...*.. + ..........*.*... + ...........*.... + ................ + ................ + ...*............ + ..*.*........... + .*...*.......... + *.....*......... + .*...*.......... + ..*.*........... + ...*............ + + 53 + diams + + + + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ...*............ + ..*.*........... + .*...*.......... + *.....*......... + .*...*.......... + ..*.*........... + ...*............ + + 54 + sparsediam + + + + .......*.......* + ......*......... + .....*.......... + ................ + ................ + ................ + .*.............. + *............... + .......*.......* + ..............*. + .............*.. + ................ + ................ + ................ + .........*...... + ........*....... + + 55 + rain + + + *** + 1 + solid + + + ****.. + 2 + dashed + + + *.. + 3 + dots + + + ***..*.. + 4 + dashDot + + + **.. + 5 + shortDash + + + ****..**.. + 6 + doubleDash + + + *... + 7 + hidden + + + *** + 8 + thickLine + + diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-full.lydrc b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-full.lydrc new file mode 100755 index 00000000..093edb8c --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-full.lydrc @@ -0,0 +1,924 @@ + + + + + drc + + + + false + false + + true + drc_scripts + tools_menu.drc.end + dsl + drc-dsl-xml + # +# DRC for SKY130 according to : +# https://skywater-pdk.readthedocs.io/en/latest/rules/periphery.html +# https://skywater-pdk.readthedocs.io/en/latest/rules/layers.html +# +# Distributed under GNU GPLv3: https://www.gnu.org/licenses/ +# +# History : +# 2020-10-04 : v1.0 : initial release +# +########################################################################################## + +# optionnal for a batch launch : klayout -b -rd input=my_layout.gds -rd report=sky130_drc.txt -r drc_sky130.drc +if $input + source($input) +end + +if $report + report("SKY130 DRC runset", $report) +else + report("SKY130 DRC runset", File.join(File.dirname(RBA::CellView::active.filename), "sky130_drc.txt")) +end + +AL = true # do not change +CU = false # do not change +# choose betwen only one of AL or CU back-end flow here : +backend_flow = AL + +# enable / disable rule groups +FEOL = true # front-end-of-line checks +BEOL = true # back-end-of-line checks +OFFGRID = true # manufacturing grid/angle checks + +# klayout setup +######################## +# use a tile size of 1mm - not used in deep mode- +tiles(1000.um) +# use a tile border of 10 micron: +tile_borders(1.um) +#no_borders + +# hierachical +deep + +if $thr + threads($thr) +else + threads(4) +end + +# if more inof is needed, set true +verbose(true) +#verbose(false) + +# layers definitions +######################## + +# all except purpose (datatype) 5 -- label and 44 -- via +li_wildcard = "67/20" +mcon_wildcard = "67/44" + +m1_wildcard = "68/20" +via_wildcard = "68/44" + +m2_wildcard = "69/20" +via2_wildcard = "69/44" + +m3_wildcard = "70/20" +via3_wildcard = "70/44" + +m4_wildcard = "71/20" +via4_wildcard = "71/44" + +m5_wildcard = "72/20" + + +diff = input(65, 20) +tap = polygons(65, 44) +nwell = polygons(64, 20) +dnwell = polygons(64, 18) +pwbm = polygons(19, 44) +pwde = polygons(124, 20) +natfet = polygons(124, 21) +hvtr = polygons(18, 20) +hvtp = polygons(78, 44) +ldntm = polygons(11, 44) +hvi = polygons(75, 20) +tunm = polygons(80, 20) +lvtn = polygons(125, 44) +poly = polygons(66, 20) +hvntm = polygons(125, 20) +nsdm = polygons(93, 44) +psdm = polygons(94, 20) +rpm = polygons(86, 20) +urpm = polygons(79, 20) +npc = polygons(95, 20) +licon = polygons(66, 44) + +li = polygons(li_wildcard) +mcon = polygons(mcon_wildcard) + +m1 = polygons(m1_wildcard) +via = polygons(via_wildcard) + +m2 = polygons(m2_wildcard) +via2 = polygons(via2_wildcard) + +m3 = polygons(m3_wildcard) +via3 = polygons(via3_wildcard) + +m4 = polygons(m4_wildcard) +via4 = polygons(via4_wildcard) + +m5 = polygons(m5_wildcard) + +pad = polygons(76, 20) +nsm = polygons(61, 20) +capm = polygons(89, 44) +cap2m = polygons(97, 44) +vhvi = polygons(74, 21) +uhvi = polygons(74, 22) +npn = polygons(82, 20) +inductor = polygons(82, 24) +vpp = polygons(82, 64) +pnp = polygons(82, 44) +lvs_prune = polygons(84, 44) +ncm = polygons(92, 44) +padcenter = polygons(81, 20) +mf = polygons(76, 44) +areaid_sl = polygons(81, 1) +areaid_ce = polygons(81, 2) +areaid_fe = polygons(81, 3) +areaid_sc = polygons(81, 4) +areaid_sf = polygons(81, 6) +areaid_sw = polygons(81, 7) +areaid_sr = polygons(81, 8) +areaid_mt = polygons(81, 10) +areaid_dt = polygons(81, 11) +areaid_ft = polygons(81, 12) +areaid_ww = polygons(81, 13) +areaid_ld = polygons(81, 14) +areaid_ns = polygons(81, 15) +areaid_ij = polygons(81, 17) +areaid_zr = polygons(81, 18) +areaid_ed = polygons(81, 19) +areaid_de = polygons(81, 23) +areaid_rd = polygons(81, 24) +areaid_dn = polygons(81, 50) +areaid_cr = polygons(81, 51) +areaid_cd = polygons(81, 52) +areaid_st = polygons(81, 53) +areaid_op = polygons(81, 54) +areaid_en = polygons(81, 57) +areaid_en20 = polygons(81, 58) +areaid_le = polygons(81, 60) +areaid_hl = polygons(81, 63) +areaid_sd = polygons(81, 70) +areaid_po = polygons(81, 81) +areaid_it = polygons(81, 84) +areaid_et = polygons(81, 101) +areaid_lvt = polygons(81, 108) +areaid_re = polygons(81, 125) +areaid_ag = polygons(81, 79) +poly_rs = polygons(66, 13) +diff_rs = polygons(65, 13) +pwell_rs = polygons(64, 13) +li_rs = polygons(67, 13) +cfom = polygons(22, 20) + + +# Define a new custom function that selects polygons by their number of holes: +# It will return a new layer containing those polygons with min to max holes. +# max can be nil to omit the upper limit. +class DRC::DRCLayer + def with_holes(min, max) + new_data = RBA::Region::new + self.data.each do |p| + if p.holes >= (min || 0) && (!max || p.holes <= max) + new_data.insert(p) + end + end + DRC::DRCLayer::new(@engine, new_data) + end +end + +# DRC section +######################## +info("DRC section") + +if FEOL +info("FEOL section") +gate = diff & poly + +# dnwell +dnwell.width(3.0, euclidian).output("dnwell.2", "dnwell.2 : min. dnwell width : 3.0um") +dnwell.not(uhvi).not(areaid_po).isolated(6.3, euclidian).output("dnwell.3", "dnwell.3 : min. dnwell spacing : 6.3um") +dnwell.and(pnp).output("dnwell.4", "dnwell.4 : dnwell must not overlap pnp") +dnwell.and(psdm).edges.not(psdm.edges).output("dnwell.5", "p+ must not straddle dnwell") +# dnwell.6 rue not coded + +# nwell +nwell.width(0.84, euclidian).output("nwell.1", "nwell.1 : min. nwell width : 0.84um") +nwell.isolated(1.27, euclidian).output("nwell.2a", "nwell.2a : min. nwell spacing (merged if less) : 1.27um") +# rule nwell.4 is suitable for digital cells +#nwell.not(uhvi).not(areaid_en20).not_interacting(tap.and(licon).and(li)).output("nwell.4", "nwell4 : all nwell exempt inside uhvi must contain a n+tap") +nwell.enclosing(dnwell.not(uhvi).not(areaid_po), 0.4, euclidian).output("nwell.5", "nwell.5 : min. nwell enclosing dnwell exempt unside uhvi : 0.4um") +dnwell.enclosing(nwell.not(uhvi), 1.03, euclidian).output("nwell.6", "nwell.6 : min. dnwell enclosing nwell exempt unside uhvi : 1.03um") +dnwell.separation(nwell, 4.5, euclidian).output("nwell.7", "nwell.7 : min. dnwell separation nwell : 4.5um") + +# pwbm +pwbm.not(uhvi).output("pwbm", "pwbm must be inside uhvi") +dnwell.and(uhvi).edges.not(pwbm).output("pwbm.4", "pwbm.4 : dnwell inside uhvi must be enclosed by pwbm") + +# pwde +pwde.not(pwbm).output("pwdem.3", "pwdem.3 : pwde must be inside pwbm") +pwde.not(uhvi).output("pwdem.4", "pwdem.4 : pwde must be inside uhvi") +pwde.not(dnwell).output("pwdem.5", "pwdem.5 : pwde must be inside dnwell") + +# hvtp +#hvtp.not(nwell).output("hvtp", "hvtp must inside nwell") +hvtp.width(0.38, euclidian).output("hvtp.1", "hvtp.1 : min. hvtp width : 0.38um") +hvtp.isolated(0.38, euclidian).output("hvtp.2", "hvtp.2 : min. hvtp spacing : 0.38um") +hvtp.enclosing(gate.and(psdm), 0.18, euclidian).output("hvtp.3", "hvtp.3 : min. hvtp enclosure of pfet gate : 0.18um") +hvtp.separation(gate.and(psdm), 0.18, euclidian).output("hvtp.4", "hvtp.4 : min. hvtp spacing pfet gate: 0.18um") +hvtp.with_area(0..0.265).output("hvtp.5", "hvtp.5 : min. hvtp area : 0.265um²") + +# hvtr +hvtr.width(0.38, euclidian).output("hvtr.1", "hvtr.1 : min. hvtr width : 0.38um") +hvtr.isolated(0.38, euclidian).output("hvtr.2", "hvtr.2 : min. hvtr spacing : 0.38um") + +# lvtn +lvtn.width(0.38, euclidian).output("lvtn.1", "lvtn.1 : min. lvtn width : 0.38um") +lvtn.isolated(0.38, euclidian).output("lvtn.2", "lvtn.2 : min. lvtn spacing : 0.38um") +lvtn.separation(diff.and(poly).not(uhvi), 0.18, euclidian).output("lvtn.3a", "lvtn.3a : min. lvtn spacing to gate : 0.18um") +lvtn.separation(diff.and(nwell).not(poly), 0.235, projection).output("lvtn.3b", "lvtn.3b : min. lvtn spacing to pfet s/d : 0.18um") +lvtn.enclosing(gate.not(uhvi), 0.18, euclidian).output("lvtn.4b", "lvtn.4b : min. lvtn enclosing to gate : 0.18um") +lvtn.separation(hvtp, 0.38, euclidian).output("lvtn.9", "lvtn.9 : min. lvtn spacing hvtp : 0.38um") +nwell.not_interacting(gate.and(nwell.not(hvi).not(areaid_ce))).enclosing(lvtn.not(uhvi), 0.18, euclidian).polygons.without_area(0).output("lvtn.4b", "lvtn.4b : min. lvtn enclosure of gate : 0.18um") +lvtn.separation(nwell.inside(areaid_ce), 0.38, euclidian).output("lvtn.12", "lvtn.12 : min. lvtn spacing nwell inside areaid.ce : 0.38um") +lvtn.with_area(0..0.265).output("lvtn.13", "lvtn.13 : min. lvtn area : 0.265um²") + +# ncm +ncm.and(tap.and(nwell).or(diff.not(nwell))).output("ncm.x.3", "ncm.x.3 : ncm must not overlap n+diff") +ncm.width(0.38, euclidian).output("ncm.1", "ncm.1 : min. ncm width : 0.38um") +ncm.isolated(0.38, euclidian).output("ncm.2", "ncm.2 : min. ncm spacing manual merge if smaller : 0.38um") +ncm.enclosing(diff.and(nwell), 0.18, euclidian).output("ncm.3", "ncm.3 : min. ncm enclosure of p+diff : 0.18um") +ncm.separation(lvtn.and(diff), 0.23, euclidian).output("ncm.5", "ncm.5 : min. ncm spacing lvtn diff : 0.23um") +ncm.separation(diff.not(nwell), 0.2, euclidian).output("ncm.6", "ncm.6 : min. ncm spacing nfet : 0.2um") +ncm.with_area(0..0.265).output("ncm.7", "ncm.13 : min. ncm area : 0.265um²") + +# diff-tap +difftap = diff + tap +difftap.width(0.15, euclidian).output("difftap.1", "difftap.1 : min. difftap width : 0.15um") +not_in_cell1 = layout(source.cell_obj).select("s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b" , "-s8fpls_pl8", "-s8fpls_rdrv4" , "-s8fpls_rdrv4f", "-s8fpls_rdrv8") +not_in_cell1_diff = not_in_cell1.input(65, 20) +not_in_cell1_diff.not(areaid_sc).not(poly).edges.and(gate.edges).with_length(0,0.42).output("difftap.2", "difftap.2: min. gate (exempt areaid.sc) width : 0.42um") +diff.and(areaid_sc).not(poly).edges.and(gate.edges).with_length(0,0.36).output("difftap.2", "difftap.2: min. gate inside areaid.sc width : 0.36um") +difftap.isolated(0.27, euclidian).output("difftap.3", "difftap.3 : min. difftap spacing : 0.27um") +tap.edges.and(diff.edges).with_length(0,0.29).output("difftap.4", "difftap.4 : min. tap bound by diffusion : 0.29um") +tap.edges.and(diff.edges).space(0.4, projection).output("difftap.5", "difftap.5 : min. tap bound by 2 diffusions : 0.4um") +(tap.edges.and(diff.edges)).extended(0.01, 0.01, 0, 0, false).not(tap.and(diff)).and(diff.or(tap)).output("difftap.6", "difftap.6 : diff and tap not allowed to extend beyong their abutting ege") +tap.edges.not_interacting(diff.edges).separation(diff.edges, 0.13, euclidian).output("difftap.7", "difftap.7 : min. diff/tap spacing to non-coincident diff edge : 0.13um") +diff.edges.not_interacting(tap.edges).separation(tap.edges, 0.13, euclidian).output("difftap.7", "difftap.7 : min. diff/tap spacing to non-coincident tap edge : 0.13um") +nwell.enclosing(diff.not(uhvi).and(psdm), 0.18, euclidian).output("difftap.8", "difftap.8 : min. p+diff enclosure by nwell : 0.18um") +diff.not(uhvi).and(nsdm).separation(nwell, 0.34, euclidian).output("difftap.9", "difftap.9 : min. n+diff spacing to nwell : 0.34um") +nwell.enclosing(tap.not(uhvi).and(nsdm), 0.18, euclidian).output("difftap.10", "difftap.10 : min. n+tap enclosure by nwell : 0.18um") +tap.not(uhvi).and(psdm).separation(nwell, 0.13, euclidian).output("difftap.11", "difftap.11 : min. p+tap spacing to nwell : 0.13um") + +# tunm +tunm.width(0.41, euclidian).output("tunm.1", "tunm.1 : min. tunm width : 0.41um") +tunm.isolated(0.5, euclidian).output("tunm.2", "tunm.2 : min. tunm spacing : 0.5um") +tunm.enclosing(gate, 0.095, euclidian).output("tunm.3", "tunm.3 : min. tunm beyond gate : 0.095um") +tunm.separation(gate.not_interacting(tunm), 0.095, euclidian).output("tunm.4", "tunm.4 : min. tunm spacing to gate outside tunm: 0.095um") +gate.and(tunm).edges.not(gate.edges).output("tunm.5", "tunm.5 : gate must not straddle tunm") +tunm.not(dnwell).output("tunm.6a", "tunm.6a : tunm not allowed outside dnwell") +tunm.with_area(0..0.672).output("tunm.7", "tunm.7 : min. tunm area : 0.672um²") + +# poly +poly.width(0.15, euclidian).output("poly.1a", "poly.1a : min. poly width : 0.15um") +poly.not(diff).edges.and(gate.and(lvtn).edges).space(0.35, euclidian).output("poly.1b", "poly.1b: min. lvtn gate width : 0.35um") +poly.isolated(0.21, euclidian).output("poly.2", "poly.2 : min. poly spacing : 0.21um") +poly.and(rpm.or(urpm).or(poly_rs)).width(0.33, euclidian).output("poly.3", "poly.3 : min. poly resistor width : 0.33um") +poly.not(gate).separation(diff, 0.075, projection).polygons.without_area(0).output("poly.4", "poly.4 : min. poly on field spacing to diff : 0.075um") +poly.not(gate).separation(tap, 0.055, euclidian).output("poly.5", "poly.5 : min. poly on field spacing to tap : 0.055um") +gate.separation(tap, 0.3, projection).polygons.and(diff).output("poly.6", "poly.6 : min. gate spacing to tap : 0.3um") +diff.enclosing(gate, 0.25, projection).polygons.without_area(0).output("poly.7", "poly.7 : min. source/drain length : 0.25um") +poly.enclosing(gate, 0.13, projection).polygons.without_area(0).output("poly.8", "poly.8 : min. poly extention gate (endcap) : 0.13um") +poly.and(rpm.or(urpm).or(poly_rs)).separation(poly.or(difftap), 0.48, euclidian).polygons.without_area(0).output("poly.9", "poly.9 : min. poly resistor space to poly or diff/tap : 0.48um") +diff.merged.edges.end_segments(0.01).and(poly).output("poly.10", "poly.10 : poly must not overlap diff corner") +gate.with_angle(0 .. 90).output("poly.11", "poly.11 : non 90 degree angle gate") +not_in_cell3 = layout(source.cell_obj).select("s8fgvr_n_fg2") +not_in_cell3_poly = not_in_cell3.input(66, 20) +not_in_cell3_poly.not(hvi).not(nwell.not(hvi)).and(tap).output("poly.12", "poly.12 : poly must not overlap tap") +poly.and(diff_rs).output("poly.15", "poly.15 : poly must not overlap diff resistor") + +# rpm +rpm.width(1.27, euclidian).output("rpm.1a", "rpm.1a : min. rpm width : 1.27um") +rpm.isolated(0.84, euclidian).output("rpm.2", "rpm.2 : min. rpm spacing : 0.84um") +rpm.enclosing(poly.and(poly_rs).and(psdm), 0.2, euclidian).output("rpm.3", "rpm.3 : min. rpm enclosure of poly resistor : 0.2um") +psdm.enclosing(poly.and(poly_rs).and(rpm), 0.11, euclidian).output("rpm.4", "rpm.4 : min. psdm enclosure of poly resistor : 0.11um") +npc.enclosing(poly.and(poly_rs).and(rpm), 0.095, euclidian).output("rpm.5", "rpm.5 : min. npc enclosure of poly resistor : 0.095um") +rpm.separation(nsdm, 0.2, euclidian).output("rpm.6", "rpm.6 : min. rpm spacing nsdm: 0.2um") +rpm.separation(poly, 0.2, euclidian).output("rpm.7", "rpm.7 : min. rpm spacing poly: 0.2um") +rpm.and(poly).edges.not(poly.edges).output("rpm.8", "rpm.8 : poly must not straddle rpm") +poly.and(poly_rs).and(rpm).separation(hvntm, 0.185, euclidian).output("rpm.9", "rpm.9 : min. poly resistor spacing hvntm: 0.185um") +rpm.and(pwbm).output("rpm.10", "rpm.107 : min. rpm spacing pwbm: na") + +# varac +varac = poly & tap & (nwell - hvi) - areaid_ce +tap.not(poly).edges.and(varac.edges).space(0.18, euclidian).output("varac.1", "varac.1: min. varac channel length : 0.18um") +tap.and(poly).edges.and(varac.edges).space(1.0, euclidian).output("varac.2", "varac.2: min. varac channel wdth : 1.0um") +varac.separation(hvtp, 0.18, euclidian).output("varac.3", "varac.3: min. varac channel space to hvtp : 0.18um") +varac.separation(licon.and(tap), 0.25, euclidian).output("varac.4", "varac.4: min. varac channel space to licon on tap : 0.25um") +nwell.enclosing(poly.overlapping(varac), 0.15, euclidian).output("varac.5", "varac.5: min. nwell enclosure of poly overlapping varac channel : 0.15um") +tap.overlapping(varac).separation(difftap, 0.27, euclidian).polygons.without_area(0).output("varac.6", "varac.6: min. varac channel tap space to difftap : 0.27um") +nwell.overlapping(varac).and(diff.and(nwell)).output("varac.7", "varac.7: nwell overlapping varac channel must not overlap p+diff") + +# photo +photodiode = dnwell & areaid_po +photodiode.edges.without_length(3.0).output("photo.2", "photo.2 : minimum/maximum width of photodiode : 3.0um") +photodiode.isolated(5.0, euclidian).output("photo.3", "photo.3 : mini. photodiode spacing : 5.0um") +photodiode.separation(dnwell, 5.3, euclidian).output("photo.4", "photo.4 : mini. photodiode spacing to dnwell : 5.3um") +areaid_po.not(dnwell).output("photo.5.6", "photo.5.6 : photodiode edges must coincide areaid.po and enclosed by dnwell") +photodiode.not(tap.not(nwell).holes).output("photo.7", "photo.7 : photodiode must be enclosed by p+tap ring") +photodiode.and(nwell).edges.without_length(0.84).output("photo.8", "photo.8 : minimum/maximum width of nwell inside photodiode : 0.84um") +areaid_po.edges.and(photodiode.and(nwell).sized(1.08)).without_length(12.0).output("photo.9", "photo.9 : minimum/maximum enclosure of nwell by photodiode : 1.08um") +photodiode.and(tap).edges.without_length(0.41).output("photo.10", "photo.10 : minimum/maximum width of tap inside photodiode : 0.41um") + +# npc +npc.width(0.27, euclidian).output("npc.1", "npc.1 : min. npc width : 0.27um") +npc.isolated(0.27, euclidian).output("npc.2", "npc.2 : min. npc spacing, should be mnually merge if less : 0.27um") +npc.separation(gate, 0.09, euclidian).output("npc.4", "npc.4 : min. npc spacing to gate : 0.09um") + +# nsdm/psdm +npsdm = nsdm + psdm +nsdm.width(0.38, euclidian).output("nsdm.1", "nsdm.1 : min. nsdm width : 0.38um") +psdm.width(0.38, euclidian).output("psdm.1", "psdm.1 : min. psdm width : 0.38um") +nsdm.isolated(0.38, euclidian).output("n/psdm.1", "n/psdm.1 : min. nsdm spacing, should be mnually merge if less : 0.38um") +psdm.isolated(0.38, euclidian).output("n/psdm.1", "n/psdm.1 : min. psdm spacing, should be mnually merge if less : 0.38um") +npsdm.enclosing(diff, 0.125, euclidian).polygons.not(tap.sized(0.125)).output("n/psdm.5a", "n/psdm.5a : min. n/psdm enclosure diff except butting edge : 0.125um") +npsdm.enclosing(tap, 0.125, euclidian).polygons.not(diff.sized(0.125)).output("n/psdm.5b", "n/psdm.5b : min. n/psdm enclosure tap except butting edge : 0.125um") +tap.edges.and(diff.edges).not(npsdm).output("n/psdm.6", "n/psdm.6 : min. n/psdm enclosure of butting edge : 0.0um") +nsdm.and(difftap).separation(psdm.and(difftap), 0.13, euclidian).polygons.without_area(0).output("n/psdm.7", "n/psdm.7 : min. nsdm diff spacing to psdm diff except butting edge : 0.13um") +diff.and((nsdm.and(nwell)).or(psdm.not(nwell))).output("n/psdm.8", "n/psdm.8 : diff should be the opposite type of well/substrate underneath") +tap.and((nsdm.not(nwell)).or(psdm.and(nwell))).output("n/psdm.8", "n/psdm.8 : tap should be the same type of well/substrate underneath") +tap.and(diff).without_area(0).output("tap and diff", "tap and diff must not overlap") +nsdm.with_area(0..0.265).output("n/psdm.10a", "n/psdm.10a : min. nsdm area : 0.265um²") +psdm.with_area(0..0.265).output("n/psdm.10b", "n/psdm.10b : min. psdm area : 0.265um²") + +# licon +licon.not(poly.interacting(poly_rs)).edges.without_length(0.17).output("licon.1", "licon.1 : minimum/maximum width of licon : 0.17um") +licon.and(poly.interacting(poly_rs)).not_interacting((licon.and(poly.interacting(poly_rs)).edges.with_length(0.19)).or(licon.and(poly.interacting(poly_rs)).edges.with_length(2.0))).output("licon.1b/c", "licon.1b/c : minimum/maximum width/length of licon inside poly resistor : 2.0/0.19um") +licon.isolated(0.17, euclidian).output("licon.2", "licon.2 : min. licon spacing : 0.17um") +licon.and(poly.interacting(poly_rs)).edges.with_length(0.19).space(0.35, euclidian).output("licon.2b", "licon.2b : min. licon 0.19um edge on resistor spacing : 0.35um") +licon.interacting(licon.and(poly.interacting(poly_rs)).edges.with_length(2.0)).separation(licon.and(poly.interacting(poly_rs)), 0.51, euclidian).output("licon.2c", "licon.2c : min. licon 2.0um edge on resistor spacing : 0.51um") +licon.and(poly.interacting(poly_rs)).separation(licon.not(poly.interacting(poly_rs)), 0.51, euclidian).output("licon.2d", "licon.2d : min. licon on resistor spacing other licon : 0.51um") +# rule licon.3 not coded +licon.not(li).not(poly.or(diff).or(tap)).output("licon.4", "licon.4 : min. licon must overlap li and (poly or tap or diff) ") +diff.enclosing(licon, 0.04, euclidian).output("licon.5", "licon.5 : min. diff enclosure of licon : 0.04um") +tap.edges.and(diff.edges).separation(licon.and(tap).edges, 0.06, euclidian).output("licon.6", "licon.6 : min. abutting edge spacing to licon tap : 0.06um") +licon_edges_with_less_enclosure_tap = tap.enclosing(licon, 0.12, projection).second_edges +opposite1 = (licon.edges - licon_edges_with_less_enclosure_tap).width(0.17 + 1.dbu, projection).polygons +licon.not_interacting(opposite1).output("licon.7", "licon.7 : min. tap enclosure of licon by one of 2 opposite edges : 0.12um") +poly.enclosing(licon, 0.05, euclidian).output("licon.8", "licon.8 : min. poly enclosure of licon : 0.05um") +licon008 = licon.interacting(poly.enclosing(licon, 0.08, euclidian).polygons) +licon_edges_with_less_enclosure_poly = poly.enclosing(licon, 0.08, projection).second_edges +opposite2 = (licon.edges - licon_edges_with_less_enclosure_poly).width(0.17 + 1.dbu, projection).polygons +licon008.not_interacting(opposite2).output("licon.8a", "licon.8a : min. poly enclosure of licon by one of 2 opposite edges : 0.08um") +# rule licon.9 not coded +licon.and(tap.and(nwell.not(hvi))).separation(varac, 0.25, euclidian).output("licon.10", "licon.10 : min. licon spacing to varac channel : 0.25um") +not_in_cell4 = layout(source.cell_obj).select("-s8fs_gwdlvx4", "-s8fs_gwdlvx8", "-s8fs_hvrsw_x4", "-s8fs_hvrsw8", "-s8fs_hvrsw264", "-s8fs_hvrsw520", "-s8fs_rdecdrv", "-s8fs_rdec8”, “s8fs_rdec32", "-s8fs_rdec264", "-s8fs_rdec520") +not_in_cell4_licon = not_in_cell4.input(66, 44) +not_in_cell4_licon.and(diff.or(tap)).separation(gate.not(areaid_sc), 0.055, euclidian).output("licon.11", "licon.11 : min. licon spacing to gate : 0.055um") +licon.and(diff.or(tap)).separation(gate.and(areaid_sc), 0.05, euclidian).output("licon.11a", "licon.11a : min. licon spacing to gate inside areaid.sc : 0.05um") +in_cell4 = layout(source.cell_obj).select("+s8fs_gwdlvx4", "+s8fs_gwdlvx8", "+s8fs_hvrsw_x4", "+s8fs_hvrsw8", "+s8fs_hvrsw264", "+s8fs_hvrsw520") +in_cell4_licon = in_cell4.input(66, 44) +in_cell4_licon.and(diff.or(tap)).separation(gate, 0.04, euclidian).output("licon.11c", "licon.11c : min. licon spacing to gate for specific cells: 0.04um") +# rules 11.b , 11.d not coded +diff.interacting(gate).not(diff.interacting(gate).width(5.7, euclidian).polygons).output("licon.12", "licon.12 : max. sd width without licon : 5.7um") +licon.and(diff.or(tap)).separation(npc, 0.09, euclidian).output("licon.13", "licon.13 : min. difftap licon spacing to npc : 0.09um") +licon.and(poly).separation(diff.or(tap), 0.19, euclidian).output("licon.14", "licon.14 : min. poly licon spacing to difftap : 0.19um") +npc.enclosing(licon.and(poly), 0.1, euclidian).output("licon.15", "licon.15 : min. npc enclosure of poly-licon : 0.1um") +# rule licon.16 not applicable for the diff for the nmos of a nand gates or the pmos of a nor gates +#diff.not(gate).not_interacting(licon).output("licon.16", "licon.16 : diff must enclose one licon") +tap.not(uhvi).not_interacting(licon).output("licon.16", "licon.16 : tap must enclose one licon") +poly.and(tap).edges.not(tap.edges).output("licon.17", "licon.17 : tap must not straddle poly") +npc.not_interacting(licon.and(poly)).output("licon.18", "licon.18 : npc mut enclosed one poly-licon") + +# vpp +vpp.width(1.43, euclidian).output("vpp.1", "vpp.1 : min. vpp width : 1.43um") +# rules 1.b, 1.c not coded +vpp.and(poly.or(difftap)).output("vpp.3", "vpp.3 : vpp must not overlapp poly or diff or tap") +vpp.and(nwell).edges.not(vpp.edges).output("vpp.4", "vpp.4 : vpp must not straddle nwell") +vpp.and(dnwell).edges.not(vpp.edges).output("vpp.4", "vpp.4 : vpp must not straddle dnwell") +vpp.and(poly.or(li).or(m1).or(m2)).separation(poly.or(li).or(m1).or(m2), 1.5, euclidian).polygons.with_area(2.25,nil).output("vpp.5", "vpp.5 : min. vpp spacing to poly or li or m1 or m2 : 1.5um") +vpp.with_area(0..area(vpp.and(m3))*0.25).output("vpp.5a", "vpp.5a : max. m3 density in vpp : 0.25") +vpp.with_area(0..area(vpp.and(m4))*0.3).output("vpp.5b", "vpp.5b : max. m4 density in vpp : 0.3") +vpp.with_area(0..area(vpp.and(m5))*0.4).output("vpp.5c", "vpp.5c : max. m5 density in vpp : 0.4") +nwell.enclosing(vpp, 1.5, euclidian).output("vpp.8", "vpp.8 : nwell enclosure of vpp : 1.5") +vpp.separation(nwell, 1.5, euclidian).polygons.without_area(0).output("vpp.9", "vpp.9 : vpp spacing to nwell : 1.5") +# rule vpp.10 not coded +# rule vpp.11 not coded because moscap is not defined properly by any gds layer +# rules vpp.12a, 12b, 12c not coded because specific to one cell +if backend_flow = CU + m1.separation(vpp.and(m1), 0.16, euclidian).polygons.without_area(0).output("vpp.13", "vpp.13 : m1 spacing to m1inside vpp : 0.16") +end + +# CAPM +capm.width(1.0, euclidian).output("capm.1", "capm.1 : min. capm width : 1.0um") +capm.isolated(0.84, euclidian).output("capm.2a", "capm.2a : min. capm spacing : 0.84um") +m2.interacting(capm).isolated(1.2, euclidian).output("capm.2b", "capm.2b : min. capm spacing : 1.2um") +m2.enclosing(capm, 0.14, euclidian).output("capm.3", "capm.3 : min. m2 enclosure of capm : 0.14um") +capm.enclosing(via2, 0.14, euclidian).output("capm.4", "capm.4 : min. capm enclosure of via2 : 0.14um") +capm.separation(via2, 0.14, euclidian).output("capm.5", "capm.5 : min. capm spacing to via2 : 0.14um") +capm.sized(-20.0).sized(20.0).output("capm.6", "capm.6 : max. capm lenght/width : 20um") +capm.with_angle(0 .. 90).output("capm.7", "capm.7 : capm not rectangle") +capm.separation(via, 0.14, euclidian).polygons.without_area(0).output("capm.8", "capm.8 : min. capm spacing to via : 0.14um") +capm.and(nwell).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle nwell") +capm.and(diff).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle diff") +capm.and(tap).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle tap") +capm.and(poly).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle poly") +capm.and(li).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle li") +capm.and(m1).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle m1") +capm.separation(m2.not_interacting(capm), 0.14, euclidian).output("capm.11", "capm.11 : min. capm spacing to m2 not overlapping capm : 0.5um") + +end #FEOL + +if BEOL +info("BEOL section") + +# li +not_in_cell5 = source.select("-s8rf2_xcmvpp_hd5_*") +not_in_cell5_li = not_in_cell5.polygons(li_wildcard) +not_in_cell5_li.width(0.17, euclidian).output("li.1", "li.1 : min. li width : 0.17um") + +in_cell5_li = li - not_in_cell5_li +in_cell5_li.width(0.14, euclidian).output("li.1a", "li.1a : min. li width for the cells s8rf2_xcmvpp_hd5_* : 0.14um") + +# rule li.2 not coded + +not_in_cell5_li.space(0.17, euclidian).output("li.3", "li.3 : min. li spacing : 0.17um") +in_cell5_li.space(0.14, euclidian).output("li.3a", "li.3a : min. li spacing for the cells s8rf2_xcmvpp_hd5_* : 0.14um") +licon08 = licon.interacting(li.enclosing(licon, 0.08, euclidian).polygons) +licon_edges_with_less_enclosure_li = li.enclosing(licon, 0.08, projection).second_edges +opposite3 = (licon.edges - licon_edges_with_less_enclosure_li).width(0.17 + 1.dbu, projection).polygons +licon08.not_interacting(opposite3).output("li.5", "li.5 : min. li enclosure of licon of 2 opposite edges : 0.08um") +li.with_area(0..0.0561).output("li.6", "li.6 : min. li area : 0.0561um²") + +# ct +mcon.edges.without_length(0.17).output("ct.1", "ct.1 : minimum/maximum width of mcon : 0.17um") +mcon.space(0.19, euclidian).output("ct.2", "ct.2 : min. mcon spacing : 0.19um") +# rule ct.3 not coded +mcon.not(li).output("ct.4", "ct.4 : mcon should covered by li") +if backend_flow = CU + li.interacting(li.and(m1).not(mcon).with_holes(1,10)).enclosing(mcon, 0.2, euclidian).output("ct.irdrop.1", "ct.irdrop.1 : min. li enclsoure of 1..10 mcon : 0.2um") + li.interacting(li.and(m1).not(mcon).with_holes(11,100)).enclosing(mcon, 0.3, euclidian).output("ct.irdrop.2", "ct.irdrop.2 : min. li enclsoure of 11..100 mcon : 0.3um") +end + +# m1 +m1.width(0.14, euclidian).output("m1.1", "m1.1 : min. m1 width : 0.14um") + +huge_m1 = m1.sized(-1.5).sized(1.5) +non_huge_m1 = m1 - huge_m1 + +non_huge_m1.space(0.14, euclidian).output("m1.2", "m1.2 : min. m1 spacing : 0.14um") + +(huge_m1.separation(non_huge_m1, 0.28, euclidian) + huge_m1.space(0.28, euclidian)).output("m1.3ab", "m1.3ab : min. 3um.m1 spacing m1 : 0.28um") + +not_in_cell6 = layout(source.cell_obj).select("-s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b", "-s8fpls_pl8", "-s8fs_cmux4_fm") +not_in_cell6_m1 = not_in_cell6.input(m1_wildcard) +not_in_cell6_m1.enclosing(mcon, 0.03, euclidian).output("m1.4", "m1.4 : min. m1 enclosure of mcon : 0.03um") +in_cell6 = layout(source.cell_obj).select("+s8cell_ee_plus_sseln_a", "+s8cell_ee_plus_sseln_b", "+s8cell_ee_plus_sselp_a", "+s8cell_ee_plus_sselp_b", "+s8fpls_pl8", "+s8fs_cmux4_fm") +in_cell6_m1 = in_cell6.input(m1_wildcard) +in_cell6_m1.enclosing(mcon, 0.005, euclidian).output("m1.4a", "m1.4a : min. m1 enclosure of mcon for specific cells : 0.005um") +m1.with_area(0..0.083).output("m1.6", "m1.6 : min. m1 area : 0.083um²") +m1.holes.with_area(0..0.14).output("m1.7", "m1.7 : min. m1 holes area : 0.14um²") +if backend_flow = AL + mcon06 = mcon.interacting(poly.enclosing(m1, 0.06, euclidian).polygons) + mcon_edges_with_less_enclosure_m1 = m1.enclosing(mcon, 0.06, projection).second_edges + opposite4 = (mcon.edges - mcon_edges_with_less_enclosure_m1).width(0.17 + 1.dbu, projection).polygons + mcon06.not_interacting(opposite4).output("m1.5", "m1.5 : min. m1 enclosure of mcon of 2 opposite edges : 0.06um") + # rule m1.pd.1, rule m1.pd.2a, rule m1.pd.2b not coded +end +if bakend_flow = CU + m1.sized(-2.0).sized(2.0).output("m1.11", "m1.11 : max. m1 width after slotting : 4.0um") + # rule m1.12 not coded because inconsistent with m1.11 + # rule m1.13, m1.14, m1.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +end + +# via +#rule via.3 not coded +via.not(m1).output("via.4c.5c", "via.4c.5c : m1 must enclose all via") +if backend_flow = AL + via.not(areaid_mt).edges.without_length(0.15).output("via.1a", "via.1a : minimum/maximum width of via : 0.15um") + via.and(areaid_mt).not_interacting((via.and(areaid_mt).edges.without_length(0.15)).or(via.and(areaid_mt).edges.without_length(0.23)).or(via.and(areaid_mt).edges.without_length(0.28))).output("via.1b", "via.1b : minimum/maximum width of via in areaid.mt: 0.15um or 0.23um or 0.28um") + via.isolated(0.17, euclidian).output("via.2", "via.2 : min. via spacing : 0.17um") + m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.055, euclidian).output("via.4a", "via.4a : min. m1 enclosure of 0.15um via : 0.055um") + m1.enclosing(via.not_interacting(via.edges.without_length(0.23)), 0.03, euclidian).output("via.4b", "via.4b : min. m1 enclosure of 0.23um via : 0.03um") + via1_edges_with_less_enclosure_m1 = m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.085, projection).second_edges + opposite5 = (via.not_interacting(via.edges.without_length(0.15)).edges - via1_edges_with_less_enclosure_m1).width(0.15 + 1.dbu, projection).polygons + via.not_interacting(via.edges.without_length(0.15)).not_interacting(opposite5).output("via1.5a", "via1.5a : min. m1 enclosure of 0.15um via of 2 opposite edges : 0.085um") + via2_edges_with_less_enclosure_m1 = m1.enclosing(via.not_interacting(via.edges.without_length(0.23)), 0.06, projection).second_edges + opposite6 = (via.not_interacting(via.edges.without_length(0.23)).edges - via2_edges_with_less_enclosure_m1).width(0.23 + 1.dbu, projection).polygons + via.not_interacting(via.edges.without_length(0.23)).not_interacting(opposite6).output("via1.5b", "via1.5b : min. m1 enclosure of 0.23um via of 2 opposite edges : 0.06um") +end +if backend_flow = CU + via.not(areaid_mt).edges.without_length(0.18).output("via.11", "via.11 : minimum/maximum width of via : 0.18um") + via.isolated(0.13, euclidian).output("via.12", "via.12 : min. via spacing : 0.13um") + # rule via.13 not coded because not understandable + via1_edges_with_less_enclosure_m1 = m1.enclosing(via, 0.04, projection).second_edges + opposite5 = (via.edges - via1_edges_with_less_enclosure_m1).width(0.18 + 1.dbu, projection).polygons + via.not_interacting(opposite5).output("via1.14", "via1.14 : min. m1 enclosure of 0.04um via of 2 opposite edges : 0.04um") + # rules via.irdrop.1, via.irdrop.2, via.irdrop.3, via.irdrop.4 not coded because not understandable +end + +# m2 +m2.width(0.14, euclidian).output("m2.1", "m2.1 : min. m2 width : 0.14um") + +huge_m2 = m2.sized(-1.5).sized(1.5) +non_huge_m2 = m2 - huge_m2 + +non_huge_m2.space(0.14, euclidian).output("m2.2", "m2.2 : min. m2 spacing : 0.14um") + +(huge_m2.separation(non_huge_m2, 0.28, euclidian) + huge_m2.space(0.28, euclidian)).output("m2.3ab", "m2.3ab : min. 3um.m2 spacing m2 : 0.28um") + +# rule m2.3c not coded +m2.with_area(0..0.0676).output("m2.6", "m2.6 : min. m2 area : 0.0676um²") +m2.holes.with_area(0..0.14).output("m2.7", "m2.7 : min. m2 holes area : 0.14um²") +via.not(m2).output("m2.via", "m2.via : m2 must enclose via") +if backend_flow = AL + m2.enclosing(via, 0.055, euclidian).output("m2.4", "m2.4 : min. m2 enclosure of via : 0.055um") + via_edges_with_less_enclosure_m2 = m2.enclosing(via, 0.085, projection).second_edges + opposite7 = (via.edges - via_edges_with_less_enclosure_m2).width(0.2 + 1.dbu, projection).polygons + via.not_interacting(opposite7).output("m2.5", "m2.5 : min. m2 enclosure of via of 2 opposite edges : 0.085um") + # rule m2.pd.1, rule m2.pd.2a, rule m2.pd.2b not coded +end +if bakend_flow = CU + m2.sized(-2.0).sized(2.0).output("m2.11", "m2.11 : max. m2 width after slotting : 4.0um") + # rule m2.12 not coded because inconsistent with m2.11 + # rule m2.13, m2.14, m2.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +end + +# via2 +#rule via233 not coded +via2.not(m2).output("via2", "via2 : m2 must enclose all via2") +if backend_flow = AL + via2.not(areaid_mt).edges.without_length(0.2).output("via2.1a", "via2.1a : minimum/maximum width of via2 : 0.2um") + via2.and(areaid_mt).not_interacting((via2.and(areaid_mt).edges.without_length(0.2)).or(via2.and(areaid_mt).edges.without_length(1.2)).or(via2.and(areaid_mt).edges.without_length(1.5))).output("via2.1b", "via2.1b : minimum/maximum width of via2 in areaid.mt: 0.2um or 1.2um or 1.5um") + via2.isolated(0.2, euclidian).output("via2.2", "via2.2 : min. via2 spacing : 0.2um") + m2.enclosing(via2, 0.04, euclidian).output("via2.4", "via2.4 : min. m2 enclosure of via2 : 0.04um") + m2.enclosing(via2.not_interacting(via2.edges.without_length(1.5)), 0.14, euclidian).output("via2.4a", "via2.4a : min. m2 enclosure of 1.5um via2 : 0.14um") + via2_edges_with_less_enclosure_m2 = m2.enclosing(via2, 0.085, projection).second_edges + opposite8 = (via2.edges - via2_edges_with_less_enclosure_m2).width(0.2 + 1.dbu, projection).polygons + via2.not_interacting(opposite8).output("via2.5", "via2.5 : min. m2 enclosure of via2 of 2 opposite edges : 0.085um") +end +if backend_flow = CU + via2.edges.without_length(0.21).output("via2.11", "via2.11 : minimum/maximum width of via2 : 0.21um") + via2.isolated(0.18, euclidian).output("via2.12", "via2.12 : min. via2 spacing : 0.18um") + # rule via2.13 not coded because not understandable, or not clear + m2.enclosing(via2, 0.035, euclidian).output("via2.14", "via2.14 : min. m2 enclosure of via2 : 0.035um") + # rules via2.irdrop.1, via2.irdrop.2, via2.irdrop.3, via2.irdrop.4 not coded because not understandable +end + +# m3 +m3.width(0.3, euclidian).output("m3.1", "m3.1 : min. m3 width : 0.3um") + +huge_m3 = m3.sized(-1.5).sized(1.5) +non_huge_m3 = m3 - huge_m3 + +non_huge_m3.space(0.3, euclidian).output("m3.2", "m3.2 : min. m3 spacing : 0.3um") + +(huge_m3.separation(non_huge_m3, 0.4, euclidian) + huge_m3.space(0.4, euclidian)).output("m3.3ab", "m3.3ab : min. 3um.m3 spacing m3 : 0.4um") + +# rule m3.3c not coded +m3.with_area(0..0.24).output("m3.6", "m3.6 : min. m2 area : 0.24um²") +via2.not(m3).output("m3.via2", "m3.via2 : m3 must enclose via2") +if backend_flow = AL + m3.enclosing(via2, 0.065, euclidian).output("m3.4", "m3.4 : min. m3 enclosure of via2 : 0.065um") + via2_edges_with_less_enclosure_m3 = m3.enclosing(via2, 0.085, projection).second_edges + # m3.5 N/A + # opposite9 = (via2.edges - via2_edges_with_less_enclosure_m3).width(0.3 + 1.dbu, projection).polygons + # via2.not_interacting(opposite9).output("m3.5", "m3.5 : min. m3 enclosure of via2 of 2 opposite edges : 0.085um") + # rule m3.pd.1, rule m3.pd.2a, rule m3.pd.2b not coded +end +if bakend_flow = CU + m3.holes.with_area(0..0.2).output("m3.7", "m3.7 : min. m2 holes area : 0.2um²") + m3.sized(-2.0).sized(2.0).output("m3.11", "m3.11 : max. m3 width after slotting : 4.0um") + # rule m3.12 not coded because inconsistent with m3.11 + # rule m3.13, m3.14, m3.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +end + +# via3 +#rule via3.3 not coded +via3.not(m3).output("via3", "via3 : m3 must enclose all via3") +if backend_flow = AL + via3.not(areaid_mt).edges.without_length(0.2).output("via3.1a", "via3.1a : minimum/maximum width of via3 : 0.2um") + via3.and(areaid_mt).not_interacting((via3.and(areaid_mt).edges.without_length(0.2)).or(via3.and(areaid_mt).edges.without_length(0.8))).output("via3.1a", "via3.1a : minimum/maximum width of via3 in areaid.mt: 0.2um or 0.8um") + via3.isolated(0.2, euclidian).output("via3.2", "via3.2 : min. via3 spacing : 0.2um") + m3.enclosing(via3, 0.06, euclidian).output("via3.4", "via3.4 : min. m3 enclosure of via3 : 0.06um") + via3_edges_with_less_enclosure_m3 = m3.enclosing(via3, 0.09, projection).second_edges + opposite10 = (via3.edges - via3_edges_with_less_enclosure_m3).width(0.2 + 1.dbu, projection).polygons + via3.not_interacting(opposite10).output("via3.5", "via3.5 : min. m2 enclosure of via3 of 2 opposite edges : 0.09um") +end +if backend_flow = CU + via3.edges.without_length(0.21).output("via3.11", "via3.11 : minimum/maximum width of via3 : 0.21um") + via3.isolated(0.18, euclidian).output("via3.12", "via3.12 : min. via3 spacing : 0.18um") + m3.enclosing(via3, 0.055, euclidian).output("via3.13", "via3.13 : min. m3 enclosure of via3 : 0.055um") + # rule via3.14 not coded because not understandable, or not clear + # rules via3.irdrop.1, via3.irdrop.2, via3.irdrop.3, via3.irdrop.4 not coded because not understandable +end + +# m4 +m4.width(0.3, euclidian).output("m4.1", "m4.1 : min. m4 width : 0.3um") + +huge_m4 = m4.sized(-1.5).sized(1.5) +non_huge_m4 = m4 - huge_m4 + +non_huge_m4.space(0.3, euclidian).output("m4.2", "m4.2 : min. m4 spacing : 0.3um") + +(huge_m4.separation(non_huge_m4, 0.4, euclidian) + huge_m4.space(0.4, euclidian)).output("m4.5ab", "m4.5ab : min. 3um.m4 spacing m4 : 0.4um") + +m4.with_area(0..0.24).output("m4.4", "m4.4 : min. m2 area : 0.24um²") +via3.not(m4).output("m4.via3", "m4.via3 : m4 must enclose via3") +if backend_flow = AL + m4.enclosing(via3, 0.065, euclidian).output("m4.3", "m4.3 : min. m4 enclosure of via3 : 0.065um") + # m4.5 doesn't exist + # via3_edges_with_less_enclosure_m4 = m4.enclosing(via2, 0.085, projection).second_edges + # opposite9 = (via3.edges - via3_edges_with_less_enclosure_m4).width(0.3 + 1.dbu, projection).polygons + # via3.not_interacting(opposite9).output("m4.5", "m4.5 : min. m4 enclosure of via3 of 2 opposite edges : 0.085um") + # rule m4.pd.1, rule m4.pd.2a, rule m4.pd.2b not coded +end +if bakend_flow = CU + m4.holes.with_area(0..0.2).output("m4.7", "m4.7 : min. m2 holes area : 0.2um²") + m4.sized(-5.0).sized(5.0).output("m4.11", "m4.11 : max. m4 width after slotting : 10.0um") + # rule m4.12 not coded because inconsistent with m4.11 + # rule m4.13, m4.14, m4.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 + m4.enclosing(via3, 0.06, euclidian).output("m4.15", "m4.15 : min. m4 enclosure of via3 : 0.06um") +end + +# via4 +via4.edges.without_length(0.8).output("via4.1a", "via4.1a : minimum/maximum width of via4 : 0.8um") +via4.isolated(0.8, euclidian).output("via4.2", "via4.2 : min. via4 spacing : 0.8um") +#rule via4.3 not coded +m4.enclosing(via4, 0.19, euclidian).output("via4.4", "via4.4 : min. m4 enclosure of via4 : 0.19um") +via4.not(m4).output("via4", "via4 : m4 must enclose all via4") +if backend_flow = CU + # rules via4.irdrop.1, via4.irdrop.2, via4.irdrop.3, via4.irdrop.4 not coded because not understandable +end + +# m5 +m5.width(1.6, euclidian).output("m5.1", "m5.1 : min. m5 width : 1.6um") + +m5.space(1.6, euclidian).output("m5.2", "m5.2 : min. m5 spacing : 1.6um") + +via4.not(m5).output("m5.via4", "m5.via4 : m5 must enclose via4") +m5.enclosing(via4, 0.31, euclidian).output("m5.3", "m4.3 : min. m5 enclosure of via4 : 0.31um") + +# nsm +nsm.width(3.0, euclidian).output("nsm.1", "nsm.1 : min. nsm width : 3.0um") +nsm.isolated(4.0, euclidian).output("nsm.2", "nsm.2 : min. nsm spacing : 4.0um") +nsm.enclosing(diff, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of diff : 3.0um") +nsm.enclosing(tap, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of tap : 3.0um") +nsm.enclosing(poly, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of poly : 3.0um") +nsm.enclosing(li, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of li : 3.0um") +nsm.enclosing(m1, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m1 : 3.0um") +nsm.enclosing(m2, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m2 : 3.0um") +nsm.enclosing(m3, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m3 : 3.0um") +nsm.enclosing(m4, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m4 : 3.0um") +nsm.enclosing(m5, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m5 : 3.0um") +nsm.enclosing(cfom, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of cfom : 3.0um") +if backend_flow = AL + nsm.separation(diff, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to diff : 1.0um") + nsm.separation(tap, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to tap : 1.0um") + nsm.separation(poly, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to poly : 1.0um") + nsm.separation(li, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to li : 1.0um") + nsm.separation(m1, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m1 : 1.0um") + nsm.separation(m2, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m2 : 1.0um") + nsm.separation(m3, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m3 : 1.0um") + nsm.separation(m4, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m4 : 1.0um") + nsm.separation(m5, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m5 : 1.0um") + nsm.separation(cfom, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to cfom : 1.0um") +end + +# pad +pad.isolated(1.27, euclidian).output("pad.2", "pad.2 : min. pad spacing : 1.27um") + +end #BEOL + +if FEOL +info("FEOL section") + +# mf +mf.not_interacting(mf.edges.without_length(0.8)).output("mf.1", "mf.1 : minimum/maximum width of fuse : 0.8um") +mf.not_interacting(mf.edges.without_length(7.2)).output("mf.2", "mf.2 : minimum/maximum length of fuse : 7.2um") +mf.isolated(1.96, euclidian).output("mf.3", "mf.3 : min. fuse center spacing : 2.76um") +# fuses need more clarification on fuse_shield, fuse layers ... + +# hvi +hvi.width(0.6, euclidian).output("hvi.1", "hvi.1 : min. hvi width : 0.6um") +hvi.isolated(0.7, euclidian).output("hvi.2", "hvi.2 : min. hvi spacing, merge if less : 0.7um") +hvi.and(tunm).output("hvi.4", "hvi.4 : hvi must not overlapp tunm") +hvi.and(nwell).separation(nwell, 2.0, euclidian).output("hvnwell.8", "hvnwelli.8 : min. hvnwel spacing to nwell : 2.0") +areaid_hl.not(hvi).output("hvnwel.9", "hvnwell.9 : hvi must overlapp hvnwell") +# rule hvnell.10 not coded +diff.not(psdm.and(diff_rs)).and(hvi).width(0.29, euclidian).output("hvdifftap.14", "hvdifftap.14 : min. diff inside hvi width : 0.29um") +diff.and(psdm.and(diff_rs)).and(hvi).width(0.15, euclidian).output("hvdifftap.14a", "hvdifftap.14a : min. p+diff resistor inside hvi width : 0.15um") +diff.and(hvi).isolated(0.3, euclidian).output("hvdifftap.15a", "hvdifftap.15a : min. diff inside hvi spacing : 0.3um") +diff.and(hvi).and(nsdm).separation(diff.and(hvi).and(psdm), 0.37, euclidian).polygons.without_area(0).output("hvdifftap.15b", "hvdifftap.15b : min. n+diff inside hvi spacing to p+diff inside hvi except abutting: 0.37um") +tap.and(hvi).edges.and(diff).without_length(0.7).output("hvdifftap.16", "hvdifftap.16 : min. tap inside hvi abuttng diff : 0.7um") +hvi.and(nwell).enclosing(diff, 0.33, euclidian).output("hvdifftap.17", "hvdifftap.17 : min. hvnwell enclosure of p+diff : 0.33um") +hvi.and(nwell).separation(diff, 0.43, euclidian).output("hvdifftap.18", "hvdifftap.18 : min. hvnwell spacing to n+diff : 0.43um") +hvi.and(nwell).enclosing(tap, 0.33, euclidian).output("hvdifftap.19", "hvdifftap.19 : min. hvnwell enclosure of n+tap : 0.33um") +hvi.and(nwell).separation(tap, 0.43, euclidian).output("hvdifftap.20", "hvdifftap.20 : min. hvnwell spacing to p+tap : 0.43um") +hvi.and(diff).edges.not(diff.edges).output("hvdifftap.21", "hvdifftap.21 : diff must not straddle hvi") +hvi.and(tap).edges.not(tap.edges).output("hvdifftap.21", "hvdifftap.21 : tap must not straddle hvi") +hvi.enclosing(difftap, 0.18, euclidian).output("hvdifftap.22", "hvdifftap.22 : min. hvi enclosure of diff or tap : 0.18um") +hvi.separation(difftap, 0.18, euclidian).output("hvdifftap.23", "hvdifftap.23 : min. hvi spacing to diff or tap : 0.18um") +hvi.and(diff).not(nwell).separation(nwell, 0.43, euclidian).output("hvdifftap.24", "hvdifftap.24 : min. hv n+diff spacing to nwell : 0.43um") +diff.and(hvi).not(nwell).isolated(1.07, euclidian).polygons.and(tap).output("hvdifftap.25", "hvdifftap.25 : min. n+diff inside hvi spacing accros p+tap : 1.07um") +diff.not(poly).edges.and(gate.and(hvi).edges).space(0.35, euclidian).output("hvpoly.13", "hvpoly.13: min. hvi gate length : 0.5um") +hvi.and(poly).edges.not(poly.edges).output("hvpoly.14", "hvpoly.14 : poly must not straddle hvi") + +# hvntm +hvntm.width(0.7, euclidian).output("hvntm.1", "hvntm.1 : min. hvntm width : 0.7um") +hvntm.isolated(0.7, euclidian).output("hvntm.2", "hvntm.2 : min. hvntm spacing : 0.7um") +hvntm.enclosing(diff.and(nwell).and(hvi), 0.185, euclidian).output("hvntm.3", "hvntm.3 : min. hvntm enclosure of hv n+diff : 0.185um") +hvntm.separation(diff.not(nwell).not(hvi), 0.185, euclidian).output("hvntm.4", "hvntm.4 : min. hvntm spacing to n+diff : 0.185um") +hvntm.separation(diff.and(nwell).not(hvi), 0.185, euclidian).output("hvntm.5", "hvntm.5 : min. hvntm spacing to p+diff : 0.185um") +hvntm.separation(tap.not(nwell).not(hvi), 0.185, euclidian).polygons.without_area(0).output("hvntm.6a", "hvntm.6a : min. hvntm spacing to p+tap : 0.185um") +hvntm.and(areaid_ce).output("hvntm.9", "hvntm.9 : hvntm must not overlapp areaid.ce") + +# denmos +poly.not_interacting(pwde).interacting(areaid_en).width(1.055, projection).output("denmos.1", "denmos.1 : min. de_nfet gate width : 1.055um") +diff.not_interacting(pwde).enclosing(poly.interacting(areaid_en), 0.28, projection).polygons.without_area(0).output("denmos.2", "denmos.2 : min. de_nfet source ouside poly width : 0.28um") +diff.not_interacting(pwde).and(poly.interacting(areaid_en)).width(0.925, projection).output("denmos.3", "denmos.3 : min. de_nfet source inside poly width : 0.925um") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).width(0.17, euclidian).output("denmos.4", "denmos.4 : min. de_nfet drain width : 0.17um") +nwell.not_interacting(pwde).and(poly.interacting(areaid_en)).width(0.225, projection).polygons.or(nwell.and(poly.interacting(areaid_en)).sized(-0.1125).sized(0.1125)).output("denmos.5", "denmos.5 : min. de_nfet source inside nwell width : 0.225m") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).separation(diff.interacting(poly.interacting(areaid_en)), 1.585, projection).output("denmos.6", "denmos.6 : min. de_nfet source spacing to drain : 1.585um") +nwell.not_interacting(pwde).and(poly.and(diff).interacting(areaid_en)).edges.without_length(5.0, nil).output("denmos.7", "denmos.7 : min. de_nfet channel width : 5.0um") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("denmos.8", "denmos.8 : 90deg. not allowed for de_nfet drain") +nwell.not_interacting(pwde).interacting(areaid_en).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("denmos.9a", "denmos.9a : 90deg. not allowed for de_nfet nwell") +nwell.not_interacting(pwde).interacting(areaid_en).edges.with_angle(45).without_length(0.607..0.609).output("denmos.9a", "denmos.9a : 45deg. bevels of de_nfet nwell should be 0.43um from corners") +nwell.not_interacting(pwde).interacting(areaid_en).edges.with_angle(135).without_length(0.607..0.609).output("denmos.9a", "denmos.9a : 45deg. bevels of de_nfet nwell should be 0.43um from corners") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(45).without_length(0.7..0.71).output("denmos.9b", "denmos.9b : 45deg. bevels of de_nfet drain should be 0.05um from corners") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(135).without_length(0.7..0.71).output("denmos.9b", "denmos.9b : 45deg. bevels of de_nfet drain should be 0.05um from corners") +nwell.not_interacting(pwde).enclosing(diff.interacting(areaid_en).not_interacting(poly), 0.66, euclidian).output("denmos.10", "denmos.10 : min. nwell enclosure of de_nfet drain : 0.66um") +nwell.not_interacting(pwde).interacting(areaid_en).separation(tap.not(nwell), 0.86, euclidian).output("denmos.11", "denmos.11 : min. de_nfet nwell spacing to tap : 0.86um") +nwell.not_interacting(pwde).interacting(areaid_en).isolated(2.4, euclidian).output("denmos.12", "denmos.12 : min. de_nfet nwell : 2.4um") +nsdm.not_interacting(pwde).enclosing(diff.interacting(areaid_en).interacting(poly), 0.13, euclidian).output("denmos.13", "denmos.13 : min. nsdm enclosure of de_nfet source : 0.13um") + +# depmos +poly.interacting(pwde).interacting(areaid_en).width(1.05, projection).output("depmos.1", "depmos.1 : min. de_pfet gate width : 1.05um") +diff.interacting(pwde).enclosing(poly.interacting(areaid_en), 0.28, projection).polygons.without_area(0).output("depmos.2", "depmos.2 : min. de_pfet source ouside poly width : 0.28um") +diff.interacting(pwde).and(poly.interacting(areaid_en)).width(0.92, projection).output("depmos.3", "depmos.3 : min. de_pfet source inside poly width : 0.92um") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).width(0.17, euclidian).output("depmos.4", "depmos.4 : min. de_pfet drain width : 0.17um") +pwde.not(nwell).and(poly.interacting(areaid_en)).width(0.26, projection).polygons.or(pwde.not(nwell).and(poly.interacting(areaid_en)).sized(-0.13).sized(0.13)).output("depmos.5", "depmos.5 : min. de_pfet source inside nwell width : 0.26m") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).separation(diff.interacting(poly.interacting(areaid_en)), 1.19, projection).output("depmos.6", "depmos.6 : min. de_pfet source spacing to drain : 1.19um") +nwell.interacting(pwde).and(poly.and(diff).interacting(areaid_en)).edges.without_length(5.0, nil).output("depmos.7", "depmos.7 : min. de_pfet channel width : 5.0um") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("depmos.8", "depmos.8 : 90deg. not allowed for de_pfet drain") +pwde.not(nwell).interacting(areaid_en).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("depmos.9a", "depmos.9a : 90deg. not allowed for de_pfet pwell") +pwde.not(nwell).interacting(areaid_en).edges.with_angle(45).without_length(0.607..0.609).output("depmos.9a", "depmos.9a : 45deg. bevels of de_pfet pwell should be 0.43um from corners") +pwde.not(nwell).interacting(areaid_en).edges.with_angle(135).without_length(0.607..0.609).output("depmos.9a", "depmos.9a : 45deg. bevels of de_pfet pwell should be 0.43um from corners") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(45).without_length(0.7..0.71).output("depmos.9b", "depmos.9b : 45deg. bevels of de_pfet drain should be 0.05um from corners") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(135).without_length(0.7..0.71).output("depmos.9b", "depmos.9b : 45deg. bevels of de_pfet drain should be 0.05um from corners") +nwell.interacting(pwde).separation(diff.interacting(areaid_en).not_interacting(poly), 0.86, euclidian).output("depmos.10", "depmos.10 : min. pwell enclosure of de_pfet drain : 0.86um") +pwde.not(nwell).interacting(areaid_en).separation(tap.and(nwell), 0.66, euclidian).output("depmos.11", "depmos.11 : min. de_pfet pwell spacing to tap : 0.66um") +psdm.interacting(pwde).enclosing(diff.interacting(areaid_en).interacting(poly), 0.13, euclidian).output("depmos.12", "depmos.12 : min. psdm enclosure of de_pfet source : 0.13um") + +# extd +areaid_en.and(difftap).edges.not(difftap.edges).output("extd.1", "extd.1 : difftap must not straddle areaid.en") +difftap.interacting(areaid_en).not(poly).with_area(0).output("extd.2", "extd.2 : poly must not overlapp entirely difftap in areaid.en") +# rules extd.4, extd.5, extd.6, extd.7 not coded because specific to some cells + +# vhvi +# rules vhvi.vhv.1, vhvi.vhv.2, vhvi.vhv.3, vhvi.vhv.4, vhvi.vhv.5, vhvi.vhv.6 not coded +vhvi.width(0.02, euclidian).output("vhvi.1", "vhvi.1 : min. vhvi width : 0.02um") +vhvi.and(areaid_ce).output("vhvi.2", "vhvi.2 : vhvi must not overlap areaid.ce") +vhvi.and(hvi).output("vhvi.3", "vhvi.3 : vhvi must not overlap hvi") +# rules vhvi.4, vhvi.6 not coded +vhvi.and(diff).edges.not(diff.edges).output("vhvi.5", "vhvi.5 : vhvi must not straddle diff") +vhvi.and(tap).edges.not(tap.edges).output("vhvi.5", "vhvi.5 : vhvi must not straddle tap") +vhvi.and(poly).edges.not(poly.edges).output("vhvi.7", "vhvi.7 : vhvi must not straddle poly") + +nwell.and(vhvi).separation(nwell, 2.5, euclidian).output("hv.nwell.1", "hv.nwell.1 : min. vhvi nwell spacing to nwell : 2.5um") +diff.and(vhvi).isolated(0.3, euclidian).output("hv.diff.1", "hv.diff.1 : min. vhvi diff spacing : 0.3um") +nwell.interacting(diff.and(vhvi)).separation(diff.not(nwell), 0.43, euclidian).output("hv.diff.2", "hv.diff.2 : min. vhvi nwell spacing n+diff : 0.43um") +diff.and(vhvi).not(nwell).separation(nwell, 0.55, euclidian).output("hv.diff.3a", "hv.diff.3a : min. vhvi n+diff spacing nwell : 0.55um") +# rule hv.diff.3b not coded +poly.and(vhvi).not(diff).separation(diff, 0.3, euclidian).polygons.without_area(0).output("hv.poly.2", "hv.poly.2 : min. vhvi poly spacing to diff : 0.3um") +poly.and(vhvi).not(diff).separation(nwell, 0.55, euclidian).polygons.without_area(0).output("hv.poly.3", "hv.poly.3 : min. vhvi poly spacing to nwell : 0.55um") +nwell.enclosing(poly.and(vhvi).not(diff), 0.3, euclidian).polygons.without_area(0).output("hv.poly.4", "hv.poly.4 : min. nwell enclosure of vhvi poly : 0.3um") +#poly.and(vhvi).enclosing(diff.interacting(areaid_en), 0.16, projection).polygons.without_area(0).output("hv.poly.6", "hv.poly.6 : min. poly enclosure of hvfet gate : 0.16um") +# rule hv.poly.7 not coded + +# uhvi +uhvi.and(diff).edges.not(diff.edges).output("uhvi.1", "uhvi.1 : diff must not straddle uhvi") +uhvi.and(tap).edges.not(tap.edges).output("uhvi.1", "uhvi.1 : tap must not straddle uhvi") +uhvi.and(poly).edges.not(poly.edges).output("uhvi.2", "uhvi.2 : poly must not straddle uhvi") +pwbm.not(uhvi).output("uhvi.3", "uhvi.3 : uhvi must not enclose pwbm") +uhvi.and(dnwell).edges.not(dnwell.edges).output("uhvi.4", "uhvi.4 : dnwell must not straddle uhvi") +areaid_en20.not(uhvi).output("uhvi.5", "uhvi.5 : uhvi must not enclose areaid.en20") +#dnwell.not(uhvi).output("uhvi.6", "uhvi.6 : uhvi must not enclose dnwell") +natfet.not(uhvi).output("uhvi.7", "uhvi.7 : uhvi must not enclose natfet") + +# pwell_res +pwell_rs.width(2.65).output("pwres.2", "pwres.2 : min. pwell resistor width : 2.65um") +pwell_rs.sized(-2.65).sized(2.65).output("pwres.2", "pwres.2 : max. pwell resistor width : 2.65um") +pwell_rs.interacting(pwell_rs.edges.with_length(2.651,26.499)).output("pwres.3", "pwres.3 : min. pwell resistor length : 26.5um") +pwell_rs.interacting(pwell_rs.edges.with_length(265.0, nil)).output("pwres.4", "pwres.4 : max. pwell resistor length : 265um") +tap.interacting(pwell_rs).separation(nwell, 0.22, euclidian).output("pwres.5", "pwres.5 : min. pwell resistor tap spacing to nwell : 0.22um") +tap.interacting(pwell_rs).and(tap.sized(0.22).and(nwell)).output("pwres.5", "pwres.5 : max. pwell resistor tap spacing to nwell : 0.22um") +tap.interacting(pwell_rs).width(0.53).output("pwres.6", "pwres.6 : min. width of tap inside pwell resistor : 0.53um") +tap.interacting(pwell_rs).sized(-0.265).sized(0.265).output("pwres.6", "pwres.6 : max. width of tap inside pwell resistor : 0.53um") +# rules pwres.7a, pwres.7b not coded +pwell_rs.and(diff).output("pwres.8", "pwres.8 : diff not allowed inside pwell resistor") +pwell_rs.and(poly).output("pwres.8", "pwres.8 : poly not allowed inside pwell resistor") +# rules pwres.9, pwres.10 not coded + +# rf_diode +areaid_re.with_angle(0 .. 90).output("rfdiode.1", "rfdiode.1 : non 90 degree angle areaid.re") +areaid_re.not(nwell).or(nwell.interacting(areaid_re).not(areaid_re)).output("rfdiode.2", "rfdiode.2 : areaid.re must coincide rf nwell diode") +# rule rfdiode.3 not coded + +end #FEOL + +if OFFGRID +info("OFFGRID-ANGLES section") + +dnwell.ongrid(0.005).output("dnwell_OFFGRID", "x.1b : OFFGRID vertex on dnwell") +dnwell.with_angle(0 .. 45).output("dnwell_angle", "x.3a : non 45 degree angle dnwell") +nwell.ongrid(0.005).output("nwell_OFFGRID", "x.1b : OFFGRID vertex on nwell") +nwell.with_angle(0 .. 45).output("nwell_angle", "x.3a : non 45 degree angle nwell") +pwbm.ongrid(0.005).output("pwbm_OFFGRID", "x.1b : OFFGRID vertex on pwbm") +pwbm.with_angle(0 .. 45).output("pwbm_angle", "x.3a : non 45 degree angle pwbm") +pwde.ongrid(0.005).output("pwde_OFFGRID", "x.1b : OFFGRID vertex on pwde") +pwde.with_angle(0 .. 45).output("pwde_angle", "x.3a : non 45 degree angle pwde") +hvtp.ongrid(0.005).output("hvtp_OFFGRID", "x.1b : OFFGRID vertex on hvtp") +hvtp.with_angle(0 .. 45).output("hvtp_angle", "x.3a : non 45 degree angle hvtp") +hvtr.ongrid(0.005).output("hvtr_OFFGRID", "x.1b : OFFGRID vertex on hvtr") +hvtr.with_angle(0 .. 45).output("hvtr_angle", "x.3a : non 45 degree angle hvtr") +lvtn.ongrid(0.005).output("lvtn_OFFGRID", "x.1b : OFFGRID vertex on lvtn") +lvtn.with_angle(0 .. 45).output("lvtn_angle", "x.3a : non 45 degree angle lvtn") +ncm.ongrid(0.005).output("ncm_OFFGRID", "x.1b : OFFGRID vertex on ncm") +ncm.with_angle(0 .. 45).output("ncm_angle", "x.3a : non 45 degree angle ncm") +diff.ongrid(0.005).output("diff_OFFGRID", "x.1b : OFFGRID vertex on diff") +tap.ongrid(0.005).output("tap_OFFGRID", "x.1b : OFFGRID vertex on tap") +diff.not(areaid_en.and(uhvi)).with_angle(0 .. 90).output("diff_angle", "x.2 : non 90 degree angle diff") +diff.and(areaid_en.and(uhvi)).with_angle(0 .. 45).output("diff_angle", "x.2c : non 45 degree angle diff") +tap.not(areaid_en.and(uhvi)).with_angle(0 .. 90).output("tap_angle", "x.2 : non 90 degree angle tap") +tap.and(areaid_en.and(uhvi)).with_angle(0 .. 45).output("tap_angle", "x.2c : non 45 degree angle tap") +tunm.ongrid(0.005).output("tunm_OFFGRID", "x.1b : OFFGRID vertex on tunm") +tunm.with_angle(0 .. 45).output("tunm_angle", "x.3a : non 45 degree angle tunm") +poly.ongrid(0.005).output("poly_OFFGRID", "x.1b : OFFGRID vertex on poly") +poly.with_angle(0 .. 90).output("poly_angle", "x.2 : non 90 degree angle poly") +rpm.ongrid(0.005).output("rpm_OFFGRID", "x.1b : OFFGRID vertex on rpm") +rpm.with_angle(0 .. 45).output("rpm_angle", "x.3a : non 45 degree angle rpm") +npc.ongrid(0.005).output("npc_OFFGRID", "x.1b : OFFGRID vertex on npc") +npc.with_angle(0 .. 45).output("npc_angle", "x.3a : non 45 degree angle npc") +nsdm.ongrid(0.005).output("nsdm_OFFGRID", "x.1b : OFFGRID vertex on nsdm") +nsdm.with_angle(0 .. 45).output("nsdm_angle", "x.3a : non 45 degree angle nsdm") +psdm.ongrid(0.005).output("psdm_OFFGRID", "x.1b : OFFGRID vertex on psdm") +psdm.with_angle(0 .. 45).output("psdm_angle", "x.3a : non 45 degree angle psdm") +licon.ongrid(0.005).output("licon_OFFGRID", "x.1b : OFFGRID vertex on licon") +licon.with_angle(0 .. 90).output("licon_angle", "x.2 : non 90 degree angle licon") +li.ongrid(0.005).output("li_OFFGRID", "x.1b : OFFGRID vertex on li") +li.with_angle(0 .. 45).output("li_angle", "x.3a : non 45 degree angle li") +mcon.ongrid(0.005).output("ct_OFFGRID", "x.1b : OFFGRID vertex on mcon") +mcon.with_angle(0 .. 90).output("ct_angle", "x.2 : non 90 degree angle mcon") +vpp.ongrid(0.005).output("vpp_OFFGRID", "x.1b : OFFGRID vertex on vpp") +vpp.with_angle(0 .. 45).output("vpp_angle", "x.3a : non 45 degree angle vpp") +m1.ongrid(0.005).output("m1_OFFGRID", "x.1b : OFFGRID vertex on m1") +m1.with_angle(0 .. 45).output("m1_angle", "x.3a : non 45 degree angle m1") +via.ongrid(0.005).output("via_OFFGRID", "x.1b : OFFGRID vertex on via") +via.with_angle(0 .. 90).output("via_angle", "x.2 : non 90 degree angle via") +m2.ongrid(0.005).output("m2_OFFGRID", "x.1b : OFFGRID vertex on m2") +m2.with_angle(0 .. 45).output("m2_angle", "x.3a : non 45 degree angle m2") +via2.ongrid(0.005).output("via2_OFFGRID", "x.1b : OFFGRID vertex on via2") +via2.with_angle(0 .. 90).output("via2_angle", "x.2 : non 90 degree angle via2") +m3.ongrid(0.005).output("m3_OFFGRID", "x.1b : OFFGRID vertex on m3") +m3.with_angle(0 .. 45).output("m3_angle", "x.3a : non 45 degree angle m3") +via3.ongrid(0.005).output("via3_OFFGRID", "x.1b : OFFGRID vertex on via3") +via3.with_angle(0 .. 90).output("via3_angle", "x.2 : non 90 degree angle via3") +nsm.ongrid(0.005).output("nsm_OFFGRID", "x.1b : OFFGRID vertex on nsm") +nsm.with_angle(0 .. 45).output("nsm_angle", "x.3a : non 45 degree angle nsm") +m4.ongrid(0.005).output("m4_OFFGRID", "x.1b : OFFGRID vertex on m4") +m4.with_angle(0 .. 45).output("m4_angle", "x.3a : non 45 degree angle m4") +via4.ongrid(0.005).output("via4_OFFGRID", "x.1b : OFFGRID vertex on via4") +via4.with_angle(0 .. 90).output("via4_angle", "x.2 : non 90 degree angle via4") +m5.ongrid(0.005).output("m5_OFFGRID", "x.1b : OFFGRID vertex on m5") +m5.with_angle(0 .. 45).output("m5_angle", "x.3a : non 45 degree angle m5") +pad.ongrid(0.005).output("pad_OFFGRID", "x.1b : OFFGRID vertex on pad") +pad.with_angle(0 .. 45).output("pad_angle", "x.3a : non 45 degree angle pad") +mf.ongrid(0.005).output("mf_OFFGRID", "x.1b : OFFGRID vertex on mf") +mf.with_angle(0 .. 90).output("mf_angle", "x.2 : non 90 degree angle mf") +hvi.ongrid(0.005).output("hvi_OFFGRID", "x.1b : OFFGRID vertex on hvi") +hvi.with_angle(0 .. 45).output("hvi_angle", "x.3a : non 45 degree angle hvi") +hvntm.ongrid(0.005).output("hvntm_OFFGRID", "x.1b : OFFGRID vertex on hvntm") +hvntm.with_angle(0 .. 45).output("hvntm_angle", "x.3a : non 45 degree angle hvntm") +vhvi.ongrid(0.005).output("vhvi_OFFGRID", "x.1b : OFFGRID vertex on vhvi") +vhvi.with_angle(0 .. 45).output("vhvi_angle", "x.3a : non 45 degree angle vhvi") +uhvi.ongrid(0.005).output("uhvi_OFFGRID", "x.1b : OFFGRID vertex on uhvi") +uhvi.with_angle(0 .. 45).output("uhvi_angle", "x.3a : non 45 degree angle uhvi") +pwell_rs.ongrid(0.005).output("pwell_rs_OFFGRID", "x.1b : OFFGRID vertex on pwell_rs") +pwell_rs.with_angle(0 .. 45).output("pwell_rs_angle", "x.3a : non 45 degree angle pwell_rs") +areaid_re.ongrid(0.005).output("areaid_re_OFFGRID", "x.1b : OFFGRID vertex on areaid.re") + +end #OFFGRID + diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-lvs-wip.lylvs b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-lvs-wip.lylvs new file mode 100755 index 00000000..42dff63a --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-lvs-wip.lylvs @@ -0,0 +1,87 @@ + + + + + lvs + + + + false + false + + true + lvs_scripts + tools_menu.lvs.end + dsl + lvs-dsl-xml + # +# Extraction for SKY130 +# +############################ + +# layers definitions +######################## +LI = polygons(67, 20) +LITXT = input(67, 5) +LIPIN = polygons(67, 16) +LIRES = polygons(67, 13) +MCON = polygons(67, 44) +MET1 = polygons(68, 20) +MET1TXT = input(68, 5) +MET1PIN = polygons(68, 16) +MET1RES = polygons(68, 13) +VIA1 = polygons(68, 44) +MET2 = polygons(69, 20) +MET2TXT = input(69, 5) +MET2PIN = polygons(69, 16) +MET2RES = polygons(69, 13) +VIA2 = polygons(69, 44) +MET3 = polygons(70, 20) +MET3TXT = input(70, 5) +MET3PIN = polygons(70, 16) +MET3RES = polygons(70, 13) +VIA3 = polygons(70, 44) +MET4 = polygons(71, 20) +MET4TXT = input(71, 5) +MET4PIN = polygons(71, 16) +MET4RES = polygons(71, 13) +VIA4 = polygons(71, 44) +MET5 = polygons(72, 20) +MET5TXT = input(72, 5) +MET5PIN = polygons(72, 16) +MET5RES = polygons(72, 13) + +# Define connectivity for netlist extraction + +# Inter-layer +connect(LI, MCON) +connect(MCON, MET1) +connect(MET1,VIA1) +connect(VIA1, MET2) +connect(MET2, VIA2) +connect(VIA2, MET3) +connect(MET3, VIA3) +connect(VIA3, MET4) +connect(MET4, VIA4) +connect(VIA4, MET5) +# Attaching labels +connect(LI, LITXT) +connect(MET1, MET1TXT) +connect(MET2, MET2TXT) +connect(MET3, MET3TXT) +connect(MET4, MET4TXT) +connect(MET5, MET5TXT) + +# Enter your Ruby code here +netlist = l2n_data.netlist +netlist.combine_devices +netlist.make_top_level_pins +netlist.purge +netlist.purge_nets + +writer = RBA::NetlistSpiceWriter::new + +path = "ringo_simplified.cir" + +netlist.write(path, writer, "Netlist comment") + diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-mr.lydrc b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-mr.lydrc new file mode 100755 index 00000000..63038409 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A-mr.lydrc @@ -0,0 +1,923 @@ + + + + + drc + + + + false + false + + true + drc_scripts + tools_menu.drc.end + dsl + drc-dsl-xml + # +# DRC for SKY130 according to : +# https://skywater-pdk.readthedocs.io/en/latest/rules/periphery.html +# https://skywater-pdk.readthedocs.io/en/latest/rules/layers.html +# +# Distributed under GNU GPLv3: https://www.gnu.org/licenses/ +# +# History : +# 2020-10-04 : v1.0 : initial release +# +########################################################################################## + +# optionnal for a batch launch : klayout -b -rd input=my_layout.gds -rd report=sky130_drc.txt -r drc_sky130.drc +if $input + source($input) +end + +if $report + report("SKY130 DRC runset", $report) +else + report("SKY130 DRC runset", File.join(File.dirname(RBA::CellView::active.filename), "sky130_drc.txt")) +end + +AL = true # do not change +CU = false # do not change +# choose betwen only one of AL or CU back-end flow here : +backend_flow = AL + +# enable / disable rule groups +FEOL = true # front-end-of-line checks +BEOL = true # back-end-of-line checks +OFFGRID = true # manufacturing grid/angle checks + +# klayout setup +######################## +# use a tile size of 1mm - not used in deep mode- +tiles(1000.um) +# use a tile border of 10 micron: +tile_borders(1.um) +#no_borders + +# hierachical +deep + +if $thr + threads($thr) +else + threads(4) +end + +# if more inof is needed, set true + verbose(true) +#verbose(false) + +# layers definitions +######################## + +# all except purpose (datatype) 5 -- label and 44 -- via +li_wildcard = "67/0-4,6-43,45-*" +mcon_wildcard = "67/44" + +m1_wildcard = "68/0-4,6-43,45-*" +via_wildcard = "68/44" + +m2_wildcard = "69/0-4,6-43,45-*" +via2_wildcard = "69/44" + +m3_wildcard = "70/0-4,6-43,45-*" +via3_wildcard = "70/44" + +m4_wildcard = "71/0-4,6-43,45-*" +via4_wildcard = "71/44" + +m5_wildcard = "72/0-4,6-43,45-*" + +diff = input(65, 20) +tap = polygons(65, 44) +nwell = polygons(64, 20) +dnwell = polygons(64, 18) +pwbm = polygons(19, 44) +pwde = polygons(124, 20) +natfet = polygons(124, 21) +hvtr = polygons(18, 20) +hvtp = polygons(78, 44) +ldntm = polygons(11, 44) +hvi = polygons(75, 20) +tunm = polygons(80, 20) +lvtn = polygons(125, 44) +poly = polygons(66, 20) +hvntm = polygons(125, 20) +nsdm = polygons(93, 44) +psdm = polygons(94, 20) +rpm = polygons(86, 20) +urpm = polygons(79, 20) +npc = polygons(95, 20) +licon = polygons(66, 44) + +li = polygons(li_wildcard) +mcon = polygons(mcon_wildcard) + +m1 = polygons(m1_wildcard) +via = polygons(via_wildcard) + +m2 = polygons(m2_wildcard) +via2 = polygons(via2_wildcard) + +m3 = polygons(m3_wildcard) +via3 = polygons(via3_wildcard) + +m4 = polygons(m4_wildcard) +via4 = polygons(via4_wildcard) + +m5 = polygons(m5_wildcard) + +pad = polygons(76, 20) +nsm = polygons(61, 20) +capm = polygons(89, 44) +cap2m = polygons(97, 44) +vhvi = polygons(74, 21) +uhvi = polygons(74, 22) +npn = polygons(82, 20) +inductor = polygons(82, 24) +vpp = polygons(82, 64) +pnp = polygons(82, 44) +lvs_prune = polygons(84, 44) +ncm = polygons(92, 44) +padcenter = polygons(81, 20) +mf = polygons(76, 44) +areaid_sl = polygons(81, 1) +areaid_ce = polygons(81, 2) +areaid_fe = polygons(81, 3) +areaid_sc = polygons(81, 4) +areaid_sf = polygons(81, 6) +areaid_sw = polygons(81, 7) +areaid_sr = polygons(81, 8) +areaid_mt = polygons(81, 10) +areaid_dt = polygons(81, 11) +areaid_ft = polygons(81, 12) +areaid_ww = polygons(81, 13) +areaid_ld = polygons(81, 14) +areaid_ns = polygons(81, 15) +areaid_ij = polygons(81, 17) +areaid_zr = polygons(81, 18) +areaid_ed = polygons(81, 19) +areaid_de = polygons(81, 23) +areaid_rd = polygons(81, 24) +areaid_dn = polygons(81, 50) +areaid_cr = polygons(81, 51) +areaid_cd = polygons(81, 52) +areaid_st = polygons(81, 53) +areaid_op = polygons(81, 54) +areaid_en = polygons(81, 57) +areaid_en20 = polygons(81, 58) +areaid_le = polygons(81, 60) +areaid_hl = polygons(81, 63) +areaid_sd = polygons(81, 70) +areaid_po = polygons(81, 81) +areaid_it = polygons(81, 84) +areaid_et = polygons(81, 101) +areaid_lvt = polygons(81, 108) +areaid_re = polygons(81, 125) +areaid_ag = polygons(81, 79) +poly_rs = polygons(66, 13) +diff_rs = polygons(65, 13) +pwell_rs = polygons(64, 13) +li_rs = polygons(67, 13) +cfom = polygons(22, 20) + + +# Define a new custom function that selects polygons by their number of holes: +# It will return a new layer containing those polygons with min to max holes. +# max can be nil to omit the upper limit. +class DRC::DRCLayer + def with_holes(min, max) + new_data = RBA::Region::new + self.data.each do |p| + if p.holes >= (min || 0) && (!max || p.holes <= max) + new_data.insert(p) + end + end + DRC::DRCLayer::new(@engine, new_data) + end +end + +# DRC section +######################## +info("DRC section") + +if FEOL +info("FEOL section") +gate = diff & poly + +# dnwell +dnwell.width(3.0, euclidian).output("dnwell.2", "dnwell.2 : min. dnwell width : 3.0um") +# dnwell.not(uhvi).not(areaid_po).isolated(6.3, euclidian).output("dnwell.3", "dnwell.3 : min. dnwell spacing : 6.3um") +# dnwell.and(pnp).output("dnwell.4", "dnwell.4 : dnwell must not overlap pnp") +# dnwell.and(psdm).edges.not(psdm.edges).output("dnwell.5", "p+ must not straddle dnwell") +# # dnwell.6 rue not coded + +# nwell +nwell.width(0.84, euclidian).output("nwell.1", "nwell.1 : min. nwell width : 0.84um") +nwell.isolated(1.27, euclidian).output("nwell.2a", "nwell.2a : min. nwell spacing (merged if less) : 1.27um") +# rule nwell.4 is suitable for digital cells +#nwell.not(uhvi).not(areaid_en20).not_interacting(tap.and(licon).and(li)).output("nwell.4", "nwell4 : all nwell exempt inside uhvi must contain a n+tap") +# nwell.enclosing(dnwell.not(uhvi).not(areaid_po), 0.4, euclidian).output("nwell.5", "nwell.5 : min. nwell enclosing dnwell exempt unside uhvi : 0.4um") +# dnwell.enclosing(nwell.not(uhvi), 1.03, euclidian).output("nwell.6", "nwell.6 : min. dnwell enclosing nwell exempt unside uhvi : 1.03um") +# dnwell.separation(nwell, 4.5, euclidian).output("nwell.7", "nwell.7 : min. dnwell separation nwell : 4.5um") + +# pwbm +# pwbm.not(uhvi).output("pwbm", "pwbm must be inside uhvi") +# dnwell.and(uhvi).edges.not(pwbm).output("pwbm.4", "pwbm.4 : dnwell inside uhvi must be enclosed by pwbm") + +# pwde +# pwde.not(pwbm).output("pwdem.3", "pwdem.3 : pwde must be inside pwbm") +# pwde.not(uhvi).output("pwdem.4", "pwdem.4 : pwde must be inside uhvi") +# pwde.not(dnwell).output("pwdem.5", "pwdem.5 : pwde must be inside dnwell") + +# hvtp +#hvtp.not(nwell).output("hvtp", "hvtp must inside nwell") +hvtp.width(0.38, euclidian).output("hvtp.1", "hvtp.1 : min. hvtp width : 0.38um") +hvtp.isolated(0.38, euclidian).output("hvtp.2", "hvtp.2 : min. hvtp spacing : 0.38um") +# hvtp.enclosing(gate.and(psdm), 0.18, euclidian).output("hvtp.3", "hvtp.3 : min. hvtp enclosure of pfet gate : 0.18um") +# hvtp.separation(gate.and(psdm), 0.18, euclidian).output("hvtp.4", "hvtp.4 : min. hvtp spacing pfet gate: 0.18um") +# hvtp.with_area(0..0.265).output("hvtp.5", "hvtp.5 : min. hvtp area : 0.265um²") + +# hvtr +hvtr.width(0.38, euclidian).output("hvtr.1", "hvtr.1 : min. hvtr width : 0.38um") +hvtr.isolated(0.38, euclidian).output("hvtr.2", "hvtr.2 : min. hvtr spacing : 0.38um") + +# lvtn +# lvtn.width(0.38, euclidian).output("lvtn.1", "lvtn.1 : min. lvtn width : 0.38um") +lvtn.isolated(0.38, euclidian).output("lvtn.2", "lvtn.2 : min. lvtn spacing : 0.38um") +# lvtn.separation(diff.and(poly).not(uhvi), 0.18, euclidian).output("lvtn.3a", "lvtn.3a : min. lvtn spacing to gate : 0.18um") +# lvtn.separation(diff.and(nwell).not(poly), 0.235, projection).output("lvtn.3b", "lvtn.3b : min. lvtn spacing to pfet s/d : 0.18um") +# lvtn.enclosing(gate.not(uhvi), 0.18, euclidian).output("lvtn.4b", "lvtn.4b : min. lvtn enclosing to gate : 0.18um") +# lvtn.separation(hvtp, 0.38, euclidian).output("lvtn.9", "lvtn.9 : min. lvtn spacing hvtp : 0.38um") +# nwell.not_interacting(gate.and(nwell.not(hvi).not(areaid_ce))).enclosing(lvtn.not(uhvi), 0.18, euclidian).polygons.without_area(0).output("lvtn.4b", "lvtn.4b : min. lvtn enclosure of gate : 0.18um") +# lvtn.separation(nwell.inside(areaid_ce), 0.38, euclidian).output("lvtn.12", "lvtn.12 : min. lvtn spacing nwell inside areaid.ce : 0.38um") +# lvtn.with_area(0..0.265).output("lvtn.13", "lvtn.13 : min. lvtn area : 0.265um²") + +# ncm +# ncm.and(tap.and(nwell).or(diff.not(nwell))).output("ncm.x.3", "ncm.x.3 : ncm must not overlap n+diff") +ncm.width(0.38, euclidian).output("ncm.1", "ncm.1 : min. ncm width : 0.38um") +# ncm.isolated(0.38, euclidian).output("ncm.2", "ncm.2 : min. ncm spacing manual merge if smaller : 0.38um") +# ncm.enclosing(diff.and(nwell), 0.18, euclidian).output("ncm.3", "ncm.3 : min. ncm enclosure of p+diff : 0.18um") +# ncm.separation(lvtn.and(diff), 0.23, euclidian).output("ncm.5", "ncm.5 : min. ncm spacing lvtn diff : 0.23um") +# ncm.separation(diff.not(nwell), 0.2, euclidian).output("ncm.6", "ncm.6 : min. ncm spacing nfet : 0.2um") +# ncm.with_area(0..0.265).output("ncm.7", "ncm.13 : min. ncm area : 0.265um²") + +# diff-tap +difftap = diff + tap +difftap.width(0.15, euclidian).output("difftap.1", "difftap.1 : min. difftap width : 0.15um") +# not_in_cell1 = layout(source.cell_obj).select("s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b" , "-s8fpls_pl8", "-s8fpls_rdrv4" , "-s8fpls_rdrv4f", "-s8fpls_rdrv8") +# not_in_cell1_diff = not_in_cell1.input(65, 20) +# not_in_cell1_diff.not(areaid_sc).not(poly).edges.and(gate.edges).with_length(0,0.42).output("difftap.2", "difftap.2: min. gate (exempt areaid.sc) width : 0.42um") +# diff.and(areaid_sc).not(poly).edges.and(gate.edges).with_length(0,0.36).output("difftap.2", "difftap.2: min. gate inside areaid.sc width : 0.36um") +difftap.isolated(0.27, euclidian).output("difftap.3", "difftap.3 : min. difftap spacing : 0.27um") +# tap.edges.and(diff.edges).with_length(0,0.29).output("difftap.4", "difftap.4 : min. tap bound by diffusion : 0.29um") +# tap.edges.and(diff.edges).space(0.4, projection).output("difftap.5", "difftap.5 : min. tap bound by 2 diffusions : 0.4um") +# (tap.edges.and(diff.edges)).extended(0.01, 0.01, 0, 0, false).not(tap.and(diff)).and(diff.or(tap)).output("difftap.6", "difftap.6 : diff and tap not allowed to extend beyong their abutting ege") +# tap.edges.not_interacting(diff.edges).separation(diff.edges, 0.13, euclidian).output("difftap.7", "difftap.7 : min. diff/tap spacing to non-coincident diff edge : 0.13um") +# diff.edges.not_interacting(tap.edges).separation(tap.edges, 0.13, euclidian).output("difftap.7", "difftap.7 : min. diff/tap spacing to non-coincident tap edge : 0.13um") +# nwell.enclosing(diff.not(uhvi).and(psdm), 0.18, euclidian).output("difftap.8", "difftap.8 : min. p+diff enclosure by nwell : 0.18um") +# diff.not(uhvi).and(nsdm).separation(nwell, 0.34, euclidian).output("difftap.9", "difftap.9 : min. n+diff spacing to nwell : 0.34um") +# nwell.enclosing(tap.not(uhvi).and(nsdm), 0.18, euclidian).output("difftap.10", "difftap.10 : min. n+tap enclosure by nwell : 0.18um") +# tap.not(uhvi).and(psdm).separation(nwell, 0.13, euclidian).output("difftap.11", "difftap.11 : min. p+tap spacing to nwell : 0.13um") + +# tunm +tunm.width(0.41, euclidian).output("tunm.1", "tunm.1 : min. tunm width : 0.41um") +tunm.isolated(0.5, euclidian).output("tunm.2", "tunm.2 : min. tunm spacing : 0.5um") +# tunm.enclosing(gate, 0.095, euclidian).output("tunm.3", "tunm.3 : min. tunm beyond gate : 0.095um") +# tunm.separation(gate.not_interacting(tunm), 0.095, euclidian).output("tunm.4", "tunm.4 : min. tunm spacing to gate outside tunm: 0.095um") +# gate.and(tunm).edges.not(gate.edges).output("tunm.5", "tunm.5 : gate must not straddle tunm") +# tunm.not(dnwell).output("tunm.6a", "tunm.6a : tunm not allowed outside dnwell") +# tunm.with_area(0..0.672).output("tunm.7", "tunm.7 : min. tunm area : 0.672um²") + +# poly +poly.width(0.15, euclidian).output("poly.1a", "poly.1a : min. poly width : 0.15um") +# poly.not(diff).edges.and(gate.and(lvtn).edges).space(0.35, euclidian).output("poly.1b", "poly.1b: min. lvtn gate width : 0.35um") +poly.isolated(0.21, euclidian).output("poly.2", "poly.2 : min. poly spacing : 0.21um") +# poly.and(rpm.or(urpm).or(poly_rs)).width(0.33, euclidian).output("poly.3", "poly.3 : min. poly resistor width : 0.33um") +# poly.not(gate).separation(diff, 0.075, projection).polygons.without_area(0).output("poly.4", "poly.4 : min. poly on field spacing to diff : 0.075um") +# poly.not(gate).separation(tap, 0.055, euclidian).output("poly.5", "poly.5 : min. poly on field spacing to tap : 0.055um") +# gate.separation(tap, 0.3, projection).polygons.and(diff).output("poly.6", "poly.6 : min. gate spacing to tap : 0.3um") +# diff.enclosing(gate, 0.25, projection).polygons.without_area(0).output("poly.7", "poly.7 : min. source/drain length : 0.25um") +# poly.enclosing(gate, 0.13, projection).polygons.without_area(0).output("poly.8", "poly.8 : min. poly extention gate (endcap) : 0.13um") +# poly.and(rpm.or(urpm).or(poly_rs)).separation(poly.or(difftap), 0.48, euclidian).polygons.without_area(0).output("poly.9", "poly.9 : min. poly resistor space to poly or diff/tap : 0.48um") +# diff.merged.edges.end_segments(0.01).and(poly).output("poly.10", "poly.10 : poly must not overlap diff corner") +# gate.with_angle(0 .. 90).output("poly.11", "poly.11 : non 90 degree angle gate") +# not_in_cell3 = layout(source.cell_obj).select("s8fgvr_n_fg2") +# not_in_cell3_poly = not_in_cell3.input(66, 20) +# not_in_cell3_poly.not(hvi).not(nwell.not(hvi)).and(tap).output("poly.12", "poly.12 : poly must not overlap tap") +# poly.and(diff_rs).output("poly.15", "poly.15 : poly must not overlap diff resistor") + +# rpm +rpm.width(1.27, euclidian).output("rpm.1a", "rpm.1a : min. rpm width : 1.27um") +rpm.isolated(0.84, euclidian).output("rpm.2", "rpm.2 : min. rpm spacing : 0.84um") +# rpm.enclosing(poly.and(poly_rs).and(psdm), 0.2, euclidian).output("rpm.3", "rpm.3 : min. rpm enclosure of poly resistor : 0.2um") +# psdm.enclosing(poly.and(poly_rs).and(rpm), 0.11, euclidian).output("rpm.4", "rpm.4 : min. psdm enclosure of poly resistor : 0.11um") +# npc.enclosing(poly.and(poly_rs).and(rpm), 0.095, euclidian).output("rpm.5", "rpm.5 : min. npc enclosure of poly resistor : 0.095um") +# rpm.separation(nsdm, 0.2, euclidian).output("rpm.6", "rpm.6 : min. rpm spacing nsdm: 0.2um") +# rpm.separation(poly, 0.2, euclidian).output("rpm.7", "rpm.7 : min. rpm spacing poly: 0.2um") +# rpm.and(poly).edges.not(poly.edges).output("rpm.8", "rpm.8 : poly must not straddle rpm") +# poly.and(poly_rs).and(rpm).separation(hvntm, 0.185, euclidian).output("rpm.9", "rpm.9 : min. poly resistor spacing hvntm: 0.185um") +# rpm.and(pwbm).output("rpm.10", "rpm.107 : min. rpm spacing pwbm: na") + +# varac +# varac = poly & tap & (nwell - hvi) - areaid_ce +# tap.not(poly).edges.and(varac.edges).space(0.18, euclidian).output("varac.1", "varac.1: min. varac channel length : 0.18um") +# tap.and(poly).edges.and(varac.edges).space(1.0, euclidian).output("varac.2", "varac.2: min. varac channel wdth : 1.0um") +# varac.separation(hvtp, 0.18, euclidian).output("varac.3", "varac.3: min. varac channel space to hvtp : 0.18um") +# varac.separation(licon.and(tap), 0.25, euclidian).output("varac.4", "varac.4: min. varac channel space to licon on tap : 0.25um") +# nwell.enclosing(poly.overlapping(varac), 0.15, euclidian).output("varac.5", "varac.5: min. nwell enclosure of poly overlapping varac channel : 0.15um") +# tap.overlapping(varac).separation(difftap, 0.27, euclidian).polygons.without_area(0).output("varac.6", "varac.6: min. varac channel tap space to difftap : 0.27um") +# nwell.overlapping(varac).and(diff.and(nwell)).output("varac.7", "varac.7: nwell overlapping varac channel must not overlap p+diff") + +# photo +# photodiode = dnwell & areaid_po +# photodiode.edges.without_length(3.0).output("photo.2", "photo.2 : minimum/maximum width of photodiode : 3.0um") +# photodiode.isolated(5.0, euclidian).output("photo.3", "photo.3 : mini. photodiode spacing : 5.0um") +# photodiode.separation(dnwell, 5.3, euclidian).output("photo.4", "photo.4 : mini. photodiode spacing to dnwell : 5.3um") +# areaid_po.not(dnwell).output("photo.5.6", "photo.5.6 : photodiode edges must coincide areaid.po and enclosed by dnwell") +# photodiode.not(tap.not(nwell).holes).output("photo.7", "photo.7 : photodiode must be enclosed by p+tap ring") +# photodiode.and(nwell).edges.without_length(0.84).output("photo.8", "photo.8 : minimum/maximum width of nwell inside photodiode : 0.84um") +# areaid_po.edges.and(photodiode.and(nwell).sized(1.08)).without_length(12.0).output("photo.9", "photo.9 : minimum/maximum enclosure of nwell by photodiode : 1.08um") +# photodiode.and(tap).edges.without_length(0.41).output("photo.10", "photo.10 : minimum/maximum width of tap inside photodiode : 0.41um") + +# npc +npc.width(0.27, euclidian).output("npc.1", "npc.1 : min. npc width : 0.27um") +npc.isolated(0.27, euclidian).output("npc.2", "npc.2 : min. npc spacing, should be mnually merge if less : 0.27um") +# npc.separation(gate, 0.09, euclidian).output("npc.4", "npc.4 : min. npc spacing to gate : 0.09um") + +# nsdm/psdm +# npsdm = nsdm + psdm +# nsdm.width(0.38, euclidian).output("nsdm.1", "nsdm.1 : min. nsdm width : 0.38um") +# psdm.width(0.38, euclidian).output("psdm.1", "psdm.1 : min. psdm width : 0.38um") +# nsdm.isolated(0.38, euclidian).output("n/psdm.1", "n/psdm.1 : min. nsdm spacing, should be mnually merge if less : 0.38um") +# psdm.isolated(0.38, euclidian).output("n/psdm.1", "n/psdm.1 : min. psdm spacing, should be mnually merge if less : 0.38um") +# npsdm.enclosing(diff, 0.125, euclidian).polygons.not(tap.sized(0.125)).output("n/psdm.5a", "n/psdm.5a : min. n/psdm enclosure diff except butting edge : 0.125um") +# npsdm.enclosing(tap, 0.125, euclidian).polygons.not(diff.sized(0.125)).output("n/psdm.5b", "n/psdm.5b : min. n/psdm enclosure tap except butting edge : 0.125um") +# tap.edges.and(diff.edges).not(npsdm).output("n/psdm.6", "n/psdm.6 : min. n/psdm enclosure of butting edge : 0.0um") +# nsdm.and(difftap).separation(psdm.and(difftap), 0.13, euclidian).polygons.without_area(0).output("n/psdm.7", "n/psdm.7 : min. nsdm diff spacing to psdm diff except butting edge : 0.13um") +# diff.and((nsdm.and(nwell)).or(psdm.not(nwell))).output("n/psdm.8", "n/psdm.8 : diff should be the opposite type of well/substrate underneath") +# tap.and((nsdm.not(nwell)).or(psdm.and(nwell))).output("n/psdm.8", "n/psdm.8 : tap should be the same type of well/substrate underneath") +# tap.and(diff).without_area(0).output("tap and diff", "tap and diff must not overlap") +# nsdm.with_area(0..0.265).output("n/psdm.10a", "n/psdm.10a : min. nsdm area : 0.265um²") +# psdm.with_area(0..0.265).output("n/psdm.10b", "n/psdm.10b : min. psdm area : 0.265um²") + +# licon +licon.not(poly.interacting(poly_rs)).edges.without_length(0.17).output("licon.1", "licon.1 : minimum/maximum width of licon : 0.17um") +licon.and(poly.interacting(poly_rs)).not_interacting((licon.and(poly.interacting(poly_rs)).edges.with_length(0.19)).or(licon.and(poly.interacting(poly_rs)).edges.with_length(2.0))).output("licon.1b/c", "licon.1b/c : minimum/maximum width/length of licon inside poly resistor : 2.0/0.19um") +# licon.isolated(0.17, euclidian).output("licon.2", "licon.2 : min. licon spacing : 0.17um") +# licon.and(poly.interacting(poly_rs)).edges.with_length(0.19).space(0.35, euclidian).output("licon.2b", "licon.2b : min. licon 0.19um edge on resistor spacing : 0.35um") +# licon.interacting(licon.and(poly.interacting(poly_rs)).edges.with_length(2.0)).separation(licon.and(poly.interacting(poly_rs)), 0.51, euclidian).output("licon.2c", "licon.2c : min. licon 2.0um edge on resistor spacing : 0.51um") +# licon.and(poly.interacting(poly_rs)).separation(licon.not(poly.interacting(poly_rs)), 0.51, euclidian).output("licon.2d", "licon.2d : min. licon on resistor spacing other licon : 0.51um") +# rule licon.3 not coded +# licon.not(li).not(poly.or(diff).or(tap)).output("licon.4", "licon.4 : min. licon must overlap li and (poly or tap or diff) ") +# diff.enclosing(licon, 0.04, euclidian).output("licon.5", "licon.5 : min. diff enclosure of licon : 0.04um") +# tap.edges.and(diff.edges).separation(licon.and(tap).edges, 0.06, euclidian).output("licon.6", "licon.6 : min. abutting edge spacing to licon tap : 0.06um") +# licon_edges_with_less_enclosure_tap = tap.enclosing(licon, 0.12, projection).second_edges +# opposite1 = (licon.edges - licon_edges_with_less_enclosure_tap).width(0.17 + 1.dbu, projection).polygons +# licon.not_interacting(opposite1).output("licon.7", "licon.7 : min. tap enclosure of licon by one of 2 opposite edges : 0.12um") +# poly.enclosing(licon, 0.05, euclidian).output("licon.8", "licon.8 : min. poly enclosure of licon : 0.05um") +# licon008 = licon.interacting(poly.enclosing(licon, 0.08, euclidian).polygons) +# licon_edges_with_less_enclosure_poly = poly.enclosing(licon, 0.08, projection).second_edges +# opposite2 = (licon.edges - licon_edges_with_less_enclosure_poly).width(0.17 + 1.dbu, projection).polygons +# licon008.not_interacting(opposite2).output("licon.8a", "licon.8a : min. poly enclosure of licon by one of 2 opposite edges : 0.08um") +# # rule licon.9 not coded +# licon.and(tap.and(nwell.not(hvi))).separation(varac, 0.25, euclidian).output("licon.10", "licon.10 : min. licon spacing to varac channel : 0.25um") +# not_in_cell4 = layout(source.cell_obj).select("-s8fs_gwdlvx4", "-s8fs_gwdlvx8", "-s8fs_hvrsw_x4", "-s8fs_hvrsw8", "-s8fs_hvrsw264", "-s8fs_hvrsw520", "-s8fs_rdecdrv", "-s8fs_rdec8”, “s8fs_rdec32", "-s8fs_rdec264", "-s8fs_rdec520") +# not_in_cell4_licon = not_in_cell4.input(66, 44) +# not_in_cell4_licon.and(diff.or(tap)).separation(gate.not(areaid_sc), 0.055, euclidian).output("licon.11", "licon.11 : min. licon spacing to gate : 0.055um") +# licon.and(diff.or(tap)).separation(gate.and(areaid_sc), 0.05, euclidian).output("licon.11a", "licon.11a : min. licon spacing to gate inside areaid.sc : 0.05um") +# in_cell4 = layout(source.cell_obj).select("+s8fs_gwdlvx4", "+s8fs_gwdlvx8", "+s8fs_hvrsw_x4", "+s8fs_hvrsw8", "+s8fs_hvrsw264", "+s8fs_hvrsw520") +# in_cell4_licon = in_cell4.input(66, 44) +# in_cell4_licon.and(diff.or(tap)).separation(gate, 0.04, euclidian).output("licon.11c", "licon.11c : min. licon spacing to gate for specific cells: 0.04um") +# # rules 11.b , 11.d not coded +# diff.interacting(gate).not(diff.interacting(gate).width(5.7, euclidian).polygons).output("licon.12", "licon.12 : max. sd width without licon : 5.7um") +licon.and(diff.or(tap)).separation(npc, 0.09, euclidian).output("licon.13", "licon.13 : min. difftap licon spacing to npc : 0.09um") +# licon.and(poly).separation(diff.or(tap), 0.19, euclidian).output("licon.14", "licon.14 : min. poly licon spacing to difftap : 0.19um") +# npc.enclosing(licon.and(poly), 0.1, euclidian).output("licon.15", "licon.15 : min. npc enclosure of poly-licon : 0.1um") +# rule licon.16 not applicable for the diff for the nmos of a nand gates or the pmos of a nor gates +#diff.not(gate).not_interacting(licon).output("licon.16", "licon.16 : diff must enclose one licon") +# tap.not(uhvi).not_interacting(licon).output("licon.16", "licon.16 : tap must enclose one licon") +poly.and(tap).edges.not(tap.edges).output("licon.17", "licon.17 : tap must not straddle poly") +# npc.not_interacting(licon.and(poly)).output("licon.18", "licon.18 : npc mut enclosed one poly-licon") + +# vpp +# vpp.width(1.43, euclidian).output("vpp.1", "vpp.1 : min. vpp width : 1.43um") +# # rules 1.b, 1.c not coded +# vpp.and(poly.or(difftap)).output("vpp.3", "vpp.3 : vpp must not overlapp poly or diff or tap") +# vpp.and(nwell).edges.not(vpp.edges).output("vpp.4", "vpp.4 : vpp must not straddle nwell") +# vpp.and(dnwell).edges.not(vpp.edges).output("vpp.4", "vpp.4 : vpp must not straddle dnwell") +# vpp.and(poly.or(li).or(m1).or(m2)).separation(poly.or(li).or(m1).or(m2), 1.5, euclidian).polygons.with_area(2.25,nil).output("vpp.5", "vpp.5 : min. vpp spacing to poly or li or m1 or m2 : 1.5um") +# vpp.with_area(0..area(vpp.and(m3))*0.25).output("vpp.5a", "vpp.5a : max. m3 density in vpp : 0.25") +# vpp.with_area(0..area(vpp.and(m4))*0.3).output("vpp.5b", "vpp.5b : max. m4 density in vpp : 0.3") +# vpp.with_area(0..area(vpp.and(m5))*0.4).output("vpp.5c", "vpp.5c : max. m5 density in vpp : 0.4") +# nwell.enclosing(vpp, 1.5, euclidian).output("vpp.8", "vpp.8 : nwell enclosure of vpp : 1.5") +# vpp.separation(nwell, 1.5, euclidian).polygons.without_area(0).output("vpp.9", "vpp.9 : vpp spacing to nwell : 1.5") +# # rule vpp.10 not coded +# # rule vpp.11 not coded because moscap is not defined properly by any gds layer +# # rules vpp.12a, 12b, 12c not coded because specific to one cell +# if backend_flow = CU +# m1.separation(vpp.and(m1), 0.16, euclidian).polygons.without_area(0).output("vpp.13", "vpp.13 : m1 spacing to m1inside vpp : 0.16") +# end + +# CAPM +capm.width(1.0, euclidian).output("capm.1", "capm.1 : min. capm width : 1.0um") +capm.isolated(0.84, euclidian).output("capm.2a", "capm.2a : min. capm spacing : 0.84um") +m2.interacting(capm).isolated(1.2, euclidian).output("capm.2b", "capm.2b : min. capm spacing : 1.2um") +m2.enclosing(capm, 0.14, euclidian).output("capm.3", "capm.3 : min. m2 enclosure of capm : 0.14um") +capm.enclosing(via2, 0.14, euclidian).output("capm.4", "capm.4 : min. capm enclosure of via2 : 0.14um") +capm.separation(via2, 0.14, euclidian).output("capm.5", "capm.5 : min. capm spacing to via2 : 0.14um") +# capm.sized(-20.0).sized(20.0).output("capm.6", "capm.6 : max. capm lenght/width : 20um") +# capm.with_angle(0 .. 90).output("capm.7", "capm.7 : capm not rectangle") +# capm.separation(via, 0.14, euclidian).polygons.without_area(0).output("capm.8", "capm.8 : min. capm spacing to via : 0.14um") +# capm.and(nwell).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle nwell") +# capm.and(diff).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle diff") +# capm.and(tap).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle tap") +# capm.and(poly).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle poly") +# capm.and(li).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle li") +# capm.and(m1).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle m1") +# capm.separation(m2.not_interacting(capm), 0.14, euclidian).output("capm.11", "capm.11 : min. capm spacing to m2 not overlapping capm : 0.5um") + +end #FEOL + +if BEOL +info("BEOL section") + +# li +not_in_cell5 = source.select("-s8rf2_xcmvpp_hd5_*") +not_in_cell5_li = not_in_cell5.polygons(li_wildcard) +not_in_cell5_li.width(0.17, euclidian).output("li.1", "li.1 : min. li width : 0.17um") + +# in_cell5_li = li - not_in_cell5_li +# in_cell5_li.width(0.14, euclidian).output("li.1a", "li.1a : min. li width for the cells s8rf2_xcmvpp_hd5_* : 0.14um") + +# rule li.2 not coded + +not_in_cell5_li.space(0.17, euclidian).output("li.3", "li.3 : min. li spacing : 0.17um") +# in_cell5_li.space(0.14, euclidian).output("li.3a", "li.3a : min. li spacing for the cells s8rf2_xcmvpp_hd5_* : 0.14um") +licon08 = licon.interacting(li.enclosing(licon, 0.08, euclidian).polygons) +licon_edges_with_less_enclosure_li = li.enclosing(licon, 0.08, projection).second_edges +opposite3 = (licon.edges - licon_edges_with_less_enclosure_li).width(0.17 + 1.dbu, projection).polygons +licon08.not_interacting(opposite3).output("li.5", "li.5 : min. li enclosure of licon of 2 opposite edges : 0.08um") +li.with_area(0..0.0561).output("li.6", "li.6 : min. li area : 0.0561um²") + +# ct +mcon.edges.without_length(0.17).output("ct.1", "ct.1 : minimum/maximum width of mcon : 0.17um") +mcon.space(0.19, euclidian).output("ct.2", "ct.2 : min. mcon spacing : 0.19um") +# rule ct.3 not coded +mcon.not(li).output("ct.4", "ct.4 : mcon should covered by li") +# if backend_flow = CU +# li.interacting(li.and(m1).not(mcon).with_holes(1,10)).enclosing(mcon, 0.2, euclidian).output("ct.irdrop.1", "ct.irdrop.1 : min. li enclsoure of 1..10 mcon : 0.2um") +# li.interacting(li.and(m1).not(mcon).with_holes(11,100)).enclosing(mcon, 0.3, euclidian).output("ct.irdrop.2", "ct.irdrop.2 : min. li enclsoure of 11..100 mcon : 0.3um") +# end +# +# m1 +m1.width(0.14, euclidian).output("m1.1", "m1.1 : min. m1 width : 0.14um") + +huge_m1 = m1.sized(-1.5).sized(1.5) +non_huge_m1 = m1 - huge_m1 + +non_huge_m1.space(0.14, euclidian).output("m1.2", "m1.2 : min. m1 spacing : 0.14um") + +(huge_m1.separation(non_huge_m1, 0.28, euclidian) + huge_m1.space(0.28, euclidian)).output("m1.3ab", "m1.3ab : min. 3um.m1 spacing m1 : 0.28um") + +not_in_cell6 = layout(source.cell_obj).select("-s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b", "-s8fpls_pl8", "-s8fs_cmux4_fm") +not_in_cell6_m1 = not_in_cell6.input(m1_wildcard) +not_in_cell6_m1.enclosing(mcon, 0.03, euclidian).output("m1.4", "m1.4 : min. m1 enclosure of mcon : 0.03um") +in_cell6 = layout(source.cell_obj).select("+s8cell_ee_plus_sseln_a", "+s8cell_ee_plus_sseln_b", "+s8cell_ee_plus_sselp_a", "+s8cell_ee_plus_sselp_b", "+s8fpls_pl8", "+s8fs_cmux4_fm") +in_cell6_m1 = in_cell6.input(m1_wildcard) +in_cell6_m1.enclosing(mcon, 0.005, euclidian).output("m1.4a", "m1.4a : min. m1 enclosure of mcon for specific cells : 0.005um") +m1.with_area(0..0.083).output("m1.6", "m1.6 : min. m1 area : 0.083um²") +m1.holes.with_area(0..0.14).output("m1.7", "m1.7 : min. m1 holes area : 0.14um²") +if backend_flow = AL + mcon06 = mcon.interacting(poly.enclosing(m1, 0.06, euclidian).polygons) + mcon_edges_with_less_enclosure_m1 = m1.enclosing(mcon, 0.06, projection).second_edges + opposite4 = (mcon.edges - mcon_edges_with_less_enclosure_m1).width(0.17 + 1.dbu, projection).polygons + mcon06.not_interacting(opposite4).output("m1.5", "m1.5 : min. m1 enclosure of mcon of 2 opposite edges : 0.06um") + # rule m1.pd.1, rule m1.pd.2a, rule m1.pd.2b not coded +end +#if bakend_flow = CU +# m1.sized(-2.0).sized(2.0).output("m1.11", "m1.11 : max. m1 width after slotting : 4.0um") +# # rule m1.12 not coded because inconsistent with m1.11 +# # rule m1.13, m1.14, m1.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +#end + +# via +#rule via.3 not coded +# via.not(m1).output("via.4c.5c", "via.4c.5c : m1 must enclose all via") +if backend_flow = AL + via.not(areaid_mt).edges.without_length(0.15).output("via.1a", "via.1a : minimum/maximum width of via : 0.15um") + # via.and(areaid_mt).not_interacting((via.and(areaid_mt).edges.without_length(0.15)).or(via.and(areaid_mt).edges.without_length(0.23)).or(via.and(areaid_mt).edges.without_length(0.28))).output("via.1b", "via.1b : minimum/maximum width of via in areaid.mt: 0.15um or 0.23um or 0.28um") + via.isolated(0.17, euclidian).output("via.2", "via.2 : min. via spacing : 0.17um") + m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.055, euclidian).output("via.4a", "via.4a : min. m1 enclosure of 0.15um via : 0.055um") + # m1.enclosing(via.not_interacting(via.edges.without_length(0.23)), 0.03, euclidian).output("via.4b", "via.4b : min. m1 enclosure of 0.23um via : 0.03um") + via1_edges_with_less_enclosure_m1 = m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.085, projection).second_edges + opposite5 = (via.not_interacting(via.edges.without_length(0.15)).edges - via1_edges_with_less_enclosure_m1).width(0.15 + 1.dbu, projection).polygons + via.not_interacting(via.edges.without_length(0.15)).not_interacting(opposite5).output("via1.5a", "via1.5a : min. m1 enclosure of 0.15um via of 2 opposite edges : 0.085um") + via2_edges_with_less_enclosure_m1 = m1.enclosing(via.not_interacting(via.edges.without_length(0.23)), 0.06, projection).second_edges + opposite6 = (via.not_interacting(via.edges.without_length(0.23)).edges - via2_edges_with_less_enclosure_m1).width(0.23 + 1.dbu, projection).polygons + # via.not_interacting(via.edges.without_length(0.23)).not_interacting(opposite6).output("via1.5b", "via1.5b : min. m1 enclosure of 0.23um via of 2 opposite edges : 0.06um") +end +# if backend_flow = CU + # via.not(areaid_mt).edges.without_length(0.18).output("via.11", "via.11 : minimum/maximum width of via : 0.18um") + # via.isolated(0.13, euclidian).output("via.12", "via.12 : min. via spacing : 0.13um") + # rule via.13 not coded because not understandable + # via1_edges_with_less_enclosure_m1 = m1.enclosing(via, 0.04, projection).second_edges + # opposite5 = (via.edges - via1_edges_with_less_enclosure_m1).width(0.18 + 1.dbu, projection).polygons + # via.not_interacting(opposite5).output("via1.14", "via1.14 : min. m1 enclosure of 0.04um via of 2 opposite edges : 0.04um") + # rules via.irdrop.1, via.irdrop.2, via.irdrop.3, via.irdrop.4 not coded because not understandable +# end + +# m2 +m2.width(0.14, euclidian).output("m2.1", "m2.1 : min. m2 width : 0.14um") + +huge_m2 = m2.sized(-1.5).sized(1.5) +non_huge_m2 = m2 - huge_m2 + +non_huge_m2.space(0.14, euclidian).output("m2.2", "m2.2 : min. m2 spacing : 0.14um") + +(huge_m2.separation(non_huge_m2, 0.28, euclidian) + huge_m2.space(0.28, euclidian)).output("m2.3ab", "m2.3ab : min. 3um.m2 spacing m2 : 0.28um") + +# rule m2.3c not coded +m2.with_area(0..0.0676).output("m2.6", "m2.6 : min. m2 area : 0.0676um²") +m2.holes.with_area(0..0.14).output("m2.7", "m2.7 : min. m2 holes area : 0.14um²") +# via.not(m2).output("m2.via", "m2.via : m2 must enclose via") +if backend_flow = AL + m2.enclosing(via, 0.055, euclidian).output("m2.4", "m2.4 : min. m2 enclosure of via : 0.055um") + via_edges_with_less_enclosure_m2 = m2.enclosing(via, 0.085, projection).second_edges + opposite7 = (via.edges - via_edges_with_less_enclosure_m2).width(0.2 + 1.dbu, projection).polygons + via.not_interacting(opposite7).output("m2.5", "m2.5 : min. m2 enclosure of via of 2 opposite edges : 0.085um") + # rule m2.pd.1, rule m2.pd.2a, rule m2.pd.2b not coded +end +# if bakend_flow = CU + # m2.sized(-2.0).sized(2.0).output("m2.11", "m2.11 : max. m2 width after slotting : 4.0um") + # rule m2.12 not coded because inconsistent with m2.11 + # rule m2.13, m2.14, m2.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +# end + +# via2 +#rule via233 not coded +# via2.not(m2).output("via2", "via2 : m2 must enclose all via2") +if backend_flow = AL + via2.not(areaid_mt).edges.without_length(0.2).output("via2.1a", "via2.1a : minimum/maximum width of via2 : 0.2um") + # via2.and(areaid_mt).not_interacting((via2.and(areaid_mt).edges.without_length(0.2)).or(via2.and(areaid_mt).edges.without_length(1.2)).or(via2.and(areaid_mt).edges.without_length(1.5))).output("via2.1b", "via2.1b : minimum/maximum width of via2 in areaid.mt: 0.2um or 1.2um or 1.5um") + via2.isolated(0.2, euclidian).output("via2.2", "via2.2 : min. via2 spacing : 0.2um") + m2.enclosing(via2, 0.04, euclidian).output("via2.4", "via2.4 : min. m2 enclosure of via2 : 0.04um") + m2.enclosing(via2.not_interacting(via2.edges.without_length(1.5)), 0.14, euclidian).output("via2.4a", "via2.4a : min. m2 enclosure of 1.5um via2 : 0.14um") + via2_edges_with_less_enclosure_m2 = m2.enclosing(via2, 0.085, projection).second_edges + opposite8 = (via2.edges - via2_edges_with_less_enclosure_m2).width(0.2 + 1.dbu, projection).polygons + via2.not_interacting(opposite8).output("via2.5", "via2.5 : min. m2 enclosure of via2 of 2 opposite edges : 0.085um") +end +# if backend_flow = CU + # via2.edges.without_length(0.21).output("via2.11", "via2.11 : minimum/maximum width of via2 : 0.21um") + # via2.isolated(0.18, euclidian).output("via2.12", "via2.12 : min. via2 spacing : 0.18um") + # rule via2.13 not coded because not understandable, or not clear + # m2.enclosing(via2, 0.035, euclidian).output("via2.14", "via2.14 : min. m2 enclosure of via2 : 0.035um") + # rules via2.irdrop.1, via2.irdrop.2, via2.irdrop.3, via2.irdrop.4 not coded because not understandable +# end + +# m3 +m3.width(0.3, euclidian).output("m3.1", "m3.1 : min. m3 width : 0.3um") + +huge_m3 = m3.sized(-1.5).sized(1.5) +non_huge_m3 = m3 - huge_m3 + +non_huge_m3.space(0.3, euclidian).output("m3.2", "m3.2 : min. m3 spacing : 0.3um") + +# (huge_m3.separation(non_huge_m3, 0.4, euclidian) + huge_m3.space(0.4, euclidian)).output("m3.3ab", "m3.3ab : min. 3um.m3 spacing m3 : 0.4um") + +# rule m3.3c not coded +# m3.with_area(0..0.24).output("m3.6", "m3.6 : min. m2 area : 0.24um²") +# via2.not(m3).output("m3.via2", "m3.via2 : m3 must enclose via2") +if backend_flow = AL + m3.enclosing(via2, 0.065, euclidian).output("m3.4", "m3.4 : min. m3 enclosure of via2 : 0.065um") + # via2_edges_with_less_enclosure_m3 = m3.enclosing(via2, 0.085, projection).second_edges + # m3.5 N/A + # opposite9 = (via2.edges - via2_edges_with_less_enclosure_m3).width(0.3 + 1.dbu, projection).polygons + # via2.not_interacting(opposite9).output("m3.5", "m3.5 : min. m3 enclosure of via2 of 2 opposite edges : 0.085um") + # rule m3.pd.1, rule m3.pd.2a, rule m3.pd.2b not coded +end +# if bakend_flow = CU + # m3.holes.with_area(0..0.2).output("m3.7", "m3.7 : min. m2 holes area : 0.2um²") + # m3.sized(-2.0).sized(2.0).output("m3.11", "m3.11 : max. m3 width after slotting : 4.0um") + # rule m3.12 not coded because inconsistent with m3.11 + # rule m3.13, m3.14, m3.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +# end + +# via3 +#rule via3.3 not coded +# via3.not(m3).output("via3", "via3 : m3 must enclose all via3") +if backend_flow = AL + via3.not(areaid_mt).edges.without_length(0.2).output("via3.1a", "via3.1a : minimum/maximum width of via3 : 0.2um") + via3.and(areaid_mt).not_interacting((via3.and(areaid_mt).edges.without_length(0.2)).or(via3.and(areaid_mt).edges.without_length(0.8))).output("via3.1a", "via3.1a : minimum/maximum width of via3 in areaid.mt: 0.2um or 0.8um") + via3.isolated(0.2, euclidian).output("via3.2", "via3.2 : min. via3 spacing : 0.2um") + m3.enclosing(via3, 0.06, euclidian).output("via3.4", "via3.4 : min. m3 enclosure of via3 : 0.06um") + via3_edges_with_less_enclosure_m3 = m3.enclosing(via3, 0.09, projection).second_edges + opposite10 = (via3.edges - via3_edges_with_less_enclosure_m3).width(0.2 + 1.dbu, projection).polygons + via3.not_interacting(opposite10).output("via3.5", "via3.5 : min. m2 enclosure of via3 of 2 opposite edges : 0.09um") +end +# if backend_flow = CU + # via3.edges.without_length(0.21).output("via3.11", "via3.11 : minimum/maximum width of via3 : 0.21um") + # via3.isolated(0.18, euclidian).output("via3.12", "via3.12 : min. via3 spacing : 0.18um") + # m3.enclosing(via3, 0.055, euclidian).output("via3.13", "via3.13 : min. m3 enclosure of via3 : 0.055um") + # rule via3.14 not coded because not understandable, or not clear + # rules via3.irdrop.1, via3.irdrop.2, via3.irdrop.3, via3.irdrop.4 not coded because not understandable +# end + +# m4 +m4.width(0.3, euclidian).output("m4.1", "m4.1 : min. m4 width : 0.3um") + +huge_m4 = m4.sized(-1.5).sized(1.5) +non_huge_m4 = m4 - huge_m4 + +non_huge_m4.space(0.3, euclidian).output("m4.2", "m4.2 : min. m4 spacing : 0.3um") + +(huge_m4.separation(non_huge_m4, 0.4, euclidian) + huge_m4.space(0.4, euclidian)).output("m4.5ab", "m4.5ab : min. 3um.m4 spacing m4 : 0.4um") + +# m4.with_area(0..0.24).output("m4.4", "m4.4 : min. m2 area : 0.24um²") +# via3.not(m4).output("m4.via3", "m4.via3 : m4 must enclose via3") +if backend_flow = AL + m4.enclosing(via3, 0.065, euclidian).output("m4.3", "m4.3 : min. m4 enclosure of via3 : 0.065um") + # m4.5 doesn't exist + # via3_edges_with_less_enclosure_m4 = m4.enclosing(via2, 0.085, projection).second_edges + # opposite9 = (via3.edges - via3_edges_with_less_enclosure_m4).width(0.3 + 1.dbu, projection).polygons + # via3.not_interacting(opposite9).output("m4.5", "m4.5 : min. m4 enclosure of via3 of 2 opposite edges : 0.085um") + # rule m4.pd.1, rule m4.pd.2a, rule m4.pd.2b not coded +end +if bakend_flow = CU + # m4.holes.with_area(0..0.2).output("m4.7", "m4.7 : min. m2 holes area : 0.2um²") + # m4.sized(-5.0).sized(5.0).output("m4.11", "m4.11 : max. m4 width after slotting : 10.0um") + # rule m4.12 not coded because inconsistent with m4.11 + # rule m4.13, m4.14, m4.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 + # m4.enclosing(via3, 0.06, euclidian).output("m4.15", "m4.15 : min. m4 enclosure of via3 : 0.06um") +end + +# via4 +via4.edges.without_length(0.8).output("via4.1a", "via4.1a : minimum/maximum width of via4 : 0.8um") +via4.isolated(0.8, euclidian).output("via4.2", "via4.2 : min. via4 spacing : 0.8um") +#rule via4.3 not coded +m4.enclosing(via4, 0.19, euclidian).output("via4.4", "via4.4 : min. m4 enclosure of via4 : 0.19um") +via4.not(m4).output("via4", "via4 : m4 must enclose all via4") +if backend_flow = CU + # rules via4.irdrop.1, via4.irdrop.2, via4.irdrop.3, via4.irdrop.4 not coded because not understandable +end + +# m5 +m5.width(1.6, euclidian).output("m5.1", "m5.1 : min. m5 width : 1.6um") + +m5.space(1.6, euclidian).output("m5.2", "m5.2 : min. m5 spacing : 1.6um") + +# via4.not(m5).output("m5.via4", "m5.via4 : m5 must enclose via4") +m5.enclosing(via4, 0.31, euclidian).output("m5.3", "m4.3 : min. m5 enclosure of via4 : 0.31um") + +# nsm +# nsm.width(3.0, euclidian).output("nsm.1", "nsm.1 : min. nsm width : 3.0um") +# nsm.isolated(4.0, euclidian).output("nsm.2", "nsm.2 : min. nsm spacing : 4.0um") +# nsm.enclosing(diff, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of diff : 3.0um") +# nsm.enclosing(tap, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of tap : 3.0um") +# nsm.enclosing(poly, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of poly : 3.0um") +# nsm.enclosing(li, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of li : 3.0um") +# nsm.enclosing(m1, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m1 : 3.0um") +# nsm.enclosing(m2, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m2 : 3.0um") +# nsm.enclosing(m3, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m3 : 3.0um") +# nsm.enclosing(m4, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m4 : 3.0um") +# nsm.enclosing(m5, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m5 : 3.0um") +# nsm.enclosing(cfom, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of cfom : 3.0um") +# if backend_flow = AL +# nsm.separation(diff, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to diff : 1.0um") +# nsm.separation(tap, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to tap : 1.0um") +# nsm.separation(poly, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to poly : 1.0um") +# nsm.separation(li, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to li : 1.0um") +# nsm.separation(m1, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m1 : 1.0um") +# nsm.separation(m2, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m2 : 1.0um") +# nsm.separation(m3, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m3 : 1.0um") +# nsm.separation(m4, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m4 : 1.0um") +# nsm.separation(m5, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m5 : 1.0um") +# nsm.separation(cfom, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to cfom : 1.0um") +# end + +# pad +pad.isolated(1.27, euclidian).output("pad.2", "pad.2 : min. pad spacing : 1.27um") + +end #BEOL + +if FEOL +info("FEOL section") + +# mf +#mf.not_interacting(mf.edges.without_length(0.8)).output("mf.1", "mf.1 : minimum/maximum width of fuse : 0.8um") +#mf.not_interacting(mf.edges.without_length(7.2)).output("mf.2", "mf.2 : minimum/maximum length of fuse : 7.2um") +#mf.isolated(1.96, euclidian).output("mf.3", "mf.3 : min. fuse center spacing : 2.76um") +# fuses need more clarification on fuse_shield, fuse layers ... + +# hvi +hvi.width(0.6, euclidian).output("hvi.1", "hvi.1 : min. hvi width : 0.6um") +# hvi.isolated(0.7, euclidian).output("hvi.2", "hvi.2 : min. hvi spacing, merge if less : 0.7um") +# hvi.and(tunm).output("hvi.4", "hvi.4 : hvi must not overlapp tunm") +# hvi.and(nwell).separation(nwell, 2.0, euclidian).output("hvnwell.8", "hvnwelli.8 : min. hvnwel spacing to nwell : 2.0") +# areaid_hl.not(hvi).output("hvnwel.9", "hvnwell.9 : hvi must overlapp hvnwell") +# rule hvnell.10 not coded +# diff.not(psdm.and(diff_rs)).and(hvi).width(0.29, euclidian).output("hvdifftap.14", "hvdifftap.14 : min. diff inside hvi width : 0.29um") +# diff.and(psdm.and(diff_rs)).and(hvi).width(0.15, euclidian).output("hvdifftap.14a", "hvdifftap.14a : min. p+diff resistor inside hvi width : 0.15um") +# diff.and(hvi).isolated(0.3, euclidian).output("hvdifftap.15a", "hvdifftap.15a : min. diff inside hvi spacing : 0.3um") +# diff.and(hvi).and(nsdm).separation(diff.and(hvi).and(psdm), 0.37, euclidian).polygons.without_area(0).output("hvdifftap.15b", "hvdifftap.15b : min. n+diff inside hvi spacing to p+diff inside hvi except abutting: 0.37um") +# tap.and(hvi).edges.and(diff).without_length(0.7).output("hvdifftap.16", "hvdifftap.16 : min. tap inside hvi abuttng diff : 0.7um") +# hvi.and(nwell).enclosing(diff, 0.33, euclidian).output("hvdifftap.17", "hvdifftap.17 : min. hvnwell enclosure of p+diff : 0.33um") +# hvi.and(nwell).separation(diff, 0.43, euclidian).output("hvdifftap.18", "hvdifftap.18 : min. hvnwell spacing to n+diff : 0.43um") +# hvi.and(nwell).enclosing(tap, 0.33, euclidian).output("hvdifftap.19", "hvdifftap.19 : min. hvnwell enclosure of n+tap : 0.33um") +# hvi.and(nwell).separation(tap, 0.43, euclidian).output("hvdifftap.20", "hvdifftap.20 : min. hvnwell spacing to p+tap : 0.43um") +# hvi.and(diff).edges.not(diff.edges).output("hvdifftap.21", "hvdifftap.21 : diff must not straddle hvi") +# hvi.and(tap).edges.not(tap.edges).output("hvdifftap.21", "hvdifftap.21 : tap must not straddle hvi") +# hvi.enclosing(difftap, 0.18, euclidian).output("hvdifftap.22", "hvdifftap.22 : min. hvi enclosure of diff or tap : 0.18um") +# hvi.separation(difftap, 0.18, euclidian).output("hvdifftap.23", "hvdifftap.23 : min. hvi spacing to diff or tap : 0.18um") +# hvi.and(diff).not(nwell).separation(nwell, 0.43, euclidian).output("hvdifftap.24", "hvdifftap.24 : min. hv n+diff spacing to nwell : 0.43um") +# diff.and(hvi).not(nwell).isolated(1.07, euclidian).polygons.and(tap).output("hvdifftap.25", "hvdifftap.25 : min. n+diff inside hvi spacing accros p+tap : 1.07um") +# diff.not(poly).edges.and(gate.and(hvi).edges).space(0.35, euclidian).output("hvpoly.13", "hvpoly.13: min. hvi gate length : 0.5um") +# hvi.and(poly).edges.not(poly.edges).output("hvpoly.14", "hvpoly.14 : poly must not straddle hvi") + +# hvntm +hvntm.width(0.7, euclidian).output("hvntm.1", "hvntm.1 : min. hvntm width : 0.7um") +hvntm.isolated(0.7, euclidian).output("hvntm.2", "hvntm.2 : min. hvntm spacing : 0.7um") +# hvntm.enclosing(diff.and(nwell).and(hvi), 0.185, euclidian).output("hvntm.3", "hvntm.3 : min. hvntm enclosure of hv n+diff : 0.185um") +# hvntm.separation(diff.not(nwell).not(hvi), 0.185, euclidian).output("hvntm.4", "hvntm.4 : min. hvntm spacing to n+diff : 0.185um") +# hvntm.separation(diff.and(nwell).not(hvi), 0.185, euclidian).output("hvntm.5", "hvntm.5 : min. hvntm spacing to p+diff : 0.185um") +# hvntm.separation(tap.not(nwell).not(hvi), 0.185, euclidian).polygons.without_area(0).output("hvntm.6a", "hvntm.6a : min. hvntm spacing to p+tap : 0.185um") +# hvntm.and(areaid_ce).output("hvntm.9", "hvntm.9 : hvntm must not overlapp areaid.ce") + +# denmos +# poly.not_interacting(pwde).interacting(areaid_en).width(1.055, projection).output("denmos.1", "denmos.1 : min. de_nfet gate width : 1.055um") +# diff.not_interacting(pwde).enclosing(poly.interacting(areaid_en), 0.28, projection).polygons.without_area(0).output("denmos.2", "denmos.2 : min. de_nfet source ouside poly width : 0.28um") +# diff.not_interacting(pwde).and(poly.interacting(areaid_en)).width(0.925, projection).output("denmos.3", "denmos.3 : min. de_nfet source inside poly width : 0.925um") +# diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).width(0.17, euclidian).output("denmos.4", "denmos.4 : min. de_nfet drain width : 0.17um") +# nwell.not_interacting(pwde).and(poly.interacting(areaid_en)).width(0.225, projection).polygons.or(nwell.and(poly.interacting(areaid_en)).sized(-0.1125).sized(0.1125)).output("denmos.5", "denmos.5 : min. de_nfet source inside nwell width : 0.225m") +# diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).separation(diff.interacting(poly.interacting(areaid_en)), 1.585, projection).output("denmos.6", "denmos.6 : min. de_nfet source spacing to drain : 1.585um") +# nwell.not_interacting(pwde).and(poly.and(diff).interacting(areaid_en)).edges.without_length(5.0, nil).output("denmos.7", "denmos.7 : min. de_nfet channel width : 5.0um") +# diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("denmos.8", "denmos.8 : 90deg. not allowed for de_nfet drain") +# nwell.not_interacting(pwde).interacting(areaid_en).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("denmos.9a", "denmos.9a : 90deg. not allowed for de_nfet nwell") +# nwell.not_interacting(pwde).interacting(areaid_en).edges.with_angle(45).without_length(0.607..0.609).output("denmos.9a", "denmos.9a : 45deg. bevels of de_nfet nwell should be 0.43um from corners") +# nwell.not_interacting(pwde).interacting(areaid_en).edges.with_angle(135).without_length(0.607..0.609).output("denmos.9a", "denmos.9a : 45deg. bevels of de_nfet nwell should be 0.43um from corners") +# diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(45).without_length(0.7..0.71).output("denmos.9b", "denmos.9b : 45deg. bevels of de_nfet drain should be 0.05um from corners") +# diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(135).without_length(0.7..0.71).output("denmos.9b", "denmos.9b : 45deg. bevels of de_nfet drain should be 0.05um from corners") +# nwell.not_interacting(pwde).enclosing(diff.interacting(areaid_en).not_interacting(poly), 0.66, euclidian).output("denmos.10", "denmos.10 : min. nwell enclosure of de_nfet drain : 0.66um") +# nwell.not_interacting(pwde).interacting(areaid_en).separation(tap.not(nwell), 0.86, euclidian).output("denmos.11", "denmos.11 : min. de_nfet nwell spacing to tap : 0.86um") +# nwell.not_interacting(pwde).interacting(areaid_en).isolated(2.4, euclidian).output("denmos.12", "denmos.12 : min. de_nfet nwell : 2.4um") +# nsdm.not_interacting(pwde).enclosing(diff.interacting(areaid_en).interacting(poly), 0.13, euclidian).output("denmos.13", "denmos.13 : min. nsdm enclosure of de_nfet source : 0.13um") + +# depmos +# poly.interacting(pwde).interacting(areaid_en).width(1.05, projection).output("depmos.1", "depmos.1 : min. de_pfet gate width : 1.05um") +# diff.interacting(pwde).enclosing(poly.interacting(areaid_en), 0.28, projection).polygons.without_area(0).output("depmos.2", "depmos.2 : min. de_pfet source ouside poly width : 0.28um") +# diff.interacting(pwde).and(poly.interacting(areaid_en)).width(0.92, projection).output("depmos.3", "depmos.3 : min. de_pfet source inside poly width : 0.92um") +# diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).width(0.17, euclidian).output("depmos.4", "depmos.4 : min. de_pfet drain width : 0.17um") +# pwde.not(nwell).and(poly.interacting(areaid_en)).width(0.26, projection).polygons.or(pwde.not(nwell).and(poly.interacting(areaid_en)).sized(-0.13).sized(0.13)).output("depmos.5", "depmos.5 : min. de_pfet source inside nwell width : 0.26m") +# diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).separation(diff.interacting(poly.interacting(areaid_en)), 1.19, projection).output("depmos.6", "depmos.6 : min. de_pfet source spacing to drain : 1.19um") +# nwell.interacting(pwde).and(poly.and(diff).interacting(areaid_en)).edges.without_length(5.0, nil).output("depmos.7", "depmos.7 : min. de_pfet channel width : 5.0um") +# diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("depmos.8", "depmos.8 : 90deg. not allowed for de_pfet drain") +# pwde.not(nwell).interacting(areaid_en).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("depmos.9a", "depmos.9a : 90deg. not allowed for de_pfet pwell") +# pwde.not(nwell).interacting(areaid_en).edges.with_angle(45).without_length(0.607..0.609).output("depmos.9a", "depmos.9a : 45deg. bevels of de_pfet pwell should be 0.43um from corners") +# pwde.not(nwell).interacting(areaid_en).edges.with_angle(135).without_length(0.607..0.609).output("depmos.9a", "depmos.9a : 45deg. bevels of de_pfet pwell should be 0.43um from corners") +# diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(45).without_length(0.7..0.71).output("depmos.9b", "depmos.9b : 45deg. bevels of de_pfet drain should be 0.05um from corners") +# diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(135).without_length(0.7..0.71).output("depmos.9b", "depmos.9b : 45deg. bevels of de_pfet drain should be 0.05um from corners") +# nwell.interacting(pwde).separation(diff.interacting(areaid_en).not_interacting(poly), 0.86, euclidian).output("depmos.10", "depmos.10 : min. pwell enclosure of de_pfet drain : 0.86um") +# pwde.not(nwell).interacting(areaid_en).separation(tap.and(nwell), 0.66, euclidian).output("depmos.11", "depmos.11 : min. de_pfet pwell spacing to tap : 0.66um") +# psdm.interacting(pwde).enclosing(diff.interacting(areaid_en).interacting(poly), 0.13, euclidian).output("depmos.12", "depmos.12 : min. psdm enclosure of de_pfet source : 0.13um") + +# extd +# areaid_en.and(difftap).edges.not(difftap.edges).output("extd.1", "extd.1 : difftap must not straddle areaid.en") +# difftap.interacting(areaid_en).not(poly).with_area(0).output("extd.2", "extd.2 : poly must not overlapp entirely difftap in areaid.en") +# rules extd.4, extd.5, extd.6, extd.7 not coded because specific to some cells + +# vhvi +# rules vhvi.vhv.1, vhvi.vhv.2, vhvi.vhv.3, vhvi.vhv.4, vhvi.vhv.5, vhvi.vhv.6 not coded +# vhvi.width(0.02, euclidian).output("vhvi.1", "vhvi.1 : min. vhvi width : 0.02um") +# vhvi.and(areaid_ce).output("vhvi.2", "vhvi.2 : vhvi must not overlap areaid.ce") +# vhvi.and(hvi).output("vhvi.3", "vhvi.3 : vhvi must not overlap hvi") +# # rules vhvi.4, vhvi.6 not coded +# vhvi.and(diff).edges.not(diff.edges).output("vhvi.5", "vhvi.5 : vhvi must not straddle diff") +# vhvi.and(tap).edges.not(tap.edges).output("vhvi.5", "vhvi.5 : vhvi must not straddle tap") +# vhvi.and(poly).edges.not(poly.edges).output("vhvi.7", "vhvi.7 : vhvi must not straddle poly") + +# nwell.and(vhvi).separation(nwell, 2.5, euclidian).output("hv.nwell.1", "hv.nwell.1 : min. vhvi nwell spacing to nwell : 2.5um") +# diff.and(vhvi).isolated(0.3, euclidian).output("hv.diff.1", "hv.diff.1 : min. vhvi diff spacing : 0.3um") +# nwell.interacting(diff.and(vhvi)).separation(diff.not(nwell), 0.43, euclidian).output("hv.diff.2", "hv.diff.2 : min. vhvi nwell spacing n+diff : 0.43um") +# diff.and(vhvi).not(nwell).separation(nwell, 0.55, euclidian).output("hv.diff.3a", "hv.diff.3a : min. vhvi n+diff spacing nwell : 0.55um") +# # rule hv.diff.3b not coded +# poly.and(vhvi).not(diff).separation(diff, 0.3, euclidian).polygons.without_area(0).output("hv.poly.2", "hv.poly.2 : min. vhvi poly spacing to diff : 0.3um") +# poly.and(vhvi).not(diff).separation(nwell, 0.55, euclidian).polygons.without_area(0).output("hv.poly.3", "hv.poly.3 : min. vhvi poly spacing to nwell : 0.55um") +# nwell.enclosing(poly.and(vhvi).not(diff), 0.3, euclidian).polygons.without_area(0).output("hv.poly.4", "hv.poly.4 : min. nwell enclosure of vhvi poly : 0.3um") +# poly.and(vhvi).enclosing(diff.interacting(areaid_en), 0.16, projection).polygons.without_area(0).output("hv.poly.6", "hv.poly.6 : min. poly enclosure of hvfet gate : 0.16um") +# rule hv.poly.7 not coded + +# uhvi +# uhvi.and(diff).edges.not(diff.edges).output("uhvi.1", "uhvi.1 : diff must not straddle uhvi") +# uhvi.and(tap).edges.not(tap.edges).output("uhvi.1", "uhvi.1 : tap must not straddle uhvi") +# uhvi.and(poly).edges.not(poly.edges).output("uhvi.2", "uhvi.2 : poly must not straddle uhvi") +# pwbm.not(uhvi).output("uhvi.3", "uhvi.3 : uhvi must not enclose pwbm") +# uhvi.and(dnwell).edges.not(dnwell.edges).output("uhvi.4", "uhvi.4 : dnwell must not straddle uhvi") +# areaid_en20.not(uhvi).output("uhvi.5", "uhvi.5 : uhvi must not enclose areaid.en20") +# #dnwell.not(uhvi).output("uhvi.6", "uhvi.6 : uhvi must not enclose dnwell") +# natfet.not(uhvi).output("uhvi.7", "uhvi.7 : uhvi must not enclose natfet") + +# pwell_res +# pwell_rs.width(2.65).output("pwres.2", "pwres.2 : min. pwell resistor width : 2.65um") +# pwell_rs.sized(-2.65).sized(2.65).output("pwres.2", "pwres.2 : max. pwell resistor width : 2.65um") +# pwell_rs.interacting(pwell_rs.edges.with_length(2.651,26.499)).output("pwres.3", "pwres.3 : min. pwell resistor length : 26.5um") +# pwell_rs.interacting(pwell_rs.edges.with_length(265.0, nil)).output("pwres.4", "pwres.4 : max. pwell resistor length : 265um") +# tap.interacting(pwell_rs).separation(nwell, 0.22, euclidian).output("pwres.5", "pwres.5 : min. pwell resistor tap spacing to nwell : 0.22um") +# tap.interacting(pwell_rs).and(tap.sized(0.22).and(nwell)).output("pwres.5", "pwres.5 : max. pwell resistor tap spacing to nwell : 0.22um") +# tap.interacting(pwell_rs).width(0.53).output("pwres.6", "pwres.6 : min. width of tap inside pwell resistor : 0.53um") +# tap.interacting(pwell_rs).sized(-0.265).sized(0.265).output("pwres.6", "pwres.6 : max. width of tap inside pwell resistor : 0.53um") +# # rules pwres.7a, pwres.7b not coded +# pwell_rs.and(diff).output("pwres.8", "pwres.8 : diff not allowed inside pwell resistor") +# pwell_rs.and(poly).output("pwres.8", "pwres.8 : poly not allowed inside pwell resistor") +# rules pwres.9, pwres.10 not coded + +# rf_diode +# areaid_re.with_angle(0 .. 90).output("rfdiode.1", "rfdiode.1 : non 90 degree angle areaid.re") +# areaid_re.not(nwell).or(nwell.interacting(areaid_re).not(areaid_re)).output("rfdiode.2", "rfdiode.2 : areaid.re must coincide rf nwell diode") +# rule rfdiode.3 not coded + +end #FEOL + +if OFFGRID +info("OFFGRID-ANGLES section") + +dnwell.ongrid(0.005).output("dnwell_OFFGRID", "x.1b : OFFGRID vertex on dnwell") +dnwell.with_angle(0 .. 45).output("dnwell_angle", "x.3a : non 45 degree angle dnwell") +nwell.ongrid(0.005).output("nwell_OFFGRID", "x.1b : OFFGRID vertex on nwell") +nwell.with_angle(0 .. 45).output("nwell_angle", "x.3a : non 45 degree angle nwell") +pwbm.ongrid(0.005).output("pwbm_OFFGRID", "x.1b : OFFGRID vertex on pwbm") +pwbm.with_angle(0 .. 45).output("pwbm_angle", "x.3a : non 45 degree angle pwbm") +pwde.ongrid(0.005).output("pwde_OFFGRID", "x.1b : OFFGRID vertex on pwde") +pwde.with_angle(0 .. 45).output("pwde_angle", "x.3a : non 45 degree angle pwde") +hvtp.ongrid(0.005).output("hvtp_OFFGRID", "x.1b : OFFGRID vertex on hvtp") +hvtp.with_angle(0 .. 45).output("hvtp_angle", "x.3a : non 45 degree angle hvtp") +hvtr.ongrid(0.005).output("hvtr_OFFGRID", "x.1b : OFFGRID vertex on hvtr") +hvtr.with_angle(0 .. 45).output("hvtr_angle", "x.3a : non 45 degree angle hvtr") +lvtn.ongrid(0.005).output("lvtn_OFFGRID", "x.1b : OFFGRID vertex on lvtn") +lvtn.with_angle(0 .. 45).output("lvtn_angle", "x.3a : non 45 degree angle lvtn") +ncm.ongrid(0.005).output("ncm_OFFGRID", "x.1b : OFFGRID vertex on ncm") +ncm.with_angle(0 .. 45).output("ncm_angle", "x.3a : non 45 degree angle ncm") +diff.ongrid(0.005).output("diff_OFFGRID", "x.1b : OFFGRID vertex on diff") +tap.ongrid(0.005).output("tap_OFFGRID", "x.1b : OFFGRID vertex on tap") +diff.not(areaid_en.and(uhvi)).with_angle(0 .. 90).output("diff_angle", "x.2 : non 90 degree angle diff") +diff.and(areaid_en.and(uhvi)).with_angle(0 .. 45).output("diff_angle", "x.2c : non 45 degree angle diff") +tap.not(areaid_en.and(uhvi)).with_angle(0 .. 90).output("tap_angle", "x.2 : non 90 degree angle tap") +tap.and(areaid_en.and(uhvi)).with_angle(0 .. 45).output("tap_angle", "x.2c : non 45 degree angle tap") +tunm.ongrid(0.005).output("tunm_OFFGRID", "x.1b : OFFGRID vertex on tunm") +tunm.with_angle(0 .. 45).output("tunm_angle", "x.3a : non 45 degree angle tunm") +poly.ongrid(0.005).output("poly_OFFGRID", "x.1b : OFFGRID vertex on poly") +poly.with_angle(0 .. 90).output("poly_angle", "x.2 : non 90 degree angle poly") +rpm.ongrid(0.005).output("rpm_OFFGRID", "x.1b : OFFGRID vertex on rpm") +rpm.with_angle(0 .. 45).output("rpm_angle", "x.3a : non 45 degree angle rpm") +npc.ongrid(0.005).output("npc_OFFGRID", "x.1b : OFFGRID vertex on npc") +npc.with_angle(0 .. 45).output("npc_angle", "x.3a : non 45 degree angle npc") +nsdm.ongrid(0.005).output("nsdm_OFFGRID", "x.1b : OFFGRID vertex on nsdm") +nsdm.with_angle(0 .. 45).output("nsdm_angle", "x.3a : non 45 degree angle nsdm") +psdm.ongrid(0.005).output("psdm_OFFGRID", "x.1b : OFFGRID vertex on psdm") +psdm.with_angle(0 .. 45).output("psdm_angle", "x.3a : non 45 degree angle psdm") +licon.ongrid(0.005).output("licon_OFFGRID", "x.1b : OFFGRID vertex on licon") +licon.with_angle(0 .. 90).output("licon_angle", "x.2 : non 90 degree angle licon") +li.ongrid(0.005).output("li_OFFGRID", "x.1b : OFFGRID vertex on li") +li.with_angle(0 .. 45).output("li_angle", "x.3a : non 45 degree angle li") +mcon.ongrid(0.005).output("ct_OFFGRID", "x.1b : OFFGRID vertex on mcon") +mcon.with_angle(0 .. 90).output("ct_angle", "x.2 : non 90 degree angle mcon") +vpp.ongrid(0.005).output("vpp_OFFGRID", "x.1b : OFFGRID vertex on vpp") +vpp.with_angle(0 .. 45).output("vpp_angle", "x.3a : non 45 degree angle vpp") +m1.ongrid(0.005).output("m1_OFFGRID", "x.1b : OFFGRID vertex on m1") +m1.with_angle(0 .. 45).output("m1_angle", "x.3a : non 45 degree angle m1") +via.ongrid(0.005).output("via_OFFGRID", "x.1b : OFFGRID vertex on via") +via.with_angle(0 .. 90).output("via_angle", "x.2 : non 90 degree angle via") +m2.ongrid(0.005).output("m2_OFFGRID", "x.1b : OFFGRID vertex on m2") +m2.with_angle(0 .. 45).output("m2_angle", "x.3a : non 45 degree angle m2") +via2.ongrid(0.005).output("via2_OFFGRID", "x.1b : OFFGRID vertex on via2") +via2.with_angle(0 .. 90).output("via2_angle", "x.2 : non 90 degree angle via2") +m3.ongrid(0.005).output("m3_OFFGRID", "x.1b : OFFGRID vertex on m3") +m3.with_angle(0 .. 45).output("m3_angle", "x.3a : non 45 degree angle m3") +via3.ongrid(0.005).output("via3_OFFGRID", "x.1b : OFFGRID vertex on via3") +via3.with_angle(0 .. 90).output("via3_angle", "x.2 : non 90 degree angle via3") +nsm.ongrid(0.005).output("nsm_OFFGRID", "x.1b : OFFGRID vertex on nsm") +nsm.with_angle(0 .. 45).output("nsm_angle", "x.3a : non 45 degree angle nsm") +m4.ongrid(0.005).output("m4_OFFGRID", "x.1b : OFFGRID vertex on m4") +m4.with_angle(0 .. 45).output("m4_angle", "x.3a : non 45 degree angle m4") +via4.ongrid(0.005).output("via4_OFFGRID", "x.1b : OFFGRID vertex on via4") +via4.with_angle(0 .. 90).output("via4_angle", "x.2 : non 90 degree angle via4") +m5.ongrid(0.005).output("m5_OFFGRID", "x.1b : OFFGRID vertex on m5") +m5.with_angle(0 .. 45).output("m5_angle", "x.3a : non 45 degree angle m5") +pad.ongrid(0.005).output("pad_OFFGRID", "x.1b : OFFGRID vertex on pad") +pad.with_angle(0 .. 45).output("pad_angle", "x.3a : non 45 degree angle pad") +mf.ongrid(0.005).output("mf_OFFGRID", "x.1b : OFFGRID vertex on mf") +mf.with_angle(0 .. 90).output("mf_angle", "x.2 : non 90 degree angle mf") +hvi.ongrid(0.005).output("hvi_OFFGRID", "x.1b : OFFGRID vertex on hvi") +hvi.with_angle(0 .. 45).output("hvi_angle", "x.3a : non 45 degree angle hvi") +hvntm.ongrid(0.005).output("hvntm_OFFGRID", "x.1b : OFFGRID vertex on hvntm") +hvntm.with_angle(0 .. 45).output("hvntm_angle", "x.3a : non 45 degree angle hvntm") +vhvi.ongrid(0.005).output("vhvi_OFFGRID", "x.1b : OFFGRID vertex on vhvi") +vhvi.with_angle(0 .. 45).output("vhvi_angle", "x.3a : non 45 degree angle vhvi") +uhvi.ongrid(0.005).output("uhvi_OFFGRID", "x.1b : OFFGRID vertex on uhvi") +uhvi.with_angle(0 .. 45).output("uhvi_angle", "x.3a : non 45 degree angle uhvi") +pwell_rs.ongrid(0.005).output("pwell_rs_OFFGRID", "x.1b : OFFGRID vertex on pwell_rs") +pwell_rs.with_angle(0 .. 45).output("pwell_rs_angle", "x.3a : non 45 degree angle pwell_rs") +areaid_re.ongrid(0.005).output("areaid_re_OFFGRID", "x.1b : OFFGRID vertex on areaid.re") + +end #OFFGRID + diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.drc.xml b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.drc.xml new file mode 100755 index 00000000..f4e159dd --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.drc.xml @@ -0,0 +1,901 @@ +# +# DRC for SKY130 according to : +# https://skywater-pdk.readthedocs.io/en/latest/rules/periphery.html +# https://skywater-pdk.readthedocs.io/en/latest/rules/layers.html +# +# Distributed under GNU GPLv3: https://www.gnu.org/licenses/ +# +# History : +# 2020-10-04 : v1.0 : initial release +# +########################################################################################## + +# optionnal for a batch launch : klayout -b -rd input=my_layout.gds -rd report=sky130_drc.txt -r drc_sky130.drc +if $input + source($input) +end + +if $report + report("SKY130 DRC runset", $report) +else + report("SKY130 DRC runset", File.join(File.dirname(RBA::CellView::active.filename), "sky130_drc.txt")) +end + +AL = true # do not change +CU = false # do not change +# choose betwen only one of AL or CU back-end flow here : +backend_flow = AL + +# enable / disable rule groups +FEOL = false # front-end-of-line checks +BEOL = true # back-end-of-line checks +OFFGRID = true # manufacturing grid/angle checks + +# klayout setup +######################## +# use a tile size of 1mm - not used in deep mode- +tiles(1000.um) +# use a tile border of 10 micron: +tile_borders(1.um) +#no_borders + +# hierachical +deep + +# use 4 cpu cores +threads(4) +# if more inof is needed, set true +verbose(true) + +# layers definitions +######################## + +# all except purpose (datatype) 5 -- label and 44 -- via +li_wildcard = "67/0-4,6-43,45-*" +mcon_wildcard = "67/44" + +m1_wildcard = "68/0-4,6-43,45-*" +via_wildcard = "68/44" + +m2_wildcard = "69/0-4,6-43,45-*" +via2_wildcard = "69/44" + +m3_wildcard = "70/0-4,6-43,45-*" +via3_wildcard = "70/44" + +m4_wildcard = "71/0-4,6-43,45-*" +via4_wildcard = "71/44" + +m5_wildcard = "72/0-4,6-43,45-*" + +diff = input(65, 20) +tap = polygons(65, 44) +nwell = polygons(64, 20) +dnwell = polygons(64, 18) +pwbm = polygons(19, 44) +pwde = polygons(124, 20) +natfet = polygons(124, 21) +hvtr = polygons(18, 20) +hvtp = polygons(78, 44) +ldntm = polygons(11, 44) +hvi = polygons(75, 20) +tunm = polygons(80, 20) +lvtn = polygons(125, 44) +poly = polygons(66, 20) +hvntm = polygons(125, 20) +nsdm = polygons(93, 44) +psdm = polygons(94, 20) +rpm = polygons(86, 20) +urpm = polygons(79, 20) +npc = polygons(95, 20) +licon = polygons(66, 44) + +li = polygons(li_wildcard) +mcon = polygons(mcon_wildcard) + +m1 = polygons(m1_wildcard) +via = polygons(via_wildcard) + +m2 = polygons(m2_wildcard) +via2 = polygons(via2_wildcard) + +m3 = polygons(m3_wildcard) +via3 = polygons(via3_wildcard) + +m4 = polygons(m4_wildcard) +via4 = polygons(via4_wildcard) + +m5 = polygons(m5_wildcard) + +pad = polygons(76, 20) +nsm = polygons(61, 20) +capm = polygons(89, 44) +cap2m = polygons(97, 44) +vhvi = polygons(74, 21) +uhvi = polygons(74, 22) +npn = polygons(82, 20) +inductor = polygons(82, 24) +vpp = polygons(82, 64) +pnp = polygons(82, 44) +lvs_prune = polygons(84, 44) +ncm = polygons(92, 44) +padcenter = polygons(81, 20) +mf = polygons(76, 44) +areaid_sl = polygons(81, 1) +areaid_ce = polygons(81, 2) +areaid_fe = polygons(81, 3) +areaid_sc = polygons(81, 4) +areaid_sf = polygons(81, 6) +areaid_sw = polygons(81, 7) +areaid_sr = polygons(81, 8) +areaid_mt = polygons(81, 10) +areaid_dt = polygons(81, 11) +areaid_ft = polygons(81, 12) +areaid_ww = polygons(81, 13) +areaid_ld = polygons(81, 14) +areaid_ns = polygons(81, 15) +areaid_ij = polygons(81, 17) +areaid_zr = polygons(81, 18) +areaid_ed = polygons(81, 19) +areaid_de = polygons(81, 23) +areaid_rd = polygons(81, 24) +areaid_dn = polygons(81, 50) +areaid_cr = polygons(81, 51) +areaid_cd = polygons(81, 52) +areaid_st = polygons(81, 53) +areaid_op = polygons(81, 54) +areaid_en = polygons(81, 57) +areaid_en20 = polygons(81, 58) +areaid_le = polygons(81, 60) +areaid_hl = polygons(81, 63) +areaid_sd = polygons(81, 70) +areaid_po = polygons(81, 81) +areaid_it = polygons(81, 84) +areaid_et = polygons(81, 101) +areaid_lvt = polygons(81, 108) +areaid_re = polygons(81, 125) +areaid_ag = polygons(81, 79) +poly_rs = polygons(66, 13) +diff_rs = polygons(65, 13) +pwell_rs = polygons(64, 13) +li_rs = polygons(67, 13) +cfom = polygons(22, 20) + + +# Define a new custom function that selects polygons by their number of holes: +# It will return a new layer containing those polygons with min to max holes. +# max can be nil to omit the upper limit. +class DRC::DRCLayer + def with_holes(min, max) + new_data = RBA::Region::new + self.data.each do |p| + if p.holes >= (min || 0) && (!max || p.holes <= max) + new_data.insert(p) + end + end + DRC::DRCLayer::new(@engine, new_data) + end +end + +# DRC section +######################## +info("DRC section") + +if FEOL +info("FEOL section") +gate = diff & poly + +# dnwell +dnwell.width(3.0, euclidian).output("dnwell.2", "dnwell.2 : min. dnwell width : 3.0um") +dnwell.not(uhvi).not(areaid_po).isolated(6.3, euclidian).output("dnwell.3", "dnwell.3 : min. dnwell spacing : 6.3um") +dnwell.and(pnp).output("dnwell.4", "dnwell.4 : dnwell must not overlap pnp") +dnwell.and(psdm).edges.not(psdm.edges).output("dnwell.5", "p+ must not straddle dnwell") +# dnwell.6 rue not coded + +# nwell +nwell.width(0.84, euclidian).output("nwell.1", "nwell.1 : min. nwell width : 0.84um") +nwell.isolated(1.27, euclidian).output("nwell.2a", "nwell.2a : min. nwell spacing (merged if less) : 1.27um") +# rule nwell.4 is suitable for digital cells +#nwell.not(uhvi).not(areaid_en20).not_interacting(tap.and(licon).and(li)).output("nwell.4", "nwell4 : all nwell exempt inside uhvi must contain a n+tap") +nwell.enclosing(dnwell.not(uhvi).not(areaid_po), 0.4, euclidian).output("nwell.5", "nwell.5 : min. nwell enclosing dnwell exempt unside uhvi : 0.4um") +dnwell.enclosing(nwell.not(uhvi), 1.03, euclidian).output("nwell.6", "nwell.6 : min. dnwell enclosing nwell exempt unside uhvi : 1.03um") +dnwell.separation(nwell, 4.5, euclidian).output("nwell.7", "nwell.7 : min. dnwell separation nwell : 4.5um") + +# pwbm +pwbm.not(uhvi).output("pwbm", "pwbm must be inside uhvi") +dnwell.and(uhvi).edges.not(pwbm).output("pwbm.4", "pwbm.4 : dnwell inside uhvi must be enclosed by pwbm") + +# pwde +pwde.not(pwbm).output("pwdem.3", "pwdem.3 : pwde must be inside pwbm") +pwde.not(uhvi).output("pwdem.4", "pwdem.4 : pwde must be inside uhvi") +pwde.not(dnwell).output("pwdem.5", "pwdem.5 : pwde must be inside dnwell") + +# hvtp +#hvtp.not(nwell).output("hvtp", "hvtp must inside nwell") +hvtp.width(0.38, euclidian).output("hvtp.1", "hvtp.1 : min. hvtp width : 0.38um") +hvtp.isolated(0.38, euclidian).output("hvtp.2", "hvtp.2 : min. hvtp spacing : 0.38um") +hvtp.enclosing(gate.and(psdm), 0.18, euclidian).output("hvtp.3", "hvtp.3 : min. hvtp enclosure of pfet gate : 0.18um") +hvtp.separation(gate.and(psdm), 0.18, euclidian).output("hvtp.4", "hvtp.4 : min. hvtp spacing pfet gate: 0.18um") +hvtp.with_area(0..0.265).output("hvtp.5", "hvtp.5 : min. hvtp area : 0.265um²") + +# hvtr +hvtr.width(0.38, euclidian).output("hvtr.1", "hvtr.1 : min. hvtr width : 0.38um") +hvtr.isolated(0.38, euclidian).output("hvtr.2", "hvtr.2 : min. hvtr spacing : 0.38um") + +# lvtn +lvtn.width(0.38, euclidian).output("lvtn.1", "lvtn.1 : min. lvtn width : 0.38um") +lvtn.isolated(0.38, euclidian).output("lvtn.2", "lvtn.2 : min. lvtn spacing : 0.38um") +lvtn.separation(diff.and(poly).not(uhvi), 0.18, euclidian).output("lvtn.3a", "lvtn.3a : min. lvtn spacing to gate : 0.18um") +lvtn.separation(diff.and(nwell).not(poly), 0.235, projection).output("lvtn.3b", "lvtn.3b : min. lvtn spacing to pfet s/d : 0.18um") +lvtn.enclosing(gate.not(uhvi), 0.18, euclidian).output("lvtn.4b", "lvtn.4b : min. lvtn enclosing to gate : 0.18um") +lvtn.separation(hvtp, 0.38, euclidian).output("lvtn.9", "lvtn.9 : min. lvtn spacing hvtp : 0.38um") +nwell.not_interacting(gate.and(nwell.not(hvi).not(areaid_ce))).enclosing(lvtn.not(uhvi), 0.18, euclidian).polygons.without_area(0).output("lvtn.4b", "lvtn.4b : min. lvtn enclosure of gate : 0.18um") +lvtn.separation(nwell.inside(areaid_ce), 0.38, euclidian).output("lvtn.12", "lvtn.12 : min. lvtn spacing nwell inside areaid.ce : 0.38um") +lvtn.with_area(0..0.265).output("lvtn.13", "lvtn.13 : min. lvtn area : 0.265um²") + +# ncm +ncm.and(tap.and(nwell).or(diff.not(nwell))).output("ncm.x.3", "ncm.x.3 : ncm must not overlap n+diff") +ncm.width(0.38, euclidian).output("ncm.1", "ncm.1 : min. ncm width : 0.38um") +ncm.isolated(0.38, euclidian).output("ncm.2", "ncm.2 : min. ncm spacing manual merge if smaller : 0.38um") +ncm.enclosing(diff.and(nwell), 0.18, euclidian).output("ncm.3", "ncm.3 : min. ncm enclosure of p+diff : 0.18um") +ncm.separation(lvtn.and(diff), 0.23, euclidian).output("ncm.5", "ncm.5 : min. ncm spacing lvtn diff : 0.23um") +ncm.separation(diff.not(nwell), 0.2, euclidian).output("ncm.6", "ncm.6 : min. ncm spacing nfet : 0.2um") +ncm.with_area(0..0.265).output("ncm.7", "ncm.13 : min. ncm area : 0.265um²") + +# diff-tap +difftap = diff + tap +difftap.width(0.15, euclidian).output("difftap.1", "difftap.1 : min. difftap width : 0.15um") +not_in_cell1 = layout(source.cell_obj).select("s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b" , "-s8fpls_pl8", "-s8fpls_rdrv4" , "-s8fpls_rdrv4f", "-s8fpls_rdrv8") +not_in_cell1_diff = not_in_cell1.input(65, 20) +not_in_cell1_diff.not(areaid_sc).not(poly).edges.and(gate.edges).with_length(0,0.42).output("difftap.2", "difftap.2: min. gate (exempt areaid.sc) width : 0.42um") +diff.and(areaid_sc).not(poly).edges.and(gate.edges).with_length(0,0.36).output("difftap.2", "difftap.2: min. gate inside areaid.sc width : 0.36um") +difftap.isolated(0.27, euclidian).output("difftap.3", "difftap.3 : min. difftap spacing : 0.27um") +tap.edges.and(diff.edges).with_length(0,0.29).output("difftap.4", "difftap.4 : min. tap bound by diffusion : 0.29um") +tap.edges.and(diff.edges).space(0.4, projection).output("difftap.5", "difftap.5 : min. tap bound by 2 diffusions : 0.4um") +(tap.edges.and(diff.edges)).extended(0.01, 0.01, 0, 0, false).not(tap.and(diff)).and(diff.or(tap)).output("difftap.6", "difftap.6 : diff and tap not allowed to extend beyong their abutting ege") +tap.edges.not_interacting(diff.edges).separation(diff.edges, 0.13, euclidian).output("difftap.7", "difftap.7 : min. diff/tap spacing to non-coincident diff edge : 0.13um") +diff.edges.not_interacting(tap.edges).separation(tap.edges, 0.13, euclidian).output("difftap.7", "difftap.7 : min. diff/tap spacing to non-coincident tap edge : 0.13um") +nwell.enclosing(diff.not(uhvi).and(psdm), 0.18, euclidian).output("difftap.8", "difftap.8 : min. p+diff enclosure by nwell : 0.18um") +diff.not(uhvi).and(nsdm).separation(nwell, 0.34, euclidian).output("difftap.9", "difftap.9 : min. n+diff spacing to nwell : 0.34um") +nwell.enclosing(tap.not(uhvi).and(nsdm), 0.18, euclidian).output("difftap.10", "difftap.10 : min. n+tap enclosure by nwell : 0.18um") +tap.not(uhvi).and(psdm).separation(nwell, 0.13, euclidian).output("difftap.11", "difftap.11 : min. p+tap spacing to nwell : 0.13um") + +# tunm +tunm.width(0.41, euclidian).output("tunm.1", "tunm.1 : min. tunm width : 0.41um") +tunm.isolated(0.5, euclidian).output("tunm.2", "tunm.2 : min. tunm spacing : 0.5um") +tunm.enclosing(gate, 0.095, euclidian).output("tunm.3", "tunm.3 : min. tunm beyond gate : 0.095um") +tunm.separation(gate.not_interacting(tunm), 0.095, euclidian).output("tunm.4", "tunm.4 : min. tunm spacing to gate outside tunm: 0.095um") +gate.and(tunm).edges.not(gate.edges).output("tunm.5", "tunm.5 : gate must not straddle tunm") +tunm.not(dnwell).output("tunm.6a", "tunm.6a : tunm not allowed outside dnwell") +tunm.with_area(0..0.672).output("tunm.7", "tunm.7 : min. tunm area : 0.672um²") + +# poly +poly.width(0.15, euclidian).output("poly.1a", "poly.1a : min. poly width : 0.15um") +poly.not(diff).edges.and(gate.and(lvtn).edges).space(0.35, euclidian).output("poly.1b", "poly.1b: min. lvtn gate width : 0.35um") +poly.isolated(0.21, euclidian).output("poly.2", "poly.2 : min. poly spacing : 0.21um") +poly.and(rpm.or(urpm).or(poly_rs)).width(0.33, euclidian).output("poly.3", "poly.3 : min. poly resistor width : 0.33um") +poly.not(gate).separation(diff, 0.075, projection).polygons.without_area(0).output("poly.4", "poly.4 : min. poly on field spacing to diff : 0.075um") +poly.not(gate).separation(tap, 0.055, euclidian).output("poly.5", "poly.5 : min. poly on field spacing to tap : 0.055um") +gate.separation(tap, 0.3, projection).polygons.and(diff).output("poly.6", "poly.6 : min. gate spacing to tap : 0.3um") +diff.enclosing(gate, 0.25, projection).polygons.without_area(0).output("poly.7", "poly.7 : min. source/drain length : 0.25um") +poly.enclosing(gate, 0.13, projection).polygons.without_area(0).output("poly.8", "poly.8 : min. poly extention gate (endcap) : 0.13um") +poly.and(rpm.or(urpm).or(poly_rs)).separation(poly.or(difftap), 0.48, euclidian).polygons.without_area(0).output("poly.9", "poly.9 : min. poly resistor space to poly or diff/tap : 0.48um") +diff.merged.edges.end_segments(0.01).and(poly).output("poly.10", "poly.10 : poly must not overlap diff corner") +gate.with_angle(0 .. 90).output("poly.11", "poly.11 : non 90 degree angle gate") +not_in_cell3 = layout(source.cell_obj).select("s8fgvr_n_fg2") +not_in_cell3_poly = not_in_cell3.input(66, 20) +not_in_cell3_poly.not(hvi).not(nwell.not(hvi)).and(tap).output("poly.12", "poly.12 : poly must not overlap tap") +poly.and(diff_rs).output("poly.15", "poly.15 : poly must not overlap diff resistor") + +# rpm +rpm.width(1.27, euclidian).output("rpm.1a", "rpm.1a : min. rpm width : 1.27um") +rpm.isolated(0.84, euclidian).output("rpm.2", "rpm.2 : min. rpm spacing : 0.84um") +rpm.enclosing(poly.and(poly_rs).and(psdm), 0.2, euclidian).output("rpm.3", "rpm.3 : min. rpm enclosure of poly resistor : 0.2um") +psdm.enclosing(poly.and(poly_rs).and(rpm), 0.11, euclidian).output("rpm.4", "rpm.4 : min. psdm enclosure of poly resistor : 0.11um") +npc.enclosing(poly.and(poly_rs).and(rpm), 0.095, euclidian).output("rpm.5", "rpm.5 : min. npc enclosure of poly resistor : 0.095um") +rpm.separation(nsdm, 0.2, euclidian).output("rpm.6", "rpm.6 : min. rpm spacing nsdm: 0.2um") +rpm.separation(poly, 0.2, euclidian).output("rpm.7", "rpm.7 : min. rpm spacing poly: 0.2um") +rpm.and(poly).edges.not(poly.edges).output("rpm.8", "rpm.8 : poly must not straddle rpm") +poly.and(poly_rs).and(rpm).separation(hvntm, 0.185, euclidian).output("rpm.9", "rpm.9 : min. poly resistor spacing hvntm: 0.185um") +rpm.and(pwbm).output("rpm.10", "rpm.107 : min. rpm spacing pwbm: na") + +# varac +varac = poly & tap & (nwell - hvi) - areaid_ce +tap.not(poly).edges.and(varac.edges).space(0.18, euclidian).output("varac.1", "varac.1: min. varac channel length : 0.18um") +tap.and(poly).edges.and(varac.edges).space(1.0, euclidian).output("varac.2", "varac.2: min. varac channel wdth : 1.0um") +varac.separation(hvtp, 0.18, euclidian).output("varac.3", "varac.3: min. varac channel space to hvtp : 0.18um") +varac.separation(licon.and(tap), 0.25, euclidian).output("varac.4", "varac.4: min. varac channel space to licon on tap : 0.25um") +nwell.enclosing(poly.overlapping(varac), 0.15, euclidian).output("varac.5", "varac.5: min. nwell enclosure of poly overlapping varac channel : 0.15um") +tap.overlapping(varac).separation(difftap, 0.27, euclidian).polygons.without_area(0).output("varac.6", "varac.6: min. varac channel tap space to difftap : 0.27um") +nwell.overlapping(varac).and(diff.and(nwell)).output("varac.7", "varac.7: nwell overlapping varac channel must not overlap p+diff") + +# photo +photodiode = dnwell & areaid_po +photodiode.edges.without_length(3.0).output("photo.2", "photo.2 : minimum/maximum width of photodiode : 3.0um") +photodiode.isolated(5.0, euclidian).output("photo.3", "photo.3 : mini. photodiode spacing : 5.0um") +photodiode.separation(dnwell, 5.3, euclidian).output("photo.4", "photo.4 : mini. photodiode spacing to dnwell : 5.3um") +areaid_po.not(dnwell).output("photo.5.6", "photo.5.6 : photodiode edges must coincide areaid.po and enclosed by dnwell") +photodiode.not(tap.not(nwell).holes).output("photo.7", "photo.7 : photodiode must be enclosed by p+tap ring") +photodiode.and(nwell).edges.without_length(0.84).output("photo.8", "photo.8 : minimum/maximum width of nwell inside photodiode : 0.84um") +areaid_po.edges.and(photodiode.and(nwell).sized(1.08)).without_length(12.0).output("photo.9", "photo.9 : minimum/maximum enclosure of nwell by photodiode : 1.08um") +photodiode.and(tap).edges.without_length(0.41).output("photo.10", "photo.10 : minimum/maximum width of tap inside photodiode : 0.41um") + +# npc +npc.width(0.27, euclidian).output("npc.1", "npc.1 : min. npc width : 0.27um") +npc.isolated(0.27, euclidian).output("npc.2", "npc.2 : min. npc spacing, should be mnually merge if less : 0.27um") +npc.separation(gate, 0.09, euclidian).output("npc.4", "npc.4 : min. npc spacing to gate : 0.09um") + +# nsdm/psdm +npsdm = nsdm + psdm +nsdm.width(0.38, euclidian).output("nsdm.1", "nsdm.1 : min. nsdm width : 0.38um") +psdm.width(0.38, euclidian).output("psdm.1", "psdm.1 : min. psdm width : 0.38um") +nsdm.isolated(0.38, euclidian).output("n/psdm.1", "n/psdm.1 : min. nsdm spacing, should be mnually merge if less : 0.38um") +psdm.isolated(0.38, euclidian).output("n/psdm.1", "n/psdm.1 : min. psdm spacing, should be mnually merge if less : 0.38um") +npsdm.enclosing(diff, 0.125, euclidian).polygons.not(tap.sized(0.125)).output("n/psdm.5a", "n/psdm.5a : min. n/psdm enclosure diff except butting edge : 0.125um") +npsdm.enclosing(tap, 0.125, euclidian).polygons.not(diff.sized(0.125)).output("n/psdm.5b", "n/psdm.5b : min. n/psdm enclosure tap except butting edge : 0.125um") +tap.edges.and(diff.edges).not(npsdm).output("n/psdm.6", "n/psdm.6 : min. n/psdm enclosure of butting edge : 0.0um") +nsdm.and(difftap).separation(psdm.and(difftap), 0.13, euclidian).polygons.without_area(0).output("n/psdm.7", "n/psdm.7 : min. nsdm diff spacing to psdm diff except butting edge : 0.13um") +diff.and((nsdm.and(nwell)).or(psdm.not(nwell))).output("n/psdm.8", "n/psdm.8 : diff should be the opposite type of well/substrate underneath") +tap.and((nsdm.not(nwell)).or(psdm.and(nwell))).output("n/psdm.8", "n/psdm.8 : tap should be the same type of well/substrate underneath") +tap.and(diff).without_area(0).output("tap and diff", "tap and diff must not overlap") +nsdm.with_area(0..0.265).output("n/psdm.10a", "n/psdm.10a : min. nsdm area : 0.265um²") +psdm.with_area(0..0.265).output("n/psdm.10b", "n/psdm.10b : min. psdm area : 0.265um²") + +# licon +licon.not(poly.interacting(poly_rs)).edges.without_length(0.17).output("licon.1", "licon.1 : minimum/maximum width of licon : 0.17um") +licon.and(poly.interacting(poly_rs)).not_interacting((licon.and(poly.interacting(poly_rs)).edges.with_length(0.19)).or(licon.and(poly.interacting(poly_rs)).edges.with_length(2.0))).output("licon.1b/c", "licon.1b/c : minimum/maximum width/length of licon inside poly resistor : 2.0/0.19um") +licon.isolated(0.17, euclidian).output("licon.2", "licon.2 : min. licon spacing : 0.17um") +licon.and(poly.interacting(poly_rs)).edges.with_length(0.19).space(0.35, euclidian).output("licon.2b", "licon.2b : min. licon 0.19um edge on resistor spacing : 0.35um") +licon.interacting(licon.and(poly.interacting(poly_rs)).edges.with_length(2.0)).separation(licon.and(poly.interacting(poly_rs)), 0.51, euclidian).output("licon.2c", "licon.2c : min. licon 2.0um edge on resistor spacing : 0.51um") +licon.and(poly.interacting(poly_rs)).separation(licon.not(poly.interacting(poly_rs)), 0.51, euclidian).output("licon.2d", "licon.2d : min. licon on resistor spacing other licon : 0.51um") +# rule licon.3 not coded +licon.not(li).not(poly.or(diff).or(tap)).output("licon.4", "licon.4 : min. licon must overlap li and (poly or tap or diff) ") +diff.enclosing(licon, 0.04, euclidian).output("licon.5", "licon.5 : min. diff enclosure of licon : 0.04um") +tap.edges.and(diff.edges).separation(licon.and(tap).edges, 0.06, euclidian).output("licon.6", "licon.6 : min. abutting edge spacing to licon tap : 0.06um") +licon_edges_with_less_enclosure_tap = tap.enclosing(licon, 0.12, projection).second_edges +opposite1 = (licon.edges - licon_edges_with_less_enclosure_tap).width(0.17 + 1.dbu, projection).polygons +licon.not_interacting(opposite1).output("licon.7", "licon.7 : min. tap enclosure of licon by one of 2 opposite edges : 0.12um") +poly.enclosing(licon, 0.05, euclidian).output("licon.8", "licon.8 : min. poly enclosure of licon : 0.05um") +licon008 = licon.interacting(poly.enclosing(licon, 0.08, euclidian).polygons) +licon_edges_with_less_enclosure_poly = poly.enclosing(licon, 0.08, projection).second_edges +opposite2 = (licon.edges - licon_edges_with_less_enclosure_poly).width(0.17 + 1.dbu, projection).polygons +licon008.not_interacting(opposite2).output("licon.8a", "licon.8a : min. poly enclosure of licon by one of 2 opposite edges : 0.08um") +# rule licon.9 not coded +licon.and(tap.and(nwell.not(hvi))).separation(varac, 0.25, euclidian).output("licon.10", "licon.10 : min. licon spacing to varac channel : 0.25um") +not_in_cell4 = layout(source.cell_obj).select("-s8fs_gwdlvx4", "-s8fs_gwdlvx8", "-s8fs_hvrsw_x4", "-s8fs_hvrsw8", "-s8fs_hvrsw264", "-s8fs_hvrsw520", "-s8fs_rdecdrv", "-s8fs_rdec8”, “s8fs_rdec32", "-s8fs_rdec264", "-s8fs_rdec520") +not_in_cell4_licon = not_in_cell4.input(66, 44) +not_in_cell4_licon.and(diff.or(tap)).separation(gate.not(areaid_sc), 0.055, euclidian).output("licon.11", "licon.11 : min. licon spacing to gate : 0.055um") +licon.and(diff.or(tap)).separation(gate.and(areaid_sc), 0.05, euclidian).output("licon.11a", "licon.11a : min. licon spacing to gate inside areaid.sc : 0.05um") +in_cell4 = layout(source.cell_obj).select("+s8fs_gwdlvx4", "+s8fs_gwdlvx8", "+s8fs_hvrsw_x4", "+s8fs_hvrsw8", "+s8fs_hvrsw264", "+s8fs_hvrsw520") +in_cell4_licon = in_cell4.input(66, 44) +in_cell4_licon.and(diff.or(tap)).separation(gate, 0.04, euclidian).output("licon.11c", "licon.11c : min. licon spacing to gate for specific cells: 0.04um") +# rules 11.b , 11.d not coded +diff.interacting(gate).not(diff.interacting(gate).width(5.7, euclidian).polygons).output("licon.12", "licon.12 : max. sd width without licon : 5.7um") +licon.and(diff.or(tap)).separation(npc, 0.09, euclidian).output("licon.13", "licon.13 : min. difftap licon spacing to npc : 0.09um") +licon.and(poly).separation(diff.or(tap), 0.19, euclidian).output("licon.14", "licon.14 : min. poly licon spacing to difftap : 0.19um") +npc.enclosing(licon.and(poly), 0.1, euclidian).output("licon.15", "licon.15 : min. npc enclosure of poly-licon : 0.1um") +# rule licon.16 not applicable for the diff for the nmos of a nand gates or the pmos of a nor gates +#diff.not(gate).not_interacting(licon).output("licon.16", "licon.16 : diff must enclose one licon") +tap.not(uhvi).not_interacting(licon).output("licon.16", "licon.16 : tap must enclose one licon") +poly.and(tap).edges.not(tap.edges).output("licon.17", "licon.17 : tap must not straddle poly") +npc.not_interacting(licon.and(poly)).output("licon.18", "licon.18 : npc mut enclosed one poly-licon") + +# vpp +vpp.width(1.43, euclidian).output("vpp.1", "vpp.1 : min. vpp width : 1.43um") +# rules 1.b, 1.c not coded +vpp.and(poly.or(difftap)).output("vpp.3", "vpp.3 : vpp must not overlapp poly or diff or tap") +vpp.and(nwell).edges.not(vpp.edges).output("vpp.4", "vpp.4 : vpp must not straddle nwell") +vpp.and(dnwell).edges.not(vpp.edges).output("vpp.4", "vpp.4 : vpp must not straddle dnwell") +vpp.and(poly.or(li).or(m1).or(m2)).separation(poly.or(li).or(m1).or(m2), 1.5, euclidian).polygons.with_area(2.25,nil).output("vpp.5", "vpp.5 : min. vpp spacing to poly or li or m1 or m2 : 1.5um") +vpp.with_area(0..area(vpp.and(m3))*0.25).output("vpp.5a", "vpp.5a : max. m3 density in vpp : 0.25") +vpp.with_area(0..area(vpp.and(m4))*0.3).output("vpp.5b", "vpp.5b : max. m4 density in vpp : 0.3") +vpp.with_area(0..area(vpp.and(m5))*0.4).output("vpp.5c", "vpp.5c : max. m5 density in vpp : 0.4") +nwell.enclosing(vpp, 1.5, euclidian).output("vpp.8", "vpp.8 : nwell enclosure of vpp : 1.5") +vpp.separation(nwell, 1.5, euclidian).polygons.without_area(0).output("vpp.9", "vpp.9 : vpp spacing to nwell : 1.5") +# rule vpp.10 not coded +# rule vpp.11 not coded because moscap is not defined properly by any gds layer +# rules vpp.12a, 12b, 12c not coded because specific to one cell +if backend_flow = CU + m1.separation(vpp.and(m1), 0.16, euclidian).polygons.without_area(0).output("vpp.13", "vpp.13 : m1 spacing to m1inside vpp : 0.16") +end + +# CAPM +capm.width(1.0, euclidian).output("capm.1", "capm.1 : min. capm width : 1.0um") +capm.isolated(0.84, euclidian).output("capm.2a", "capm.2a : min. capm spacing : 0.84um") +m2.interacting(capm).isolated(1.2, euclidian).output("capm.2b", "capm.2b : min. capm spacing : 1.2um") +m2.enclosing(capm, 0.14, euclidian).output("capm.3", "capm.3 : min. m2 enclosure of capm : 0.14um") +capm.enclosing(via2, 0.14, euclidian).output("capm.4", "capm.4 : min. capm enclosure of via2 : 0.14um") +capm.separation(via2, 0.14, euclidian).output("capm.5", "capm.5 : min. capm spacing to via2 : 0.14um") +capm.sized(-20.0).sized(20.0).output("capm.6", "capm.6 : max. capm lenght/width : 20um") +capm.with_angle(0 .. 90).output("capm.7", "capm.7 : capm not rectangle") +capm.separation(via, 0.14, euclidian).polygons.without_area(0).output("capm.8", "capm.8 : min. capm spacing to via : 0.14um") +capm.and(nwell).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle nwell") +capm.and(diff).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle diff") +capm.and(tap).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle tap") +capm.and(poly).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle poly") +capm.and(li).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle li") +capm.and(m1).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle m1") +capm.separation(m2.not_interacting(capm), 0.14, euclidian).output("capm.11", "capm.11 : min. capm spacing to m2 not overlapping capm : 0.5um") + +end #FEOL + +if BEOL +info("BEOL section") + +# li +not_in_cell5 = source.select("-s8rf2_xcmvpp_hd5_*") +not_in_cell5_li = not_in_cell5.polygons(li_wildcard) +not_in_cell5_li.width(0.17, euclidian).output("li.1", "li.1 : min. li width : 0.17um") + +in_cell5_li = li - not_in_cell5_li +in_cell5_li.width(0.14, euclidian).output("li.1a", "li.1a : min. li width for the cells s8rf2_xcmvpp_hd5_* : 0.14um") + +# rule li.2 not coded + +not_in_cell5_li.space(0.17, euclidian).output("li.3", "li.3 : min. li spacing : 0.17um") +in_cell5_li.space(0.14, euclidian).output("li.3a", "li.3a : min. li spacing for the cells s8rf2_xcmvpp_hd5_* : 0.14um") +licon08 = licon.interacting(li.enclosing(licon, 0.08, euclidian).polygons) +licon_edges_with_less_enclosure_li = li.enclosing(licon, 0.08, projection).second_edges +opposite3 = (licon.edges - licon_edges_with_less_enclosure_li).width(0.17 + 1.dbu, projection).polygons +licon08.not_interacting(opposite3).output("li.5", "li.5 : min. li enclosure of licon of 2 opposite edges : 0.08um") +li.with_area(0..0.0561).output("li.6", "li.6 : min. li area : 0.0561um²") + +# ct +mcon.edges.without_length(0.17).output("ct.1", "ct.1 : minimum/maximum width of mcon : 0.17um") +mcon.space(0.19, euclidian).output("ct.2", "ct.2 : min. mcon spacing : 0.19um") +# rule ct.3 not coded +mcon.not(li).output("ct.4", "ct.4 : mcon should covered by li") +if backend_flow = CU + li.interacting(li.and(m1).not(mcon).with_holes(1,10)).enclosing(mcon, 0.2, euclidian).output("ct.irdrop.1", "ct.irdrop.1 : min. li enclsoure of 1..10 mcon : 0.2um") + li.interacting(li.and(m1).not(mcon).with_holes(11,100)).enclosing(mcon, 0.3, euclidian).output("ct.irdrop.2", "ct.irdrop.2 : min. li enclsoure of 11..100 mcon : 0.3um") +end + +# m1 +m1.width(0.14, euclidian).output("m1.1", "m1.1 : min. m1 width : 0.14um") + +huge_m1 = m1.sized(-1.5).sized(1.5) +non_huge_m1 = m1 - huge_m1 + +non_huge_m1.space(0.14, euclidian).output("m1.2", "m1.2 : min. m1 spacing : 0.14um") + +(huge_m1.separation(non_huge_m1, 0.28, euclidian) + huge_m1.space(0.28, euclidian)).output("m1.3ab", "m1.3ab : min. 3um.m1 spacing m1 : 0.28um") + +not_in_cell6 = layout(source.cell_obj).select("-s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b", "-s8fpls_pl8", "-s8fs_cmux4_fm") +not_in_cell6_m1 = not_in_cell6.input(m1_wildcard) +not_in_cell6_m1.enclosing(mcon, 0.03, euclidian).output("m1.4", "m1.4 : min. m1 enclosure of mcon : 0.03um") +in_cell6 = layout(source.cell_obj).select("+s8cell_ee_plus_sseln_a", "+s8cell_ee_plus_sseln_b", "+s8cell_ee_plus_sselp_a", "+s8cell_ee_plus_sselp_b", "+s8fpls_pl8", "+s8fs_cmux4_fm") +in_cell6_m1 = in_cell6.input(m1_wildcard) +in_cell6_m1.enclosing(mcon, 0.005, euclidian).output("m1.4a", "m1.4a : min. m1 enclosure of mcon for specific cells : 0.005um") +m1.with_area(0..0.083).output("m1.6", "m1.6 : min. m1 area : 0.083um²") +m1.holes.with_area(0..0.14).output("m1.7", "m1.7 : min. m1 holes area : 0.14um²") +if backend_flow = AL + mcon06 = mcon.interacting(poly.enclosing(m1, 0.06, euclidian).polygons) + mcon_edges_with_less_enclosure_m1 = m1.enclosing(mcon, 0.06, projection).second_edges + opposite4 = (mcon.edges - mcon_edges_with_less_enclosure_m1).width(0.17 + 1.dbu, projection).polygons + mcon06.not_interacting(opposite4).output("m1.5", "m1.5 : min. m1 enclosure of mcon of 2 opposite edges : 0.06um") + # rule m1.pd.1, rule m1.pd.2a, rule m1.pd.2b not coded +end +if bakend_flow = CU + m1.sized(-2.0).sized(2.0).output("m1.11", "m1.11 : max. m1 width after slotting : 4.0um") + # rule m1.12 not coded because inconsistent with m1.11 + # rule m1.13, m1.14, m1.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +end + +# via +#rule via.3 not coded +via.not(m1).output("via.4c.5c", "via.4c.5c : m1 must enclose all via") +if backend_flow = AL + via.not(areaid_mt).edges.without_length(0.15).output("via.1a", "via.1a : minimum/maximum width of via : 0.15um") + via.and(areaid_mt).not_interacting((via.and(areaid_mt).edges.without_length(0.15)).or(via.and(areaid_mt).edges.without_length(0.23)).or(via.and(areaid_mt).edges.without_length(0.28))).output("via.1b", "via.1b : minimum/maximum width of via in areaid.mt: 0.15um or 0.23um or 0.28um") + via.isolated(0.17, euclidian).output("via.2", "via.2 : min. via spacing : 0.17um") + m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.055, euclidian).output("via.4a", "via.4a : min. m1 enclosure of 0.15um via : 0.055um") + m1.enclosing(via.not_interacting(via.edges.without_length(0.23)), 0.03, euclidian).output("via.4b", "via.4b : min. m1 enclosure of 0.23um via : 0.03um") + via1_edges_with_less_enclosure_m1 = m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.085, projection).second_edges + opposite5 = (via.not_interacting(via.edges.without_length(0.15)).edges - via1_edges_with_less_enclosure_m1).width(0.15 + 1.dbu, projection).polygons + via.not_interacting(via.edges.without_length(0.15)).not_interacting(opposite5).output("via1.5a", "via1.5a : min. m1 enclosure of 0.15um via of 2 opposite edges : 0.085um") + via2_edges_with_less_enclosure_m1 = m1.enclosing(via.not_interacting(via.edges.without_length(0.23)), 0.06, projection).second_edges + opposite6 = (via.not_interacting(via.edges.without_length(0.23)).edges - via2_edges_with_less_enclosure_m1).width(0.23 + 1.dbu, projection).polygons + via.not_interacting(via.edges.without_length(0.23)).not_interacting(opposite6).output("via1.5b", "via1.5b : min. m1 enclosure of 0.23um via of 2 opposite edges : 0.06um") +end +if backend_flow = CU + via.not(areaid_mt).edges.without_length(0.18).output("via.11", "via.11 : minimum/maximum width of via : 0.18um") + via.isolated(0.13, euclidian).output("via.12", "via.12 : min. via spacing : 0.13um") + # rule via.13 not coded because not understandable + via1_edges_with_less_enclosure_m1 = m1.enclosing(via, 0.04, projection).second_edges + opposite5 = (via.edges - via1_edges_with_less_enclosure_m1).width(0.18 + 1.dbu, projection).polygons + via.not_interacting(opposite5).output("via1.14", "via1.14 : min. m1 enclosure of 0.04um via of 2 opposite edges : 0.04um") + # rules via.irdrop.1, via.irdrop.2, via.irdrop.3, via.irdrop.4 not coded because not understandable +end + +# m2 +m2.width(0.14, euclidian).output("m2.1", "m2.1 : min. m2 width : 0.14um") + +huge_m2 = m2.sized(-1.5).sized(1.5) +non_huge_m2 = m2 - huge_m2 + +non_huge_m2.space(0.14, euclidian).output("m2.2", "m2.2 : min. m2 spacing : 0.14um") + +(huge_m2.separation(non_huge_m2, 0.28, euclidian) + huge_m2.space(0.28, euclidian)).output("m2.3ab", "m2.3ab : min. 3um.m2 spacing m2 : 0.28um") + +# rule m2.3c not coded +m2.with_area(0..0.0676).output("m2.6", "m2.6 : min. m2 area : 0.0676um²") +m2.holes.with_area(0..0.14).output("m2.7", "m2.7 : min. m2 holes area : 0.14um²") +via.not(m2).output("m2.via", "m2.via : m2 must enclose via") +if backend_flow = AL + m2.enclosing(via, 0.055, euclidian).output("m2.4", "m2.4 : min. m2 enclosure of via : 0.055um") + via_edges_with_less_enclosure_m2 = m2.enclosing(via, 0.085, projection).second_edges + opposite7 = (via.edges - via_edges_with_less_enclosure_m2).width(0.2 + 1.dbu, projection).polygons + via.not_interacting(opposite7).output("m2.5", "m2.5 : min. m2 enclosure of via of 2 opposite edges : 0.085um") + # rule m2.pd.1, rule m2.pd.2a, rule m2.pd.2b not coded +end +if bakend_flow = CU + m2.sized(-2.0).sized(2.0).output("m2.11", "m2.11 : max. m2 width after slotting : 4.0um") + # rule m2.12 not coded because inconsistent with m2.11 + # rule m2.13, m2.14, m2.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +end + +# via2 +#rule via233 not coded +via2.not(m2).output("via2", "via2 : m2 must enclose all via2") +if backend_flow = AL + via2.not(areaid_mt).edges.without_length(0.2).output("via2.1a", "via2.1a : minimum/maximum width of via2 : 0.2um") + via2.and(areaid_mt).not_interacting((via2.and(areaid_mt).edges.without_length(0.2)).or(via2.and(areaid_mt).edges.without_length(1.2)).or(via2.and(areaid_mt).edges.without_length(1.5))).output("via2.1b", "via2.1b : minimum/maximum width of via2 in areaid.mt: 0.2um or 1.2um or 1.5um") + via2.isolated(0.2, euclidian).output("via2.2", "via2.2 : min. via2 spacing : 0.2um") + m2.enclosing(via2, 0.04, euclidian).output("via2.4", "via2.4 : min. m2 enclosure of via2 : 0.04um") + m2.enclosing(via2.not_interacting(via2.edges.without_length(1.5)), 0.14, euclidian).output("via2.4a", "via2.4a : min. m2 enclosure of 1.5um via2 : 0.14um") + via2_edges_with_less_enclosure_m2 = m2.enclosing(via2, 0.085, projection).second_edges + opposite8 = (via2.edges - via2_edges_with_less_enclosure_m2).width(0.2 + 1.dbu, projection).polygons + via2.not_interacting(opposite8).output("via2.5", "via2.5 : min. m2 enclosure of via2 of 2 opposite edges : 0.085um") +end +if backend_flow = CU + via2.edges.without_length(0.21).output("via2.11", "via2.11 : minimum/maximum width of via2 : 0.21um") + via2.isolated(0.18, euclidian).output("via2.12", "via2.12 : min. via2 spacing : 0.18um") + # rule via2.13 not coded because not understandable, or not clear + m2.enclosing(via2, 0.035, euclidian).output("via2.14", "via2.14 : min. m2 enclosure of via2 : 0.035um") + # rules via2.irdrop.1, via2.irdrop.2, via2.irdrop.3, via2.irdrop.4 not coded because not understandable +end + +# m3 +m3.width(0.3, euclidian).output("m3.1", "m3.1 : min. m3 width : 0.3um") + +huge_m3 = m3.sized(-1.5).sized(1.5) +non_huge_m3 = m3 - huge_m3 + +non_huge_m3.space(0.3, euclidian).output("m3.2", "m3.2 : min. m3 spacing : 0.3um") + +(huge_m3.separation(non_huge_m3, 0.4, euclidian) + huge_m3.space(0.4, euclidian)).output("m3.3ab", "m3.3ab : min. 3um.m3 spacing m3 : 0.4um") + +# rule m3.3c not coded +m3.with_area(0..0.24).output("m3.6", "m3.6 : min. m2 area : 0.24um²") +via2.not(m3).output("m3.via2", "m3.via2 : m3 must enclose via2") +if backend_flow = AL + m3.enclosing(via2, 0.065, euclidian).output("m3.4", "m3.4 : min. m3 enclosure of via2 : 0.065um") + via2_edges_with_less_enclosure_m3 = m3.enclosing(via2, 0.085, projection).second_edges + # m3.5 N/A + # opposite9 = (via2.edges - via2_edges_with_less_enclosure_m3).width(0.3 + 1.dbu, projection).polygons + # via2.not_interacting(opposite9).output("m3.5", "m3.5 : min. m3 enclosure of via2 of 2 opposite edges : 0.085um") + # rule m3.pd.1, rule m3.pd.2a, rule m3.pd.2b not coded +end +if bakend_flow = CU + m3.holes.with_area(0..0.2).output("m3.7", "m3.7 : min. m2 holes area : 0.2um²") + m3.sized(-2.0).sized(2.0).output("m3.11", "m3.11 : max. m3 width after slotting : 4.0um") + # rule m3.12 not coded because inconsistent with m3.11 + # rule m3.13, m3.14, m3.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +end + +# via3 +#rule via3.3 not coded +via3.not(m3).output("via3", "via3 : m3 must enclose all via3") +if backend_flow = AL + via3.not(areaid_mt).edges.without_length(0.2).output("via3.1a", "via3.1a : minimum/maximum width of via3 : 0.2um") + via3.and(areaid_mt).not_interacting((via3.and(areaid_mt).edges.without_length(0.2)).or(via3.and(areaid_mt).edges.without_length(0.8))).output("via3.1a", "via3.1a : minimum/maximum width of via3 in areaid.mt: 0.2um or 0.8um") + via3.isolated(0.2, euclidian).output("via3.2", "via3.2 : min. via3 spacing : 0.2um") + m3.enclosing(via3, 0.06, euclidian).output("via3.4", "via3.4 : min. m3 enclosure of via3 : 0.06um") + via3_edges_with_less_enclosure_m3 = m3.enclosing(via3, 0.09, projection).second_edges + opposite10 = (via3.edges - via3_edges_with_less_enclosure_m3).width(0.2 + 1.dbu, projection).polygons + via3.not_interacting(opposite10).output("via3.5", "via3.5 : min. m2 enclosure of via3 of 2 opposite edges : 0.09um") +end +if backend_flow = CU + via3.edges.without_length(0.21).output("via3.11", "via3.11 : minimum/maximum width of via3 : 0.21um") + via3.isolated(0.18, euclidian).output("via3.12", "via3.12 : min. via3 spacing : 0.18um") + m3.enclosing(via3, 0.055, euclidian).output("via3.13", "via3.13 : min. m3 enclosure of via3 : 0.055um") + # rule via3.14 not coded because not understandable, or not clear + # rules via3.irdrop.1, via3.irdrop.2, via3.irdrop.3, via3.irdrop.4 not coded because not understandable +end + +# m4 +m4.width(0.3, euclidian).output("m4.1", "m4.1 : min. m4 width : 0.3um") + +huge_m4 = m4.sized(-1.5).sized(1.5) +non_huge_m4 = m4 - huge_m4 + +non_huge_m4.space(0.3, euclidian).output("m4.2", "m4.2 : min. m4 spacing : 0.3um") + +(huge_m4.separation(non_huge_m4, 0.4, euclidian) + huge_m4.space(0.4, euclidian)).output("m4.5ab", "m4.5ab : min. 3um.m4 spacing m4 : 0.4um") + +m4.with_area(0..0.24).output("m4.4", "m4.4 : min. m2 area : 0.24um²") +via3.not(m4).output("m4.via3", "m4.via3 : m4 must enclose via3") +if backend_flow = AL + m4.enclosing(via3, 0.065, euclidian).output("m4.3", "m4.3 : min. m4 enclosure of via3 : 0.065um") + # m4.5 doesn't exist + # via3_edges_with_less_enclosure_m4 = m4.enclosing(via2, 0.085, projection).second_edges + # opposite9 = (via3.edges - via3_edges_with_less_enclosure_m4).width(0.3 + 1.dbu, projection).polygons + # via3.not_interacting(opposite9).output("m4.5", "m4.5 : min. m4 enclosure of via3 of 2 opposite edges : 0.085um") + # rule m4.pd.1, rule m4.pd.2a, rule m4.pd.2b not coded +end +if bakend_flow = CU + m4.holes.with_area(0..0.2).output("m4.7", "m4.7 : min. m2 holes area : 0.2um²") + m4.sized(-5.0).sized(5.0).output("m4.11", "m4.11 : max. m4 width after slotting : 10.0um") + # rule m4.12 not coded because inconsistent with m4.11 + # rule m4.13, m4.14, m4.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 + m4.enclosing(via3, 0.06, euclidian).output("m4.15", "m4.15 : min. m4 enclosure of via3 : 0.06um") +end + +# via4 +via4.edges.without_length(0.8).output("via4.1a", "via4.1a : minimum/maximum width of via4 : 0.8um") +via4.isolated(0.8, euclidian).output("via4.2", "via4.2 : min. via4 spacing : 0.8um") +#rule via4.3 not coded +m4.enclosing(via4, 0.19, euclidian).output("via4.4", "via4.4 : min. m4 enclosure of via4 : 0.19um") +via4.not(m4).output("via4", "via4 : m4 must enclose all via4") +if backend_flow = CU + # rules via4.irdrop.1, via4.irdrop.2, via4.irdrop.3, via4.irdrop.4 not coded because not understandable +end + +# m5 +m5.width(1.6, euclidian).output("m5.1", "m5.1 : min. m5 width : 1.6um") + +m5.space(1.6, euclidian).output("m5.2", "m5.2 : min. m5 spacing : 1.6um") + +via4.not(m5).output("m5.via4", "m5.via4 : m5 must enclose via4") +m5.enclosing(via4, 0.31, euclidian).output("m5.3", "m4.3 : min. m5 enclosure of via4 : 0.31um") + +# nsm +nsm.width(3.0, euclidian).output("nsm.1", "nsm.1 : min. nsm width : 3.0um") +nsm.isolated(4.0, euclidian).output("nsm.2", "nsm.2 : min. nsm spacing : 4.0um") +nsm.enclosing(diff, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of diff : 3.0um") +nsm.enclosing(tap, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of tap : 3.0um") +nsm.enclosing(poly, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of poly : 3.0um") +nsm.enclosing(li, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of li : 3.0um") +nsm.enclosing(m1, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m1 : 3.0um") +nsm.enclosing(m2, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m2 : 3.0um") +nsm.enclosing(m3, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m3 : 3.0um") +nsm.enclosing(m4, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m4 : 3.0um") +nsm.enclosing(m5, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m5 : 3.0um") +nsm.enclosing(cfom, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of cfom : 3.0um") +if backend_flow = AL + nsm.separation(diff, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to diff : 1.0um") + nsm.separation(tap, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to tap : 1.0um") + nsm.separation(poly, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to poly : 1.0um") + nsm.separation(li, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to li : 1.0um") + nsm.separation(m1, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m1 : 1.0um") + nsm.separation(m2, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m2 : 1.0um") + nsm.separation(m3, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m3 : 1.0um") + nsm.separation(m4, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m4 : 1.0um") + nsm.separation(m5, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m5 : 1.0um") + nsm.separation(cfom, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to cfom : 1.0um") +end + +# pad +pad.isolated(1.27, euclidian).output("pad.2", "pad.2 : min. pad spacing : 1.27um") + +end #BEOL + +if FEOL +info("FEOL section") + +# mf +mf.not_interacting(mf.edges.without_length(0.8)).output("mf.1", "mf.1 : minimum/maximum width of fuse : 0.8um") +mf.not_interacting(mf.edges.without_length(7.2)).output("mf.2", "mf.2 : minimum/maximum length of fuse : 7.2um") +mf.isolated(1.96, euclidian).output("mf.3", "mf.3 : min. fuse center spacing : 2.76um") +# fuses need more clarification on fuse_shield, fuse layers ... + +# hvi +hvi.width(0.6, euclidian).output("hvi.1", "hvi.1 : min. hvi width : 0.6um") +hvi.isolated(0.7, euclidian).output("hvi.2", "hvi.2 : min. hvi spacing, merge if less : 0.7um") +hvi.and(tunm).output("hvi.4", "hvi.4 : hvi must not overlapp tunm") +hvi.and(nwell).separation(nwell, 2.0, euclidian).output("hvnwell.8", "hvnwelli.8 : min. hvnwel spacing to nwell : 2.0") +areaid_hl.not(hvi).output("hvnwel.9", "hvnwell.9 : hvi must overlapp hvnwell") +# rule hvnell.10 not coded +diff.not(psdm.and(diff_rs)).and(hvi).width(0.29, euclidian).output("hvdifftap.14", "hvdifftap.14 : min. diff inside hvi width : 0.29um") +diff.and(psdm.and(diff_rs)).and(hvi).width(0.15, euclidian).output("hvdifftap.14a", "hvdifftap.14a : min. p+diff resistor inside hvi width : 0.15um") +diff.and(hvi).isolated(0.3, euclidian).output("hvdifftap.15a", "hvdifftap.15a : min. diff inside hvi spacing : 0.3um") +diff.and(hvi).and(nsdm).separation(diff.and(hvi).and(psdm), 0.37, euclidian).polygons.without_area(0).output("hvdifftap.15b", "hvdifftap.15b : min. n+diff inside hvi spacing to p+diff inside hvi except abutting: 0.37um") +tap.and(hvi).edges.and(diff).without_length(0.7).output("hvdifftap.16", "hvdifftap.16 : min. tap inside hvi abuttng diff : 0.7um") +hvi.and(nwell).enclosing(diff, 0.33, euclidian).output("hvdifftap.17", "hvdifftap.17 : min. hvnwell enclosure of p+diff : 0.33um") +hvi.and(nwell).separation(diff, 0.43, euclidian).output("hvdifftap.18", "hvdifftap.18 : min. hvnwell spacing to n+diff : 0.43um") +hvi.and(nwell).enclosing(tap, 0.33, euclidian).output("hvdifftap.19", "hvdifftap.19 : min. hvnwell enclosure of n+tap : 0.33um") +hvi.and(nwell).separation(tap, 0.43, euclidian).output("hvdifftap.20", "hvdifftap.20 : min. hvnwell spacing to p+tap : 0.43um") +hvi.and(diff).edges.not(diff.edges).output("hvdifftap.21", "hvdifftap.21 : diff must not straddle hvi") +hvi.and(tap).edges.not(tap.edges).output("hvdifftap.21", "hvdifftap.21 : tap must not straddle hvi") +hvi.enclosing(difftap, 0.18, euclidian).output("hvdifftap.22", "hvdifftap.22 : min. hvi enclosure of diff or tap : 0.18um") +hvi.separation(difftap, 0.18, euclidian).output("hvdifftap.23", "hvdifftap.23 : min. hvi spacing to diff or tap : 0.18um") +hvi.and(diff).not(nwell).separation(nwell, 0.43, euclidian).output("hvdifftap.24", "hvdifftap.24 : min. hv n+diff spacing to nwell : 0.43um") +diff.and(hvi).not(nwell).isolated(1.07, euclidian).polygons.and(tap).output("hvdifftap.25", "hvdifftap.25 : min. n+diff inside hvi spacing accros p+tap : 1.07um") +diff.not(poly).edges.and(gate.and(hvi).edges).space(0.35, euclidian).output("hvpoly.13", "hvpoly.13: min. hvi gate length : 0.5um") +hvi.and(poly).edges.not(poly.edges).output("hvpoly.14", "hvpoly.14 : poly must not straddle hvi") + +# hvntm +hvntm.width(0.7, euclidian).output("hvntm.1", "hvntm.1 : min. hvntm width : 0.7um") +hvntm.isolated(0.7, euclidian).output("hvntm.2", "hvntm.2 : min. hvntm spacing : 0.7um") +hvntm.enclosing(diff.and(nwell).and(hvi), 0.185, euclidian).output("hvntm.3", "hvntm.3 : min. hvntm enclosure of hv n+diff : 0.185um") +hvntm.separation(diff.not(nwell).not(hvi), 0.185, euclidian).output("hvntm.4", "hvntm.4 : min. hvntm spacing to n+diff : 0.185um") +hvntm.separation(diff.and(nwell).not(hvi), 0.185, euclidian).output("hvntm.5", "hvntm.5 : min. hvntm spacing to p+diff : 0.185um") +hvntm.separation(tap.not(nwell).not(hvi), 0.185, euclidian).polygons.without_area(0).output("hvntm.6a", "hvntm.6a : min. hvntm spacing to p+tap : 0.185um") +hvntm.and(areaid_ce).output("hvntm.9", "hvntm.9 : hvntm must not overlapp areaid.ce") + +# denmos +poly.not_interacting(pwde).interacting(areaid_en).width(1.055, projection).output("denmos.1", "denmos.1 : min. de_nfet gate width : 1.055um") +diff.not_interacting(pwde).enclosing(poly.interacting(areaid_en), 0.28, projection).polygons.without_area(0).output("denmos.2", "denmos.2 : min. de_nfet source ouside poly width : 0.28um") +diff.not_interacting(pwde).and(poly.interacting(areaid_en)).width(0.925, projection).output("denmos.3", "denmos.3 : min. de_nfet source inside poly width : 0.925um") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).width(0.17, euclidian).output("denmos.4", "denmos.4 : min. de_nfet drain width : 0.17um") +nwell.not_interacting(pwde).and(poly.interacting(areaid_en)).width(0.225, projection).polygons.or(nwell.and(poly.interacting(areaid_en)).sized(-0.1125).sized(0.1125)).output("denmos.5", "denmos.5 : min. de_nfet source inside nwell width : 0.225m") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).separation(diff.interacting(poly.interacting(areaid_en)), 1.585, projection).output("denmos.6", "denmos.6 : min. de_nfet source spacing to drain : 1.585um") +nwell.not_interacting(pwde).and(poly.and(diff).interacting(areaid_en)).edges.without_length(5.0, nil).output("denmos.7", "denmos.7 : min. de_nfet channel width : 5.0um") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("denmos.8", "denmos.8 : 90deg. not allowed for de_nfet drain") +nwell.not_interacting(pwde).interacting(areaid_en).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("denmos.9a", "denmos.9a : 90deg. not allowed for de_nfet nwell") +nwell.not_interacting(pwde).interacting(areaid_en).edges.with_angle(45).without_length(0.607..0.609).output("denmos.9a", "denmos.9a : 45deg. bevels of de_nfet nwell should be 0.43um from corners") +nwell.not_interacting(pwde).interacting(areaid_en).edges.with_angle(135).without_length(0.607..0.609).output("denmos.9a", "denmos.9a : 45deg. bevels of de_nfet nwell should be 0.43um from corners") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(45).without_length(0.7..0.71).output("denmos.9b", "denmos.9b : 45deg. bevels of de_nfet drain should be 0.05um from corners") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(135).without_length(0.7..0.71).output("denmos.9b", "denmos.9b : 45deg. bevels of de_nfet drain should be 0.05um from corners") +nwell.not_interacting(pwde).enclosing(diff.interacting(areaid_en).not_interacting(poly), 0.66, euclidian).output("denmos.10", "denmos.10 : min. nwell enclosure of de_nfet drain : 0.66um") +nwell.not_interacting(pwde).interacting(areaid_en).separation(tap.not(nwell), 0.86, euclidian).output("denmos.11", "denmos.11 : min. de_nfet nwell spacing to tap : 0.86um") +nwell.not_interacting(pwde).interacting(areaid_en).isolated(2.4, euclidian).output("denmos.12", "denmos.12 : min. de_nfet nwell : 2.4um") +nsdm.not_interacting(pwde).enclosing(diff.interacting(areaid_en).interacting(poly), 0.13, euclidian).output("denmos.13", "denmos.13 : min. nsdm enclosure of de_nfet source : 0.13um") + +# depmos +poly.interacting(pwde).interacting(areaid_en).width(1.05, projection).output("depmos.1", "depmos.1 : min. de_pfet gate width : 1.05um") +diff.interacting(pwde).enclosing(poly.interacting(areaid_en), 0.28, projection).polygons.without_area(0).output("depmos.2", "depmos.2 : min. de_pfet source ouside poly width : 0.28um") +diff.interacting(pwde).and(poly.interacting(areaid_en)).width(0.92, projection).output("depmos.3", "depmos.3 : min. de_pfet source inside poly width : 0.92um") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).width(0.17, euclidian).output("depmos.4", "depmos.4 : min. de_pfet drain width : 0.17um") +pwde.not(nwell).and(poly.interacting(areaid_en)).width(0.26, projection).polygons.or(pwde.not(nwell).and(poly.interacting(areaid_en)).sized(-0.13).sized(0.13)).output("depmos.5", "depmos.5 : min. de_pfet source inside nwell width : 0.26m") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).separation(diff.interacting(poly.interacting(areaid_en)), 1.19, projection).output("depmos.6", "depmos.6 : min. de_pfet source spacing to drain : 1.19um") +nwell.interacting(pwde).and(poly.and(diff).interacting(areaid_en)).edges.without_length(5.0, nil).output("depmos.7", "depmos.7 : min. de_pfet channel width : 5.0um") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("depmos.8", "depmos.8 : 90deg. not allowed for de_pfet drain") +pwde.not(nwell).interacting(areaid_en).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("depmos.9a", "depmos.9a : 90deg. not allowed for de_pfet pwell") +pwde.not(nwell).interacting(areaid_en).edges.with_angle(45).without_length(0.607..0.609).output("depmos.9a", "depmos.9a : 45deg. bevels of de_pfet pwell should be 0.43um from corners") +pwde.not(nwell).interacting(areaid_en).edges.with_angle(135).without_length(0.607..0.609).output("depmos.9a", "depmos.9a : 45deg. bevels of de_pfet pwell should be 0.43um from corners") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(45).without_length(0.7..0.71).output("depmos.9b", "depmos.9b : 45deg. bevels of de_pfet drain should be 0.05um from corners") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(135).without_length(0.7..0.71).output("depmos.9b", "depmos.9b : 45deg. bevels of de_pfet drain should be 0.05um from corners") +nwell.interacting(pwde).separation(diff.interacting(areaid_en).not_interacting(poly), 0.86, euclidian).output("depmos.10", "depmos.10 : min. pwell enclosure of de_pfet drain : 0.86um") +pwde.not(nwell).interacting(areaid_en).separation(tap.and(nwell), 0.66, euclidian).output("depmos.11", "depmos.11 : min. de_pfet pwell spacing to tap : 0.66um") +psdm.interacting(pwde).enclosing(diff.interacting(areaid_en).interacting(poly), 0.13, euclidian).output("depmos.12", "depmos.12 : min. psdm enclosure of de_pfet source : 0.13um") + +# extd +areaid_en.and(difftap).edges.not(difftap.edges).output("extd.1", "extd.1 : difftap must not straddle areaid.en") +difftap.interacting(areaid_en).not(poly).with_area(0).output("extd.2", "extd.2 : poly must not overlapp entirely difftap in areaid.en") +# rules extd.4, extd.5, extd.6, extd.7 not coded because specific to some cells + +# vhvi +# rules vhvi.vhv.1, vhvi.vhv.2, vhvi.vhv.3, vhvi.vhv.4, vhvi.vhv.5, vhvi.vhv.6 not coded +vhvi.width(0.02, euclidian).output("vhvi.1", "vhvi.1 : min. vhvi width : 0.02um") +vhvi.and(areaid_ce).output("vhvi.2", "vhvi.2 : vhvi must not overlap areaid.ce") +vhvi.and(hvi).output("vhvi.3", "vhvi.3 : vhvi must not overlap hvi") +# rules vhvi.4, vhvi.6 not coded +vhvi.and(diff).edges.not(diff.edges).output("vhvi.5", "vhvi.5 : vhvi must not straddle diff") +vhvi.and(tap).edges.not(tap.edges).output("vhvi.5", "vhvi.5 : vhvi must not straddle tap") +vhvi.and(poly).edges.not(poly.edges).output("vhvi.7", "vhvi.7 : vhvi must not straddle poly") + +nwell.and(vhvi).separation(nwell, 2.5, euclidian).output("hv.nwell.1", "hv.nwell.1 : min. vhvi nwell spacing to nwell : 2.5um") +diff.and(vhvi).isolated(0.3, euclidian).output("hv.diff.1", "hv.diff.1 : min. vhvi diff spacing : 0.3um") +nwell.interacting(diff.and(vhvi)).separation(diff.not(nwell), 0.43, euclidian).output("hv.diff.2", "hv.diff.2 : min. vhvi nwell spacing n+diff : 0.43um") +diff.and(vhvi).not(nwell).separation(nwell, 0.55, euclidian).output("hv.diff.3a", "hv.diff.3a : min. vhvi n+diff spacing nwell : 0.55um") +# rule hv.diff.3b not coded +poly.and(vhvi).not(diff).separation(diff, 0.3, euclidian).polygons.without_area(0).output("hv.poly.2", "hv.poly.2 : min. vhvi poly spacing to diff : 0.3um") +poly.and(vhvi).not(diff).separation(nwell, 0.55, euclidian).polygons.without_area(0).output("hv.poly.3", "hv.poly.3 : min. vhvi poly spacing to nwell : 0.55um") +nwell.enclosing(poly.and(vhvi).not(diff), 0.3, euclidian).polygons.without_area(0).output("hv.poly.4", "hv.poly.4 : min. nwell enclosure of vhvi poly : 0.3um") +#poly.and(vhvi).enclosing(diff.interacting(areaid_en), 0.16, projection).polygons.without_area(0).output("hv.poly.6", "hv.poly.6 : min. poly enclosure of hvfet gate : 0.16um") +# rule hv.poly.7 not coded + +# uhvi +uhvi.and(diff).edges.not(diff.edges).output("uhvi.1", "uhvi.1 : diff must not straddle uhvi") +uhvi.and(tap).edges.not(tap.edges).output("uhvi.1", "uhvi.1 : tap must not straddle uhvi") +uhvi.and(poly).edges.not(poly.edges).output("uhvi.2", "uhvi.2 : poly must not straddle uhvi") +pwbm.not(uhvi).output("uhvi.3", "uhvi.3 : uhvi must not enclose pwbm") +uhvi.and(dnwell).edges.not(dnwell.edges).output("uhvi.4", "uhvi.4 : dnwell must not straddle uhvi") +areaid_en20.not(uhvi).output("uhvi.5", "uhvi.5 : uhvi must not enclose areaid.en20") +#dnwell.not(uhvi).output("uhvi.6", "uhvi.6 : uhvi must not enclose dnwell") +natfet.not(uhvi).output("uhvi.7", "uhvi.7 : uhvi must not enclose natfet") + +# pwell_res +pwell_rs.width(2.65).output("pwres.2", "pwres.2 : min. pwell resistor width : 2.65um") +pwell_rs.sized(-2.65).sized(2.65).output("pwres.2", "pwres.2 : max. pwell resistor width : 2.65um") +pwell_rs.interacting(pwell_rs.edges.with_length(2.651,26.499)).output("pwres.3", "pwres.3 : min. pwell resistor length : 26.5um") +pwell_rs.interacting(pwell_rs.edges.with_length(265.0, nil)).output("pwres.4", "pwres.4 : max. pwell resistor length : 265um") +tap.interacting(pwell_rs).separation(nwell, 0.22, euclidian).output("pwres.5", "pwres.5 : min. pwell resistor tap spacing to nwell : 0.22um") +tap.interacting(pwell_rs).and(tap.sized(0.22).and(nwell)).output("pwres.5", "pwres.5 : max. pwell resistor tap spacing to nwell : 0.22um") +tap.interacting(pwell_rs).width(0.53).output("pwres.6", "pwres.6 : min. width of tap inside pwell resistor : 0.53um") +tap.interacting(pwell_rs).sized(-0.265).sized(0.265).output("pwres.6", "pwres.6 : max. width of tap inside pwell resistor : 0.53um") +# rules pwres.7a, pwres.7b not coded +pwell_rs.and(diff).output("pwres.8", "pwres.8 : diff not allowed inside pwell resistor") +pwell_rs.and(poly).output("pwres.8", "pwres.8 : poly not allowed inside pwell resistor") +# rules pwres.9, pwres.10 not coded + +# rf_diode +areaid_re.with_angle(0 .. 90).output("rfdiode.1", "rfdiode.1 : non 90 degree angle areaid.re") +areaid_re.not(nwell).or(nwell.interacting(areaid_re).not(areaid_re)).output("rfdiode.2", "rfdiode.2 : areaid.re must coincide rf nwell diode") +# rule rfdiode.3 not coded + +end #FEOL + +if OFFGRID +info("OFFGRID-ANGLES section") + +dnwell.ongrid(0.005).output("dnwell_OFFGRID", "x.1b : OFFGRID vertex on dnwell") +dnwell.with_angle(0 .. 45).output("dnwell_angle", "x.3a : non 45 degree angle dnwell") +nwell.ongrid(0.005).output("nwell_OFFGRID", "x.1b : OFFGRID vertex on nwell") +nwell.with_angle(0 .. 45).output("nwell_angle", "x.3a : non 45 degree angle nwell") +pwbm.ongrid(0.005).output("pwbm_OFFGRID", "x.1b : OFFGRID vertex on pwbm") +pwbm.with_angle(0 .. 45).output("pwbm_angle", "x.3a : non 45 degree angle pwbm") +pwde.ongrid(0.005).output("pwde_OFFGRID", "x.1b : OFFGRID vertex on pwde") +pwde.with_angle(0 .. 45).output("pwde_angle", "x.3a : non 45 degree angle pwde") +hvtp.ongrid(0.005).output("hvtp_OFFGRID", "x.1b : OFFGRID vertex on hvtp") +hvtp.with_angle(0 .. 45).output("hvtp_angle", "x.3a : non 45 degree angle hvtp") +hvtr.ongrid(0.005).output("hvtr_OFFGRID", "x.1b : OFFGRID vertex on hvtr") +hvtr.with_angle(0 .. 45).output("hvtr_angle", "x.3a : non 45 degree angle hvtr") +lvtn.ongrid(0.005).output("lvtn_OFFGRID", "x.1b : OFFGRID vertex on lvtn") +lvtn.with_angle(0 .. 45).output("lvtn_angle", "x.3a : non 45 degree angle lvtn") +ncm.ongrid(0.005).output("ncm_OFFGRID", "x.1b : OFFGRID vertex on ncm") +ncm.with_angle(0 .. 45).output("ncm_angle", "x.3a : non 45 degree angle ncm") +diff.ongrid(0.005).output("diff_OFFGRID", "x.1b : OFFGRID vertex on diff") +tap.ongrid(0.005).output("tap_OFFGRID", "x.1b : OFFGRID vertex on tap") +diff.not(areaid_en.and(uhvi)).with_angle(0 .. 90).output("diff_angle", "x.2 : non 90 degree angle diff") +diff.and(areaid_en.and(uhvi)).with_angle(0 .. 45).output("diff_angle", "x.2c : non 45 degree angle diff") +tap.not(areaid_en.and(uhvi)).with_angle(0 .. 90).output("tap_angle", "x.2 : non 90 degree angle tap") +tap.and(areaid_en.and(uhvi)).with_angle(0 .. 45).output("tap_angle", "x.2c : non 45 degree angle tap") +tunm.ongrid(0.005).output("tunm_OFFGRID", "x.1b : OFFGRID vertex on tunm") +tunm.with_angle(0 .. 45).output("tunm_angle", "x.3a : non 45 degree angle tunm") +poly.ongrid(0.005).output("poly_OFFGRID", "x.1b : OFFGRID vertex on poly") +poly.with_angle(0 .. 90).output("poly_angle", "x.2 : non 90 degree angle poly") +rpm.ongrid(0.005).output("rpm_OFFGRID", "x.1b : OFFGRID vertex on rpm") +rpm.with_angle(0 .. 45).output("rpm_angle", "x.3a : non 45 degree angle rpm") +npc.ongrid(0.005).output("npc_OFFGRID", "x.1b : OFFGRID vertex on npc") +npc.with_angle(0 .. 45).output("npc_angle", "x.3a : non 45 degree angle npc") +nsdm.ongrid(0.005).output("nsdm_OFFGRID", "x.1b : OFFGRID vertex on nsdm") +nsdm.with_angle(0 .. 45).output("nsdm_angle", "x.3a : non 45 degree angle nsdm") +psdm.ongrid(0.005).output("psdm_OFFGRID", "x.1b : OFFGRID vertex on psdm") +psdm.with_angle(0 .. 45).output("psdm_angle", "x.3a : non 45 degree angle psdm") +licon.ongrid(0.005).output("licon_OFFGRID", "x.1b : OFFGRID vertex on licon") +licon.with_angle(0 .. 90).output("licon_angle", "x.2 : non 90 degree angle licon") +li.ongrid(0.005).output("li_OFFGRID", "x.1b : OFFGRID vertex on li") +li.with_angle(0 .. 45).output("li_angle", "x.3a : non 45 degree angle li") +mcon.ongrid(0.005).output("ct_OFFGRID", "x.1b : OFFGRID vertex on mcon") +mcon.with_angle(0 .. 90).output("ct_angle", "x.2 : non 90 degree angle mcon") +vpp.ongrid(0.005).output("vpp_OFFGRID", "x.1b : OFFGRID vertex on vpp") +vpp.with_angle(0 .. 45).output("vpp_angle", "x.3a : non 45 degree angle vpp") +m1.ongrid(0.005).output("m1_OFFGRID", "x.1b : OFFGRID vertex on m1") +m1.with_angle(0 .. 45).output("m1_angle", "x.3a : non 45 degree angle m1") +via.ongrid(0.005).output("via_OFFGRID", "x.1b : OFFGRID vertex on via") +via.with_angle(0 .. 90).output("via_angle", "x.2 : non 90 degree angle via") +m2.ongrid(0.005).output("m2_OFFGRID", "x.1b : OFFGRID vertex on m2") +m2.with_angle(0 .. 45).output("m2_angle", "x.3a : non 45 degree angle m2") +via2.ongrid(0.005).output("via2_OFFGRID", "x.1b : OFFGRID vertex on via2") +via2.with_angle(0 .. 90).output("via2_angle", "x.2 : non 90 degree angle via2") +m3.ongrid(0.005).output("m3_OFFGRID", "x.1b : OFFGRID vertex on m3") +m3.with_angle(0 .. 45).output("m3_angle", "x.3a : non 45 degree angle m3") +via3.ongrid(0.005).output("via3_OFFGRID", "x.1b : OFFGRID vertex on via3") +via3.with_angle(0 .. 90).output("via3_angle", "x.2 : non 90 degree angle via3") +nsm.ongrid(0.005).output("nsm_OFFGRID", "x.1b : OFFGRID vertex on nsm") +nsm.with_angle(0 .. 45).output("nsm_angle", "x.3a : non 45 degree angle nsm") +m4.ongrid(0.005).output("m4_OFFGRID", "x.1b : OFFGRID vertex on m4") +m4.with_angle(0 .. 45).output("m4_angle", "x.3a : non 45 degree angle m4") +via4.ongrid(0.005).output("via4_OFFGRID", "x.1b : OFFGRID vertex on via4") +via4.with_angle(0 .. 90).output("via4_angle", "x.2 : non 90 degree angle via4") +m5.ongrid(0.005).output("m5_OFFGRID", "x.1b : OFFGRID vertex on m5") +m5.with_angle(0 .. 45).output("m5_angle", "x.3a : non 45 degree angle m5") +pad.ongrid(0.005).output("pad_OFFGRID", "x.1b : OFFGRID vertex on pad") +pad.with_angle(0 .. 45).output("pad_angle", "x.3a : non 45 degree angle pad") +mf.ongrid(0.005).output("mf_OFFGRID", "x.1b : OFFGRID vertex on mf") +mf.with_angle(0 .. 90).output("mf_angle", "x.2 : non 90 degree angle mf") +hvi.ongrid(0.005).output("hvi_OFFGRID", "x.1b : OFFGRID vertex on hvi") +hvi.with_angle(0 .. 45).output("hvi_angle", "x.3a : non 45 degree angle hvi") +hvntm.ongrid(0.005).output("hvntm_OFFGRID", "x.1b : OFFGRID vertex on hvntm") +hvntm.with_angle(0 .. 45).output("hvntm_angle", "x.3a : non 45 degree angle hvntm") +vhvi.ongrid(0.005).output("vhvi_OFFGRID", "x.1b : OFFGRID vertex on vhvi") +vhvi.with_angle(0 .. 45).output("vhvi_angle", "x.3a : non 45 degree angle vhvi") +uhvi.ongrid(0.005).output("uhvi_OFFGRID", "x.1b : OFFGRID vertex on uhvi") +uhvi.with_angle(0 .. 45).output("uhvi_angle", "x.3a : non 45 degree angle uhvi") +pwell_rs.ongrid(0.005).output("pwell_rs_OFFGRID", "x.1b : OFFGRID vertex on pwell_rs") +pwell_rs.with_angle(0 .. 45).output("pwell_rs_angle", "x.3a : non 45 degree angle pwell_rs") +areaid_re.ongrid(0.005).output("areaid_re_OFFGRID", "x.1b : OFFGRID vertex on areaid.re") + +end #OFFGRID diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.krc b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.krc new file mode 100755 index 00000000..8b23e116 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.krc @@ -0,0 +1,516 @@ + + + false + false + 10 + true + + auto + true + 1 + by-name + true + true + auto + 50 + false + false + + any-top + 1000000000 + 1 + fit-marker + BrowseInstancesForm="AdnQywACAAAAAANkAAACAAAABY4AAALgAAADZwAAAh0AAAWLAAAC3QAAAAAAAAAACL4=";splitter2="AAAA/wAAAAEAAAACAAABCAAAAQgBAAAABgEAAAABAQ==";lv_cell_instance="AAAA/wAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp8AAAACAQAAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAACAAABPAAAAAEAAAAAAAABYwAAAAEAAAAAAAAD6AD/////";lv_cell="AAAA/wAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqAAAAADAQAAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAADAAABEgAAAAEAAAAAAAAAZAAAAAEAAAAAAAABKgAAAAEAAAAAAAAD6AD/////"; + 32 + false + 255,157,157[0] 255,128,168[1] 192,128,255[2] 149,128,255[3] 128,134,255[4] 128,168,255[5] 255,0,0[6] 255,0,128[7] 255,0,255[8] 128,0,255[9] 0,0,255[10] 0,128,255[11] 128,0,0[12] 128,0,87[13] 128,0,128[14] 80,0,128[15] 0,0,128[16] 0,64,128[17] 128,255,251[18] 128,255,141[19] 175,255,128[20] 243,255,128[21] 255,194,128[22] 255,160,128[23] 0,255,255[24] 1,255,107[25] 145,255,0[26] 221,255,0[27] 255,174,0[28] 255,128,0[29] 0,128,128[30] 0,128,80[31] 0,128,0[32] 80,128,0[33] 128,128,0[34] 128,80,0[35] 255,255,255 192,192,192 128,128,128 96,96,96 64,64,64 0,0,0 + add + auto + 50 + false + + 4 + + false + file='/home/mk/Downloads/RAM_4Kx32.def';import-mode=0; + true + 0 + 0.01,0.005 + + 0.1 + true + true + true + false + true + true + 2 + 5 + false + 1 + false + 0 + 10 + any + 0.005 + -1 + 0 + false + caravel_00020002_fill_pattern + 0 + 0 + 1 + + false + + true + 0 + 0 + 1 + 1 + 1000 + false + any + flush + 0.0 + 0.0 + 0.1 + true + false + left + 0 + ABC + bottom + true + true + false + true + r0 *1 0,0 + auto + auto + auto + 0.005 + auto + true + invisible + dots + tenths-dotted-lines + true + auto + 1 + 5 + true + true + 1 + true + 1 + sky130A + auto + 0 + true + true + 0 + '@@navigator_menu.navigator_main_menu.navigator_all_hier_levels':'';'@@navigator_menu.navigator_main_menu.navigator_freeze':'';'@@navigator_menu.navigator_main_menu.navigator_show_images':'';'@bookmarks_context_menu.follow_selection':'';'@bookmarks_context_menu.load_bookmarks':'';'@bookmarks_context_menu.manage_bookmarks':'';'@bookmarks_context_menu.save_bookmarks':'';'@hcp_context_menu.cell_user_properties':'';'@hcp_context_menu.flat_mode':'';'@hcp_context_menu.hide_cell':'';'@hcp_context_menu.open_current':'';'@hcp_context_menu.save_cell_as':'';'@hcp_context_menu.show_all':'';'@hcp_context_menu.show_as_top':'Ctrl+T';'@hcp_context_menu.show_cell':'';'@hcp_context_menu.sorting.by_area':'';'@hcp_context_menu.sorting.by_name':'';'@hcp_context_menu.split_mode':'';'@lcp_context_menu.add_others':'';'@lcp_context_menu.clean_up':'';'@lcp_context_menu.copy':'';'@lcp_context_menu.cut':'';'@lcp_context_menu.del':'';'@lcp_context_menu.group':'';'@lcp_context_menu.hide':'';'@lcp_context_menu.hide_all':'';'@lcp_context_menu.hide_empty_layers':'';'@lcp_context_menu.insert':'';'@lcp_context_menu.invvalid':'';'@lcp_context_menu.paste':'';'@lcp_context_menu.regroup_menu.flatten':'';'@lcp_context_menu.regroup_menu.grp_d':'';'@lcp_context_menu.regroup_menu.grp_i':'';'@lcp_context_menu.regroup_menu.grp_l':'';'@lcp_context_menu.rename':'';'@lcp_context_menu.select_all':'';'@lcp_context_menu.select_source':'';'@lcp_context_menu.show':'';'@lcp_context_menu.show_all':'';'@lcp_context_menu.show_only':'';'@lcp_context_menu.sort_menu.sort_dli':'';'@lcp_context_menu.sort_menu.sort_idl':'';'@lcp_context_menu.sort_menu.sort_ild':'';'@lcp_context_menu.sort_menu.sort_ldi':'';'@lcp_context_menu.sort_menu.sort_name':'';'@lcp_context_menu.tab_menu.new_tab':'';'@lcp_context_menu.tab_menu.remove_tab':'';'@lcp_context_menu.tab_menu.rename_tab':'';'@lcp_context_menu.test_shapes_in_view':'';'@lcp_context_menu.ungroup':'';'@lcp_context_menu.valid':'';'@lcp_tabs_context_menu.new_tab':'';'@lcp_tabs_context_menu.remove_tab':'';'@lcp_tabs_context_menu.rename_tab':'';'@secrets.duplicate_interactive':'';'@secrets.paste_interactive':'';'@secrets.sel_move_interactive':'';'@toolbar.move':'';'@toolbar.next_display_state':'';'@toolbar.prev_display_state':'';'@toolbar.ruler':'';'@toolbar.select':'';'@toolbar.technology_selector':'';bookmark_menu:'';bookmark_menu.bookmark_view:'';bookmark_menu.goto_bookmark_menu:'';bookmark_menu.load_bookmarks:'';bookmark_menu.manage_bookmarks:'';bookmark_menu.save_bookmarks:'';edit_menu:'';edit_menu.add_image:'';edit_menu.cancel:'';edit_menu.clear_all_rulers:'';edit_menu.configure_rulers:'';edit_menu.copy:'';edit_menu.cut:'';edit_menu.delete:'';edit_menu.duplicate:'';edit_menu.image_menu:'';edit_menu.image_menu.bring_to_back:'';edit_menu.image_menu.bring_to_front:'';edit_menu.image_menu.clear_all_images:'';edit_menu.mode_menu:'';edit_menu.mode_menu.move:'';edit_menu.mode_menu.ruler:'';edit_menu.mode_menu.select:'';edit_menu.paste:'';edit_menu.redo:'';edit_menu.search_replace_viewer:'';edit_menu.select_menu:'';edit_menu.select_menu.disable_all:'';edit_menu.select_menu.enable_all:'';edit_menu.select_menu.pi_enable_10:'';edit_menu.select_menu.pi_enable_11:'';edit_menu.select_menu.pi_enable_12:'';edit_menu.select_menu.pi_enable_13:'';edit_menu.select_menu.pi_enable_15:'';edit_menu.select_menu.pi_enable_7:'';edit_menu.select_menu.pi_enable_8:'';edit_menu.select_menu.pi_enable_9:'';edit_menu.select_menu.select_all:'';edit_menu.select_menu.unselect_all:'';edit_menu.selection_menu:'';edit_menu.selection_menu.sel_flip_x:'';edit_menu.selection_menu.sel_flip_y:'';edit_menu.selection_menu.sel_free_rot:'';edit_menu.selection_menu.sel_move:'';edit_menu.selection_menu.sel_move_to:'';edit_menu.selection_menu.sel_rot_ccw:'';edit_menu.selection_menu.sel_rot_cw:'';edit_menu.selection_menu.sel_scale:'';edit_menu.show_properties:'';edit_menu.undo:'';file_menu:'';file_menu.clone:'';file_menu.close:'';file_menu.close_all:'';file_menu.exit:none;file_menu.import_menu:'';file_menu.import_menu.import_def:'';file_menu.import_menu.import_gerber_menu:'';file_menu.import_menu.import_gerber_menu.import_gerber_new:'';file_menu.import_menu.import_gerber_menu.import_gerber_new_free:'';file_menu.import_menu.import_gerber_menu.import_gerber_open:'';file_menu.import_menu.import_gerber_menu.import_gerber_recent:'';file_menu.import_menu.import_lef:'';file_menu.import_menu.import_stream:'';file_menu.layout_props:'';file_menu.layout_stats:'';file_menu.load_layer_props:'';file_menu.open:'';file_menu.open_new_panel:'';file_menu.open_recent_menu:'';file_menu.open_recent_menu.open_recent_1:'';file_menu.open_recent_menu.open_recent_2:'';file_menu.open_same_panel:'';file_menu.print:'';file_menu.pull_in:'';file_menu.reader_options:'';file_menu.reload:'';file_menu.restore_session:'';file_menu.save:'Ctrl+S';file_menu.save_all:'';file_menu.save_as:'';file_menu.save_layer_props:'';file_menu.save_session:'';file_menu.screenshot:'';file_menu.setup:'';file_menu.view_log:'';file_menu.writer_options:'';help_menu:'';help_menu.about:'';help_menu.about_qt:'';help_menu.assistant:'';help_menu.show_all_tips:'';macros_menu:'';macros_menu.examples:'';macros_menu.examples.macro_in_menu_browser:'';macros_menu.examples.macro_in_menu_datamap:'';macros_menu.examples.macro_in_menu_dump_menu:'';macros_menu.examples.macro_in_menu_flatten:'';macros_menu.examples.macro_in_menu_fractal:'';macros_menu.examples.macro_in_menu_qtdialog:'';macros_menu.examples.macro_in_menu_qtrubyserver:'';macros_menu.examples.macro_in_menu_screenshots:'';macros_menu.examples.macro_in_menu_sokoban:'';macros_menu.macro_development:'';tools_menu:'';tools_menu.browse_instances:'';tools_menu.browse_markers:'Ctrl+M';tools_menu.browse_netlists:'';tools_menu.browse_shapes:'';tools_menu.diff_tool:'';tools_menu.drc:'';tools_menu.drc.edit_script:'';tools_menu.drc.new_script:'';tools_menu.edit_layer_stack:'';tools_menu.lvs:'';tools_menu.lvs.edit_script:'';tools_menu.lvs.macro_in_menu_lvs:'';tools_menu.lvs.new_script:'';tools_menu.net_trace:'';tools_menu.packages:'';tools_menu.shapes_to_markers:'';tools_menu.shapes_to_markers.scan_layers:'';tools_menu.shapes_to_markers.scan_layers_flat:'';tools_menu.technologies:'';tools_menu.trace_all_nets_menu:'';tools_menu.trace_all_nets_menu.trace_all_nets:'Ctrl+Q';tools_menu.trace_all_nets_menu.trace_all_nets_flat:'';tools_menu.xor_tool:'';tools_menu.xsection_script_submenu:'';tools_menu.xsection_script_submenu.xsection_for_technology:'';tools_menu.xsection_script_submenu.xsection_script_load:'';view_menu:'';view_menu.default_grid:'';view_menu.default_grid.default_grid_1:'';view_menu.default_grid.default_grid_2:'';view_menu.default_grid.default_grid_3:'';view_menu.no_stipples:'';view_menu.reset_window_state:'';view_menu.show_bookmarks_view:'';view_menu.show_cell_boxes:'';view_menu.show_grid:'';view_menu.show_hierarchy_panel:'';view_menu.show_layer_panel:'';view_menu.show_layer_toolbox:'';view_menu.show_libraries_view:'';view_menu.show_markers:'';view_menu.show_navigator:'';view_menu.show_texts:'';view_menu.show_toolbar:'';view_menu.synchronized_views:'';view_menu.transient_selection:'';zoom_menu:'';zoom_menu.ascend:'';zoom_menu.dec_max_hier:'';zoom_menu.descend:'';zoom_menu.global_trans:'';zoom_menu.global_trans.m0:'';zoom_menu.global_trans.m135:'';zoom_menu.global_trans.m45:'';zoom_menu.global_trans.m90:'';zoom_menu.global_trans.r0:'';zoom_menu.global_trans.r180:'';zoom_menu.global_trans.r270:'';zoom_menu.global_trans.r90:'';zoom_menu.goto_position:'';zoom_menu.inc_max_hier:'';zoom_menu.max_hier:'';zoom_menu.max_hier_0:'';zoom_menu.max_hier_1:'';zoom_menu.next_display_state:'';zoom_menu.prev_display_state:'';zoom_menu.redraw:'';zoom_menu.select_cell:'';zoom_menu.select_current_cell:'';zoom_menu.synchronized_views:'';zoom_menu.zoom_fit:F;zoom_menu.zoom_fit_sel:'';zoom_menu.zoom_in:Z;zoom_menu.zoom_out:'Shift+Z';edit_menu.select_menu.pi_enable_14:'';file_menu.open_recent_menu.open_recent_10:'';file_menu.open_recent_menu.open_recent_3:'';file_menu.open_recent_menu.open_recent_4:'';file_menu.open_recent_menu.open_recent_5:'';file_menu.open_recent_menu.open_recent_6:'';file_menu.open_recent_menu.open_recent_7:'';file_menu.open_recent_menu.open_recent_8:'';file_menu.open_recent_menu.open_recent_9:'';tools_menu.drc.macro_in_menu_drc:'';'@hcp_context_menu.copy':'';'@hcp_context_menu.cut':'';'@hcp_context_menu.delete_cell':'';'@hcp_context_menu.flatten_cell':'';'@hcp_context_menu.new_cell':'';'@hcp_context_menu.paste':'';'@hcp_context_menu.rename_cell':'';'@hcp_context_menu.replace_cell':'';'@toolbar.box':'';'@toolbar.combine_mode':'';'@toolbar.instance':'';'@toolbar.partial':'';'@toolbar.path':'';'@toolbar.polygon':'';'@toolbar.text':'';edit_menu.cell_menu:'';edit_menu.cell_menu.adjust_cell_origin:'';edit_menu.cell_menu.convert_cell_to_static:'';edit_menu.cell_menu.delete_cell:'';edit_menu.cell_menu.flatten_cell:'';edit_menu.cell_menu.new_cell:'';edit_menu.cell_menu.rename_cell:'';edit_menu.cell_menu.replace_cell:'';edit_menu.cell_menu.user_properties:'';edit_menu.edit_options:'';edit_menu.layer_menu:'';edit_menu.layer_menu.boolean:'';edit_menu.layer_menu.clear_layer:'';edit_menu.layer_menu.copy_layer:'';edit_menu.layer_menu.delete_layer:'';edit_menu.layer_menu.edit_layer:'';edit_menu.layer_menu.merge:'';edit_menu.layer_menu.new_layer:'';edit_menu.layer_menu.size:'';edit_menu.layout_menu:'';edit_menu.layout_menu.lay_convert_to_static:'';edit_menu.layout_menu.lay_flip_x:'';edit_menu.layout_menu.lay_flip_y:'';edit_menu.layout_menu.lay_free_rot:'';edit_menu.layout_menu.lay_move:'';edit_menu.layout_menu.lay_rot_ccw:'';edit_menu.layout_menu.lay_rot_cw:'';edit_menu.layout_menu.lay_scale:'';edit_menu.mode_menu.box:'';edit_menu.mode_menu.instance:'';edit_menu.mode_menu.partial:'';edit_menu.mode_menu.path:'';edit_menu.mode_menu.polygon:'';edit_menu.mode_menu.text:'';edit_menu.search_replace_editor:'';edit_menu.selection_menu.align:'';edit_menu.selection_menu.change_layer:'';edit_menu.selection_menu.convert_to_cell:'';edit_menu.selection_menu.convert_to_pcell:'';edit_menu.selection_menu.difference:'';edit_menu.selection_menu.flatten_insts:'';edit_menu.selection_menu.intersection:'';edit_menu.selection_menu.make_array:'';edit_menu.selection_menu.make_cell:'';edit_menu.selection_menu.make_cell_variants:'';edit_menu.selection_menu.move_hier_up:'';edit_menu.selection_menu.resolve_arefs:'';edit_menu.selection_menu.round_corners:'';edit_menu.selection_menu.separate:'';edit_menu.selection_menu.size:'';edit_menu.selection_menu.tap:'';edit_menu.selection_menu.union:'';edit_menu.utils_menu:'';edit_menu.utils_menu.clip_tool:'';edit_menu.utils_menu.fill_tool:'';file_menu.new_layout:'';file_menu.new_panel:'';view_menu.edit_top_level_selection:'';tools_menu.drc.macro_in_menu_drc_sky130:'';tools_menu.drc.macro_in_menu_drc_sky130_1:'';tools_menu.lvs.macro_in_menu_lvs_sky130:'';'@hcp_context_menu.macro_in_menu_replace_cells':'';'@hcp_context_menu.macro_in_menu_write_childcells':'';'@hcp_context_menu.sorting.by_area_reverse':'';'@secrets.select_next_item':'';'@secrets.select_next_item_add':'';bookmark_menu.open_recent_menu_bookmarks:'';edit_menu.select_menu.pi_enable_16:'';edit_menu.select_menu.pi_enable_18:'';edit_menu.select_menu.pi_enable_19:'';edit_menu.select_menu.pi_enable_20:'';edit_menu.selection_menu.macro_in_menu_scale_anisotropic:'';file_menu.macro_in_menu_screenshot:'';file_menu.open_recent_menu_layer_props:'';file_menu.open_recent_menu_sessions:'';macros_menu.macro_in_menu_array_of_labels:'';tools_menu.macro_in_menu_calc_area:'';tools_menu.macro_in_menu_calc_area_hier:'';tools_menu.macro_in_menu_cell_bbox:'';tools_menu.macro_in_menu_dump_flat_shapes:'';tools_menu.macro_in_menu_list_layers:'';tools_menu.macro_in_menu_search_odd_width_paths:'';view_menu.mouse_tracking:'';view_menu.show_images:'';tools_menu.drc.macro_in_menu_drc_1:'';tools_menu.drc.macro_in_menu_drc_2:'' + CIRCUIT_ + DEVICE_ + NET_ + 'PR_' + true + true + 1000 + #800000 + 255,0,0 0,255,0 0,0,255 0,0,0 255,0,255 0,255,255 160,80,255 136,45,0 + true + -1 + 1 + 50 + 3 + false + -1 + 100000000 + false + 1 + dont-change + NetlistBrowserDialog="AdnQywABAAAAAAPsAAAAAAAAB2gAAASRAAAD7QAAABYAAAdnAAAEjAAAAAAAAA==";splitter_2="AAAA/wAAAAAAAAABAAACAAEAAAAGAQAAAAE=";splitter="AAAA/wAAAAAAAAACAAAAlQAAAs4BAAAABgEAAAAB";directory_tree="AAAA/wAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAADAgAAAAEAAAABAAAAGQAAAswAAAADAQEAAQAAAAAAAAAAAAAAAJYAAAAZAAAAgQAAAAAAAAADAAABWgAAAAEAAAAAAAAAAAAAAAEAAAAAAAABcgAAAAEAAAAA";hierarchy_tree="AAAA/wAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAABAQAAAQAAAAAAAAAAAAAAAGQAAAAZAAAAgQAAAAAAAAABAAAAkwAAAAEAAAAA"; + false + true + false + true + + 0 1 2 3 + + python + + + true + true + DejaVu Sans + 13 + + 2 + + false + true + basic:'Alert'=(bold:true,color:'#bf0303',background:'#f7e7e7'),'Attribute'=(color:'#0057ae'),'Base-N Integer'=(color:'#b07e00'),'Built-in'=(bold:true,color:'#644a9b'),'Character'=(color:'#ff80e0'),'Comment'=(italic:true,color:'#888786'),'Control Flow'=(bold:true,color:'#1f1c1b'),'Data Type'=(color:'#0057ae'),'Decimal/Value'=(color:'#b07e00'),'Error'=(color:'#bf0303'),'Extension'=(color:'#0095ff'),'Floating Point'=(color:'#b07e00'),'Function'=(color:'#442886'),'Import'=(color:'#ff5500'),'Keyword'=(bold:true),'Normal'=(),'Operator'=(color:'#1f1c1b'),'Others'=(color:'#006e26'),'Preprocessor'=(color:'#006e28'),'Region Marker'=(color:'#0057ae',background:'#e1eaf8'),'Special Character'=(color:'#3daee9'),'Special String'=(color:'#ff5500'),'String'=(color:'#bf0303'),'Variable'=(color:'#0057ae'),'Verbatim String'=(color:'#bf0303');ruby:'Access Control'=(color:'#0000ff'),'Attribute Definition'=(),'Bin'=(),'Blockcomment'=(),'Char'=(),'Class Variable'=(),'Command'=(color:'#aa3000'),'Comment'=(),'Constant'=(),'Constant Value'=(color:'#bb1188'),'Data'=(),'Dec'=(),'Default globals'=(bold:true,color:'#c00000'),'Definition'=(),'Delimiter'=(color:'#ff9fec'),'Error'=(),'Expression'=(),'Float'=(),'GDL input'=(),'Global Constant'=(bold:true,color:'#bb1188'),'Global Variable'=(color:'#c00000'),'Here Document'=(),'Hex'=(),'Instance Variable'=(),'Kernel methods'=(color:'#000080'),'Keyword'=(),'Member'=(),'Message'=(color:'#4000a7'),'Module mixin methods'=(color:'#000080'),'Normal Text'=(),'Octal'=(),'Operator'=(color:'#ff9fec'),'Pseudo variable'=(),'RDoc Value'=(),'Raw String'=(color:'#dd4a4a'),'Region Marker'=(color:'#0000ff'),'Regular Expression'=(color:'#4a5704'),'String'=(),'Substitution'=(),'Symbol'=(color:'#d40000');python:'Builtin Function'=(),'ClassNames'=(italic:false,bold:true,color:'#fcad3d'),'Comment'=(),'Complex'=(),'Decorator'=(),'Definition Keyword'=(),'Error'=(),'Exceptions'=(),'Extensions'=(),'F-String'=(),'Float'=(),'Flow Control Keyword'=(),'Hex'=(),'Import'=(),'Int'=(),'Normal Text'=(),'Octal'=(),'Operator'=(),'Operator Keyword'=(),'Overloaders'=(),'Raw F-String'=(),'Raw String'=(),'Special Variable'=(),'String'=(),'String Char'=(),'String Substitution'=(); + 8 + + MacroEditorDialog="AdnQywACAAAAAAGRAAABrgAABYYAAATGAAABlAAAAcsAAAWDAAAEwwAAAAAAAAAACgA=";splitter="AAAA/wAAAAEAAAADAAAAnAAAAGQAAACOAQAAAAYBAAAAAgE=";splitter_2="AAAA/wAAAAEAAAADAAAAVAAAAFQAAABUAQAAAAYBAAAAAQE=";watchList="AAAA/wAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMgAAAACAQAAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAACAAAAZAAAAAEAAAAAAAAAZAAAAAEAAAAAAAAD6AD/////";variableList="AAAA/wAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMgAAAACAQAAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAACAAAAZAAAAAEAAAAAAAAAZAAAAAEAAAAAAAAD6AD/////";mainHSplitter="AAAA/wAAAAEAAAACAAABEAAAA8MBAAAABgEAAAABAQ==";splitter_7="AAAA/wAAAAEAAAABAAAAiwAAAAAGAQAAAAEB";lvs_tree="AAAA/wAAAAAAAAABAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAABAQEAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAABAAAAZAAAAAEAAAAAAAAD6AAAAABk";drc_tree="AAAA/wAAAAAAAAABAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAABAQEAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAABAAAAZAAAAAEAAAAAAAAD6AAAAABk";pymacros_tree="AAAA/wAAAAAAAAABAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAABAQEAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAABAAAAZAAAAAEAAAAAAAAD6AAAAABk";macros_tree="AAAA/wAAAAAAAAABAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQoAAAABAQEAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAABAAABCgAAAAEAAAAAAAAD6AAAAABk"; + true + '@@navigator_menu.navigator_main_menu.navigator_all_hier_levels':false;'@@navigator_menu.navigator_main_menu.navigator_freeze':false;'@@navigator_menu.navigator_main_menu.navigator_show_images':false;'@bookmarks_context_menu.follow_selection':false;'@bookmarks_context_menu.load_bookmarks':false;'@bookmarks_context_menu.manage_bookmarks':false;'@bookmarks_context_menu.save_bookmarks':false;'@hcp_context_menu.cell_user_properties':false;'@hcp_context_menu.flat_mode':false;'@hcp_context_menu.hide_cell':false;'@hcp_context_menu.open_current':false;'@hcp_context_menu.save_cell_as':false;'@hcp_context_menu.show_all':false;'@hcp_context_menu.show_as_top':false;'@hcp_context_menu.show_cell':false;'@hcp_context_menu.sorting.by_area':false;'@hcp_context_menu.sorting.by_name':false;'@hcp_context_menu.split_mode':false;'@lcp_context_menu.add_others':false;'@lcp_context_menu.clean_up':false;'@lcp_context_menu.copy':false;'@lcp_context_menu.cut':false;'@lcp_context_menu.del':false;'@lcp_context_menu.group':false;'@lcp_context_menu.hide':false;'@lcp_context_menu.hide_all':false;'@lcp_context_menu.hide_empty_layers':false;'@lcp_context_menu.insert':false;'@lcp_context_menu.invvalid':false;'@lcp_context_menu.paste':false;'@lcp_context_menu.regroup_menu.flatten':false;'@lcp_context_menu.regroup_menu.grp_d':false;'@lcp_context_menu.regroup_menu.grp_i':false;'@lcp_context_menu.regroup_menu.grp_l':false;'@lcp_context_menu.rename':false;'@lcp_context_menu.select_all':false;'@lcp_context_menu.select_source':false;'@lcp_context_menu.show':false;'@lcp_context_menu.show_all':false;'@lcp_context_menu.show_only':false;'@lcp_context_menu.sort_menu.sort_dli':false;'@lcp_context_menu.sort_menu.sort_idl':false;'@lcp_context_menu.sort_menu.sort_ild':false;'@lcp_context_menu.sort_menu.sort_ldi':false;'@lcp_context_menu.sort_menu.sort_name':false;'@lcp_context_menu.tab_menu.new_tab':false;'@lcp_context_menu.tab_menu.remove_tab':false;'@lcp_context_menu.tab_menu.rename_tab':false;'@lcp_context_menu.test_shapes_in_view':false;'@lcp_context_menu.ungroup':false;'@lcp_context_menu.valid':false;'@lcp_tabs_context_menu.new_tab':false;'@lcp_tabs_context_menu.remove_tab':false;'@lcp_tabs_context_menu.rename_tab':false;'@secrets.duplicate_interactive':false;'@secrets.paste_interactive':false;'@secrets.sel_move_interactive':false;'@toolbar.move':false;'@toolbar.next_display_state':false;'@toolbar.prev_display_state':false;'@toolbar.ruler':false;'@toolbar.select':false;'@toolbar.technology_selector':false;bookmark_menu:false;bookmark_menu.bookmark_view:false;bookmark_menu.goto_bookmark_menu:false;bookmark_menu.load_bookmarks:false;bookmark_menu.manage_bookmarks:false;bookmark_menu.save_bookmarks:false;edit_menu:false;edit_menu.add_image:false;edit_menu.cancel:false;edit_menu.clear_all_rulers:false;edit_menu.configure_rulers:false;edit_menu.copy:false;edit_menu.cut:false;edit_menu.delete:false;edit_menu.duplicate:false;edit_menu.image_menu:false;edit_menu.image_menu.bring_to_back:false;edit_menu.image_menu.bring_to_front:false;edit_menu.image_menu.clear_all_images:false;edit_menu.mode_menu:false;edit_menu.mode_menu.move:false;edit_menu.mode_menu.ruler:false;edit_menu.mode_menu.select:false;edit_menu.paste:false;edit_menu.redo:false;edit_menu.search_replace_viewer:false;edit_menu.select_menu:false;edit_menu.select_menu.disable_all:false;edit_menu.select_menu.enable_all:false;edit_menu.select_menu.pi_enable_10:false;edit_menu.select_menu.pi_enable_11:false;edit_menu.select_menu.pi_enable_12:false;edit_menu.select_menu.pi_enable_13:false;edit_menu.select_menu.pi_enable_15:false;edit_menu.select_menu.pi_enable_7:false;edit_menu.select_menu.pi_enable_8:false;edit_menu.select_menu.pi_enable_9:false;edit_menu.select_menu.select_all:false;edit_menu.select_menu.unselect_all:false;edit_menu.selection_menu:false;edit_menu.selection_menu.sel_flip_x:false;edit_menu.selection_menu.sel_flip_y:false;edit_menu.selection_menu.sel_free_rot:false;edit_menu.selection_menu.sel_move:false;edit_menu.selection_menu.sel_move_to:false;edit_menu.selection_menu.sel_rot_ccw:false;edit_menu.selection_menu.sel_rot_cw:false;edit_menu.selection_menu.sel_scale:false;edit_menu.show_properties:false;edit_menu.undo:false;file_menu:false;file_menu.clone:false;file_menu.close:false;file_menu.close_all:false;file_menu.exit:false;file_menu.import_menu:false;file_menu.import_menu.import_def:false;file_menu.import_menu.import_gerber_menu:false;file_menu.import_menu.import_gerber_menu.import_gerber_new:false;file_menu.import_menu.import_gerber_menu.import_gerber_new_free:false;file_menu.import_menu.import_gerber_menu.import_gerber_open:false;file_menu.import_menu.import_gerber_menu.import_gerber_recent:false;file_menu.import_menu.import_lef:false;file_menu.import_menu.import_stream:false;file_menu.layout_props:false;file_menu.layout_stats:false;file_menu.load_layer_props:false;file_menu.open:false;file_menu.open_new_panel:false;file_menu.open_recent_menu:false;file_menu.open_recent_menu.open_recent_1:false;file_menu.open_recent_menu.open_recent_2:false;file_menu.open_same_panel:false;file_menu.print:false;file_menu.pull_in:false;file_menu.reader_options:false;file_menu.reload:false;file_menu.restore_session:false;file_menu.save:false;file_menu.save_all:false;file_menu.save_as:false;file_menu.save_layer_props:false;file_menu.save_session:false;file_menu.screenshot:false;file_menu.setup:false;file_menu.view_log:false;file_menu.writer_options:false;help_menu:false;help_menu.about:false;help_menu.about_qt:false;help_menu.assistant:false;help_menu.show_all_tips:false;macros_menu:false;macros_menu.examples:false;macros_menu.examples.macro_in_menu_browser:false;macros_menu.examples.macro_in_menu_datamap:false;macros_menu.examples.macro_in_menu_dump_menu:false;macros_menu.examples.macro_in_menu_flatten:false;macros_menu.examples.macro_in_menu_fractal:false;macros_menu.examples.macro_in_menu_qtdialog:false;macros_menu.examples.macro_in_menu_qtrubyserver:false;macros_menu.examples.macro_in_menu_screenshots:false;macros_menu.examples.macro_in_menu_sokoban:false;macros_menu.macro_development:false;tools_menu:false;tools_menu.browse_instances:false;tools_menu.browse_markers:false;tools_menu.browse_netlists:false;tools_menu.browse_shapes:false;tools_menu.diff_tool:false;tools_menu.drc:false;tools_menu.drc.edit_script:false;tools_menu.drc.new_script:false;tools_menu.edit_layer_stack:false;tools_menu.lvs:false;tools_menu.lvs.edit_script:false;tools_menu.lvs.macro_in_menu_lvs:false;tools_menu.lvs.new_script:false;tools_menu.net_trace:false;tools_menu.packages:false;tools_menu.shapes_to_markers:false;tools_menu.shapes_to_markers.scan_layers:false;tools_menu.shapes_to_markers.scan_layers_flat:false;tools_menu.technologies:false;tools_menu.trace_all_nets_menu:false;tools_menu.trace_all_nets_menu.trace_all_nets:false;tools_menu.trace_all_nets_menu.trace_all_nets_flat:false;tools_menu.xor_tool:false;tools_menu.xsection_script_submenu:false;tools_menu.xsection_script_submenu.xsection_for_technology:false;tools_menu.xsection_script_submenu.xsection_script_load:false;view_menu:false;view_menu.default_grid:false;view_menu.default_grid.default_grid_1:false;view_menu.default_grid.default_grid_2:false;view_menu.default_grid.default_grid_3:false;view_menu.no_stipples:false;view_menu.reset_window_state:false;view_menu.show_bookmarks_view:false;view_menu.show_cell_boxes:false;view_menu.show_grid:false;view_menu.show_hierarchy_panel:false;view_menu.show_layer_panel:false;view_menu.show_layer_toolbox:false;view_menu.show_libraries_view:false;view_menu.show_markers:false;view_menu.show_navigator:false;view_menu.show_texts:false;view_menu.show_toolbar:false;view_menu.synchronized_views:false;view_menu.transient_selection:false;zoom_menu:false;zoom_menu.ascend:false;zoom_menu.dec_max_hier:false;zoom_menu.descend:false;zoom_menu.global_trans:false;zoom_menu.global_trans.m0:false;zoom_menu.global_trans.m135:false;zoom_menu.global_trans.m45:false;zoom_menu.global_trans.m90:false;zoom_menu.global_trans.r0:false;zoom_menu.global_trans.r180:false;zoom_menu.global_trans.r270:false;zoom_menu.global_trans.r90:false;zoom_menu.goto_position:false;zoom_menu.inc_max_hier:false;zoom_menu.max_hier:false;zoom_menu.max_hier_0:false;zoom_menu.max_hier_1:false;zoom_menu.next_display_state:false;zoom_menu.prev_display_state:false;zoom_menu.redraw:false;zoom_menu.select_cell:false;zoom_menu.select_current_cell:false;zoom_menu.synchronized_views:false;zoom_menu.zoom_fit:false;zoom_menu.zoom_fit_sel:false;zoom_menu.zoom_in:false;zoom_menu.zoom_out:false;edit_menu.select_menu.pi_enable_14:false;file_menu.open_recent_menu.open_recent_10:false;file_menu.open_recent_menu.open_recent_3:false;file_menu.open_recent_menu.open_recent_4:false;file_menu.open_recent_menu.open_recent_5:false;file_menu.open_recent_menu.open_recent_6:false;file_menu.open_recent_menu.open_recent_7:false;file_menu.open_recent_menu.open_recent_8:false;file_menu.open_recent_menu.open_recent_9:false;tools_menu.drc.macro_in_menu_drc:false;'@hcp_context_menu.copy':false;'@hcp_context_menu.cut':false;'@hcp_context_menu.delete_cell':false;'@hcp_context_menu.flatten_cell':false;'@hcp_context_menu.new_cell':false;'@hcp_context_menu.paste':false;'@hcp_context_menu.rename_cell':false;'@hcp_context_menu.replace_cell':false;'@toolbar.box':false;'@toolbar.combine_mode':false;'@toolbar.instance':false;'@toolbar.partial':false;'@toolbar.path':false;'@toolbar.polygon':false;'@toolbar.text':false;edit_menu.cell_menu:false;edit_menu.cell_menu.adjust_cell_origin:false;edit_menu.cell_menu.convert_cell_to_static:false;edit_menu.cell_menu.delete_cell:false;edit_menu.cell_menu.flatten_cell:false;edit_menu.cell_menu.new_cell:false;edit_menu.cell_menu.rename_cell:false;edit_menu.cell_menu.replace_cell:false;edit_menu.cell_menu.user_properties:false;edit_menu.edit_options:false;edit_menu.layer_menu:false;edit_menu.layer_menu.boolean:false;edit_menu.layer_menu.clear_layer:false;edit_menu.layer_menu.copy_layer:false;edit_menu.layer_menu.delete_layer:false;edit_menu.layer_menu.edit_layer:false;edit_menu.layer_menu.merge:false;edit_menu.layer_menu.new_layer:false;edit_menu.layer_menu.size:false;edit_menu.layout_menu:false;edit_menu.layout_menu.lay_convert_to_static:false;edit_menu.layout_menu.lay_flip_x:false;edit_menu.layout_menu.lay_flip_y:false;edit_menu.layout_menu.lay_free_rot:false;edit_menu.layout_menu.lay_move:false;edit_menu.layout_menu.lay_rot_ccw:false;edit_menu.layout_menu.lay_rot_cw:false;edit_menu.layout_menu.lay_scale:false;edit_menu.mode_menu.box:false;edit_menu.mode_menu.instance:false;edit_menu.mode_menu.partial:false;edit_menu.mode_menu.path:false;edit_menu.mode_menu.polygon:false;edit_menu.mode_menu.text:false;edit_menu.search_replace_editor:false;edit_menu.selection_menu.align:false;edit_menu.selection_menu.change_layer:false;edit_menu.selection_menu.convert_to_cell:false;edit_menu.selection_menu.convert_to_pcell:false;edit_menu.selection_menu.difference:false;edit_menu.selection_menu.flatten_insts:false;edit_menu.selection_menu.intersection:false;edit_menu.selection_menu.make_array:false;edit_menu.selection_menu.make_cell:false;edit_menu.selection_menu.make_cell_variants:false;edit_menu.selection_menu.move_hier_up:false;edit_menu.selection_menu.resolve_arefs:false;edit_menu.selection_menu.round_corners:false;edit_menu.selection_menu.separate:false;edit_menu.selection_menu.size:false;edit_menu.selection_menu.tap:false;edit_menu.selection_menu.union:false;edit_menu.utils_menu:false;edit_menu.utils_menu.clip_tool:false;edit_menu.utils_menu.fill_tool:false;file_menu.new_layout:false;file_menu.new_panel:false;view_menu.edit_top_level_selection:false;tools_menu.drc.macro_in_menu_drc_sky130:false;tools_menu.drc.macro_in_menu_drc_sky130_1:false;tools_menu.lvs.macro_in_menu_lvs_sky130:false;'@hcp_context_menu.macro_in_menu_replace_cells':false;'@hcp_context_menu.macro_in_menu_write_childcells':false;'@hcp_context_menu.sorting.by_area_reverse':false;'@secrets.select_next_item':false;'@secrets.select_next_item_add':false;bookmark_menu.open_recent_menu_bookmarks:false;edit_menu.select_menu.pi_enable_16:false;edit_menu.select_menu.pi_enable_18:false;edit_menu.select_menu.pi_enable_19:false;edit_menu.select_menu.pi_enable_20:false;edit_menu.selection_menu.macro_in_menu_scale_anisotropic:false;file_menu.macro_in_menu_screenshot:false;file_menu.open_recent_menu_layer_props:false;file_menu.open_recent_menu_sessions:false;macros_menu.macro_in_menu_array_of_labels:false;tools_menu.macro_in_menu_calc_area:false;tools_menu.macro_in_menu_calc_area_hier:false;tools_menu.macro_in_menu_cell_bbox:false;tools_menu.macro_in_menu_dump_flat_shapes:false;tools_menu.macro_in_menu_list_layers:false;tools_menu.macro_in_menu_search_odd_width_paths:false;view_menu.mouse_tracking:false;view_menu.show_images:false;tools_menu.drc.macro_in_menu_drc_1:false;tools_menu.drc.macro_in_menu_drc_2:false + 16 + 0 + '/ciic/designs/caravel.develop/gds/mgmt_protect.gds.gz'@'sky130A' '/ciic/designs/caravel.develop/gds/mgmt_protect_hv.gds.gz'@'sky130A' '/ciic/pdks/sky130-drc-regression-tests/design-testcases/mpw-two/slot-040/user_analog_project_wrapper.gds.gz'@'sky130A' '/ciic/designs/caravel.mpw-one-final-metal-fix/gds/mgmt_protect_hv.gds.gz'@'sky130A' '/ciic/designs/caravel.develop/gds/sky130_fd_sc_hvl__lsbufhv2lv_1_wrapped.gds'@'sky130A' '/ciic/pdks/sky130-drc-regression-tests/design-testcases/mpw-2/slot-025/caravel_00020019.oas'@'sky130A' '/ciic/pdks/sky130-drc-regression-tests/design-testcases/mpw-2/slot-040/caravel_00020028/caravel_00020028.oas'@'sky130A' '/ciic/pdks/sky130-drc-regression-tests/design-testcases/mpw-2/slot-005/caravel_00020005/caravel_00020005.oas'@'sky130A' '/ciic/designs/caravel.develop/gds/caravan.gds'@'sky130A' '/ciic/designs/caravel.develop/gds/caravel.gds'@'sky130A' '/ciic/designs/caravel.develop/gds/mprj_logic_high.gds'@'sky130A' '/ciic/designs/caravel.develop/gds/chip_io.gds'@'sky130A' '/ciic/designs/caravel.develop/gds/mgmt_core.gds'@'sky130A' '/ciic/pdks/sky130-drc-regression-tests/user-designs-google-mpw/mpw-2/slot-040/caravel_00020028/caravel_00020028.oas'@'sky130A' '/home/mkk/Downloads/slot-040-refs_heads_main-gds/caravel_00020028.oas'@'sky130A' '/ciic/designs/caravel.develop/gds/mgmt_protect_hv.gds'@'sky130A' + + + + false + true + false + auto + 255,0,0 0,255,0 0,0,255 255,255,0 255,0,255 0,255,255 160,80,255 255,160,0 + true + -1 + -1 + 50 + -1 + -1 + 1000000 + 0 + 1 + dont-change + 0.15 + 2 + + database-top + #ff0000 + -1 + 1 + 3 + -1 + 10000000 + false + 3 + fit-marker + MarkerBrowserDialog="AdnQywABAAAAAAIzAAAAJQAABugAAAQ0AAACNAAAADsAAAbnAAAELwAAAAAAAA==";splitter_2="AAAA/wAAAAAAAAACAAACNQAAAmcBAAAABgEAAAAB";splitter="AAAA/wAAAAAAAAACAAAA/QAAAP8BAAAABgEAAAAC";markers_list="AAAA/wAAAAAAAAABAAAAAAAAAAMBAAAABAAAAAAAAAACAAAAAwAAAAEAAAAEAAAAAAAAAAMAAAABAAAAAgAAAAAAAAAAAAAExQAAAAQBAQABAAAAAAAAAAAAAAAAZAAAABgAAACBAAAAAAAAAAQAAAA1AAAAAQAAAAAAAANPAAAAAQAAAAAAAABkAAAAAQAAAAAAAADdAAAAAQAAAAA=";directory_tree="AAAA/wAAAAAAAAABAAAAAQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAiEAAAACAQEAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAACAAABCgAAAAEAAAAAAAABFwAAAAEAAAAA"; + false + #ff0000 + true + true + true + any + 8 + mode=normal,title=Ruler,category=_ruler,fmt=$D,fmt_x=$X,fmt_y=$Y,position=auto,xalign=auto,yalign=auto,xlabel_xalign=auto,xlabel_yalign=auto,ylabel_xalign=auto,ylabel_yalign=auto,style=cross_both,outline=diag,snap=true,angle_constraint=global;mode=single_click,title=Cross,category=_cross,fmt='$U,$V',fmt_x='',fmt_y='',position=auto,xalign=auto,yalign=auto,xlabel_xalign=auto,xlabel_yalign=auto,ylabel_xalign=auto,ylabel_yalign=auto,style=cross_both,outline=diag,snap=true,angle_constraint=global;mode=auto_metric,title=Measure,category=_measure,fmt=$D,fmt_x=$X,fmt_y=$Y,position=auto,xalign=auto,yalign=auto,xlabel_xalign=auto,xlabel_yalign=auto,ylabel_xalign=auto,ylabel_yalign=auto,style=ruler,outline=diag,snap=true,angle_constraint=global;mode=normal,title=Ellipse,category='',fmt='',fmt_x='W=$(abs(X))',fmt_y='H=$(abs(Y))',position=auto,xalign=auto,yalign=auto,xlabel_xalign=auto,xlabel_yalign=auto,ylabel_xalign=auto,ylabel_yalign=auto,style=line,outline=ellipse,snap=true,angle_constraint=global;mode=normal,title=Box,category='',fmt='',fmt_x='W=$(abs(X))',fmt_y='H=$(abs(Y))',position=auto,xalign=auto,yalign=auto,xlabel_xalign=auto,xlabel_yalign=auto,ylabel_xalign=auto,ylabel_yalign=auto,style=cross_both,outline=box,snap=true,angle_constraint=global;mode=normal,title=XSection,category=XS,fmt=XS,fmt_x='',fmt_y='',position=auto,xalign=auto,yalign=auto,xlabel_xalign=auto,xlabel_yalign=auto,ylabel_xalign=auto,ylabel_yalign=auto,style=arrow_both,outline=diag,snap=true,angle_constraint=global + -1 + + 5 + 0 + #ff0000 + 1 + true + false + 1 + true + 3 + + any-top + 100000000 + 100000000 + 1 + dont-change + + false + true + true + true + false + false + false + true + false + false + all-cells + == + + + == + + ~ + res_amp_lin + + == + + == + + == + + + == + + == + + + == + + + == + + == + + ~ + + 1000 + find + 'instances of cells *.* where cell_name ~ "res_amp_lin"';'instances of cells *.* where cell_name ~ "res_amp"';'instances of cells *.* where cell_name ~ "*ICV*"';'instances of cells *.* where cell_name ~ "*ICV_1093*"';'instances of cells *.* where cell_name ~ "ICV_1093"';'instances of cell caravel_00020017.* where cell_name ~ "ICV_1093"';'instances of cell deconv_kernel_estimator_top_level.* where cell_name ~ "deconv_kernel_estimator_to_VIA15"';'delete instances of cell deconv_kernel_estimator_top_level.* where cell_name ~ "deconv_kernel_estimator_to_VIA15"' + instance + + 1 + fit-marker + search_replace_dialog="AdnQywACAAAAAABfAAABLAAAA6kAAAOZAAAAYgAAAUkAAAOmAAADlgAAAAAAAAAACA0=";splitter="AAAA/wAAAAEAAAACAAABxwAAATAB/////wEAAAABAA==";results="AAAA/wAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAAAAAAD6AD/////"; + true + 0 1 2 3 4 5[1] 6 7 8 9[0] 10 11 12 13 14 15 + <?xml version="1.0" encoding="utf-8"?> +<stream-import-data> + <files> + <file>/mnt/shuttles/mpw-two-b/slot-012/fuserisc/gds/cus_tg_mux41_buf</file> + </files> + <cell-name/> + <layer-offset/> + <layer-mode>original</layer-mode> + <import-mode>extra</import-mode> + <reference-points> + </reference-points> + <explicit-trans>r0 *1 0,0</explicit-trans> + <options> + <gds2> + <box-mode>1</box-mode> + <allow-big-records>true</allow-big-records> + <allow-multi-xy-records>true</allow-multi-xy-records> + </gds2> + <common> + <create-other-layers>true</create-other-layers> + <layer-map>layer_map()</layer-map> + <enable-properties>true</enable-properties> + <enable-text-objects>true</enable-text-objects> + </common> + <lefdef> + <read-all-layers>true</read-all-layers> + <layer-map>layer_map()</layer-map> + <dbu>0.001</dbu> + <produce-net-names>true</produce-net-names> + <net-property-name>#1</net-property-name> + <produce-inst-names>true</produce-inst-names> + <inst-property-name>#1</inst-property-name> + <produce-pin-names>false</produce-pin-names> + <pin-property-name>#1</pin-property-name> + <produce-cell-outlines>true</produce-cell-outlines> + <cell-outline-layer>OUTLINE</cell-outline-layer> + <produce-placement-blockages>true</produce-placement-blockages> + <placement-blockage-layer>PLACEMENT_BLK</placement-blockage-layer> + <produce-regions>true</produce-regions> + <region-layer>REGIONS</region-layer> + <produce-via-geometry>true</produce-via-geometry> + <via-geometry-suffix/> + <via-geometry-datatype>0</via-geometry-datatype> + <produce-pins>true</produce-pins> + <pins-suffix>.PIN</pins-suffix> + <pins-datatype>2</pins-datatype> + <produce-obstructions>true</produce-obstructions> + <obstructions-suffix>.OBS</obstructions-suffix> + <obstructions-datatype>3</obstructions-datatype> + <produce-blockages>true</produce-blockages> + <blockages-suffix>.BLK</blockages-suffix> + <blockages-datatype>4</blockages-datatype> + <produce-labels>true</produce-labels> + <labels-suffix>.LABEL</labels-suffix> + <labels-datatype>1</labels-datatype> + <produce-routing>true</produce-routing> + <routing-suffix/> + <routing-datatype>0</routing-datatype> + </lefdef> + <dxf> + <dbu>0.001</dbu> + <unit>1</unit> + <text-scaling>100</text-scaling> + <circle-points>100</circle-points> + <circle-accuracy>0</circle-accuracy> + <contour-accuracy>0</contour-accuracy> + <polyline-mode>0</polyline-mode> + <render-texts-as-polygons>false</render-texts-as-polygons> + <keep-other-cells>false</keep-other-cells> + <keep-layer-names>false</keep-layer-names> + <create-other-layers>true</create-other-layers> + <layer-map>layer_map()</layer-map> + </dxf> + <cif> + <wire-mode>0</wire-mode> + <dbu>0.001</dbu> + <layer-map>layer_map()</layer-map> + <create-other-layers>true</create-other-layers> + <keep-layer-names>false</keep-layer-names> + </cif> + <mag> + <lambda>1</lambda> + <dbu>0.001</dbu> + <layer-map>layer_map()</layer-map> + <create-other-layers>true</create-other-layers> + <keep-layer-names>false</keep-layer-names> + <merge>true</merge> + <lib-paths> + </lib-paths> + </mag> + </options> +</stream-import-data> + + true + tech_setup_dialog="AdnQywACAAAAAAT4AAAAsQAACEgAAAOeAAAE+wAAAM4AAAhFAAADmwAAAAAAAAAAC4A=";splitter="AAAA/wAAAAEAAAACAAABAAAAABsB/////wEAAAABAA==";tech_tree="AAAA/wAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAABAQAAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAABAAAAgAAAAAEAAAAAAAAD6AAAAABk"; + <?xml version="1.0" encoding="utf-8"?> +<technologies> + <technology> + <name/> + <description>(Default)</description> + <group/> + <dbu>0.001</dbu> + <base-path/> + <original-base-path/> + <layer-properties_file/> + <add-other-layers>true</add-other-layers> + <reader-options> + <gds2> + <box-mode>1</box-mode> + <allow-big-records>true</allow-big-records> + <allow-multi-xy-records>true</allow-multi-xy-records> + </gds2> + <common> + <create-other-layers>true</create-other-layers> + <layer-map>layer_map()</layer-map> + <enable-properties>true</enable-properties> + <enable-text-objects>true</enable-text-objects> + </common> + <lefdef> + <read-all-layers>true</read-all-layers> + <layer-map>layer_map()</layer-map> + <dbu>0.001</dbu> + <produce-net-names>true</produce-net-names> + <net-property-name>#1</net-property-name> + <produce-inst-names>true</produce-inst-names> + <inst-property-name>#1</inst-property-name> + <produce-pin-names>false</produce-pin-names> + <pin-property-name>#1</pin-property-name> + <produce-cell-outlines>true</produce-cell-outlines> + <cell-outline-layer>OUTLINE</cell-outline-layer> + <produce-placement-blockages>true</produce-placement-blockages> + <placement-blockage-layer>PLACEMENT_BLK</placement-blockage-layer> + <produce-regions>true</produce-regions> + <region-layer>REGIONS</region-layer> + <produce-via-geometry>true</produce-via-geometry> + <via-geometry-suffix/> + <via-geometry-datatype>0</via-geometry-datatype> + <produce-pins>true</produce-pins> + <pins-suffix>.PIN</pins-suffix> + <pins-datatype>2</pins-datatype> + <produce-obstructions>true</produce-obstructions> + <obstructions-suffix>.OBS</obstructions-suffix> + <obstructions-datatype>3</obstructions-datatype> + <produce-blockages>true</produce-blockages> + <blockages-suffix>.BLK</blockages-suffix> + <blockages-datatype>4</blockages-datatype> + <produce-labels>true</produce-labels> + <labels-suffix>.LABEL</labels-suffix> + <labels-datatype>1</labels-datatype> + <produce-routing>true</produce-routing> + <routing-suffix/> + <routing-datatype>0</routing-datatype> + </lefdef> + <dxf> + <dbu>0.001</dbu> + <unit>1</unit> + <text-scaling>100</text-scaling> + <circle-points>100</circle-points> + <circle-accuracy>0</circle-accuracy> + <contour-accuracy>0</contour-accuracy> + <polyline-mode>0</polyline-mode> + <render-texts-as-polygons>false</render-texts-as-polygons> + <keep-other-cells>false</keep-other-cells> + <keep-layer-names>false</keep-layer-names> + <create-other-layers>true</create-other-layers> + <layer-map>layer_map()</layer-map> + </dxf> + <cif> + <wire-mode>0</wire-mode> + <dbu>0.001</dbu> + <layer-map>layer_map()</layer-map> + <create-other-layers>true</create-other-layers> + <keep-layer-names>false</keep-layer-names> + </cif> + <mag> + <lambda>1</lambda> + <dbu>0.001</dbu> + <layer-map>layer_map()</layer-map> + <create-other-layers>true</create-other-layers> + <keep-layer-names>false</keep-layer-names> + <merge>true</merge> + <lib-paths> + </lib-paths> + </mag> + </reader-options> + <writer-options> + <gds2> + <write-timestamps>true</write-timestamps> + <write-cell-properties>false</write-cell-properties> + <write-file-properties>false</write-file-properties> + <no-zero-length-paths>false</no-zero-length-paths> + <multi-xy-records>false</multi-xy-records> + <max-vertex-count>8000</max-vertex-count> + <max-cellname-length>32000</max-cellname-length> + <libname>LIB</libname> + </gds2> + <oasis> + <compression-level>2</compression-level> + <write-cblocks>false</write-cblocks> + <strict-mode>false</strict-mode> + <write-std-properties>1</write-std-properties> + <subst-char>*</subst-char> + <permissive>false</permissive> + </oasis> + <cif> + <polygon-mode>0</polygon-mode> + </cif> + <cif> + <dummy-calls>false</dummy-calls> + <blank-separator>false</blank-separator> + </cif> + <mag> + <lambda>0</lambda> + <tech/> + <write-timestamp>true</write-timestamp> + </mag> + </writer-options> + <connectivity> + </connectivity> + </technology> +</technologies> + + false + auto + 0 + true + true + only-top-level-shown-by-default=3,editor-mode=4,editor-mode=0,hide-empty-layers=4,hide-empty-layers=0,has-non-add-edit-combine-mode=4,has-non-add-edit-combine-mode=0,tech-manager-basic-tips=4,tech-manager-basic-tips=0 + auto + true + AdnQywABAAD///7eAAAAAAAABM8AAAUD///+3wAAABYAAATOAAAE/gAAAAAAAA== + AAAA/wAAAAD9AAAAAgAAAAAAAAEsAAAEgfwCAAAABPsAAAAcAGgAcABfAGQAbwBjAGsAXwB3AGkAZABnAGUAdAEAAABSAAAEgQAAABkA////+wAAACoAbgBhAHYAaQBnAGEAdABvAHIAXwBkAG8AYwBrAF8AdwBpAGQAZwBlAHQAAAAAAP////8AAACWAP////sAAAAgAGwAaQBiAHMAXwBkAG8AYwBrAF8AdwBpAGQAZwBlAHQAAAAAUgAAA5cAAAAZAP////sAAAAcAGUAbwBfAGQAbwBjAGsAXwB3AGkAZABnAGUAdAAAAAAA/////wAAAJYA////AAAAAQAAAUMAAASB/AIAAAAD+wAAACoAYgBvAG8AawBtAGEAcgBrAHMAXwBkAG8AYwBrAF8AdwBpAGQAZwBlAHQAAAAAAP////8AAAAZAP////sAAAAcAGwAcABfAGQAbwBjAGsAXwB3AGkAZABnAGUAdAEAAABSAAAD6gAAABkA////+wAAABwAbAB0AF8AZABvAGMAawBfAHcAaQBkAGcAZQB0AQAABEIAAACRAAAAkQAAAJEAAAN1AAAEgQAAAAQAAAAEAAAACAAAAAj8AAAAAQAAAAIAAAABAAAADgB0AG8AbwBsAGIAYQByAQAAAAD/////AAAAAAAAAAA= + false + true + false + false + all + + 90 + rdb + all + true + 200 + true + 0 + diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.krc.save b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.krc.save new file mode 100755 index 00000000..1b894e75 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.krc.save @@ -0,0 +1,516 @@ + + + false + false + 10 + true + + auto + true + 1 + by-name + true + true + auto + 50 + false + false + + any-top + 1000000000 + 1 + fit-marker + BrowseInstancesForm="AdnQywACAAAAAAPoAAACJQAABhIAAAMFAAAD6wAAAkIAAAYPAAADAgAAAAAAAAAACgA=";splitter2="AAAA/wAAAAEAAAACAAABCAAAAQgBAAAABgEAAAABAQ==";lv_cell_instance="AAAA/wAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp8AAAACAQAAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAACAAABPAAAAAEAAAAAAAABYwAAAAEAAAAAAAAD6AD/////";lv_cell="AAAA/wAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqAAAAADAQAAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAADAAABEgAAAAEAAAAAAAAAZAAAAAEAAAAAAAABKgAAAAEAAAAAAAAD6AD/////"; + 32 + false + 255,157,157[0] 255,128,168[1] 192,128,255[2] 149,128,255[3] 128,134,255[4] 128,168,255[5] 255,0,0[6] 255,0,128[7] 255,0,255[8] 128,0,255[9] 0,0,255[10] 0,128,255[11] 128,0,0[12] 128,0,87[13] 128,0,128[14] 80,0,128[15] 0,0,128[16] 0,64,128[17] 128,255,251[18] 128,255,141[19] 175,255,128[20] 243,255,128[21] 255,194,128[22] 255,160,128[23] 0,255,255[24] 1,255,107[25] 145,255,0[26] 221,255,0[27] 255,174,0[28] 255,128,0[29] 0,128,128[30] 0,128,80[31] 0,128,0[32] 80,128,0[33] 128,128,0[34] 128,80,0[35] 255,255,255 192,192,192 128,128,128 96,96,96 64,64,64 0,0,0 + add + auto + 50 + false + + 4 + + false + file='/home/mk/Downloads/RAM_4Kx32.def';import-mode=0; + false + 0 + 0.01,0.005 + + 0.1 + true + true + true + false + true + true + 2 + 5 + false + 1 + false + 0 + 10 + any + 0.005 + -1 + 0 + false + caravel_00020002_fill_pattern + 0 + 0 + 1 + + false + + true + 0 + 0 + 1 + 1 + 1000 + false + any + flush + 0.0 + 0.0 + 0.1 + true + false + left + 0 + ABC + bottom + true + true + false + true + r0 *1 0,0 + auto + auto + auto + 0.005 + auto + true + invisible + dots + tenths-dotted-lines + true + auto + 1 + 5 + true + true + 1 + true + 1 + sky130A + auto + 0 + true + true + 0 + '@@navigator_menu.navigator_main_menu.navigator_all_hier_levels':'';'@@navigator_menu.navigator_main_menu.navigator_freeze':'';'@@navigator_menu.navigator_main_menu.navigator_show_images':'';'@bookmarks_context_menu.follow_selection':'';'@bookmarks_context_menu.load_bookmarks':'';'@bookmarks_context_menu.manage_bookmarks':'';'@bookmarks_context_menu.save_bookmarks':'';'@hcp_context_menu.cell_user_properties':'';'@hcp_context_menu.flat_mode':'';'@hcp_context_menu.hide_cell':'';'@hcp_context_menu.open_current':'';'@hcp_context_menu.save_cell_as':'';'@hcp_context_menu.show_all':'';'@hcp_context_menu.show_as_top':'Ctrl+T';'@hcp_context_menu.show_cell':'';'@hcp_context_menu.sorting.by_area':'';'@hcp_context_menu.sorting.by_name':'';'@hcp_context_menu.split_mode':'';'@lcp_context_menu.add_others':'';'@lcp_context_menu.clean_up':'';'@lcp_context_menu.copy':'';'@lcp_context_menu.cut':'';'@lcp_context_menu.del':'';'@lcp_context_menu.group':'';'@lcp_context_menu.hide':'';'@lcp_context_menu.hide_all':'';'@lcp_context_menu.hide_empty_layers':'';'@lcp_context_menu.insert':'';'@lcp_context_menu.invvalid':'';'@lcp_context_menu.paste':'';'@lcp_context_menu.regroup_menu.flatten':'';'@lcp_context_menu.regroup_menu.grp_d':'';'@lcp_context_menu.regroup_menu.grp_i':'';'@lcp_context_menu.regroup_menu.grp_l':'';'@lcp_context_menu.rename':'';'@lcp_context_menu.select_all':'';'@lcp_context_menu.select_source':'';'@lcp_context_menu.show':'';'@lcp_context_menu.show_all':'';'@lcp_context_menu.show_only':'';'@lcp_context_menu.sort_menu.sort_dli':'';'@lcp_context_menu.sort_menu.sort_idl':'';'@lcp_context_menu.sort_menu.sort_ild':'';'@lcp_context_menu.sort_menu.sort_ldi':'';'@lcp_context_menu.sort_menu.sort_name':'';'@lcp_context_menu.tab_menu.new_tab':'';'@lcp_context_menu.tab_menu.remove_tab':'';'@lcp_context_menu.tab_menu.rename_tab':'';'@lcp_context_menu.test_shapes_in_view':'';'@lcp_context_menu.ungroup':'';'@lcp_context_menu.valid':'';'@lcp_tabs_context_menu.new_tab':'';'@lcp_tabs_context_menu.remove_tab':'';'@lcp_tabs_context_menu.rename_tab':'';'@secrets.duplicate_interactive':'';'@secrets.paste_interactive':'';'@secrets.sel_move_interactive':'';'@toolbar.move':'';'@toolbar.next_display_state':'';'@toolbar.prev_display_state':'';'@toolbar.ruler':'';'@toolbar.select':'';'@toolbar.technology_selector':'';bookmark_menu:'';bookmark_menu.bookmark_view:'';bookmark_menu.goto_bookmark_menu:'';bookmark_menu.load_bookmarks:'';bookmark_menu.manage_bookmarks:'';bookmark_menu.save_bookmarks:'';edit_menu:'';edit_menu.add_image:'';edit_menu.cancel:'';edit_menu.clear_all_rulers:'';edit_menu.configure_rulers:'';edit_menu.copy:'';edit_menu.cut:'';edit_menu.delete:'';edit_menu.duplicate:'';edit_menu.image_menu:'';edit_menu.image_menu.bring_to_back:'';edit_menu.image_menu.bring_to_front:'';edit_menu.image_menu.clear_all_images:'';edit_menu.mode_menu:'';edit_menu.mode_menu.move:'';edit_menu.mode_menu.ruler:'';edit_menu.mode_menu.select:'';edit_menu.paste:'';edit_menu.redo:'';edit_menu.search_replace_viewer:'';edit_menu.select_menu:'';edit_menu.select_menu.disable_all:'';edit_menu.select_menu.enable_all:'';edit_menu.select_menu.pi_enable_10:'';edit_menu.select_menu.pi_enable_11:'';edit_menu.select_menu.pi_enable_12:'';edit_menu.select_menu.pi_enable_13:'';edit_menu.select_menu.pi_enable_15:'';edit_menu.select_menu.pi_enable_7:'';edit_menu.select_menu.pi_enable_8:'';edit_menu.select_menu.pi_enable_9:'';edit_menu.select_menu.select_all:'';edit_menu.select_menu.unselect_all:'';edit_menu.selection_menu:'';edit_menu.selection_menu.sel_flip_x:'';edit_menu.selection_menu.sel_flip_y:'';edit_menu.selection_menu.sel_free_rot:'';edit_menu.selection_menu.sel_move:'';edit_menu.selection_menu.sel_move_to:'';edit_menu.selection_menu.sel_rot_ccw:'';edit_menu.selection_menu.sel_rot_cw:'';edit_menu.selection_menu.sel_scale:'';edit_menu.show_properties:'';edit_menu.undo:'';file_menu:'';file_menu.clone:'';file_menu.close:'';file_menu.close_all:'';file_menu.exit:none;file_menu.import_menu:'';file_menu.import_menu.import_def:'';file_menu.import_menu.import_gerber_menu:'';file_menu.import_menu.import_gerber_menu.import_gerber_new:'';file_menu.import_menu.import_gerber_menu.import_gerber_new_free:'';file_menu.import_menu.import_gerber_menu.import_gerber_open:'';file_menu.import_menu.import_gerber_menu.import_gerber_recent:'';file_menu.import_menu.import_lef:'';file_menu.import_menu.import_stream:'';file_menu.layout_props:'';file_menu.layout_stats:'';file_menu.load_layer_props:'';file_menu.open:'';file_menu.open_new_panel:'';file_menu.open_recent_menu:'';file_menu.open_recent_menu.open_recent_1:'';file_menu.open_recent_menu.open_recent_2:'';file_menu.open_same_panel:'';file_menu.print:'';file_menu.pull_in:'';file_menu.reader_options:'';file_menu.reload:'';file_menu.restore_session:'';file_menu.save:'Ctrl+S';file_menu.save_all:'';file_menu.save_as:'';file_menu.save_layer_props:'';file_menu.save_session:'';file_menu.screenshot:'';file_menu.setup:'';file_menu.view_log:'';file_menu.writer_options:'';help_menu:'';help_menu.about:'';help_menu.about_qt:'';help_menu.assistant:'';help_menu.show_all_tips:'';macros_menu:'';macros_menu.examples:'';macros_menu.examples.macro_in_menu_browser:'';macros_menu.examples.macro_in_menu_datamap:'';macros_menu.examples.macro_in_menu_dump_menu:'';macros_menu.examples.macro_in_menu_flatten:'';macros_menu.examples.macro_in_menu_fractal:'';macros_menu.examples.macro_in_menu_qtdialog:'';macros_menu.examples.macro_in_menu_qtrubyserver:'';macros_menu.examples.macro_in_menu_screenshots:'';macros_menu.examples.macro_in_menu_sokoban:'';macros_menu.macro_development:'';tools_menu:'';tools_menu.browse_instances:'';tools_menu.browse_markers:'Ctrl+M';tools_menu.browse_netlists:'';tools_menu.browse_shapes:'';tools_menu.diff_tool:'';tools_menu.drc:'';tools_menu.drc.edit_script:'';tools_menu.drc.new_script:'';tools_menu.edit_layer_stack:'';tools_menu.lvs:'';tools_menu.lvs.edit_script:'';tools_menu.lvs.macro_in_menu_lvs:'';tools_menu.lvs.new_script:'';tools_menu.net_trace:'';tools_menu.packages:'';tools_menu.shapes_to_markers:'';tools_menu.shapes_to_markers.scan_layers:'';tools_menu.shapes_to_markers.scan_layers_flat:'';tools_menu.technologies:'';tools_menu.trace_all_nets_menu:'';tools_menu.trace_all_nets_menu.trace_all_nets:'Ctrl+Q';tools_menu.trace_all_nets_menu.trace_all_nets_flat:'';tools_menu.xor_tool:'';tools_menu.xsection_script_submenu:'';tools_menu.xsection_script_submenu.xsection_for_technology:'';tools_menu.xsection_script_submenu.xsection_script_load:'';view_menu:'';view_menu.default_grid:'';view_menu.default_grid.default_grid_1:'';view_menu.default_grid.default_grid_2:'';view_menu.default_grid.default_grid_3:'';view_menu.no_stipples:'';view_menu.reset_window_state:'';view_menu.show_bookmarks_view:'';view_menu.show_cell_boxes:'';view_menu.show_grid:'';view_menu.show_hierarchy_panel:'';view_menu.show_layer_panel:'';view_menu.show_layer_toolbox:'';view_menu.show_libraries_view:'';view_menu.show_markers:'';view_menu.show_navigator:'';view_menu.show_texts:'';view_menu.show_toolbar:'';view_menu.synchronized_views:'';view_menu.transient_selection:'';zoom_menu:'';zoom_menu.ascend:'';zoom_menu.dec_max_hier:'';zoom_menu.descend:'';zoom_menu.global_trans:'';zoom_menu.global_trans.m0:'';zoom_menu.global_trans.m135:'';zoom_menu.global_trans.m45:'';zoom_menu.global_trans.m90:'';zoom_menu.global_trans.r0:'';zoom_menu.global_trans.r180:'';zoom_menu.global_trans.r270:'';zoom_menu.global_trans.r90:'';zoom_menu.goto_position:'';zoom_menu.inc_max_hier:'';zoom_menu.max_hier:'';zoom_menu.max_hier_0:'';zoom_menu.max_hier_1:'';zoom_menu.next_display_state:'';zoom_menu.prev_display_state:'';zoom_menu.redraw:'';zoom_menu.select_cell:'';zoom_menu.select_current_cell:'';zoom_menu.synchronized_views:'';zoom_menu.zoom_fit:F;zoom_menu.zoom_fit_sel:'';zoom_menu.zoom_in:Z;zoom_menu.zoom_out:'Shift+Z';edit_menu.select_menu.pi_enable_14:'';file_menu.open_recent_menu.open_recent_10:'';file_menu.open_recent_menu.open_recent_3:'';file_menu.open_recent_menu.open_recent_4:'';file_menu.open_recent_menu.open_recent_5:'';file_menu.open_recent_menu.open_recent_6:'';file_menu.open_recent_menu.open_recent_7:'';file_menu.open_recent_menu.open_recent_8:'';file_menu.open_recent_menu.open_recent_9:'';tools_menu.drc.macro_in_menu_drc:'';'@hcp_context_menu.copy':'';'@hcp_context_menu.cut':'';'@hcp_context_menu.delete_cell':'';'@hcp_context_menu.flatten_cell':'';'@hcp_context_menu.new_cell':'';'@hcp_context_menu.paste':'';'@hcp_context_menu.rename_cell':'';'@hcp_context_menu.replace_cell':'';'@toolbar.box':'';'@toolbar.combine_mode':'';'@toolbar.instance':'';'@toolbar.partial':'';'@toolbar.path':'';'@toolbar.polygon':'';'@toolbar.text':'';edit_menu.cell_menu:'';edit_menu.cell_menu.adjust_cell_origin:'';edit_menu.cell_menu.convert_cell_to_static:'';edit_menu.cell_menu.delete_cell:'';edit_menu.cell_menu.flatten_cell:'';edit_menu.cell_menu.new_cell:'';edit_menu.cell_menu.rename_cell:'';edit_menu.cell_menu.replace_cell:'';edit_menu.cell_menu.user_properties:'';edit_menu.edit_options:'';edit_menu.layer_menu:'';edit_menu.layer_menu.boolean:'';edit_menu.layer_menu.clear_layer:'';edit_menu.layer_menu.copy_layer:'';edit_menu.layer_menu.delete_layer:'';edit_menu.layer_menu.edit_layer:'';edit_menu.layer_menu.merge:'';edit_menu.layer_menu.new_layer:'';edit_menu.layer_menu.size:'';edit_menu.layout_menu:'';edit_menu.layout_menu.lay_convert_to_static:'';edit_menu.layout_menu.lay_flip_x:'';edit_menu.layout_menu.lay_flip_y:'';edit_menu.layout_menu.lay_free_rot:'';edit_menu.layout_menu.lay_move:'';edit_menu.layout_menu.lay_rot_ccw:'';edit_menu.layout_menu.lay_rot_cw:'';edit_menu.layout_menu.lay_scale:'';edit_menu.mode_menu.box:'';edit_menu.mode_menu.instance:'';edit_menu.mode_menu.partial:'';edit_menu.mode_menu.path:'';edit_menu.mode_menu.polygon:'';edit_menu.mode_menu.text:'';edit_menu.search_replace_editor:'';edit_menu.selection_menu.align:'';edit_menu.selection_menu.change_layer:'';edit_menu.selection_menu.convert_to_cell:'';edit_menu.selection_menu.convert_to_pcell:'';edit_menu.selection_menu.difference:'';edit_menu.selection_menu.flatten_insts:'';edit_menu.selection_menu.intersection:'';edit_menu.selection_menu.make_array:'';edit_menu.selection_menu.make_cell:'';edit_menu.selection_menu.make_cell_variants:'';edit_menu.selection_menu.move_hier_up:'';edit_menu.selection_menu.resolve_arefs:'';edit_menu.selection_menu.round_corners:'';edit_menu.selection_menu.separate:'';edit_menu.selection_menu.size:'';edit_menu.selection_menu.tap:'';edit_menu.selection_menu.union:'';edit_menu.utils_menu:'';edit_menu.utils_menu.clip_tool:'';edit_menu.utils_menu.fill_tool:'';file_menu.new_layout:'';file_menu.new_panel:'';view_menu.edit_top_level_selection:'';tools_menu.drc.macro_in_menu_drc_sky130:'';tools_menu.drc.macro_in_menu_drc_sky130_1:'';tools_menu.lvs.macro_in_menu_lvs_sky130:'';'@hcp_context_menu.macro_in_menu_replace_cells':'';'@hcp_context_menu.macro_in_menu_write_childcells':'';'@hcp_context_menu.sorting.by_area_reverse':'';'@secrets.select_next_item':'';'@secrets.select_next_item_add':'';bookmark_menu.open_recent_menu_bookmarks:'';edit_menu.select_menu.pi_enable_16:'';edit_menu.select_menu.pi_enable_18:'';edit_menu.select_menu.pi_enable_19:'';edit_menu.select_menu.pi_enable_20:'';edit_menu.selection_menu.macro_in_menu_scale_anisotropic:'';file_menu.macro_in_menu_screenshot:'';file_menu.open_recent_menu_layer_props:'';file_menu.open_recent_menu_sessions:'';macros_menu.macro_in_menu_array_of_labels:'';tools_menu.macro_in_menu_calc_area:'';tools_menu.macro_in_menu_calc_area_hier:'';tools_menu.macro_in_menu_cell_bbox:'';tools_menu.macro_in_menu_dump_flat_shapes:'';tools_menu.macro_in_menu_list_layers:'';tools_menu.macro_in_menu_search_odd_width_paths:'';view_menu.mouse_tracking:'';view_menu.show_images:'';tools_menu.drc.macro_in_menu_drc_1:'';tools_menu.drc.macro_in_menu_drc_2:'' + CIRCUIT_ + DEVICE_ + NET_ + 'PR_' + true + true + 1000 + #800000 + 255,0,0 0,255,0 0,0,255 0,0,0 255,0,255 0,255,255 160,80,255 136,45,0 + true + -1 + 1 + 50 + 3 + false + -1 + 100000000 + false + 1 + dont-change + NetlistBrowserDialog="AdnQywACAAAAAAG6AAAAAAAABZwAAAP4AAABvQAAAB0AAAWZAAAD9QAAAAAAAAAABpA=";splitter_2="AAAA/wAAAAEAAAABAAACAAEAAAAGAQAAAAEB";splitter="AAAA/wAAAAEAAAACAAAAAAAAA/ABAAAABgEAAAABAQ==";directory_tree="AAAA/wAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAADAgAAAAEAAAABAAAAGQAAA7UAAAADAQEAAQAAAAAAAAAAAAAAAJYAAAAZAAAAgQAAAAAAAAADAAABtAAAAAEAAAAAAAAAAAAAAAEAAAAAAAACAQAAAAEAAAAAAAAD6AEAAACW";hierarchy_tree="AAAA/wAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAABAQAAAQAAAAAAAAAAAAAAAGQAAAAZAAAAgQAAAAAAAAABAAAAZAAAAAEAAAAAAAAD6AEAAABk"; + false + true + false + true + + 0 1 2 3 + + python + + + true + true + DejaVu Sans + 13 + + 2 + + false + true + basic:'Alert'=(bold:true,color:'#bf0303',background:'#f7e7e7'),'Attribute'=(color:'#0057ae'),'Base-N Integer'=(color:'#b07e00'),'Built-in'=(bold:true,color:'#644a9b'),'Character'=(color:'#ff80e0'),'Comment'=(italic:true,color:'#888786'),'Control Flow'=(bold:true,color:'#1f1c1b'),'Data Type'=(color:'#0057ae'),'Decimal/Value'=(color:'#b07e00'),'Error'=(color:'#bf0303'),'Extension'=(color:'#0095ff'),'Floating Point'=(color:'#b07e00'),'Function'=(color:'#442886'),'Import'=(color:'#ff5500'),'Keyword'=(bold:true),'Normal'=(),'Operator'=(color:'#1f1c1b'),'Others'=(color:'#006e26'),'Preprocessor'=(color:'#006e28'),'Region Marker'=(color:'#0057ae',background:'#e1eaf8'),'Special Character'=(color:'#3daee9'),'Special String'=(color:'#ff5500'),'String'=(color:'#bf0303'),'Variable'=(color:'#0057ae'),'Verbatim String'=(color:'#bf0303');ruby:'Access Control'=(color:'#0000ff'),'Attribute Definition'=(),'Bin'=(),'Blockcomment'=(),'Char'=(),'Class Variable'=(),'Command'=(color:'#aa3000'),'Comment'=(),'Constant'=(),'Constant Value'=(color:'#bb1188'),'Data'=(),'Dec'=(),'Default globals'=(bold:true,color:'#c00000'),'Definition'=(),'Delimiter'=(color:'#ff9fec'),'Error'=(),'Expression'=(),'Float'=(),'GDL input'=(),'Global Constant'=(bold:true,color:'#bb1188'),'Global Variable'=(color:'#c00000'),'Here Document'=(),'Hex'=(),'Instance Variable'=(),'Kernel methods'=(color:'#000080'),'Keyword'=(),'Member'=(),'Message'=(color:'#4000a7'),'Module mixin methods'=(color:'#000080'),'Normal Text'=(),'Octal'=(),'Operator'=(color:'#ff9fec'),'Pseudo variable'=(),'RDoc Value'=(),'Raw String'=(color:'#dd4a4a'),'Region Marker'=(color:'#0000ff'),'Regular Expression'=(color:'#4a5704'),'String'=(),'Substitution'=(),'Symbol'=(color:'#d40000');python:'Builtin Function'=(),'ClassNames'=(italic:false,bold:true,color:'#fcad3d'),'Comment'=(),'Complex'=(),'Decorator'=(),'Definition Keyword'=(),'Error'=(),'Exceptions'=(),'Extensions'=(),'F-String'=(),'Float'=(),'Flow Control Keyword'=(),'Hex'=(),'Import'=(),'Int'=(),'Normal Text'=(),'Octal'=(),'Operator'=(),'Operator Keyword'=(),'Overloaders'=(),'Raw F-String'=(),'Raw String'=(),'Special Variable'=(),'String'=(),'String Char'=(),'String Substitution'=(); + 8 + + MacroEditorDialog="AdnQywACAAAAAAGRAAABrgAABYYAAATGAAABlAAAAcsAAAWDAAAEwwAAAAAAAAAACgA=";splitter="AAAA/wAAAAEAAAADAAAAnAAAAGQAAACOAQAAAAYBAAAAAgE=";splitter_2="AAAA/wAAAAEAAAADAAAAVAAAAFQAAABUAQAAAAYBAAAAAQE=";watchList="AAAA/wAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMgAAAACAQAAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAACAAAAZAAAAAEAAAAAAAAAZAAAAAEAAAAAAAAD6AD/////";variableList="AAAA/wAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMgAAAACAQAAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAACAAAAZAAAAAEAAAAAAAAAZAAAAAEAAAAAAAAD6AD/////";mainHSplitter="AAAA/wAAAAEAAAACAAABEAAAA8MBAAAABgEAAAABAQ==";splitter_7="AAAA/wAAAAEAAAABAAAAiwAAAAAGAQAAAAEB";lvs_tree="AAAA/wAAAAAAAAABAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAABAQEAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAABAAAAZAAAAAEAAAAAAAAD6AAAAABk";drc_tree="AAAA/wAAAAAAAAABAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAABAQEAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAABAAAAZAAAAAEAAAAAAAAD6AAAAABk";pymacros_tree="AAAA/wAAAAAAAAABAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAABAQEAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAABAAAAZAAAAAEAAAAAAAAD6AAAAABk";macros_tree="AAAA/wAAAAAAAAABAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQoAAAABAQEAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAABAAABCgAAAAEAAAAAAAAD6AAAAABk"; + true + '@@navigator_menu.navigator_main_menu.navigator_all_hier_levels':false;'@@navigator_menu.navigator_main_menu.navigator_freeze':false;'@@navigator_menu.navigator_main_menu.navigator_show_images':false;'@bookmarks_context_menu.follow_selection':false;'@bookmarks_context_menu.load_bookmarks':false;'@bookmarks_context_menu.manage_bookmarks':false;'@bookmarks_context_menu.save_bookmarks':false;'@hcp_context_menu.cell_user_properties':false;'@hcp_context_menu.flat_mode':false;'@hcp_context_menu.hide_cell':false;'@hcp_context_menu.open_current':false;'@hcp_context_menu.save_cell_as':false;'@hcp_context_menu.show_all':false;'@hcp_context_menu.show_as_top':false;'@hcp_context_menu.show_cell':false;'@hcp_context_menu.sorting.by_area':false;'@hcp_context_menu.sorting.by_name':false;'@hcp_context_menu.split_mode':false;'@lcp_context_menu.add_others':false;'@lcp_context_menu.clean_up':false;'@lcp_context_menu.copy':false;'@lcp_context_menu.cut':false;'@lcp_context_menu.del':false;'@lcp_context_menu.group':false;'@lcp_context_menu.hide':false;'@lcp_context_menu.hide_all':false;'@lcp_context_menu.hide_empty_layers':false;'@lcp_context_menu.insert':false;'@lcp_context_menu.invvalid':false;'@lcp_context_menu.paste':false;'@lcp_context_menu.regroup_menu.flatten':false;'@lcp_context_menu.regroup_menu.grp_d':false;'@lcp_context_menu.regroup_menu.grp_i':false;'@lcp_context_menu.regroup_menu.grp_l':false;'@lcp_context_menu.rename':false;'@lcp_context_menu.select_all':false;'@lcp_context_menu.select_source':false;'@lcp_context_menu.show':false;'@lcp_context_menu.show_all':false;'@lcp_context_menu.show_only':false;'@lcp_context_menu.sort_menu.sort_dli':false;'@lcp_context_menu.sort_menu.sort_idl':false;'@lcp_context_menu.sort_menu.sort_ild':false;'@lcp_context_menu.sort_menu.sort_ldi':false;'@lcp_context_menu.sort_menu.sort_name':false;'@lcp_context_menu.tab_menu.new_tab':false;'@lcp_context_menu.tab_menu.remove_tab':false;'@lcp_context_menu.tab_menu.rename_tab':false;'@lcp_context_menu.test_shapes_in_view':false;'@lcp_context_menu.ungroup':false;'@lcp_context_menu.valid':false;'@lcp_tabs_context_menu.new_tab':false;'@lcp_tabs_context_menu.remove_tab':false;'@lcp_tabs_context_menu.rename_tab':false;'@secrets.duplicate_interactive':false;'@secrets.paste_interactive':false;'@secrets.sel_move_interactive':false;'@toolbar.move':false;'@toolbar.next_display_state':false;'@toolbar.prev_display_state':false;'@toolbar.ruler':false;'@toolbar.select':false;'@toolbar.technology_selector':false;bookmark_menu:false;bookmark_menu.bookmark_view:false;bookmark_menu.goto_bookmark_menu:false;bookmark_menu.load_bookmarks:false;bookmark_menu.manage_bookmarks:false;bookmark_menu.save_bookmarks:false;edit_menu:false;edit_menu.add_image:false;edit_menu.cancel:false;edit_menu.clear_all_rulers:false;edit_menu.configure_rulers:false;edit_menu.copy:false;edit_menu.cut:false;edit_menu.delete:false;edit_menu.duplicate:false;edit_menu.image_menu:false;edit_menu.image_menu.bring_to_back:false;edit_menu.image_menu.bring_to_front:false;edit_menu.image_menu.clear_all_images:false;edit_menu.mode_menu:false;edit_menu.mode_menu.move:false;edit_menu.mode_menu.ruler:false;edit_menu.mode_menu.select:false;edit_menu.paste:false;edit_menu.redo:false;edit_menu.search_replace_viewer:false;edit_menu.select_menu:false;edit_menu.select_menu.disable_all:false;edit_menu.select_menu.enable_all:false;edit_menu.select_menu.pi_enable_10:false;edit_menu.select_menu.pi_enable_11:false;edit_menu.select_menu.pi_enable_12:false;edit_menu.select_menu.pi_enable_13:false;edit_menu.select_menu.pi_enable_15:false;edit_menu.select_menu.pi_enable_7:false;edit_menu.select_menu.pi_enable_8:false;edit_menu.select_menu.pi_enable_9:false;edit_menu.select_menu.select_all:false;edit_menu.select_menu.unselect_all:false;edit_menu.selection_menu:false;edit_menu.selection_menu.sel_flip_x:false;edit_menu.selection_menu.sel_flip_y:false;edit_menu.selection_menu.sel_free_rot:false;edit_menu.selection_menu.sel_move:false;edit_menu.selection_menu.sel_move_to:false;edit_menu.selection_menu.sel_rot_ccw:false;edit_menu.selection_menu.sel_rot_cw:false;edit_menu.selection_menu.sel_scale:false;edit_menu.show_properties:false;edit_menu.undo:false;file_menu:false;file_menu.clone:false;file_menu.close:false;file_menu.close_all:false;file_menu.exit:false;file_menu.import_menu:false;file_menu.import_menu.import_def:false;file_menu.import_menu.import_gerber_menu:false;file_menu.import_menu.import_gerber_menu.import_gerber_new:false;file_menu.import_menu.import_gerber_menu.import_gerber_new_free:false;file_menu.import_menu.import_gerber_menu.import_gerber_open:false;file_menu.import_menu.import_gerber_menu.import_gerber_recent:false;file_menu.import_menu.import_lef:false;file_menu.import_menu.import_stream:false;file_menu.layout_props:false;file_menu.layout_stats:false;file_menu.load_layer_props:false;file_menu.open:false;file_menu.open_new_panel:false;file_menu.open_recent_menu:false;file_menu.open_recent_menu.open_recent_1:false;file_menu.open_recent_menu.open_recent_2:false;file_menu.open_same_panel:false;file_menu.print:false;file_menu.pull_in:false;file_menu.reader_options:false;file_menu.reload:false;file_menu.restore_session:false;file_menu.save:false;file_menu.save_all:false;file_menu.save_as:false;file_menu.save_layer_props:false;file_menu.save_session:false;file_menu.screenshot:false;file_menu.setup:false;file_menu.view_log:false;file_menu.writer_options:false;help_menu:false;help_menu.about:false;help_menu.about_qt:false;help_menu.assistant:false;help_menu.show_all_tips:false;macros_menu:false;macros_menu.examples:false;macros_menu.examples.macro_in_menu_browser:false;macros_menu.examples.macro_in_menu_datamap:false;macros_menu.examples.macro_in_menu_dump_menu:false;macros_menu.examples.macro_in_menu_flatten:false;macros_menu.examples.macro_in_menu_fractal:false;macros_menu.examples.macro_in_menu_qtdialog:false;macros_menu.examples.macro_in_menu_qtrubyserver:false;macros_menu.examples.macro_in_menu_screenshots:false;macros_menu.examples.macro_in_menu_sokoban:false;macros_menu.macro_development:false;tools_menu:false;tools_menu.browse_instances:false;tools_menu.browse_markers:false;tools_menu.browse_netlists:false;tools_menu.browse_shapes:false;tools_menu.diff_tool:false;tools_menu.drc:false;tools_menu.drc.edit_script:false;tools_menu.drc.new_script:false;tools_menu.edit_layer_stack:false;tools_menu.lvs:false;tools_menu.lvs.edit_script:false;tools_menu.lvs.macro_in_menu_lvs:false;tools_menu.lvs.new_script:false;tools_menu.net_trace:false;tools_menu.packages:false;tools_menu.shapes_to_markers:false;tools_menu.shapes_to_markers.scan_layers:false;tools_menu.shapes_to_markers.scan_layers_flat:false;tools_menu.technologies:false;tools_menu.trace_all_nets_menu:false;tools_menu.trace_all_nets_menu.trace_all_nets:false;tools_menu.trace_all_nets_menu.trace_all_nets_flat:false;tools_menu.xor_tool:false;tools_menu.xsection_script_submenu:false;tools_menu.xsection_script_submenu.xsection_for_technology:false;tools_menu.xsection_script_submenu.xsection_script_load:false;view_menu:false;view_menu.default_grid:false;view_menu.default_grid.default_grid_1:false;view_menu.default_grid.default_grid_2:false;view_menu.default_grid.default_grid_3:false;view_menu.no_stipples:false;view_menu.reset_window_state:false;view_menu.show_bookmarks_view:false;view_menu.show_cell_boxes:false;view_menu.show_grid:false;view_menu.show_hierarchy_panel:false;view_menu.show_layer_panel:false;view_menu.show_layer_toolbox:false;view_menu.show_libraries_view:false;view_menu.show_markers:false;view_menu.show_navigator:false;view_menu.show_texts:false;view_menu.show_toolbar:false;view_menu.synchronized_views:false;view_menu.transient_selection:false;zoom_menu:false;zoom_menu.ascend:false;zoom_menu.dec_max_hier:false;zoom_menu.descend:false;zoom_menu.global_trans:false;zoom_menu.global_trans.m0:false;zoom_menu.global_trans.m135:false;zoom_menu.global_trans.m45:false;zoom_menu.global_trans.m90:false;zoom_menu.global_trans.r0:false;zoom_menu.global_trans.r180:false;zoom_menu.global_trans.r270:false;zoom_menu.global_trans.r90:false;zoom_menu.goto_position:false;zoom_menu.inc_max_hier:false;zoom_menu.max_hier:false;zoom_menu.max_hier_0:false;zoom_menu.max_hier_1:false;zoom_menu.next_display_state:false;zoom_menu.prev_display_state:false;zoom_menu.redraw:false;zoom_menu.select_cell:false;zoom_menu.select_current_cell:false;zoom_menu.synchronized_views:false;zoom_menu.zoom_fit:false;zoom_menu.zoom_fit_sel:false;zoom_menu.zoom_in:false;zoom_menu.zoom_out:false;edit_menu.select_menu.pi_enable_14:false;file_menu.open_recent_menu.open_recent_10:false;file_menu.open_recent_menu.open_recent_3:false;file_menu.open_recent_menu.open_recent_4:false;file_menu.open_recent_menu.open_recent_5:false;file_menu.open_recent_menu.open_recent_6:false;file_menu.open_recent_menu.open_recent_7:false;file_menu.open_recent_menu.open_recent_8:false;file_menu.open_recent_menu.open_recent_9:false;tools_menu.drc.macro_in_menu_drc:false;'@hcp_context_menu.copy':false;'@hcp_context_menu.cut':false;'@hcp_context_menu.delete_cell':false;'@hcp_context_menu.flatten_cell':false;'@hcp_context_menu.new_cell':false;'@hcp_context_menu.paste':false;'@hcp_context_menu.rename_cell':false;'@hcp_context_menu.replace_cell':false;'@toolbar.box':false;'@toolbar.combine_mode':false;'@toolbar.instance':false;'@toolbar.partial':false;'@toolbar.path':false;'@toolbar.polygon':false;'@toolbar.text':false;edit_menu.cell_menu:false;edit_menu.cell_menu.adjust_cell_origin:false;edit_menu.cell_menu.convert_cell_to_static:false;edit_menu.cell_menu.delete_cell:false;edit_menu.cell_menu.flatten_cell:false;edit_menu.cell_menu.new_cell:false;edit_menu.cell_menu.rename_cell:false;edit_menu.cell_menu.replace_cell:false;edit_menu.cell_menu.user_properties:false;edit_menu.edit_options:false;edit_menu.layer_menu:false;edit_menu.layer_menu.boolean:false;edit_menu.layer_menu.clear_layer:false;edit_menu.layer_menu.copy_layer:false;edit_menu.layer_menu.delete_layer:false;edit_menu.layer_menu.edit_layer:false;edit_menu.layer_menu.merge:false;edit_menu.layer_menu.new_layer:false;edit_menu.layer_menu.size:false;edit_menu.layout_menu:false;edit_menu.layout_menu.lay_convert_to_static:false;edit_menu.layout_menu.lay_flip_x:false;edit_menu.layout_menu.lay_flip_y:false;edit_menu.layout_menu.lay_free_rot:false;edit_menu.layout_menu.lay_move:false;edit_menu.layout_menu.lay_rot_ccw:false;edit_menu.layout_menu.lay_rot_cw:false;edit_menu.layout_menu.lay_scale:false;edit_menu.mode_menu.box:false;edit_menu.mode_menu.instance:false;edit_menu.mode_menu.partial:false;edit_menu.mode_menu.path:false;edit_menu.mode_menu.polygon:false;edit_menu.mode_menu.text:false;edit_menu.search_replace_editor:false;edit_menu.selection_menu.align:false;edit_menu.selection_menu.change_layer:false;edit_menu.selection_menu.convert_to_cell:false;edit_menu.selection_menu.convert_to_pcell:false;edit_menu.selection_menu.difference:false;edit_menu.selection_menu.flatten_insts:false;edit_menu.selection_menu.intersection:false;edit_menu.selection_menu.make_array:false;edit_menu.selection_menu.make_cell:false;edit_menu.selection_menu.make_cell_variants:false;edit_menu.selection_menu.move_hier_up:false;edit_menu.selection_menu.resolve_arefs:false;edit_menu.selection_menu.round_corners:false;edit_menu.selection_menu.separate:false;edit_menu.selection_menu.size:false;edit_menu.selection_menu.tap:false;edit_menu.selection_menu.union:false;edit_menu.utils_menu:false;edit_menu.utils_menu.clip_tool:false;edit_menu.utils_menu.fill_tool:false;file_menu.new_layout:false;file_menu.new_panel:false;view_menu.edit_top_level_selection:false;tools_menu.drc.macro_in_menu_drc_sky130:false;tools_menu.drc.macro_in_menu_drc_sky130_1:false;tools_menu.lvs.macro_in_menu_lvs_sky130:false;'@hcp_context_menu.macro_in_menu_replace_cells':false;'@hcp_context_menu.macro_in_menu_write_childcells':false;'@hcp_context_menu.sorting.by_area_reverse':false;'@secrets.select_next_item':false;'@secrets.select_next_item_add':false;bookmark_menu.open_recent_menu_bookmarks:false;edit_menu.select_menu.pi_enable_16:false;edit_menu.select_menu.pi_enable_18:false;edit_menu.select_menu.pi_enable_19:false;edit_menu.select_menu.pi_enable_20:false;edit_menu.selection_menu.macro_in_menu_scale_anisotropic:false;file_menu.macro_in_menu_screenshot:false;file_menu.open_recent_menu_layer_props:false;file_menu.open_recent_menu_sessions:false;macros_menu.macro_in_menu_array_of_labels:false;tools_menu.macro_in_menu_calc_area:false;tools_menu.macro_in_menu_calc_area_hier:false;tools_menu.macro_in_menu_cell_bbox:false;tools_menu.macro_in_menu_dump_flat_shapes:false;tools_menu.macro_in_menu_list_layers:false;tools_menu.macro_in_menu_search_odd_width_paths:false;view_menu.mouse_tracking:false;view_menu.show_images:false;tools_menu.drc.macro_in_menu_drc_1:false;tools_menu.drc.macro_in_menu_drc_2:false + 16 + 1 + '/mnt/shuttles/mpw-two-b/slot-005/fabulous_sky/gds/user_project_wrapper.gds.gz'@'sky130A' '/mnt/shuttles/mpw-two-b/slot-005/fabulous_sky/gds/user_project_wrapper.gds.gz.x'@'sky130A' '/mnt/shuttles/mpw-two-b/slot-021/SOFA-Plus-eFPGA/gds/user_project_wrapper.gds.gz'@'sky130A' '/mnt/shuttles/mpw-two-b/slot-005/fabulous_sky/gds/xor.gds'@'sky130A' '/mnt/shuttles/mpw-two-b/slot-005/fabulous_sky/gds/user_project_wrapper.gds.gz.ef'@'sky130A' '/mnt/shuttles/mpw-two-b/slot-012/fuserisc/gds/user_project_wrapper.gds.gz'@'sky130A' '/mnt/shuttles/mpw-two/slot-025/fast_gcd_for_large_i/gds/caravel_00020019.oas'@'sky130A' '/mnt/shuttles/mpw-two/slot-013/amsat_txrx_ic_mpw2/gds/caravel_0002000d.oas'@'sky130A' '/mnt/shuttles/mpw-two/slot-008/lexicon/gds/caravel_00020008.oas'@'sky130A' '/mnt/shuttles/mpw-two/slot-005/fabulous_sky/gds/caravel_00020005.oas'@'sky130A' + + + + false + true + false + auto + 255,0,0 0,255,0 0,0,255 255,255,0 255,0,255 0,255,255 160,80,255 255,160,0 + true + -1 + -1 + 50 + -1 + -1 + 1000000 + 0 + 1 + dont-change + 0.15 + 2 + + database-top + #ff0000 + -1 + 1 + 3 + -1 + 10000000 + false + 3 + fit-marker + MarkerBrowserDialog="AdnQywACAAAAAAXtAAACiQAAB/UAAATRAAAF8AAAAqYAAAfyAAAEzgAAAAAAAAAACBE=";splitter_2="AAAA/wAAAAEAAAACAAABAAAAAOsBAAAABgEAAAABAQ==";splitter="AAAA/wAAAAEAAAACAAAA+wAAAP8BAAAABgEAAAACAQ==";markers_list="AAAA/wAAAAAAAAABAAAAAQAAAAMBAAAABAAAAAAAAAACAAAAAwAAAAEAAAAEAAAAAAAAAAMAAAABAAAAAgAAAAAAAAAAAAAE9AAAAAQBAQABAAAAAAAAAAAAAAAAZAAAABgAAACBAAAAAAAAAAQAAABkAAAAAQAAAAAAAANPAAAAAQAAAAAAAABkAAAAAQAAAAAAAADdAAAAAQAAAAAAAAPoAAAAAN0=";directory_tree="AAAA/wAAAAAAAAABAAAAAQAAAAEBAAAAAAAAAAAAAAAAAAAAAAAAAesAAAACAQEAAQAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAACAAABCgAAAAEAAAAAAAAA4QAAAAEAAAAAAAAD6AD/////"; + false + #ff0000 + true + true + true + any + 8 + mode=normal,title=Ruler,category=_ruler,fmt=$D,fmt_x=$X,fmt_y=$Y,position=auto,xalign=auto,yalign=auto,xlabel_xalign=auto,xlabel_yalign=auto,ylabel_xalign=auto,ylabel_yalign=auto,style=cross_both,outline=diag,snap=true,angle_constraint=global;mode=single_click,title=Cross,category=_cross,fmt='$U,$V',fmt_x='',fmt_y='',position=auto,xalign=auto,yalign=auto,xlabel_xalign=auto,xlabel_yalign=auto,ylabel_xalign=auto,ylabel_yalign=auto,style=cross_both,outline=diag,snap=true,angle_constraint=global;mode=auto_metric,title=Measure,category=_measure,fmt=$D,fmt_x=$X,fmt_y=$Y,position=auto,xalign=auto,yalign=auto,xlabel_xalign=auto,xlabel_yalign=auto,ylabel_xalign=auto,ylabel_yalign=auto,style=ruler,outline=diag,snap=true,angle_constraint=global;mode=normal,title=Ellipse,category='',fmt='',fmt_x='W=$(abs(X))',fmt_y='H=$(abs(Y))',position=auto,xalign=auto,yalign=auto,xlabel_xalign=auto,xlabel_yalign=auto,ylabel_xalign=auto,ylabel_yalign=auto,style=line,outline=ellipse,snap=true,angle_constraint=global;mode=normal,title=Box,category='',fmt='',fmt_x='W=$(abs(X))',fmt_y='H=$(abs(Y))',position=auto,xalign=auto,yalign=auto,xlabel_xalign=auto,xlabel_yalign=auto,ylabel_xalign=auto,ylabel_yalign=auto,style=cross_both,outline=box,snap=true,angle_constraint=global;mode=normal,title=XSection,category=XS,fmt=XS,fmt_x='',fmt_y='',position=auto,xalign=auto,yalign=auto,xlabel_xalign=auto,xlabel_yalign=auto,ylabel_xalign=auto,ylabel_yalign=auto,style=arrow_both,outline=diag,snap=true,angle_constraint=global + -1 + + 5 + 0 + #ff0000 + 1 + true + false + 1 + true + 3 + + any-top + 100000000 + 100000000 + 1 + dont-change + + false + true + true + true + false + false + false + true + false + false + current-cell + == + + + == + + ~ + deconv_kernel_estimator_to_VIA15 + + == + + == + + == + + + == + + == + + + == + + + == + + == + + ~ + + 1000 + delete + 'instances of cell deconv_kernel_estimator_top_level.* where cell_name ~ "deconv_kernel_estimator_to_VIA15"';'delete instances of cell deconv_kernel_estimator_top_level.* where cell_name ~ "deconv_kernel_estimator_to_VIA15"' + instance + + 1 + fit-marker + search_replace_dialog="AdnQywACAAAAAACKAAAAwQAABcwAAAM3AAAAjQAAAN4AAAXJAAADNAAAAAAAAAAABoA=";splitter="AAAA/wAAAAEAAAACAAABTQAAAQAB/////wEAAAABAA==";results="AAAA/wAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx0AAAAEAQAAAAAAAAAAAAAAAAAAAGT/////AAAAgQAAAAAAAAAEAAABggAAAAEAAAAAAAAA6wAAAAEAAAAAAAAAcQAAAAEAAAAAAAAAPwAAAAEAAAAAAAAD6AD/////"; + true + 0 1 2 3 4 5[1] 6 7 8 9[0] 10 11 12 13 14 15 + <?xml version="1.0" encoding="utf-8"?> +<stream-import-data> + <files> + <file>/mnt/shuttles/mpw-two-b/slot-012/fuserisc/gds/cus_tg_mux41_buf</file> + </files> + <cell-name/> + <layer-offset/> + <layer-mode>original</layer-mode> + <import-mode>extra</import-mode> + <reference-points> + </reference-points> + <explicit-trans>r0 *1 0,0</explicit-trans> + <options> + <gds2> + <box-mode>1</box-mode> + <allow-big-records>true</allow-big-records> + <allow-multi-xy-records>true</allow-multi-xy-records> + </gds2> + <common> + <create-other-layers>true</create-other-layers> + <layer-map>layer_map()</layer-map> + <enable-properties>true</enable-properties> + <enable-text-objects>true</enable-text-objects> + </common> + <lefdef> + <read-all-layers>true</read-all-layers> + <layer-map>layer_map()</layer-map> + <dbu>0.001</dbu> + <produce-net-names>true</produce-net-names> + <net-property-name>#1</net-property-name> + <produce-inst-names>true</produce-inst-names> + <inst-property-name>#1</inst-property-name> + <produce-pin-names>false</produce-pin-names> + <pin-property-name>#1</pin-property-name> + <produce-cell-outlines>true</produce-cell-outlines> + <cell-outline-layer>OUTLINE</cell-outline-layer> + <produce-placement-blockages>true</produce-placement-blockages> + <placement-blockage-layer>PLACEMENT_BLK</placement-blockage-layer> + <produce-regions>true</produce-regions> + <region-layer>REGIONS</region-layer> + <produce-via-geometry>true</produce-via-geometry> + <via-geometry-suffix/> + <via-geometry-datatype>0</via-geometry-datatype> + <produce-pins>true</produce-pins> + <pins-suffix>.PIN</pins-suffix> + <pins-datatype>2</pins-datatype> + <produce-obstructions>true</produce-obstructions> + <obstructions-suffix>.OBS</obstructions-suffix> + <obstructions-datatype>3</obstructions-datatype> + <produce-blockages>true</produce-blockages> + <blockages-suffix>.BLK</blockages-suffix> + <blockages-datatype>4</blockages-datatype> + <produce-labels>true</produce-labels> + <labels-suffix>.LABEL</labels-suffix> + <labels-datatype>1</labels-datatype> + <produce-routing>true</produce-routing> + <routing-suffix/> + <routing-datatype>0</routing-datatype> + </lefdef> + <dxf> + <dbu>0.001</dbu> + <unit>1</unit> + <text-scaling>100</text-scaling> + <circle-points>100</circle-points> + <circle-accuracy>0</circle-accuracy> + <contour-accuracy>0</contour-accuracy> + <polyline-mode>0</polyline-mode> + <render-texts-as-polygons>false</render-texts-as-polygons> + <keep-other-cells>false</keep-other-cells> + <keep-layer-names>false</keep-layer-names> + <create-other-layers>true</create-other-layers> + <layer-map>layer_map()</layer-map> + </dxf> + <cif> + <wire-mode>0</wire-mode> + <dbu>0.001</dbu> + <layer-map>layer_map()</layer-map> + <create-other-layers>true</create-other-layers> + <keep-layer-names>false</keep-layer-names> + </cif> + <mag> + <lambda>1</lambda> + <dbu>0.001</dbu> + <layer-map>layer_map()</layer-map> + <create-other-layers>true</create-other-layers> + <keep-layer-names>false</keep-layer-names> + <merge>true</merge> + <lib-paths> + </lib-paths> + </mag> + </options> +</stream-import-data> + + true + + <?xml version="1.0" encoding="utf-8"?> +<technologies> + <technology> + <name/> + <description>(Default)</description> + <group/> + <dbu>0.001</dbu> + <base-path/> + <original-base-path/> + <layer-properties_file/> + <add-other-layers>true</add-other-layers> + <reader-options> + <gds2> + <box-mode>1</box-mode> + <allow-big-records>true</allow-big-records> + <allow-multi-xy-records>true</allow-multi-xy-records> + </gds2> + <common> + <create-other-layers>true</create-other-layers> + <layer-map>layer_map()</layer-map> + <enable-properties>true</enable-properties> + <enable-text-objects>true</enable-text-objects> + </common> + <lefdef> + <read-all-layers>true</read-all-layers> + <layer-map>layer_map()</layer-map> + <dbu>0.001</dbu> + <produce-net-names>true</produce-net-names> + <net-property-name>#1</net-property-name> + <produce-inst-names>true</produce-inst-names> + <inst-property-name>#1</inst-property-name> + <produce-pin-names>false</produce-pin-names> + <pin-property-name>#1</pin-property-name> + <produce-cell-outlines>true</produce-cell-outlines> + <cell-outline-layer>OUTLINE</cell-outline-layer> + <produce-placement-blockages>true</produce-placement-blockages> + <placement-blockage-layer>PLACEMENT_BLK</placement-blockage-layer> + <produce-regions>true</produce-regions> + <region-layer>REGIONS</region-layer> + <produce-via-geometry>true</produce-via-geometry> + <via-geometry-suffix/> + <via-geometry-datatype>0</via-geometry-datatype> + <produce-pins>true</produce-pins> + <pins-suffix>.PIN</pins-suffix> + <pins-datatype>2</pins-datatype> + <produce-obstructions>true</produce-obstructions> + <obstructions-suffix>.OBS</obstructions-suffix> + <obstructions-datatype>3</obstructions-datatype> + <produce-blockages>true</produce-blockages> + <blockages-suffix>.BLK</blockages-suffix> + <blockages-datatype>4</blockages-datatype> + <produce-labels>true</produce-labels> + <labels-suffix>.LABEL</labels-suffix> + <labels-datatype>1</labels-datatype> + <produce-routing>true</produce-routing> + <routing-suffix/> + <routing-datatype>0</routing-datatype> + </lefdef> + <dxf> + <dbu>0.001</dbu> + <unit>1</unit> + <text-scaling>100</text-scaling> + <circle-points>100</circle-points> + <circle-accuracy>0</circle-accuracy> + <contour-accuracy>0</contour-accuracy> + <polyline-mode>0</polyline-mode> + <render-texts-as-polygons>false</render-texts-as-polygons> + <keep-other-cells>false</keep-other-cells> + <keep-layer-names>false</keep-layer-names> + <create-other-layers>true</create-other-layers> + <layer-map>layer_map()</layer-map> + </dxf> + <cif> + <wire-mode>0</wire-mode> + <dbu>0.001</dbu> + <layer-map>layer_map()</layer-map> + <create-other-layers>true</create-other-layers> + <keep-layer-names>false</keep-layer-names> + </cif> + <mag> + <lambda>1</lambda> + <dbu>0.001</dbu> + <layer-map>layer_map()</layer-map> + <create-other-layers>true</create-other-layers> + <keep-layer-names>false</keep-layer-names> + <merge>true</merge> + <lib-paths> + </lib-paths> + </mag> + </reader-options> + <writer-options> + <gds2> + <write-timestamps>true</write-timestamps> + <write-cell-properties>false</write-cell-properties> + <write-file-properties>false</write-file-properties> + <no-zero-length-paths>false</no-zero-length-paths> + <multi-xy-records>false</multi-xy-records> + <max-vertex-count>8000</max-vertex-count> + <max-cellname-length>32000</max-cellname-length> + <libname>LIB</libname> + </gds2> + <oasis> + <compression-level>2</compression-level> + <write-cblocks>false</write-cblocks> + <strict-mode>false</strict-mode> + <write-std-properties>1</write-std-properties> + <subst-char>*</subst-char> + <permissive>false</permissive> + </oasis> + <cif> + <polygon-mode>0</polygon-mode> + </cif> + <cif> + <dummy-calls>false</dummy-calls> + <blank-separator>false</blank-separator> + </cif> + <mag> + <lambda>0</lambda> + <tech/> + <write-timestamp>true</write-timestamp> + </mag> + </writer-options> + <connectivity> + </connectivity> + </technology> +</technologies> + + false + auto + 0 + true + true + only-top-level-shown-by-default=3,editor-mode=4,editor-mode=0,hide-empty-layers=4,hide-empty-layers=0,has-non-add-edit-combine-mode=4,has-non-add-edit-combine-mode=0 + auto + true + AdnQywACAAAAAADEAAAAAAAAB8QAAAT7AAAAxwAAAB0AAAfBAAAE+AAAAAAAAAAACBE= + AAAA/wAAAAD9AAAAAgAAAAAAAAGaAAAEePwCAAAABPsAAAAcAGgAcABfAGQAbwBjAGsAXwB3AGkAZABnAGUAdAEAAABOAAAEeAAAABMA////+wAAACoAbgBhAHYAaQBnAGEAdABvAHIAXwBkAG8AYwBrAF8AdwBpAGQAZwBlAHQAAAAAAP////8AAACNAP////sAAAAgAGwAaQBiAHMAXwBkAG8AYwBrAF8AdwBpAGQAZwBlAHQAAAAAUgAAA5cAAAATAP////sAAAAcAGUAbwBfAGQAbwBjAGsAXwB3AGkAZABnAGUAdAAAAAAA/////wAAAAAAAAAAAAAAAQAAANcAAAR4/AIAAAAD+wAAACoAYgBvAG8AawBtAGEAcgBrAHMAXwBkAG8AYwBrAF8AdwBpAGQAZwBlAHQAAAAAAP////8AAAATAP////sAAAAcAGwAcABfAGQAbwBjAGsAXwB3AGkAZABnAGUAdAEAAABOAAAD7QAAABMA////+wAAABwAbAB0AF8AZABvAGMAawBfAHcAaQBkAGcAZQB0AQAABEEAAACFAAAAhQAAAIUAAAR+AAAEeAAAAAQAAAAEAAAACAAAAAj8AAAAAQAAAAIAAAABAAAADgB0AG8AbwBsAGIAYQByAQAAAAD/////AAAAAAAAAAA= + false + true + false + false + all + + 90 + rdb + all + true + 200 + true + 0 + diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.lydrc b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.lydrc new file mode 100755 index 00000000..e2481410 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.lydrc @@ -0,0 +1,918 @@ + + + + + drc + + + + false + false + + true + drc_scripts + tools_menu.drc.end + dsl + drc-dsl-xml + # +# DRC for SKY130 according to : +# https://skywater-pdk.readthedocs.io/en/latest/rules/periphery.html +# https://skywater-pdk.readthedocs.io/en/latest/rules/layers.html +# +# Distributed under GNU GPLv3: https://www.gnu.org/licenses/ +# +# History : +# 2020-10-04 : v1.0 : initial release +# +########################################################################################## + +# optionnal for a batch launch : klayout -b -rd input=my_layout.gds -rd report=sky130_drc.txt -r drc_sky130.drc +if $input + source($input) +end + +if $report + report("SKY130 DRC runset", $report) +else + report("SKY130 DRC runset", File.join(File.dirname(RBA::CellView::active.filename), "sky130_drc.txt")) +end + +AL = true # do not change +CU = false # do not change +# choose betwen only one of AL or CU back-end flow here : +backend_flow = AL + +# enable / disable rule groups +FEOL = false # front-end-of-line checks +BEOL = true # back-end-of-line checks +OFFGRID = true # manufacturing grid/angle checks + +# klayout setup +######################## +# use a tile size of 1mm - not used in deep mode- +tiles(1000.um) +# use a tile border of 10 micron: +tile_borders(1.um) +#no_borders + +# hierachical +deep + +# use 4 cpu cores +threads(4) +# if more inof is needed, set true +verbose(true) + +# layers definitions +######################## + +# all except purpose (datatype) 5 -- label and 44 -- via +li_wildcard = "67/0-4,6-43,45-*" +mcon_wildcard = "67/44" + +m1_wildcard = "68/0-4,6-43,45-*" +via_wildcard = "68/44" + +m2_wildcard = "69/0-4,6-43,45-*" +via2_wildcard = "69/44" + +m3_wildcard = "70/0-4,6-43,45-*" +via3_wildcard = "70/44" + +m4_wildcard = "71/0-4,6-43,45-*" +via4_wildcard = "71/44" + +m5_wildcard = "72/0-4,6-43,45-*" + +diff = input(65, 20) +tap = polygons(65, 44) +nwell = polygons(64, 20) +dnwell = polygons(64, 18) +pwbm = polygons(19, 44) +pwde = polygons(124, 20) +natfet = polygons(124, 21) +hvtr = polygons(18, 20) +hvtp = polygons(78, 44) +ldntm = polygons(11, 44) +hvi = polygons(75, 20) +tunm = polygons(80, 20) +lvtn = polygons(125, 44) +poly = polygons(66, 20) +hvntm = polygons(125, 20) +nsdm = polygons(93, 44) +psdm = polygons(94, 20) +rpm = polygons(86, 20) +urpm = polygons(79, 20) +npc = polygons(95, 20) +licon = polygons(66, 44) + +li = polygons(li_wildcard) +mcon = polygons(mcon_wildcard) + +m1 = polygons(m1_wildcard) +via = polygons(via_wildcard) + +m2 = polygons(m2_wildcard) +via2 = polygons(via2_wildcard) + +m3 = polygons(m3_wildcard) +via3 = polygons(via3_wildcard) + +m4 = polygons(m4_wildcard) +via4 = polygons(via4_wildcard) + +m5 = polygons(m5_wildcard) + +pad = polygons(76, 20) +nsm = polygons(61, 20) +capm = polygons(89, 44) +cap2m = polygons(97, 44) +vhvi = polygons(74, 21) +uhvi = polygons(74, 22) +npn = polygons(82, 20) +inductor = polygons(82, 24) +vpp = polygons(82, 64) +pnp = polygons(82, 44) +lvs_prune = polygons(84, 44) +ncm = polygons(92, 44) +padcenter = polygons(81, 20) +mf = polygons(76, 44) +areaid_sl = polygons(81, 1) +areaid_ce = polygons(81, 2) +areaid_fe = polygons(81, 3) +areaid_sc = polygons(81, 4) +areaid_sf = polygons(81, 6) +areaid_sw = polygons(81, 7) +areaid_sr = polygons(81, 8) +areaid_mt = polygons(81, 10) +areaid_dt = polygons(81, 11) +areaid_ft = polygons(81, 12) +areaid_ww = polygons(81, 13) +areaid_ld = polygons(81, 14) +areaid_ns = polygons(81, 15) +areaid_ij = polygons(81, 17) +areaid_zr = polygons(81, 18) +areaid_ed = polygons(81, 19) +areaid_de = polygons(81, 23) +areaid_rd = polygons(81, 24) +areaid_dn = polygons(81, 50) +areaid_cr = polygons(81, 51) +areaid_cd = polygons(81, 52) +areaid_st = polygons(81, 53) +areaid_op = polygons(81, 54) +areaid_en = polygons(81, 57) +areaid_en20 = polygons(81, 58) +areaid_le = polygons(81, 60) +areaid_hl = polygons(81, 63) +areaid_sd = polygons(81, 70) +areaid_po = polygons(81, 81) +areaid_it = polygons(81, 84) +areaid_et = polygons(81, 101) +areaid_lvt = polygons(81, 108) +areaid_re = polygons(81, 125) +areaid_ag = polygons(81, 79) +poly_rs = polygons(66, 13) +diff_rs = polygons(65, 13) +pwell_rs = polygons(64, 13) +li_rs = polygons(67, 13) +cfom = polygons(22, 20) + + +# Define a new custom function that selects polygons by their number of holes: +# It will return a new layer containing those polygons with min to max holes. +# max can be nil to omit the upper limit. +class DRC::DRCLayer + def with_holes(min, max) + new_data = RBA::Region::new + self.data.each do |p| + if p.holes >= (min || 0) && (!max || p.holes <= max) + new_data.insert(p) + end + end + DRC::DRCLayer::new(@engine, new_data) + end +end + +# DRC section +######################## +info("DRC section") + +if FEOL +info("FEOL section") +gate = diff & poly + +# dnwell +dnwell.width(3.0, euclidian).output("dnwell.2", "dnwell.2 : min. dnwell width : 3.0um") +dnwell.not(uhvi).not(areaid_po).isolated(6.3, euclidian).output("dnwell.3", "dnwell.3 : min. dnwell spacing : 6.3um") +dnwell.and(pnp).output("dnwell.4", "dnwell.4 : dnwell must not overlap pnp") +dnwell.and(psdm).edges.not(psdm.edges).output("dnwell.5", "p+ must not straddle dnwell") +# dnwell.6 rue not coded + +# nwell +nwell.width(0.84, euclidian).output("nwell.1", "nwell.1 : min. nwell width : 0.84um") +nwell.isolated(1.27, euclidian).output("nwell.2a", "nwell.2a : min. nwell spacing (merged if less) : 1.27um") +# rule nwell.4 is suitable for digital cells +#nwell.not(uhvi).not(areaid_en20).not_interacting(tap.and(licon).and(li)).output("nwell.4", "nwell4 : all nwell exempt inside uhvi must contain a n+tap") +nwell.enclosing(dnwell.not(uhvi).not(areaid_po), 0.4, euclidian).output("nwell.5", "nwell.5 : min. nwell enclosing dnwell exempt unside uhvi : 0.4um") +dnwell.enclosing(nwell.not(uhvi), 1.03, euclidian).output("nwell.6", "nwell.6 : min. dnwell enclosing nwell exempt unside uhvi : 1.03um") +dnwell.separation(nwell, 4.5, euclidian).output("nwell.7", "nwell.7 : min. dnwell separation nwell : 4.5um") + +# pwbm +pwbm.not(uhvi).output("pwbm", "pwbm must be inside uhvi") +dnwell.and(uhvi).edges.not(pwbm).output("pwbm.4", "pwbm.4 : dnwell inside uhvi must be enclosed by pwbm") + +# pwde +pwde.not(pwbm).output("pwdem.3", "pwdem.3 : pwde must be inside pwbm") +pwde.not(uhvi).output("pwdem.4", "pwdem.4 : pwde must be inside uhvi") +pwde.not(dnwell).output("pwdem.5", "pwdem.5 : pwde must be inside dnwell") + +# hvtp +#hvtp.not(nwell).output("hvtp", "hvtp must inside nwell") +hvtp.width(0.38, euclidian).output("hvtp.1", "hvtp.1 : min. hvtp width : 0.38um") +hvtp.isolated(0.38, euclidian).output("hvtp.2", "hvtp.2 : min. hvtp spacing : 0.38um") +hvtp.enclosing(gate.and(psdm), 0.18, euclidian).output("hvtp.3", "hvtp.3 : min. hvtp enclosure of pfet gate : 0.18um") +hvtp.separation(gate.and(psdm), 0.18, euclidian).output("hvtp.4", "hvtp.4 : min. hvtp spacing pfet gate: 0.18um") +hvtp.with_area(0..0.265).output("hvtp.5", "hvtp.5 : min. hvtp area : 0.265um²") + +# hvtr +hvtr.width(0.38, euclidian).output("hvtr.1", "hvtr.1 : min. hvtr width : 0.38um") +hvtr.isolated(0.38, euclidian).output("hvtr.2", "hvtr.2 : min. hvtr spacing : 0.38um") + +# lvtn +lvtn.width(0.38, euclidian).output("lvtn.1", "lvtn.1 : min. lvtn width : 0.38um") +lvtn.isolated(0.38, euclidian).output("lvtn.2", "lvtn.2 : min. lvtn spacing : 0.38um") +lvtn.separation(diff.and(poly).not(uhvi), 0.18, euclidian).output("lvtn.3a", "lvtn.3a : min. lvtn spacing to gate : 0.18um") +lvtn.separation(diff.and(nwell).not(poly), 0.235, projection).output("lvtn.3b", "lvtn.3b : min. lvtn spacing to pfet s/d : 0.18um") +lvtn.enclosing(gate.not(uhvi), 0.18, euclidian).output("lvtn.4b", "lvtn.4b : min. lvtn enclosing to gate : 0.18um") +lvtn.separation(hvtp, 0.38, euclidian).output("lvtn.9", "lvtn.9 : min. lvtn spacing hvtp : 0.38um") +nwell.not_interacting(gate.and(nwell.not(hvi).not(areaid_ce))).enclosing(lvtn.not(uhvi), 0.18, euclidian).polygons.without_area(0).output("lvtn.4b", "lvtn.4b : min. lvtn enclosure of gate : 0.18um") +lvtn.separation(nwell.inside(areaid_ce), 0.38, euclidian).output("lvtn.12", "lvtn.12 : min. lvtn spacing nwell inside areaid.ce : 0.38um") +lvtn.with_area(0..0.265).output("lvtn.13", "lvtn.13 : min. lvtn area : 0.265um²") + +# ncm +ncm.and(tap.and(nwell).or(diff.not(nwell))).output("ncm.x.3", "ncm.x.3 : ncm must not overlap n+diff") +ncm.width(0.38, euclidian).output("ncm.1", "ncm.1 : min. ncm width : 0.38um") +ncm.isolated(0.38, euclidian).output("ncm.2", "ncm.2 : min. ncm spacing manual merge if smaller : 0.38um") +ncm.enclosing(diff.and(nwell), 0.18, euclidian).output("ncm.3", "ncm.3 : min. ncm enclosure of p+diff : 0.18um") +ncm.separation(lvtn.and(diff), 0.23, euclidian).output("ncm.5", "ncm.5 : min. ncm spacing lvtn diff : 0.23um") +ncm.separation(diff.not(nwell), 0.2, euclidian).output("ncm.6", "ncm.6 : min. ncm spacing nfet : 0.2um") +ncm.with_area(0..0.265).output("ncm.7", "ncm.13 : min. ncm area : 0.265um²") + +# diff-tap +difftap = diff + tap +difftap.width(0.15, euclidian).output("difftap.1", "difftap.1 : min. difftap width : 0.15um") +not_in_cell1 = layout(source.cell_obj).select("s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b" , "-s8fpls_pl8", "-s8fpls_rdrv4" , "-s8fpls_rdrv4f", "-s8fpls_rdrv8") +not_in_cell1_diff = not_in_cell1.input(65, 20) +not_in_cell1_diff.not(areaid_sc).not(poly).edges.and(gate.edges).with_length(0,0.42).output("difftap.2", "difftap.2: min. gate (exempt areaid.sc) width : 0.42um") +diff.and(areaid_sc).not(poly).edges.and(gate.edges).with_length(0,0.36).output("difftap.2", "difftap.2: min. gate inside areaid.sc width : 0.36um") +difftap.isolated(0.27, euclidian).output("difftap.3", "difftap.3 : min. difftap spacing : 0.27um") +tap.edges.and(diff.edges).with_length(0,0.29).output("difftap.4", "difftap.4 : min. tap bound by diffusion : 0.29um") +tap.edges.and(diff.edges).space(0.4, projection).output("difftap.5", "difftap.5 : min. tap bound by 2 diffusions : 0.4um") +(tap.edges.and(diff.edges)).extended(0.01, 0.01, 0, 0, false).not(tap.and(diff)).and(diff.or(tap)).output("difftap.6", "difftap.6 : diff and tap not allowed to extend beyong their abutting ege") +tap.edges.not_interacting(diff.edges).separation(diff.edges, 0.13, euclidian).output("difftap.7", "difftap.7 : min. diff/tap spacing to non-coincident diff edge : 0.13um") +diff.edges.not_interacting(tap.edges).separation(tap.edges, 0.13, euclidian).output("difftap.7", "difftap.7 : min. diff/tap spacing to non-coincident tap edge : 0.13um") +nwell.enclosing(diff.not(uhvi).and(psdm), 0.18, euclidian).output("difftap.8", "difftap.8 : min. p+diff enclosure by nwell : 0.18um") +diff.not(uhvi).and(nsdm).separation(nwell, 0.34, euclidian).output("difftap.9", "difftap.9 : min. n+diff spacing to nwell : 0.34um") +nwell.enclosing(tap.not(uhvi).and(nsdm), 0.18, euclidian).output("difftap.10", "difftap.10 : min. n+tap enclosure by nwell : 0.18um") +tap.not(uhvi).and(psdm).separation(nwell, 0.13, euclidian).output("difftap.11", "difftap.11 : min. p+tap spacing to nwell : 0.13um") + +# tunm +tunm.width(0.41, euclidian).output("tunm.1", "tunm.1 : min. tunm width : 0.41um") +tunm.isolated(0.5, euclidian).output("tunm.2", "tunm.2 : min. tunm spacing : 0.5um") +tunm.enclosing(gate, 0.095, euclidian).output("tunm.3", "tunm.3 : min. tunm beyond gate : 0.095um") +tunm.separation(gate.not_interacting(tunm), 0.095, euclidian).output("tunm.4", "tunm.4 : min. tunm spacing to gate outside tunm: 0.095um") +gate.and(tunm).edges.not(gate.edges).output("tunm.5", "tunm.5 : gate must not straddle tunm") +tunm.not(dnwell).output("tunm.6a", "tunm.6a : tunm not allowed outside dnwell") +tunm.with_area(0..0.672).output("tunm.7", "tunm.7 : min. tunm area : 0.672um²") + +# poly +poly.width(0.15, euclidian).output("poly.1a", "poly.1a : min. poly width : 0.15um") +poly.not(diff).edges.and(gate.and(lvtn).edges).space(0.35, euclidian).output("poly.1b", "poly.1b: min. lvtn gate width : 0.35um") +poly.isolated(0.21, euclidian).output("poly.2", "poly.2 : min. poly spacing : 0.21um") +poly.and(rpm.or(urpm).or(poly_rs)).width(0.33, euclidian).output("poly.3", "poly.3 : min. poly resistor width : 0.33um") +poly.not(gate).separation(diff, 0.075, projection).polygons.without_area(0).output("poly.4", "poly.4 : min. poly on field spacing to diff : 0.075um") +poly.not(gate).separation(tap, 0.055, euclidian).output("poly.5", "poly.5 : min. poly on field spacing to tap : 0.055um") +gate.separation(tap, 0.3, projection).polygons.and(diff).output("poly.6", "poly.6 : min. gate spacing to tap : 0.3um") +diff.enclosing(gate, 0.25, projection).polygons.without_area(0).output("poly.7", "poly.7 : min. source/drain length : 0.25um") +poly.enclosing(gate, 0.13, projection).polygons.without_area(0).output("poly.8", "poly.8 : min. poly extention gate (endcap) : 0.13um") +poly.and(rpm.or(urpm).or(poly_rs)).separation(poly.or(difftap), 0.48, euclidian).polygons.without_area(0).output("poly.9", "poly.9 : min. poly resistor space to poly or diff/tap : 0.48um") +diff.merged.edges.end_segments(0.01).and(poly).output("poly.10", "poly.10 : poly must not overlap diff corner") +gate.with_angle(0 .. 90).output("poly.11", "poly.11 : non 90 degree angle gate") +not_in_cell3 = layout(source.cell_obj).select("s8fgvr_n_fg2") +not_in_cell3_poly = not_in_cell3.input(66, 20) +not_in_cell3_poly.not(hvi).not(nwell.not(hvi)).and(tap).output("poly.12", "poly.12 : poly must not overlap tap") +poly.and(diff_rs).output("poly.15", "poly.15 : poly must not overlap diff resistor") + +# rpm +rpm.width(1.27, euclidian).output("rpm.1a", "rpm.1a : min. rpm width : 1.27um") +rpm.isolated(0.84, euclidian).output("rpm.2", "rpm.2 : min. rpm spacing : 0.84um") +rpm.enclosing(poly.and(poly_rs).and(psdm), 0.2, euclidian).output("rpm.3", "rpm.3 : min. rpm enclosure of poly resistor : 0.2um") +psdm.enclosing(poly.and(poly_rs).and(rpm), 0.11, euclidian).output("rpm.4", "rpm.4 : min. psdm enclosure of poly resistor : 0.11um") +npc.enclosing(poly.and(poly_rs).and(rpm), 0.095, euclidian).output("rpm.5", "rpm.5 : min. npc enclosure of poly resistor : 0.095um") +rpm.separation(nsdm, 0.2, euclidian).output("rpm.6", "rpm.6 : min. rpm spacing nsdm: 0.2um") +rpm.separation(poly, 0.2, euclidian).output("rpm.7", "rpm.7 : min. rpm spacing poly: 0.2um") +rpm.and(poly).edges.not(poly.edges).output("rpm.8", "rpm.8 : poly must not straddle rpm") +poly.and(poly_rs).and(rpm).separation(hvntm, 0.185, euclidian).output("rpm.9", "rpm.9 : min. poly resistor spacing hvntm: 0.185um") +rpm.and(pwbm).output("rpm.10", "rpm.107 : min. rpm spacing pwbm: na") + +# varac +varac = poly & tap & (nwell - hvi) - areaid_ce +tap.not(poly).edges.and(varac.edges).space(0.18, euclidian).output("varac.1", "varac.1: min. varac channel length : 0.18um") +tap.and(poly).edges.and(varac.edges).space(1.0, euclidian).output("varac.2", "varac.2: min. varac channel wdth : 1.0um") +varac.separation(hvtp, 0.18, euclidian).output("varac.3", "varac.3: min. varac channel space to hvtp : 0.18um") +varac.separation(licon.and(tap), 0.25, euclidian).output("varac.4", "varac.4: min. varac channel space to licon on tap : 0.25um") +nwell.enclosing(poly.overlapping(varac), 0.15, euclidian).output("varac.5", "varac.5: min. nwell enclosure of poly overlapping varac channel : 0.15um") +tap.overlapping(varac).separation(difftap, 0.27, euclidian).polygons.without_area(0).output("varac.6", "varac.6: min. varac channel tap space to difftap : 0.27um") +nwell.overlapping(varac).and(diff.and(nwell)).output("varac.7", "varac.7: nwell overlapping varac channel must not overlap p+diff") + +# photo +photodiode = dnwell & areaid_po +photodiode.edges.without_length(3.0).output("photo.2", "photo.2 : minimum/maximum width of photodiode : 3.0um") +photodiode.isolated(5.0, euclidian).output("photo.3", "photo.3 : mini. photodiode spacing : 5.0um") +photodiode.separation(dnwell, 5.3, euclidian).output("photo.4", "photo.4 : mini. photodiode spacing to dnwell : 5.3um") +areaid_po.not(dnwell).output("photo.5.6", "photo.5.6 : photodiode edges must coincide areaid.po and enclosed by dnwell") +photodiode.not(tap.not(nwell).holes).output("photo.7", "photo.7 : photodiode must be enclosed by p+tap ring") +photodiode.and(nwell).edges.without_length(0.84).output("photo.8", "photo.8 : minimum/maximum width of nwell inside photodiode : 0.84um") +areaid_po.edges.and(photodiode.and(nwell).sized(1.08)).without_length(12.0).output("photo.9", "photo.9 : minimum/maximum enclosure of nwell by photodiode : 1.08um") +photodiode.and(tap).edges.without_length(0.41).output("photo.10", "photo.10 : minimum/maximum width of tap inside photodiode : 0.41um") + +# npc +npc.width(0.27, euclidian).output("npc.1", "npc.1 : min. npc width : 0.27um") +npc.isolated(0.27, euclidian).output("npc.2", "npc.2 : min. npc spacing, should be mnually merge if less : 0.27um") +npc.separation(gate, 0.09, euclidian).output("npc.4", "npc.4 : min. npc spacing to gate : 0.09um") + +# nsdm/psdm +npsdm = nsdm + psdm +nsdm.width(0.38, euclidian).output("nsdm.1", "nsdm.1 : min. nsdm width : 0.38um") +psdm.width(0.38, euclidian).output("psdm.1", "psdm.1 : min. psdm width : 0.38um") +nsdm.isolated(0.38, euclidian).output("n/psdm.1", "n/psdm.1 : min. nsdm spacing, should be mnually merge if less : 0.38um") +psdm.isolated(0.38, euclidian).output("n/psdm.1", "n/psdm.1 : min. psdm spacing, should be mnually merge if less : 0.38um") +npsdm.enclosing(diff, 0.125, euclidian).polygons.not(tap.sized(0.125)).output("n/psdm.5a", "n/psdm.5a : min. n/psdm enclosure diff except butting edge : 0.125um") +npsdm.enclosing(tap, 0.125, euclidian).polygons.not(diff.sized(0.125)).output("n/psdm.5b", "n/psdm.5b : min. n/psdm enclosure tap except butting edge : 0.125um") +tap.edges.and(diff.edges).not(npsdm).output("n/psdm.6", "n/psdm.6 : min. n/psdm enclosure of butting edge : 0.0um") +nsdm.and(difftap).separation(psdm.and(difftap), 0.13, euclidian).polygons.without_area(0).output("n/psdm.7", "n/psdm.7 : min. nsdm diff spacing to psdm diff except butting edge : 0.13um") +diff.and((nsdm.and(nwell)).or(psdm.not(nwell))).output("n/psdm.8", "n/psdm.8 : diff should be the opposite type of well/substrate underneath") +tap.and((nsdm.not(nwell)).or(psdm.and(nwell))).output("n/psdm.8", "n/psdm.8 : tap should be the same type of well/substrate underneath") +tap.and(diff).without_area(0).output("tap and diff", "tap and diff must not overlap") +nsdm.with_area(0..0.265).output("n/psdm.10a", "n/psdm.10a : min. nsdm area : 0.265um²") +psdm.with_area(0..0.265).output("n/psdm.10b", "n/psdm.10b : min. psdm area : 0.265um²") + +# licon +licon.not(poly.interacting(poly_rs)).edges.without_length(0.17).output("licon.1", "licon.1 : minimum/maximum width of licon : 0.17um") +licon.and(poly.interacting(poly_rs)).not_interacting((licon.and(poly.interacting(poly_rs)).edges.with_length(0.19)).or(licon.and(poly.interacting(poly_rs)).edges.with_length(2.0))).output("licon.1b/c", "licon.1b/c : minimum/maximum width/length of licon inside poly resistor : 2.0/0.19um") +licon.isolated(0.17, euclidian).output("licon.2", "licon.2 : min. licon spacing : 0.17um") +licon.and(poly.interacting(poly_rs)).edges.with_length(0.19).space(0.35, euclidian).output("licon.2b", "licon.2b : min. licon 0.19um edge on resistor spacing : 0.35um") +licon.interacting(licon.and(poly.interacting(poly_rs)).edges.with_length(2.0)).separation(licon.and(poly.interacting(poly_rs)), 0.51, euclidian).output("licon.2c", "licon.2c : min. licon 2.0um edge on resistor spacing : 0.51um") +licon.and(poly.interacting(poly_rs)).separation(licon.not(poly.interacting(poly_rs)), 0.51, euclidian).output("licon.2d", "licon.2d : min. licon on resistor spacing other licon : 0.51um") +# rule licon.3 not coded +licon.not(li).not(poly.or(diff).or(tap)).output("licon.4", "licon.4 : min. licon must overlap li and (poly or tap or diff) ") +diff.enclosing(licon, 0.04, euclidian).output("licon.5", "licon.5 : min. diff enclosure of licon : 0.04um") +tap.edges.and(diff.edges).separation(licon.and(tap).edges, 0.06, euclidian).output("licon.6", "licon.6 : min. abutting edge spacing to licon tap : 0.06um") +licon_edges_with_less_enclosure_tap = tap.enclosing(licon, 0.12, projection).second_edges +opposite1 = (licon.edges - licon_edges_with_less_enclosure_tap).width(0.17 + 1.dbu, projection).polygons +licon.not_interacting(opposite1).output("licon.7", "licon.7 : min. tap enclosure of licon by one of 2 opposite edges : 0.12um") +poly.enclosing(licon, 0.05, euclidian).output("licon.8", "licon.8 : min. poly enclosure of licon : 0.05um") +licon008 = licon.interacting(poly.enclosing(licon, 0.08, euclidian).polygons) +licon_edges_with_less_enclosure_poly = poly.enclosing(licon, 0.08, projection).second_edges +opposite2 = (licon.edges - licon_edges_with_less_enclosure_poly).width(0.17 + 1.dbu, projection).polygons +licon008.not_interacting(opposite2).output("licon.8a", "licon.8a : min. poly enclosure of licon by one of 2 opposite edges : 0.08um") +# rule licon.9 not coded +licon.and(tap.and(nwell.not(hvi))).separation(varac, 0.25, euclidian).output("licon.10", "licon.10 : min. licon spacing to varac channel : 0.25um") +not_in_cell4 = layout(source.cell_obj).select("-s8fs_gwdlvx4", "-s8fs_gwdlvx8", "-s8fs_hvrsw_x4", "-s8fs_hvrsw8", "-s8fs_hvrsw264", "-s8fs_hvrsw520", "-s8fs_rdecdrv", "-s8fs_rdec8”, “s8fs_rdec32", "-s8fs_rdec264", "-s8fs_rdec520") +not_in_cell4_licon = not_in_cell4.input(66, 44) +not_in_cell4_licon.and(diff.or(tap)).separation(gate.not(areaid_sc), 0.055, euclidian).output("licon.11", "licon.11 : min. licon spacing to gate : 0.055um") +licon.and(diff.or(tap)).separation(gate.and(areaid_sc), 0.05, euclidian).output("licon.11a", "licon.11a : min. licon spacing to gate inside areaid.sc : 0.05um") +in_cell4 = layout(source.cell_obj).select("+s8fs_gwdlvx4", "+s8fs_gwdlvx8", "+s8fs_hvrsw_x4", "+s8fs_hvrsw8", "+s8fs_hvrsw264", "+s8fs_hvrsw520") +in_cell4_licon = in_cell4.input(66, 44) +in_cell4_licon.and(diff.or(tap)).separation(gate, 0.04, euclidian).output("licon.11c", "licon.11c : min. licon spacing to gate for specific cells: 0.04um") +# rules 11.b , 11.d not coded +diff.interacting(gate).not(diff.interacting(gate).width(5.7, euclidian).polygons).output("licon.12", "licon.12 : max. sd width without licon : 5.7um") +licon.and(diff.or(tap)).separation(npc, 0.09, euclidian).output("licon.13", "licon.13 : min. difftap licon spacing to npc : 0.09um") +licon.and(poly).separation(diff.or(tap), 0.19, euclidian).output("licon.14", "licon.14 : min. poly licon spacing to difftap : 0.19um") +npc.enclosing(licon.and(poly), 0.1, euclidian).output("licon.15", "licon.15 : min. npc enclosure of poly-licon : 0.1um") +# rule licon.16 not applicable for the diff for the nmos of a nand gates or the pmos of a nor gates +#diff.not(gate).not_interacting(licon).output("licon.16", "licon.16 : diff must enclose one licon") +tap.not(uhvi).not_interacting(licon).output("licon.16", "licon.16 : tap must enclose one licon") +poly.and(tap).edges.not(tap.edges).output("licon.17", "licon.17 : tap must not straddle poly") +npc.not_interacting(licon.and(poly)).output("licon.18", "licon.18 : npc mut enclosed one poly-licon") + +# vpp +vpp.width(1.43, euclidian).output("vpp.1", "vpp.1 : min. vpp width : 1.43um") +# rules 1.b, 1.c not coded +vpp.and(poly.or(difftap)).output("vpp.3", "vpp.3 : vpp must not overlapp poly or diff or tap") +vpp.and(nwell).edges.not(vpp.edges).output("vpp.4", "vpp.4 : vpp must not straddle nwell") +vpp.and(dnwell).edges.not(vpp.edges).output("vpp.4", "vpp.4 : vpp must not straddle dnwell") +vpp.and(poly.or(li).or(m1).or(m2)).separation(poly.or(li).or(m1).or(m2), 1.5, euclidian).polygons.with_area(2.25,nil).output("vpp.5", "vpp.5 : min. vpp spacing to poly or li or m1 or m2 : 1.5um") +vpp.with_area(0..area(vpp.and(m3))*0.25).output("vpp.5a", "vpp.5a : max. m3 density in vpp : 0.25") +vpp.with_area(0..area(vpp.and(m4))*0.3).output("vpp.5b", "vpp.5b : max. m4 density in vpp : 0.3") +vpp.with_area(0..area(vpp.and(m5))*0.4).output("vpp.5c", "vpp.5c : max. m5 density in vpp : 0.4") +nwell.enclosing(vpp, 1.5, euclidian).output("vpp.8", "vpp.8 : nwell enclosure of vpp : 1.5") +vpp.separation(nwell, 1.5, euclidian).polygons.without_area(0).output("vpp.9", "vpp.9 : vpp spacing to nwell : 1.5") +# rule vpp.10 not coded +# rule vpp.11 not coded because moscap is not defined properly by any gds layer +# rules vpp.12a, 12b, 12c not coded because specific to one cell +if backend_flow = CU + m1.separation(vpp.and(m1), 0.16, euclidian).polygons.without_area(0).output("vpp.13", "vpp.13 : m1 spacing to m1inside vpp : 0.16") +end + +# CAPM +capm.width(1.0, euclidian).output("capm.1", "capm.1 : min. capm width : 1.0um") +capm.isolated(0.84, euclidian).output("capm.2a", "capm.2a : min. capm spacing : 0.84um") +m2.interacting(capm).isolated(1.2, euclidian).output("capm.2b", "capm.2b : min. capm spacing : 1.2um") +m2.enclosing(capm, 0.14, euclidian).output("capm.3", "capm.3 : min. m2 enclosure of capm : 0.14um") +capm.enclosing(via2, 0.14, euclidian).output("capm.4", "capm.4 : min. capm enclosure of via2 : 0.14um") +capm.separation(via2, 0.14, euclidian).output("capm.5", "capm.5 : min. capm spacing to via2 : 0.14um") +capm.sized(-20.0).sized(20.0).output("capm.6", "capm.6 : max. capm lenght/width : 20um") +capm.with_angle(0 .. 90).output("capm.7", "capm.7 : capm not rectangle") +capm.separation(via, 0.14, euclidian).polygons.without_area(0).output("capm.8", "capm.8 : min. capm spacing to via : 0.14um") +capm.and(nwell).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle nwell") +capm.and(diff).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle diff") +capm.and(tap).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle tap") +capm.and(poly).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle poly") +capm.and(li).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle li") +capm.and(m1).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle m1") +capm.separation(m2.not_interacting(capm), 0.14, euclidian).output("capm.11", "capm.11 : min. capm spacing to m2 not overlapping capm : 0.5um") + +end #FEOL + +if BEOL +info("BEOL section") + +# li +not_in_cell5 = source.select("-s8rf2_xcmvpp_hd5_*") +not_in_cell5_li = not_in_cell5.polygons(li_wildcard) +not_in_cell5_li.width(0.17, euclidian).output("li.1", "li.1 : min. li width : 0.17um") + +in_cell5_li = li - not_in_cell5_li +in_cell5_li.width(0.14, euclidian).output("li.1a", "li.1a : min. li width for the cells s8rf2_xcmvpp_hd5_* : 0.14um") + +# rule li.2 not coded + +not_in_cell5_li.space(0.17, euclidian).output("li.3", "li.3 : min. li spacing : 0.17um") +in_cell5_li.space(0.14, euclidian).output("li.3a", "li.3a : min. li spacing for the cells s8rf2_xcmvpp_hd5_* : 0.14um") +licon08 = licon.interacting(li.enclosing(licon, 0.08, euclidian).polygons) +licon_edges_with_less_enclosure_li = li.enclosing(licon, 0.08, projection).second_edges +opposite3 = (licon.edges - licon_edges_with_less_enclosure_li).width(0.17 + 1.dbu, projection).polygons +licon08.not_interacting(opposite3).output("li.5", "li.5 : min. li enclosure of licon of 2 opposite edges : 0.08um") +li.with_area(0..0.0561).output("li.6", "li.6 : min. li area : 0.0561um²") + +# ct +mcon.edges.without_length(0.17).output("ct.1", "ct.1 : minimum/maximum width of mcon : 0.17um") +mcon.space(0.19, euclidian).output("ct.2", "ct.2 : min. mcon spacing : 0.19um") +# rule ct.3 not coded +mcon.not(li).output("ct.4", "ct.4 : mcon should covered by li") +if backend_flow = CU + li.interacting(li.and(m1).not(mcon).with_holes(1,10)).enclosing(mcon, 0.2, euclidian).output("ct.irdrop.1", "ct.irdrop.1 : min. li enclsoure of 1..10 mcon : 0.2um") + li.interacting(li.and(m1).not(mcon).with_holes(11,100)).enclosing(mcon, 0.3, euclidian).output("ct.irdrop.2", "ct.irdrop.2 : min. li enclsoure of 11..100 mcon : 0.3um") +end + +# m1 +m1.width(0.14, euclidian).output("m1.1", "m1.1 : min. m1 width : 0.14um") + +huge_m1 = m1.sized(-1.5).sized(1.5) +non_huge_m1 = m1 - huge_m1 + +non_huge_m1.space(0.14, euclidian).output("m1.2", "m1.2 : min. m1 spacing : 0.14um") + +(huge_m1.separation(non_huge_m1, 0.28, euclidian) + huge_m1.space(0.28, euclidian)).output("m1.3ab", "m1.3ab : min. 3um.m1 spacing m1 : 0.28um") + +not_in_cell6 = layout(source.cell_obj).select("-s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b", "-s8fpls_pl8", "-s8fs_cmux4_fm") +not_in_cell6_m1 = not_in_cell6.input(m1_wildcard) +not_in_cell6_m1.enclosing(mcon, 0.03, euclidian).output("m1.4", "m1.4 : min. m1 enclosure of mcon : 0.03um") +in_cell6 = layout(source.cell_obj).select("+s8cell_ee_plus_sseln_a", "+s8cell_ee_plus_sseln_b", "+s8cell_ee_plus_sselp_a", "+s8cell_ee_plus_sselp_b", "+s8fpls_pl8", "+s8fs_cmux4_fm") +in_cell6_m1 = in_cell6.input(m1_wildcard) +in_cell6_m1.enclosing(mcon, 0.005, euclidian).output("m1.4a", "m1.4a : min. m1 enclosure of mcon for specific cells : 0.005um") +m1.with_area(0..0.083).output("m1.6", "m1.6 : min. m1 area : 0.083um²") +m1.holes.with_area(0..0.14).output("m1.7", "m1.7 : min. m1 holes area : 0.14um²") +if backend_flow = AL + mcon06 = mcon.interacting(poly.enclosing(m1, 0.06, euclidian).polygons) + mcon_edges_with_less_enclosure_m1 = m1.enclosing(mcon, 0.06, projection).second_edges + opposite4 = (mcon.edges - mcon_edges_with_less_enclosure_m1).width(0.17 + 1.dbu, projection).polygons + mcon06.not_interacting(opposite4).output("m1.5", "m1.5 : min. m1 enclosure of mcon of 2 opposite edges : 0.06um") + # rule m1.pd.1, rule m1.pd.2a, rule m1.pd.2b not coded +end +if bakend_flow = CU + m1.sized(-2.0).sized(2.0).output("m1.11", "m1.11 : max. m1 width after slotting : 4.0um") + # rule m1.12 not coded because inconsistent with m1.11 + # rule m1.13, m1.14, m1.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +end + +# via +#rule via.3 not coded +via.not(m1).output("via.4c.5c", "via.4c.5c : m1 must enclose all via") +if backend_flow = AL + via.not(areaid_mt).edges.without_length(0.15).output("via.1a", "via.1a : minimum/maximum width of via : 0.15um") + via.and(areaid_mt).not_interacting((via.and(areaid_mt).edges.without_length(0.15)).or(via.and(areaid_mt).edges.without_length(0.23)).or(via.and(areaid_mt).edges.without_length(0.28))).output("via.1b", "via.1b : minimum/maximum width of via in areaid.mt: 0.15um or 0.23um or 0.28um") + via.isolated(0.17, euclidian).output("via.2", "via.2 : min. via spacing : 0.17um") + m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.055, euclidian).output("via.4a", "via.4a : min. m1 enclosure of 0.15um via : 0.055um") + m1.enclosing(via.not_interacting(via.edges.without_length(0.23)), 0.03, euclidian).output("via.4b", "via.4b : min. m1 enclosure of 0.23um via : 0.03um") + via1_edges_with_less_enclosure_m1 = m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.085, projection).second_edges + opposite5 = (via.not_interacting(via.edges.without_length(0.15)).edges - via1_edges_with_less_enclosure_m1).width(0.15 + 1.dbu, projection).polygons + via.not_interacting(via.edges.without_length(0.15)).not_interacting(opposite5).output("via1.5a", "via1.5a : min. m1 enclosure of 0.15um via of 2 opposite edges : 0.085um") + via2_edges_with_less_enclosure_m1 = m1.enclosing(via.not_interacting(via.edges.without_length(0.23)), 0.06, projection).second_edges + opposite6 = (via.not_interacting(via.edges.without_length(0.23)).edges - via2_edges_with_less_enclosure_m1).width(0.23 + 1.dbu, projection).polygons + via.not_interacting(via.edges.without_length(0.23)).not_interacting(opposite6).output("via1.5b", "via1.5b : min. m1 enclosure of 0.23um via of 2 opposite edges : 0.06um") +end +if backend_flow = CU + via.not(areaid_mt).edges.without_length(0.18).output("via.11", "via.11 : minimum/maximum width of via : 0.18um") + via.isolated(0.13, euclidian).output("via.12", "via.12 : min. via spacing : 0.13um") + # rule via.13 not coded because not understandable + via1_edges_with_less_enclosure_m1 = m1.enclosing(via, 0.04, projection).second_edges + opposite5 = (via.edges - via1_edges_with_less_enclosure_m1).width(0.18 + 1.dbu, projection).polygons + via.not_interacting(opposite5).output("via1.14", "via1.14 : min. m1 enclosure of 0.04um via of 2 opposite edges : 0.04um") + # rules via.irdrop.1, via.irdrop.2, via.irdrop.3, via.irdrop.4 not coded because not understandable +end + +# m2 +m2.width(0.14, euclidian).output("m2.1", "m2.1 : min. m2 width : 0.14um") + +huge_m2 = m2.sized(-1.5).sized(1.5) +non_huge_m2 = m2 - huge_m2 + +non_huge_m2.space(0.14, euclidian).output("m2.2", "m2.2 : min. m2 spacing : 0.14um") + +(huge_m2.separation(non_huge_m2, 0.28, euclidian) + huge_m2.space(0.28, euclidian)).output("m2.3ab", "m2.3ab : min. 3um.m2 spacing m2 : 0.28um") + +# rule m2.3c not coded +m2.with_area(0..0.0676).output("m2.6", "m2.6 : min. m2 area : 0.0676um²") +m2.holes.with_area(0..0.14).output("m2.7", "m2.7 : min. m2 holes area : 0.14um²") +via.not(m2).output("m2.via", "m2.via : m2 must enclose via") +if backend_flow = AL + m2.enclosing(via, 0.055, euclidian).output("m2.4", "m2.4 : min. m2 enclosure of via : 0.055um") + via_edges_with_less_enclosure_m2 = m2.enclosing(via, 0.085, projection).second_edges + opposite7 = (via.edges - via_edges_with_less_enclosure_m2).width(0.2 + 1.dbu, projection).polygons + via.not_interacting(opposite7).output("m2.5", "m2.5 : min. m2 enclosure of via of 2 opposite edges : 0.085um") + # rule m2.pd.1, rule m2.pd.2a, rule m2.pd.2b not coded +end +if bakend_flow = CU + m2.sized(-2.0).sized(2.0).output("m2.11", "m2.11 : max. m2 width after slotting : 4.0um") + # rule m2.12 not coded because inconsistent with m2.11 + # rule m2.13, m2.14, m2.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +end + +# via2 +#rule via233 not coded +via2.not(m2).output("via2", "via2 : m2 must enclose all via2") +if backend_flow = AL + via2.not(areaid_mt).edges.without_length(0.2).output("via2.1a", "via2.1a : minimum/maximum width of via2 : 0.2um") + via2.and(areaid_mt).not_interacting((via2.and(areaid_mt).edges.without_length(0.2)).or(via2.and(areaid_mt).edges.without_length(1.2)).or(via2.and(areaid_mt).edges.without_length(1.5))).output("via2.1b", "via2.1b : minimum/maximum width of via2 in areaid.mt: 0.2um or 1.2um or 1.5um") + via2.isolated(0.2, euclidian).output("via2.2", "via2.2 : min. via2 spacing : 0.2um") + m2.enclosing(via2, 0.04, euclidian).output("via2.4", "via2.4 : min. m2 enclosure of via2 : 0.04um") + m2.enclosing(via2.not_interacting(via2.edges.without_length(1.5)), 0.14, euclidian).output("via2.4a", "via2.4a : min. m2 enclosure of 1.5um via2 : 0.14um") + via2_edges_with_less_enclosure_m2 = m2.enclosing(via2, 0.085, projection).second_edges + opposite8 = (via2.edges - via2_edges_with_less_enclosure_m2).width(0.2 + 1.dbu, projection).polygons + via2.not_interacting(opposite8).output("via2.5", "via2.5 : min. m2 enclosure of via2 of 2 opposite edges : 0.085um") +end +if backend_flow = CU + via2.edges.without_length(0.21).output("via2.11", "via2.11 : minimum/maximum width of via2 : 0.21um") + via2.isolated(0.18, euclidian).output("via2.12", "via2.12 : min. via2 spacing : 0.18um") + # rule via2.13 not coded because not understandable, or not clear + m2.enclosing(via2, 0.035, euclidian).output("via2.14", "via2.14 : min. m2 enclosure of via2 : 0.035um") + # rules via2.irdrop.1, via2.irdrop.2, via2.irdrop.3, via2.irdrop.4 not coded because not understandable +end + +# m3 +m3.width(0.3, euclidian).output("m3.1", "m3.1 : min. m3 width : 0.3um") + +huge_m3 = m3.sized(-1.5).sized(1.5) +non_huge_m3 = m3 - huge_m3 + +non_huge_m3.space(0.3, euclidian).output("m3.2", "m3.2 : min. m3 spacing : 0.3um") + +(huge_m3.separation(non_huge_m3, 0.4, euclidian) + huge_m3.space(0.4, euclidian)).output("m3.3ab", "m3.3ab : min. 3um.m3 spacing m3 : 0.4um") + +# rule m3.3c not coded +m3.with_area(0..0.24).output("m3.6", "m3.6 : min. m2 area : 0.24um²") +via2.not(m3).output("m3.via2", "m3.via2 : m3 must enclose via2") +if backend_flow = AL + m3.enclosing(via2, 0.065, euclidian).output("m3.4", "m3.4 : min. m3 enclosure of via2 : 0.065um") + via2_edges_with_less_enclosure_m3 = m3.enclosing(via2, 0.085, projection).second_edges + # m3.5 N/A + # opposite9 = (via2.edges - via2_edges_with_less_enclosure_m3).width(0.3 + 1.dbu, projection).polygons + # via2.not_interacting(opposite9).output("m3.5", "m3.5 : min. m3 enclosure of via2 of 2 opposite edges : 0.085um") + # rule m3.pd.1, rule m3.pd.2a, rule m3.pd.2b not coded +end +if bakend_flow = CU + m3.holes.with_area(0..0.2).output("m3.7", "m3.7 : min. m2 holes area : 0.2um²") + m3.sized(-2.0).sized(2.0).output("m3.11", "m3.11 : max. m3 width after slotting : 4.0um") + # rule m3.12 not coded because inconsistent with m3.11 + # rule m3.13, m3.14, m3.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +end + +# via3 +#rule via3.3 not coded +via3.not(m3).output("via3", "via3 : m3 must enclose all via3") +if backend_flow = AL + via3.not(areaid_mt).edges.without_length(0.2).output("via3.1a", "via3.1a : minimum/maximum width of via3 : 0.2um") + via3.and(areaid_mt).not_interacting((via3.and(areaid_mt).edges.without_length(0.2)).or(via3.and(areaid_mt).edges.without_length(0.8))).output("via3.1a", "via3.1a : minimum/maximum width of via3 in areaid.mt: 0.2um or 0.8um") + via3.isolated(0.2, euclidian).output("via3.2", "via3.2 : min. via3 spacing : 0.2um") + m3.enclosing(via3, 0.06, euclidian).output("via3.4", "via3.4 : min. m3 enclosure of via3 : 0.06um") + via3_edges_with_less_enclosure_m3 = m3.enclosing(via3, 0.09, projection).second_edges + opposite10 = (via3.edges - via3_edges_with_less_enclosure_m3).width(0.2 + 1.dbu, projection).polygons + via3.not_interacting(opposite10).output("via3.5", "via3.5 : min. m2 enclosure of via3 of 2 opposite edges : 0.09um") +end +if backend_flow = CU + via3.edges.without_length(0.21).output("via3.11", "via3.11 : minimum/maximum width of via3 : 0.21um") + via3.isolated(0.18, euclidian).output("via3.12", "via3.12 : min. via3 spacing : 0.18um") + m3.enclosing(via3, 0.055, euclidian).output("via3.13", "via3.13 : min. m3 enclosure of via3 : 0.055um") + # rule via3.14 not coded because not understandable, or not clear + # rules via3.irdrop.1, via3.irdrop.2, via3.irdrop.3, via3.irdrop.4 not coded because not understandable +end + +# m4 +m4.width(0.3, euclidian).output("m4.1", "m4.1 : min. m4 width : 0.3um") + +huge_m4 = m4.sized(-1.5).sized(1.5) +non_huge_m4 = m4 - huge_m4 + +non_huge_m4.space(0.3, euclidian).output("m4.2", "m4.2 : min. m4 spacing : 0.3um") + +(huge_m4.separation(non_huge_m4, 0.4, euclidian) + huge_m4.space(0.4, euclidian)).output("m4.5ab", "m4.5ab : min. 3um.m4 spacing m4 : 0.4um") + +m4.with_area(0..0.24).output("m4.4", "m4.4 : min. m2 area : 0.24um²") +via3.not(m4).output("m4.via3", "m4.via3 : m4 must enclose via3") +if backend_flow = AL + m4.enclosing(via3, 0.065, euclidian).output("m4.3", "m4.3 : min. m4 enclosure of via3 : 0.065um") + # m4.5 doesn't exist + # via3_edges_with_less_enclosure_m4 = m4.enclosing(via2, 0.085, projection).second_edges + # opposite9 = (via3.edges - via3_edges_with_less_enclosure_m4).width(0.3 + 1.dbu, projection).polygons + # via3.not_interacting(opposite9).output("m4.5", "m4.5 : min. m4 enclosure of via3 of 2 opposite edges : 0.085um") + # rule m4.pd.1, rule m4.pd.2a, rule m4.pd.2b not coded +end +if bakend_flow = CU + m4.holes.with_area(0..0.2).output("m4.7", "m4.7 : min. m2 holes area : 0.2um²") + m4.sized(-5.0).sized(5.0).output("m4.11", "m4.11 : max. m4 width after slotting : 10.0um") + # rule m4.12 not coded because inconsistent with m4.11 + # rule m4.13, m4.14, m4.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 + m4.enclosing(via3, 0.06, euclidian).output("m4.15", "m4.15 : min. m4 enclosure of via3 : 0.06um") +end + +# via4 +via4.edges.without_length(0.8).output("via4.1a", "via4.1a : minimum/maximum width of via4 : 0.8um") +via4.isolated(0.8, euclidian).output("via4.2", "via4.2 : min. via4 spacing : 0.8um") +#rule via4.3 not coded +m4.enclosing(via4, 0.19, euclidian).output("via4.4", "via4.4 : min. m4 enclosure of via4 : 0.19um") +via4.not(m4).output("via4", "via4 : m4 must enclose all via4") +if backend_flow = CU + # rules via4.irdrop.1, via4.irdrop.2, via4.irdrop.3, via4.irdrop.4 not coded because not understandable +end + +# m5 +m5.width(1.6, euclidian).output("m5.1", "m5.1 : min. m5 width : 1.6um") + +m5.space(1.6, euclidian).output("m5.2", "m5.2 : min. m5 spacing : 1.6um") + +via4.not(m5).output("m5.via4", "m5.via4 : m5 must enclose via4") +m5.enclosing(via4, 0.31, euclidian).output("m5.3", "m4.3 : min. m5 enclosure of via4 : 0.31um") + +# nsm +nsm.width(3.0, euclidian).output("nsm.1", "nsm.1 : min. nsm width : 3.0um") +nsm.isolated(4.0, euclidian).output("nsm.2", "nsm.2 : min. nsm spacing : 4.0um") +nsm.enclosing(diff, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of diff : 3.0um") +nsm.enclosing(tap, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of tap : 3.0um") +nsm.enclosing(poly, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of poly : 3.0um") +nsm.enclosing(li, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of li : 3.0um") +nsm.enclosing(m1, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m1 : 3.0um") +nsm.enclosing(m2, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m2 : 3.0um") +nsm.enclosing(m3, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m3 : 3.0um") +nsm.enclosing(m4, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m4 : 3.0um") +nsm.enclosing(m5, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m5 : 3.0um") +nsm.enclosing(cfom, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of cfom : 3.0um") +if backend_flow = AL + nsm.separation(diff, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to diff : 1.0um") + nsm.separation(tap, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to tap : 1.0um") + nsm.separation(poly, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to poly : 1.0um") + nsm.separation(li, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to li : 1.0um") + nsm.separation(m1, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m1 : 1.0um") + nsm.separation(m2, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m2 : 1.0um") + nsm.separation(m3, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m3 : 1.0um") + nsm.separation(m4, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m4 : 1.0um") + nsm.separation(m5, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m5 : 1.0um") + nsm.separation(cfom, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to cfom : 1.0um") +end + +# pad +pad.isolated(1.27, euclidian).output("pad.2", "pad.2 : min. pad spacing : 1.27um") + +end #BEOL + +if FEOL +info("FEOL section") + +# mf +mf.not_interacting(mf.edges.without_length(0.8)).output("mf.1", "mf.1 : minimum/maximum width of fuse : 0.8um") +mf.not_interacting(mf.edges.without_length(7.2)).output("mf.2", "mf.2 : minimum/maximum length of fuse : 7.2um") +mf.isolated(1.96, euclidian).output("mf.3", "mf.3 : min. fuse center spacing : 2.76um") +# fuses need more clarification on fuse_shield, fuse layers ... + +# hvi +hvi.width(0.6, euclidian).output("hvi.1", "hvi.1 : min. hvi width : 0.6um") +hvi.isolated(0.7, euclidian).output("hvi.2", "hvi.2 : min. hvi spacing, merge if less : 0.7um") +hvi.and(tunm).output("hvi.4", "hvi.4 : hvi must not overlapp tunm") +hvi.and(nwell).separation(nwell, 2.0, euclidian).output("hvnwell.8", "hvnwelli.8 : min. hvnwel spacing to nwell : 2.0") +areaid_hl.not(hvi).output("hvnwel.9", "hvnwell.9 : hvi must overlapp hvnwell") +# rule hvnell.10 not coded +diff.not(psdm.and(diff_rs)).and(hvi).width(0.29, euclidian).output("hvdifftap.14", "hvdifftap.14 : min. diff inside hvi width : 0.29um") +diff.and(psdm.and(diff_rs)).and(hvi).width(0.15, euclidian).output("hvdifftap.14a", "hvdifftap.14a : min. p+diff resistor inside hvi width : 0.15um") +diff.and(hvi).isolated(0.3, euclidian).output("hvdifftap.15a", "hvdifftap.15a : min. diff inside hvi spacing : 0.3um") +diff.and(hvi).and(nsdm).separation(diff.and(hvi).and(psdm), 0.37, euclidian).polygons.without_area(0).output("hvdifftap.15b", "hvdifftap.15b : min. n+diff inside hvi spacing to p+diff inside hvi except abutting: 0.37um") +tap.and(hvi).edges.and(diff).without_length(0.7).output("hvdifftap.16", "hvdifftap.16 : min. tap inside hvi abuttng diff : 0.7um") +hvi.and(nwell).enclosing(diff, 0.33, euclidian).output("hvdifftap.17", "hvdifftap.17 : min. hvnwell enclosure of p+diff : 0.33um") +hvi.and(nwell).separation(diff, 0.43, euclidian).output("hvdifftap.18", "hvdifftap.18 : min. hvnwell spacing to n+diff : 0.43um") +hvi.and(nwell).enclosing(tap, 0.33, euclidian).output("hvdifftap.19", "hvdifftap.19 : min. hvnwell enclosure of n+tap : 0.33um") +hvi.and(nwell).separation(tap, 0.43, euclidian).output("hvdifftap.20", "hvdifftap.20 : min. hvnwell spacing to p+tap : 0.43um") +hvi.and(diff).edges.not(diff.edges).output("hvdifftap.21", "hvdifftap.21 : diff must not straddle hvi") +hvi.and(tap).edges.not(tap.edges).output("hvdifftap.21", "hvdifftap.21 : tap must not straddle hvi") +hvi.enclosing(difftap, 0.18, euclidian).output("hvdifftap.22", "hvdifftap.22 : min. hvi enclosure of diff or tap : 0.18um") +hvi.separation(difftap, 0.18, euclidian).output("hvdifftap.23", "hvdifftap.23 : min. hvi spacing to diff or tap : 0.18um") +hvi.and(diff).not(nwell).separation(nwell, 0.43, euclidian).output("hvdifftap.24", "hvdifftap.24 : min. hv n+diff spacing to nwell : 0.43um") +diff.and(hvi).not(nwell).isolated(1.07, euclidian).polygons.and(tap).output("hvdifftap.25", "hvdifftap.25 : min. n+diff inside hvi spacing accros p+tap : 1.07um") +diff.not(poly).edges.and(gate.and(hvi).edges).space(0.35, euclidian).output("hvpoly.13", "hvpoly.13: min. hvi gate length : 0.5um") +hvi.and(poly).edges.not(poly.edges).output("hvpoly.14", "hvpoly.14 : poly must not straddle hvi") + +# hvntm +hvntm.width(0.7, euclidian).output("hvntm.1", "hvntm.1 : min. hvntm width : 0.7um") +hvntm.isolated(0.7, euclidian).output("hvntm.2", "hvntm.2 : min. hvntm spacing : 0.7um") +hvntm.enclosing(diff.and(nwell).and(hvi), 0.185, euclidian).output("hvntm.3", "hvntm.3 : min. hvntm enclosure of hv n+diff : 0.185um") +hvntm.separation(diff.not(nwell).not(hvi), 0.185, euclidian).output("hvntm.4", "hvntm.4 : min. hvntm spacing to n+diff : 0.185um") +hvntm.separation(diff.and(nwell).not(hvi), 0.185, euclidian).output("hvntm.5", "hvntm.5 : min. hvntm spacing to p+diff : 0.185um") +hvntm.separation(tap.not(nwell).not(hvi), 0.185, euclidian).polygons.without_area(0).output("hvntm.6a", "hvntm.6a : min. hvntm spacing to p+tap : 0.185um") +hvntm.and(areaid_ce).output("hvntm.9", "hvntm.9 : hvntm must not overlapp areaid.ce") + +# denmos +poly.not_interacting(pwde).interacting(areaid_en).width(1.055, projection).output("denmos.1", "denmos.1 : min. de_nfet gate width : 1.055um") +diff.not_interacting(pwde).enclosing(poly.interacting(areaid_en), 0.28, projection).polygons.without_area(0).output("denmos.2", "denmos.2 : min. de_nfet source ouside poly width : 0.28um") +diff.not_interacting(pwde).and(poly.interacting(areaid_en)).width(0.925, projection).output("denmos.3", "denmos.3 : min. de_nfet source inside poly width : 0.925um") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).width(0.17, euclidian).output("denmos.4", "denmos.4 : min. de_nfet drain width : 0.17um") +nwell.not_interacting(pwde).and(poly.interacting(areaid_en)).width(0.225, projection).polygons.or(nwell.and(poly.interacting(areaid_en)).sized(-0.1125).sized(0.1125)).output("denmos.5", "denmos.5 : min. de_nfet source inside nwell width : 0.225m") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).separation(diff.interacting(poly.interacting(areaid_en)), 1.585, projection).output("denmos.6", "denmos.6 : min. de_nfet source spacing to drain : 1.585um") +nwell.not_interacting(pwde).and(poly.and(diff).interacting(areaid_en)).edges.without_length(5.0, nil).output("denmos.7", "denmos.7 : min. de_nfet channel width : 5.0um") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("denmos.8", "denmos.8 : 90deg. not allowed for de_nfet drain") +nwell.not_interacting(pwde).interacting(areaid_en).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("denmos.9a", "denmos.9a : 90deg. not allowed for de_nfet nwell") +nwell.not_interacting(pwde).interacting(areaid_en).edges.with_angle(45).without_length(0.607..0.609).output("denmos.9a", "denmos.9a : 45deg. bevels of de_nfet nwell should be 0.43um from corners") +nwell.not_interacting(pwde).interacting(areaid_en).edges.with_angle(135).without_length(0.607..0.609).output("denmos.9a", "denmos.9a : 45deg. bevels of de_nfet nwell should be 0.43um from corners") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(45).without_length(0.7..0.71).output("denmos.9b", "denmos.9b : 45deg. bevels of de_nfet drain should be 0.05um from corners") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(135).without_length(0.7..0.71).output("denmos.9b", "denmos.9b : 45deg. bevels of de_nfet drain should be 0.05um from corners") +nwell.not_interacting(pwde).enclosing(diff.interacting(areaid_en).not_interacting(poly), 0.66, euclidian).output("denmos.10", "denmos.10 : min. nwell enclosure of de_nfet drain : 0.66um") +nwell.not_interacting(pwde).interacting(areaid_en).separation(tap.not(nwell), 0.86, euclidian).output("denmos.11", "denmos.11 : min. de_nfet nwell spacing to tap : 0.86um") +nwell.not_interacting(pwde).interacting(areaid_en).isolated(2.4, euclidian).output("denmos.12", "denmos.12 : min. de_nfet nwell : 2.4um") +nsdm.not_interacting(pwde).enclosing(diff.interacting(areaid_en).interacting(poly), 0.13, euclidian).output("denmos.13", "denmos.13 : min. nsdm enclosure of de_nfet source : 0.13um") + +# depmos +poly.interacting(pwde).interacting(areaid_en).width(1.05, projection).output("depmos.1", "depmos.1 : min. de_pfet gate width : 1.05um") +diff.interacting(pwde).enclosing(poly.interacting(areaid_en), 0.28, projection).polygons.without_area(0).output("depmos.2", "depmos.2 : min. de_pfet source ouside poly width : 0.28um") +diff.interacting(pwde).and(poly.interacting(areaid_en)).width(0.92, projection).output("depmos.3", "depmos.3 : min. de_pfet source inside poly width : 0.92um") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).width(0.17, euclidian).output("depmos.4", "depmos.4 : min. de_pfet drain width : 0.17um") +pwde.not(nwell).and(poly.interacting(areaid_en)).width(0.26, projection).polygons.or(pwde.not(nwell).and(poly.interacting(areaid_en)).sized(-0.13).sized(0.13)).output("depmos.5", "depmos.5 : min. de_pfet source inside nwell width : 0.26m") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).separation(diff.interacting(poly.interacting(areaid_en)), 1.19, projection).output("depmos.6", "depmos.6 : min. de_pfet source spacing to drain : 1.19um") +nwell.interacting(pwde).and(poly.and(diff).interacting(areaid_en)).edges.without_length(5.0, nil).output("depmos.7", "depmos.7 : min. de_pfet channel width : 5.0um") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("depmos.8", "depmos.8 : 90deg. not allowed for de_pfet drain") +pwde.not(nwell).interacting(areaid_en).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("depmos.9a", "depmos.9a : 90deg. not allowed for de_pfet pwell") +pwde.not(nwell).interacting(areaid_en).edges.with_angle(45).without_length(0.607..0.609).output("depmos.9a", "depmos.9a : 45deg. bevels of de_pfet pwell should be 0.43um from corners") +pwde.not(nwell).interacting(areaid_en).edges.with_angle(135).without_length(0.607..0.609).output("depmos.9a", "depmos.9a : 45deg. bevels of de_pfet pwell should be 0.43um from corners") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(45).without_length(0.7..0.71).output("depmos.9b", "depmos.9b : 45deg. bevels of de_pfet drain should be 0.05um from corners") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(135).without_length(0.7..0.71).output("depmos.9b", "depmos.9b : 45deg. bevels of de_pfet drain should be 0.05um from corners") +nwell.interacting(pwde).separation(diff.interacting(areaid_en).not_interacting(poly), 0.86, euclidian).output("depmos.10", "depmos.10 : min. pwell enclosure of de_pfet drain : 0.86um") +pwde.not(nwell).interacting(areaid_en).separation(tap.and(nwell), 0.66, euclidian).output("depmos.11", "depmos.11 : min. de_pfet pwell spacing to tap : 0.66um") +psdm.interacting(pwde).enclosing(diff.interacting(areaid_en).interacting(poly), 0.13, euclidian).output("depmos.12", "depmos.12 : min. psdm enclosure of de_pfet source : 0.13um") + +# extd +areaid_en.and(difftap).edges.not(difftap.edges).output("extd.1", "extd.1 : difftap must not straddle areaid.en") +difftap.interacting(areaid_en).not(poly).with_area(0).output("extd.2", "extd.2 : poly must not overlapp entirely difftap in areaid.en") +# rules extd.4, extd.5, extd.6, extd.7 not coded because specific to some cells + +# vhvi +# rules vhvi.vhv.1, vhvi.vhv.2, vhvi.vhv.3, vhvi.vhv.4, vhvi.vhv.5, vhvi.vhv.6 not coded +vhvi.width(0.02, euclidian).output("vhvi.1", "vhvi.1 : min. vhvi width : 0.02um") +vhvi.and(areaid_ce).output("vhvi.2", "vhvi.2 : vhvi must not overlap areaid.ce") +vhvi.and(hvi).output("vhvi.3", "vhvi.3 : vhvi must not overlap hvi") +# rules vhvi.4, vhvi.6 not coded +vhvi.and(diff).edges.not(diff.edges).output("vhvi.5", "vhvi.5 : vhvi must not straddle diff") +vhvi.and(tap).edges.not(tap.edges).output("vhvi.5", "vhvi.5 : vhvi must not straddle tap") +vhvi.and(poly).edges.not(poly.edges).output("vhvi.7", "vhvi.7 : vhvi must not straddle poly") + +nwell.and(vhvi).separation(nwell, 2.5, euclidian).output("hv.nwell.1", "hv.nwell.1 : min. vhvi nwell spacing to nwell : 2.5um") +diff.and(vhvi).isolated(0.3, euclidian).output("hv.diff.1", "hv.diff.1 : min. vhvi diff spacing : 0.3um") +nwell.interacting(diff.and(vhvi)).separation(diff.not(nwell), 0.43, euclidian).output("hv.diff.2", "hv.diff.2 : min. vhvi nwell spacing n+diff : 0.43um") +diff.and(vhvi).not(nwell).separation(nwell, 0.55, euclidian).output("hv.diff.3a", "hv.diff.3a : min. vhvi n+diff spacing nwell : 0.55um") +# rule hv.diff.3b not coded +poly.and(vhvi).not(diff).separation(diff, 0.3, euclidian).polygons.without_area(0).output("hv.poly.2", "hv.poly.2 : min. vhvi poly spacing to diff : 0.3um") +poly.and(vhvi).not(diff).separation(nwell, 0.55, euclidian).polygons.without_area(0).output("hv.poly.3", "hv.poly.3 : min. vhvi poly spacing to nwell : 0.55um") +nwell.enclosing(poly.and(vhvi).not(diff), 0.3, euclidian).polygons.without_area(0).output("hv.poly.4", "hv.poly.4 : min. nwell enclosure of vhvi poly : 0.3um") +#poly.and(vhvi).enclosing(diff.interacting(areaid_en), 0.16, projection).polygons.without_area(0).output("hv.poly.6", "hv.poly.6 : min. poly enclosure of hvfet gate : 0.16um") +# rule hv.poly.7 not coded + +# uhvi +uhvi.and(diff).edges.not(diff.edges).output("uhvi.1", "uhvi.1 : diff must not straddle uhvi") +uhvi.and(tap).edges.not(tap.edges).output("uhvi.1", "uhvi.1 : tap must not straddle uhvi") +uhvi.and(poly).edges.not(poly.edges).output("uhvi.2", "uhvi.2 : poly must not straddle uhvi") +pwbm.not(uhvi).output("uhvi.3", "uhvi.3 : uhvi must not enclose pwbm") +uhvi.and(dnwell).edges.not(dnwell.edges).output("uhvi.4", "uhvi.4 : dnwell must not straddle uhvi") +areaid_en20.not(uhvi).output("uhvi.5", "uhvi.5 : uhvi must not enclose areaid.en20") +#dnwell.not(uhvi).output("uhvi.6", "uhvi.6 : uhvi must not enclose dnwell") +natfet.not(uhvi).output("uhvi.7", "uhvi.7 : uhvi must not enclose natfet") + +# pwell_res +pwell_rs.width(2.65).output("pwres.2", "pwres.2 : min. pwell resistor width : 2.65um") +pwell_rs.sized(-2.65).sized(2.65).output("pwres.2", "pwres.2 : max. pwell resistor width : 2.65um") +pwell_rs.interacting(pwell_rs.edges.with_length(2.651,26.499)).output("pwres.3", "pwres.3 : min. pwell resistor length : 26.5um") +pwell_rs.interacting(pwell_rs.edges.with_length(265.0, nil)).output("pwres.4", "pwres.4 : max. pwell resistor length : 265um") +tap.interacting(pwell_rs).separation(nwell, 0.22, euclidian).output("pwres.5", "pwres.5 : min. pwell resistor tap spacing to nwell : 0.22um") +tap.interacting(pwell_rs).and(tap.sized(0.22).and(nwell)).output("pwres.5", "pwres.5 : max. pwell resistor tap spacing to nwell : 0.22um") +tap.interacting(pwell_rs).width(0.53).output("pwres.6", "pwres.6 : min. width of tap inside pwell resistor : 0.53um") +tap.interacting(pwell_rs).sized(-0.265).sized(0.265).output("pwres.6", "pwres.6 : max. width of tap inside pwell resistor : 0.53um") +# rules pwres.7a, pwres.7b not coded +pwell_rs.and(diff).output("pwres.8", "pwres.8 : diff not allowed inside pwell resistor") +pwell_rs.and(poly).output("pwres.8", "pwres.8 : poly not allowed inside pwell resistor") +# rules pwres.9, pwres.10 not coded + +# rf_diode +areaid_re.with_angle(0 .. 90).output("rfdiode.1", "rfdiode.1 : non 90 degree angle areaid.re") +areaid_re.not(nwell).or(nwell.interacting(areaid_re).not(areaid_re)).output("rfdiode.2", "rfdiode.2 : areaid.re must coincide rf nwell diode") +# rule rfdiode.3 not coded + +end #FEOL + +if OFFGRID +info("OFFGRID-ANGLES section") + +dnwell.ongrid(0.005).output("dnwell_OFFGRID", "x.1b : OFFGRID vertex on dnwell") +dnwell.with_angle(0 .. 45).output("dnwell_angle", "x.3a : non 45 degree angle dnwell") +nwell.ongrid(0.005).output("nwell_OFFGRID", "x.1b : OFFGRID vertex on nwell") +nwell.with_angle(0 .. 45).output("nwell_angle", "x.3a : non 45 degree angle nwell") +pwbm.ongrid(0.005).output("pwbm_OFFGRID", "x.1b : OFFGRID vertex on pwbm") +pwbm.with_angle(0 .. 45).output("pwbm_angle", "x.3a : non 45 degree angle pwbm") +pwde.ongrid(0.005).output("pwde_OFFGRID", "x.1b : OFFGRID vertex on pwde") +pwde.with_angle(0 .. 45).output("pwde_angle", "x.3a : non 45 degree angle pwde") +hvtp.ongrid(0.005).output("hvtp_OFFGRID", "x.1b : OFFGRID vertex on hvtp") +hvtp.with_angle(0 .. 45).output("hvtp_angle", "x.3a : non 45 degree angle hvtp") +hvtr.ongrid(0.005).output("hvtr_OFFGRID", "x.1b : OFFGRID vertex on hvtr") +hvtr.with_angle(0 .. 45).output("hvtr_angle", "x.3a : non 45 degree angle hvtr") +lvtn.ongrid(0.005).output("lvtn_OFFGRID", "x.1b : OFFGRID vertex on lvtn") +lvtn.with_angle(0 .. 45).output("lvtn_angle", "x.3a : non 45 degree angle lvtn") +ncm.ongrid(0.005).output("ncm_OFFGRID", "x.1b : OFFGRID vertex on ncm") +ncm.with_angle(0 .. 45).output("ncm_angle", "x.3a : non 45 degree angle ncm") +diff.ongrid(0.005).output("diff_OFFGRID", "x.1b : OFFGRID vertex on diff") +tap.ongrid(0.005).output("tap_OFFGRID", "x.1b : OFFGRID vertex on tap") +diff.not(areaid_en.and(uhvi)).with_angle(0 .. 90).output("diff_angle", "x.2 : non 90 degree angle diff") +diff.and(areaid_en.and(uhvi)).with_angle(0 .. 45).output("diff_angle", "x.2c : non 45 degree angle diff") +tap.not(areaid_en.and(uhvi)).with_angle(0 .. 90).output("tap_angle", "x.2 : non 90 degree angle tap") +tap.and(areaid_en.and(uhvi)).with_angle(0 .. 45).output("tap_angle", "x.2c : non 45 degree angle tap") +tunm.ongrid(0.005).output("tunm_OFFGRID", "x.1b : OFFGRID vertex on tunm") +tunm.with_angle(0 .. 45).output("tunm_angle", "x.3a : non 45 degree angle tunm") +poly.ongrid(0.005).output("poly_OFFGRID", "x.1b : OFFGRID vertex on poly") +poly.with_angle(0 .. 90).output("poly_angle", "x.2 : non 90 degree angle poly") +rpm.ongrid(0.005).output("rpm_OFFGRID", "x.1b : OFFGRID vertex on rpm") +rpm.with_angle(0 .. 45).output("rpm_angle", "x.3a : non 45 degree angle rpm") +npc.ongrid(0.005).output("npc_OFFGRID", "x.1b : OFFGRID vertex on npc") +npc.with_angle(0 .. 45).output("npc_angle", "x.3a : non 45 degree angle npc") +nsdm.ongrid(0.005).output("nsdm_OFFGRID", "x.1b : OFFGRID vertex on nsdm") +nsdm.with_angle(0 .. 45).output("nsdm_angle", "x.3a : non 45 degree angle nsdm") +psdm.ongrid(0.005).output("psdm_OFFGRID", "x.1b : OFFGRID vertex on psdm") +psdm.with_angle(0 .. 45).output("psdm_angle", "x.3a : non 45 degree angle psdm") +licon.ongrid(0.005).output("licon_OFFGRID", "x.1b : OFFGRID vertex on licon") +licon.with_angle(0 .. 90).output("licon_angle", "x.2 : non 90 degree angle licon") +li.ongrid(0.005).output("li_OFFGRID", "x.1b : OFFGRID vertex on li") +li.with_angle(0 .. 45).output("li_angle", "x.3a : non 45 degree angle li") +mcon.ongrid(0.005).output("ct_OFFGRID", "x.1b : OFFGRID vertex on mcon") +mcon.with_angle(0 .. 90).output("ct_angle", "x.2 : non 90 degree angle mcon") +vpp.ongrid(0.005).output("vpp_OFFGRID", "x.1b : OFFGRID vertex on vpp") +vpp.with_angle(0 .. 45).output("vpp_angle", "x.3a : non 45 degree angle vpp") +m1.ongrid(0.005).output("m1_OFFGRID", "x.1b : OFFGRID vertex on m1") +m1.with_angle(0 .. 45).output("m1_angle", "x.3a : non 45 degree angle m1") +via.ongrid(0.005).output("via_OFFGRID", "x.1b : OFFGRID vertex on via") +via.with_angle(0 .. 90).output("via_angle", "x.2 : non 90 degree angle via") +m2.ongrid(0.005).output("m2_OFFGRID", "x.1b : OFFGRID vertex on m2") +m2.with_angle(0 .. 45).output("m2_angle", "x.3a : non 45 degree angle m2") +via2.ongrid(0.005).output("via2_OFFGRID", "x.1b : OFFGRID vertex on via2") +via2.with_angle(0 .. 90).output("via2_angle", "x.2 : non 90 degree angle via2") +m3.ongrid(0.005).output("m3_OFFGRID", "x.1b : OFFGRID vertex on m3") +m3.with_angle(0 .. 45).output("m3_angle", "x.3a : non 45 degree angle m3") +via3.ongrid(0.005).output("via3_OFFGRID", "x.1b : OFFGRID vertex on via3") +via3.with_angle(0 .. 90).output("via3_angle", "x.2 : non 90 degree angle via3") +nsm.ongrid(0.005).output("nsm_OFFGRID", "x.1b : OFFGRID vertex on nsm") +nsm.with_angle(0 .. 45).output("nsm_angle", "x.3a : non 45 degree angle nsm") +m4.ongrid(0.005).output("m4_OFFGRID", "x.1b : OFFGRID vertex on m4") +m4.with_angle(0 .. 45).output("m4_angle", "x.3a : non 45 degree angle m4") +via4.ongrid(0.005).output("via4_OFFGRID", "x.1b : OFFGRID vertex on via4") +via4.with_angle(0 .. 90).output("via4_angle", "x.2 : non 90 degree angle via4") +m5.ongrid(0.005).output("m5_OFFGRID", "x.1b : OFFGRID vertex on m5") +m5.with_angle(0 .. 45).output("m5_angle", "x.3a : non 45 degree angle m5") +pad.ongrid(0.005).output("pad_OFFGRID", "x.1b : OFFGRID vertex on pad") +pad.with_angle(0 .. 45).output("pad_angle", "x.3a : non 45 degree angle pad") +mf.ongrid(0.005).output("mf_OFFGRID", "x.1b : OFFGRID vertex on mf") +mf.with_angle(0 .. 90).output("mf_angle", "x.2 : non 90 degree angle mf") +hvi.ongrid(0.005).output("hvi_OFFGRID", "x.1b : OFFGRID vertex on hvi") +hvi.with_angle(0 .. 45).output("hvi_angle", "x.3a : non 45 degree angle hvi") +hvntm.ongrid(0.005).output("hvntm_OFFGRID", "x.1b : OFFGRID vertex on hvntm") +hvntm.with_angle(0 .. 45).output("hvntm_angle", "x.3a : non 45 degree angle hvntm") +vhvi.ongrid(0.005).output("vhvi_OFFGRID", "x.1b : OFFGRID vertex on vhvi") +vhvi.with_angle(0 .. 45).output("vhvi_angle", "x.3a : non 45 degree angle vhvi") +uhvi.ongrid(0.005).output("uhvi_OFFGRID", "x.1b : OFFGRID vertex on uhvi") +uhvi.with_angle(0 .. 45).output("uhvi_angle", "x.3a : non 45 degree angle uhvi") +pwell_rs.ongrid(0.005).output("pwell_rs_OFFGRID", "x.1b : OFFGRID vertex on pwell_rs") +pwell_rs.with_angle(0 .. 45).output("pwell_rs_angle", "x.3a : non 45 degree angle pwell_rs") +areaid_re.ongrid(0.005).output("areaid_re_OFFGRID", "x.1b : OFFGRID vertex on areaid.re") + +end #OFFGRID + diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.lydrc.sak b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.lydrc.sak new file mode 100755 index 00000000..e7a665ec --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.lydrc.sak @@ -0,0 +1,869 @@ + + + + + drc + + + + false + false + + true + drc_scripts + tools_menu.drc.end + dsl + drc-dsl-xml + # +# DRC for SKY130 according to : +# https://skywater-pdk.readthedocs.io/en/latest/rules/periphery.html +# https://skywater-pdk.readthedocs.io/en/latest/rules/layers.html +# +# Distributed under GNU GPLv3: https://www.gnu.org/licenses/ +# +# History : +# 2020-10-04 : v1.0 : initial release +# +########################################################################################## + +# optional for a batch launch : klayout -b -rd input=my_layout.gds -rd report=sky130_drc.txt -r drc_sky130.drc +# ... or with EXPLICIT TOPCELL: klayout -b -rd input=my_layout.gds -rd topcell=mychiptop -rd report=sky130_drc.txt -r drc_sky130.drc +if $input && $topcell + source($input, $topcell) +elsif $input + source($input) +end + +if $report + report("SKY130 DRC runset", $report) +else + report("SKY130 DRC runset", File.join(File.dirname(RBA::CellView::active.filename), "sky130_drc.txt")) +end + +AL = true # do not change +CU = false # do not change +# choose betwen only one of AL or CU back-end flow here : +backend_flow = AL + +# enable / disable rule groups +FEOL = true # front-end-of-line checks +BEOL = true # back-end-of-line checks +OFFGRID = true # manufacturing grid/angle checks + +# klayout setup +######################## +# use a tile size of 1mm - not used in deep mode- +tiles(1000.um) +# use a tile border of 10 micron: +tile_borders(1.um) +#no_borders + +# hierachical +deep + +# use 4 cpu cores +threads(4) +# if more inof is needed, set true +verbose(false) + +# layers definitions +######################## +diff = input(65, 20) +tap = polygons(65, 44) +nwell = polygons(64, 20) +dnwell = polygons(64, 18) +pwbm = polygons(19, 44) +pwde = polygons(124, 20) +natfet = polygons(124, 21) +hvtr = polygons(18, 20) +hvtp = polygons(78, 44) +ldntm = polygons(11, 44) +hvi = polygons(75, 20) +tunm = polygons(80, 20) +lvtn = polygons(125, 44) +poly = polygons(66, 20) +hvntm = polygons(125, 20) +nsdm = polygons(93, 44) +psdm = polygons(94, 20) +rpm = polygons(86, 20) +urpm = polygons(79, 20) +npc = polygons(95, 20) +licon = polygons(66, 44) +li = input(67, 20) +mcon = polygons(67, 44) +m1 = polygons(68, 20) +via = polygons(68, 44) +m2 = polygons(69, 20) +via2 = polygons(69, 44) +m3 = polygons(70, 20) +via3 = polygons(70, 44) +m4 = polygons(71, 20) +via4 = polygons(71, 44) +m5 = polygons(72, 20) +pad = polygons(76, 20) +nsm = polygons(61, 20) +capm = polygons(89, 44) +cap2m = polygons(97, 44) +vhvi = polygons(74, 21) +uhvi = polygons(74, 22) +npn = polygons(82, 20) +inductor = polygons(82, 24) +vpp = polygons(82, 64) +pnp = polygons(82, 44) +lvs_prune = polygons(84, 44) +ncm = polygons(92, 44) +padcenter = polygons(81, 20) +mf = polygons(76, 44) +areaid_sl = polygons(81, 1) +areaid_ce = polygons(81, 2) +areaid_fe = polygons(81, 3) +areaid_sc = polygons(81, 4) +areaid_sf = polygons(81, 6) +areaid_sw = polygons(81, 7) +areaid_sr = polygons(81, 8) +areaid_mt = polygons(81, 10) +areaid_dt = polygons(81, 11) +areaid_ft = polygons(81, 12) +areaid_ww = polygons(81, 13) +areaid_ld = polygons(81, 14) +areaid_ns = polygons(81, 15) +areaid_ij = polygons(81, 17) +areaid_zr = polygons(81, 18) +areaid_ed = polygons(81, 19) +areaid_de = polygons(81, 23) +areaid_rd = polygons(81, 24) +areaid_dn = polygons(81, 50) +areaid_cr = polygons(81, 51) +areaid_cd = polygons(81, 52) +areaid_st = polygons(81, 53) +areaid_op = polygons(81, 54) +areaid_en = polygons(81, 57) +areaid_en20 = polygons(81, 58) +areaid_le = polygons(81, 60) +areaid_hl = polygons(81, 63) +areaid_sd = polygons(81, 70) +areaid_po = polygons(81, 81) +areaid_it = polygons(81, 84) +areaid_et = polygons(81, 101) +areaid_lvt = polygons(81, 108) +areaid_re = polygons(81, 125) +areaid_ag = polygons(81, 79) +poly_rs = polygons(66, 13) +diff_rs = polygons(65, 13) +pwell_rs = polygons(64, 13) +li_rs = polygons(67, 13) +cfom = polygons(22, 20) + + +# Define a new custom function that selects polygons by their number of holes: +# It will return a new layer containing those polygons with min to max holes. +# max can be nil to omit the upper limit. +class DRC::DRCLayer + def with_holes(min, max) + new_data = RBA::Region::new + self.data.each do |p| + if p.holes >= (min || 0) && (!max || p.holes <= max) + new_data.insert(p) + end + end + DRC::DRCLayer::new(@engine, new_data) + end +end + +# DRC section +######################## +info("DRC section") + +if FEOL +info("FEOL section") +gate = diff & poly + +# dnwell +dnwell.width(3.0, euclidian).output("dnwell.2", "dnwell.2 : min. dnwell width : 3.0um") +dnwell.not(uhvi).not(areaid_po).isolated(6.3, euclidian).output("dnwell.3", "dnwell.3 : min. dnwell spacing : 6.3um") +dnwell.and(pnp).output("dnwell.4", "dnwell.4 : dnwell must not overlap pnp") +dnwell.and(psdm).edges.not(psdm.edges).output("dnwell.5", "p+ must not straddle dnwell") +# dnwell.6 rue not coded + +# nwell +nwell.width(0.84, euclidian).output("nwell.1", "nwell.1 : min. nwell width : 0.84um") +nwell.isolated(1.27, euclidian).output("nwell.2a", "nwell.2a : min. nwell spacing (merged if less) : 1.27um") +# rule nwell.4 is suitable for digital cells +#nwell.not(uhvi).not(areaid_en20).not_interacting(tap.and(licon).and(li)).output("nwell.4", "nwell4 : all nwell exempt inside uhvi must contain a n+tap") +nwell.enclosing(dnwell.not(uhvi).not(areaid_po), 0.4, euclidian).output("nwell.5", "nwell.5 : min. nwell enclosing dnwell exempt unside uhvi : 0.4um") +dnwell.enclosing(nwell.not(uhvi), 1.03, euclidian).output("nwell.6", "nwell.6 : min. dnwell enclosing nwell exempt unside uhvi : 1.03um") +dnwell.separation(nwell, 4.5, euclidian).output("nwell.7", "nwell.7 : min. dnwell separation nwell : 4.5um") + +# pwbm +pwbm.not(uhvi).output("pwbm", "pwbm must be inside uhvi") +dnwell.and(uhvi).edges.not(pwbm).output("pwbm.4", "pwbm.4 : dnwell inside uhvi must be enclosed by pwbm") + +# pwde +pwde.not(pwbm).output("pwdem.3", "pwdem.3 : pwde must be inside pwbm") +pwde.not(uhvi).output("pwdem.4", "pwdem.4 : pwde must be inside uhvi") +pwde.not(dnwell).output("pwdem.5", "pwdem.5 : pwde must be inside dnwell") + +# hvtp +#hvtp.not(nwell).output("hvtp", "hvtp must inside nwell") +hvtp.width(0.38, euclidian).output("hvtp.1", "hvtp.1 : min. hvtp width : 0.38um") +hvtp.isolated(0.38, euclidian).output("hvtp.2", "hvtp.2 : min. hvtp spacing : 0.38um") +hvtp.enclosing(gate.and(psdm), 0.18, euclidian).output("hvtp.3", "hvtp.3 : min. hvtp enclosure of pfet gate : 0.18um") +hvtp.separation(gate.and(psdm), 0.18, euclidian).output("hvtp.4", "hvtp.4 : min. hvtp spacing pfet gate: 0.18um") +hvtp.with_area(0..0.265).output("hvtp.5", "hvtp.5 : min. hvtp area : 0.265um²") + +# hvtr +hvtr.width(0.38, euclidian).output("hvtr.1", "hvtr.1 : min. hvtr width : 0.38um") +hvtr.isolated(0.38, euclidian).output("hvtr.2", "hvtr.2 : min. hvtr spacing : 0.38um") + +# lvtn +lvtn.width(0.38, euclidian).output("lvtn.1", "lvtn.1 : min. lvtn width : 0.38um") +lvtn.isolated(0.38, euclidian).output("lvtn.2", "lvtn.2 : min. lvtn spacing : 0.38um") +lvtn.separation(diff.and(poly).not(uhvi), 0.18, euclidian).output("lvtn.3a", "lvtn.3a : min. lvtn spacing to gate : 0.18um") +lvtn.separation(diff.and(nwell).not(poly), 0.235, projection).output("lvtn.3b", "lvtn.3b : min. lvtn spacing to pfet s/d : 0.18um") +lvtn.enclosing(gate.not(uhvi), 0.18, euclidian).output("lvtn.4b", "lvtn.4b : min. lvtn enclosing to gate : 0.18um") +lvtn.separation(hvtp, 0.38, euclidian).output("lvtn.9", "lvtn.9 : min. lvtn spacing hvtp : 0.38um") +nwell.not_interacting(gate.and(nwell.not(hvi).not(areaid_ce))).enclosing(lvtn.not(uhvi), 0.18, euclidian).polygons.without_area(0).output("lvtn.4b", "lvtn.4b : min. lvtn enclosure of gate : 0.18um") +lvtn.separation(nwell.inside(areaid_ce), 0.38, euclidian).output("lvtn.12", "lvtn.12 : min. lvtn spacing nwell inside areaid.ce : 0.38um") +lvtn.with_area(0..0.265).output("lvtn.13", "lvtn.13 : min. lvtn area : 0.265um²") + +# ncm +ncm.and(tap.and(nwell).or(diff.not(nwell))).output("ncm.x.3", "ncm.x.3 : ncm must not overlap n+diff") +ncm.width(0.38, euclidian).output("ncm.1", "ncm.1 : min. ncm width : 0.38um") +ncm.isolated(0.38, euclidian).output("ncm.2", "ncm.2 : min. ncm spacing manual merge if smaller : 0.38um") +ncm.enclosing(diff.and(nwell), 0.18, euclidian).output("ncm.3", "ncm.3 : min. ncm enclosure of p+diff : 0.18um") +ncm.separation(lvtn.and(diff), 0.23, euclidian).output("ncm.5", "ncm.5 : min. ncm spacing lvtn diff : 0.23um") +ncm.separation(diff.not(nwell), 0.2, euclidian).output("ncm.6", "ncm.6 : min. ncm spacing nfet : 0.2um") +ncm.with_area(0..0.265).output("ncm.7", "ncm.13 : min. ncm area : 0.265um²") + +# diff-tap +difftap = diff + tap +difftap.width(0.15, euclidian).output("difftap.1", "difftap.1 : min. difftap width : 0.15um") +not_in_cell1 = layout(source.cell_obj).select("s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b" , "-s8fpls_pl8", "-s8fpls_rdrv4" , "-s8fpls_rdrv4f", "-s8fpls_rdrv8") +not_in_cell1_diff = not_in_cell1.input(65, 20) +not_in_cell1_diff.not(areaid_sc).not(poly).edges.and(gate.edges).with_length(0,0.42).output("difftap.2", "difftap.2: min. gate (exempt areaid.sc) width : 0.42um") +diff.and(areaid_sc).not(poly).edges.and(gate.edges).with_length(0,0.36).output("difftap.2", "difftap.2: min. gate inside areaid.sc width : 0.36um") +difftap.isolated(0.27, euclidian).output("difftap.3", "difftap.3 : min. difftap spacing : 0.27um") +tap.edges.and(diff.edges).with_length(0,0.29).output("difftap.4", "difftap.4 : min. tap bound by diffusion : 0.29um") +tap.edges.and(diff.edges).space(0.4, projection).output("difftap.5", "difftap.5 : min. tap bound by 2 diffusions : 0.4um") +(tap.edges.and(diff.edges)).extended(0.01, 0.01, 0, 0, false).not(tap.and(diff)).and(diff.or(tap)).output("difftap.6", "difftap.6 : diff and tap not allowed to extend beyong their abutting ege") +tap.edges.not_interacting(diff.edges).separation(diff.edges, 0.13, euclidian).output("difftap.7", "difftap.7 : min. diff/tap spacing to non-coincident diff edge : 0.13um") +diff.edges.not_interacting(tap.edges).separation(tap.edges, 0.13, euclidian).output("difftap.7", "difftap.7 : min. diff/tap spacing to non-coincident tap edge : 0.13um") +nwell.enclosing(diff.not(uhvi).and(psdm), 0.18, euclidian).output("difftap.8", "difftap.8 : min. p+diff enclosure by nwell : 0.18um") +diff.not(uhvi).and(nsdm).separation(nwell, 0.34, euclidian).output("difftap.9", "difftap.9 : min. n+diff spacing to nwell : 0.34um") +nwell.enclosing(tap.not(uhvi).and(nsdm), 0.18, euclidian).output("difftap.10", "difftap.10 : min. n+tap enclosure by nwell : 0.18um") +tap.not(uhvi).and(psdm).separation(nwell, 0.13, euclidian).output("difftap.11", "difftap.11 : min. p+tap spacing to nwell : 0.13um") + +# tunm +tunm.width(0.41, euclidian).output("tunm.1", "tunm.1 : min. tunm width : 0.41um") +tunm.isolated(0.5, euclidian).output("tunm.2", "tunm.2 : min. tunm spacing : 0.5um") +tunm.enclosing(gate, 0.095, euclidian).output("tunm.3", "tunm.3 : min. tunm beyond gate : 0.095um") +tunm.separation(gate.not_interacting(tunm), 0.095, euclidian).output("tunm.4", "tunm.4 : min. tunm spacing to gate outside tunm: 0.095um") +gate.and(tunm).edges.not(gate.edges).output("tunm.5", "tunm.5 : gate must not straddle tunm") +tunm.not(dnwell).output("tunm.6a", "tunm.6a : tunm not allowed outside dnwell") +tunm.with_area(0..0.672).output("tunm.7", "tunm.7 : min. tunm area : 0.672um²") + +# poly +poly.width(0.15, euclidian).output("poly.1a", "poly.1a : min. poly width : 0.15um") +poly.not(diff).edges.and(gate.and(lvtn).edges).space(0.35, euclidian).output("poly.1b", "poly.1b: min. lvtn gate width : 0.35um") +poly.isolated(0.21, euclidian).output("poly.2", "poly.2 : min. poly spacing : 0.21um") +poly.and(rpm.or(urpm).or(poly_rs)).width(0.33, euclidian).output("poly.3", "poly.3 : min. poly resistor width : 0.33um") +poly.not(gate).separation(diff, 0.075, projection).polygons.without_area(0).output("poly.4", "poly.4 : min. poly on field spacing to diff : 0.075um") +poly.not(gate).separation(tap, 0.055, euclidian).output("poly.5", "poly.5 : min. poly on field spacing to tap : 0.055um") +gate.separation(tap, 0.3, projection).polygons.and(diff).output("poly.6", "poly.6 : min. gate spacing to tap : 0.3um") +diff.enclosing(gate, 0.25, projection).polygons.without_area(0).output("poly.7", "poly.7 : min. source/drain length : 0.25um") +poly.enclosing(gate, 0.13, projection).polygons.without_area(0).output("poly.8", "poly.8 : min. poly extention gate (endcap) : 0.13um") +poly.and(rpm.or(urpm).or(poly_rs)).separation(poly.or(difftap), 0.48, euclidian).polygons.without_area(0).output("poly.9", "poly.9 : min. poly resistor space to poly or diff/tap : 0.48um") +diff.merged.edges.end_segments(0.01).and(poly).output("poly.10", "poly.10 : poly must not overlap diff corner") +gate.with_angle(0 .. 90).output("poly.11", "poly.11 : non 90 degree angle gate") +not_in_cell3 = layout(source.cell_obj).select("s8fgvr_n_fg2") +not_in_cell3_poly = not_in_cell3.input(66, 20) +not_in_cell3_poly.not(hvi).not(nwell.not(hvi)).and(tap).output("poly.12", "poly.12 : poly must not overlap tap") +poly.and(diff_rs).output("poly.15", "poly.15 : poly must not overlap diff resistor") + +# rpm +rpm.width(1.27, euclidian).output("rpm.1a", "rpm.1a : min. rpm width : 1.27um") +rpm.isolated(0.84, euclidian).output("rpm.2", "rpm.2 : min. rpm spacing : 0.84um") +rpm.enclosing(poly.and(poly_rs).and(psdm), 0.2, euclidian).output("rpm.3", "rpm.3 : min. rpm enclosure of poly resistor : 0.2um") +psdm.enclosing(poly.and(poly_rs).and(rpm), 0.11, euclidian).output("rpm.4", "rpm.4 : min. psdm enclosure of poly resistor : 0.11um") +npc.enclosing(poly.and(poly_rs).and(rpm), 0.095, euclidian).output("rpm.5", "rpm.5 : min. npc enclosure of poly resistor : 0.095um") +rpm.separation(nsdm, 0.2, euclidian).output("rpm.6", "rpm.6 : min. rpm spacing nsdm: 0.2um") +rpm.separation(poly, 0.2, euclidian).output("rpm.7", "rpm.7 : min. rpm spacing poly: 0.2um") +rpm.and(poly).edges.not(poly.edges).output("rpm.8", "rpm.8 : poly must not straddle rpm") +poly.and(poly_rs).and(rpm).separation(hvntm, 0.185, euclidian).output("rpm.9", "rpm.9 : min. poly resistor spacing hvntm: 0.185um") +rpm.and(pwbm).output("rpm.10", "rpm.107 : min. rpm spacing pwbm: na") + +# varac +varac = poly & tap & (nwell - hvi) - areaid_ce +tap.not(poly).edges.and(varac.edges).space(0.18, euclidian).output("varac.1", "varac.1: min. varac channel length : 0.18um") +tap.and(poly).edges.and(varac.edges).space(1.0, euclidian).output("varac.2", "varac.2: min. varac channel wdth : 1.0um") +varac.separation(hvtp, 0.18, euclidian).output("varac.3", "varac.3: min. varac channel space to hvtp : 0.18um") +varac.separation(licon.and(tap), 0.25, euclidian).output("varac.4", "varac.4: min. varac channel space to licon on tap : 0.25um") +nwell.enclosing(poly.overlapping(varac), 0.15, euclidian).output("varac.5", "varac.5: min. nwell enclosure of poly overlapping varac channel : 0.15um") +tap.overlapping(varac).separation(difftap, 0.27, euclidian).polygons.without_area(0).output("varac.6", "varac.6: min. varac channel tap space to difftap : 0.27um") +nwell.overlapping(varac).and(diff.and(nwell)).output("varac.7", "varac.7: nwell overlapping varac channel must not overlap p+diff") + +# photo +photodiode = dnwell & areaid_po +photodiode.edges.without_length(3.0).output("photo.2", "photo.2 : minimum/maximum width of photodiode : 3.0um") +photodiode.isolated(5.0, euclidian).output("photo.3", "photo.3 : mini. photodiode spacing : 5.0um") +photodiode.separation(dnwell, 5.3, euclidian).output("photo.4", "photo.4 : mini. photodiode spacing to dnwell : 5.3um") +areaid_po.not(dnwell).output("photo.5.6", "photo.5.6 : photodiode edges must coincide areaid.po and enclosed by dnwell") +photodiode.not(tap.not(nwell).holes).output("photo.7", "photo.7 : photodiode must be enclosed by p+tap ring") +photodiode.and(nwell).edges.without_length(0.84).output("photo.8", "photo.8 : minimum/maximum width of nwell inside photodiode : 0.84um") +areaid_po.edges.and(photodiode.and(nwell).sized(1.08)).without_length(12.0).output("photo.9", "photo.9 : minimum/maximum enclosure of nwell by photodiode : 1.08um") +photodiode.and(tap).edges.without_length(0.41).output("photo.10", "photo.10 : minimum/maximum width of tap inside photodiode : 0.41um") + +# npc +npc.width(0.27, euclidian).output("npc.1", "npc.1 : min. npc width : 0.27um") +npc.isolated(0.27, euclidian).output("npc.2", "npc.2 : min. npc spacing, should be mnually merge if less : 0.27um") +npc.separation(gate, 0.09, euclidian).output("npc.4", "npc.4 : min. npc spacing to gate : 0.09um") + +# nsdm/psdm +npsdm = nsdm + psdm +nsdm.width(0.38, euclidian).output("nsdm.1", "nsdm.1 : min. nsdm width : 0.38um") +psdm.width(0.38, euclidian).output("psdm.1", "psdm.1 : min. psdm width : 0.38um") +nsdm.isolated(0.38, euclidian).output("n/psdm.1", "n/psdm.1 : min. nsdm spacing, should be mnually merge if less : 0.38um") +psdm.isolated(0.38, euclidian).output("n/psdm.1", "n/psdm.1 : min. psdm spacing, should be mnually merge if less : 0.38um") +npsdm.enclosing(diff, 0.125, euclidian).polygons.not(tap.sized(0.125)).output("n/psdm.5a", "n/psdm.5a : min. n/psdm enclosure diff except butting edge : 0.125um") +npsdm.enclosing(tap, 0.125, euclidian).polygons.not(diff.sized(0.125)).output("n/psdm.5b", "n/psdm.5b : min. n/psdm enclosure tap except butting edge : 0.125um") +tap.edges.and(diff.edges).not(npsdm).output("n/psdm.6", "n/psdm.6 : min. n/psdm enclosure of butting edge : 0.0um") +nsdm.and(difftap).separation(psdm.and(difftap), 0.13, euclidian).polygons.without_area(0).output("n/psdm.7", "n/psdm.7 : min. nsdm diff spacing to psdm diff except butting edge : 0.13um") +diff.and((nsdm.and(nwell)).or(psdm.not(nwell))).output("n/psdm.8", "n/psdm.8 : diff should be the opposite type of well/substrate underneath") +tap.and((nsdm.not(nwell)).or(psdm.and(nwell))).output("n/psdm.8", "n/psdm.8 : tap should be the same type of well/substrate underneath") +tap.and(diff).without_area(0).output("tap and diff", "tap and diff must not overlap") +nsdm.with_area(0..0.265).output("n/psdm.10a", "n/psdm.10a : min. nsdm area : 0.265um²") +psdm.with_area(0..0.265).output("n/psdm.10b", "n/psdm.10b : min. psdm area : 0.265um²") + +# licon +licon.not(poly.interacting(poly_rs)).edges.without_length(0.17).output("licon.1", "licon.1 : minimum/maximum width of licon : 0.17um") +licon.and(poly.interacting(poly_rs)).not_interacting((licon.and(poly.interacting(poly_rs)).edges.with_length(0.19)).or(licon.and(poly.interacting(poly_rs)).edges.with_length(2.0))).output("licon.1b/c", "licon.1b/c : minimum/maximum width/length of licon inside poly resistor : 2.0/0.19um") +licon.isolated(0.17, euclidian).output("licon.2", "licon.2 : min. licon spacing : 0.17um") +licon.and(poly.interacting(poly_rs)).edges.with_length(0.19).space(0.35, euclidian).output("licon.2b", "licon.2b : min. licon 0.19um edge on resistor spacing : 0.35um") +licon.interacting(licon.and(poly.interacting(poly_rs)).edges.with_length(2.0)).separation(licon.and(poly.interacting(poly_rs)), 0.51, euclidian).output("licon.2c", "licon.2c : min. licon 2.0um edge on resistor spacing : 0.51um") +licon.and(poly.interacting(poly_rs)).separation(licon.not(poly.interacting(poly_rs)), 0.51, euclidian).output("licon.2d", "licon.2d : min. licon on resistor spacing other licon : 0.51um") +# rule licon.3 not coded +licon.not(li).not(poly.or(diff).or(tap)).output("licon.4", "licon.4 : min. licon must overlap li and (poly or tap or diff) ") +diff.enclosing(licon, 0.04, euclidian).output("licon.5", "licon.5 : min. diff enclosure of licon : 0.04um") +tap.edges.and(diff.edges).separation(licon.and(tap).edges, 0.06, euclidian).output("licon.6", "licon.6 : min. abutting edge spacing to licon tap : 0.06um") +licon_edges_with_less_enclosure_tap = tap.enclosing(licon, 0.12, projection).second_edges +opposite1 = (licon.edges - licon_edges_with_less_enclosure_tap).width(0.17 + 1.dbu, projection).polygons +licon.not_interacting(opposite1).output("licon.7", "licon.7 : min. tap enclosure of licon by one of 2 opposite edges : 0.12um") +poly.enclosing(licon, 0.05, euclidian).output("licon.8", "licon.8 : min. poly enclosure of licon : 0.05um") +licon008 = licon.interacting(poly.enclosing(licon, 0.08, euclidian).polygons) +licon_edges_with_less_enclosure_poly = poly.enclosing(licon, 0.08, projection).second_edges +opposite2 = (licon.edges - licon_edges_with_less_enclosure_poly).width(0.17 + 1.dbu, projection).polygons +licon008.not_interacting(opposite2).output("licon.8a", "licon.8a : min. poly enclosure of licon by one of 2 opposite edges : 0.08um") +# rule licon.9 not coded +licon.and(tap.and(nwell.not(hvi))).separation(varac, 0.25, euclidian).output("licon.10", "licon.10 : min. licon spacing to varac channel : 0.25um") +not_in_cell4 = layout(source.cell_obj).select("-s8fs_gwdlvx4", "-s8fs_gwdlvx8", "-s8fs_hvrsw_x4", "-s8fs_hvrsw8", "-s8fs_hvrsw264", "-s8fs_hvrsw520", "-s8fs_rdecdrv", "-s8fs_rdec8”, “s8fs_rdec32", "-s8fs_rdec264", "-s8fs_rdec520") +not_in_cell4_licon = not_in_cell4.input(66, 44) +not_in_cell4_licon.and(diff.or(tap)).separation(gate.not(areaid_sc), 0.055, euclidian).output("licon.11", "licon.11 : min. licon spacing to gate : 0.055um") +licon.and(diff.or(tap)).separation(gate.and(areaid_sc), 0.05, euclidian).output("licon.11a", "licon.11a : min. licon spacing to gate inside areaid.sc : 0.05um") +in_cell4 = layout(source.cell_obj).select("+s8fs_gwdlvx4", "+s8fs_gwdlvx8", "+s8fs_hvrsw_x4", "+s8fs_hvrsw8", "+s8fs_hvrsw264", "+s8fs_hvrsw520") +in_cell4_licon = in_cell4.input(66, 44) +in_cell4_licon.and(diff.or(tap)).separation(gate, 0.04, euclidian).output("licon.11c", "licon.11c : min. licon spacing to gate for specific cells: 0.04um") +# rules 11.b , 11.d not coded +diff.interacting(gate).not(diff.interacting(gate).width(5.7, euclidian).polygons).output("licon.12", "licon.12 : max. sd width without licon : 5.7um") +licon.and(diff.or(tap)).separation(npc, 0.09, euclidian).output("licon.13", "licon.13 : min. difftap licon spacing to npc : 0.09um") +licon.and(poly).separation(diff.or(tap), 0.19, euclidian).output("licon.14", "licon.14 : min. poly licon spacing to difftap : 0.19um") +npc.enclosing(licon.and(poly), 0.1, euclidian).output("licon.15", "licon.15 : min. npc enclosure of poly-licon : 0.1um") +# rule licon.16 not applicable for the diff for the nmos of a nand gates or the pmos of a nor gates +#diff.not(gate).not_interacting(licon).output("licon.16", "licon.16 : diff must enclose one licon") +tap.not(uhvi).not_interacting(licon).output("licon.16", "licon.16 : tap must enclose one licon") +poly.and(tap).edges.not(tap.edges).output("licon.17", "licon.17 : tap must not straddle poly") +npc.not_interacting(licon.and(poly)).output("licon.18", "licon.18 : npc mut enclosed one poly-licon") + +# li +not_in_cell5 = layout(source.cell_obj).select("-s8rf2_xcmvpp_hd5_*") +not_in_cell5_li = not_in_cell5.input(67, 20) +not_in_cell5_li.width(0.17, euclidian).output("li.1", "li.1 : min. li width : 0.17um") +in_cell5 = layout(source.cell_obj).select("+s8rf2_xcmvpp_hd5_*") +in_cell5_li = in_cell5.input(67, 20) +in_cell5_li.width(0.14, euclidian).output("li.1a", "li.1a : min. li width for the cells s8rf2_xcmvpp_hd5_* : 0.14um") +# rule li.2 not coded +not_in_cell5_li.isolated(0.17, euclidian).output("li.3", "li.3 : min. li spacing : 0.17um") +in_cell5_li.isolated(0.14, euclidian).output("li.3a", "li.3a : min. li spacing for the cells s8rf2_xcmvpp_hd5_* : 0.14um") +licon08 = licon.interacting(li.enclosing(licon, 0.08, euclidian).polygons) +licon_edges_with_less_enclosure_li = li.enclosing(licon, 0.08, projection).second_edges +opposite3 = (licon.edges - licon_edges_with_less_enclosure_li).width(0.17 + 1.dbu, projection).polygons +licon08.not_interacting(opposite3).output("li.5", "li.5 : min. li enclosure of licon of 2 opposite edges : 0.08um") +li.with_area(0..0.0561).output("li.6", "li.6 : min. li area : 0.0561um²") + +# vpp +vpp.width(1.43, euclidian).output("vpp.1", "vpp.1 : min. vpp width : 1.43um") +# rules 1.b, 1.c not coded +vpp.and(poly.or(difftap)).output("vpp.3", "vpp.3 : vpp must not overlapp poly or diff or tap") +vpp.and(nwell).edges.not(vpp.edges).output("vpp.4", "vpp.4 : vpp must not straddle nwell") +vpp.and(dnwell).edges.not(vpp.edges).output("vpp.4", "vpp.4 : vpp must not straddle dnwell") +vpp.and(poly.or(li).or(m1).or(m2)).separation(poly.or(li).or(m1).or(m2), 1.5, euclidian).polygons.with_area(2.25,nil).output("vpp.5", "vpp.5 : min. vpp spacing to poly or li or m1 or m2 : 1.5um") +vpp.with_area(0..area(vpp.and(m3))*0.25).output("vpp.5a", "vpp.5a : max. m3 density in vpp : 0.25") +vpp.with_area(0..area(vpp.and(m4))*0.3).output("vpp.5b", "vpp.5b : max. m4 density in vpp : 0.3") +vpp.with_area(0..area(vpp.and(m5))*0.4).output("vpp.5c", "vpp.5c : max. m5 density in vpp : 0.4") +nwell.enclosing(vpp, 1.5, euclidian).output("vpp.8", "vpp.8 : nwell enclosure of vpp : 1.5") +vpp.separation(nwell, 1.5, euclidian).polygons.without_area(0).output("vpp.9", "vpp.9 : vpp spacing to nwell : 1.5") +# rule vpp.10 not coded +# rule vpp.11 not coded because moscap is not defined properly by any gds layer +# rules vpp.12a, 12b, 12c not coded because specific to one cell +if backend_flow = CU + m1.separation(vpp.and(m1), 0.16, euclidian).polygons.without_area(0).output("vpp.13", "vpp.13 : m1 spacing to m1inside vpp : 0.16") +end + +# CAPM +capm.width(1.0, euclidian).output("capm.1", "capm.1 : min. capm width : 1.0um") +capm.isolated(0.84, euclidian).output("capm.2a", "capm.2a : min. capm spacing : 0.84um") +m2.interacting(capm).isolated(1.2, euclidian).output("capm.2b", "capm.2b : min. capm spacing : 1.2um") +m2.enclosing(capm, 0.14, euclidian).output("capm.3", "capm.3 : min. m2 enclosure of capm : 0.14um") +capm.enclosing(via2, 0.14, euclidian).output("capm.4", "capm.4 : min. capm enclosure of via2 : 0.14um") +capm.separation(via2, 0.14, euclidian).output("capm.5", "capm.5 : min. capm spacing to via2 : 0.14um") +capm.sized(-20.0).sized(20.0).output("capm.6", "capm.6 : max. capm lenght/width : 20um") +capm.with_angle(0 .. 90).output("capm.7", "capm.7 : capm not rectangle") +capm.separation(via, 0.14, euclidian).polygons.without_area(0).output("capm.8", "capm.8 : min. capm spacing to via : 0.14um") +capm.and(nwell).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle nwell") +capm.and(diff).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle diff") +capm.and(tap).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle tap") +capm.and(poly).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle poly") +capm.and(li).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle li") +capm.and(m1).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle m1") +capm.separation(m2.not_interacting(capm), 0.14, euclidian).output("capm.11", "capm.11 : min. capm spacing to m2 not overlapping capm : 0.5um") + +end #FEOL + +if BEOL +info("BEOL section") + +# ct +mcon.edges.without_length(0.17).output("ct.1", "ct.1 : minimum/maximum width of mcon : 0.17um") +mcon.isolated(0.19, euclidian).output("ct.2", "ct.2 : min. mcon spacing : 0.19um") +# rule ct.3 not coded +mcon.not(li).output("ct.4", "ct.4 : mcon should covered by li") +if backend_flow = CU + li.interacting(li.and(m1).not(mcon).with_holes(1,10)).enclosing(mcon, 0.2, euclidian).output("ct.irdrop.1", "ct.irdrop.1 : min. li enclsoure of 1..10 mcon : 0.2um") + li.interacting(li.and(m1).not(mcon).with_holes(11,100)).enclosing(mcon, 0.3, euclidian).output("ct.irdrop.2", "ct.irdrop.2 : min. li enclsoure of 11..100 mcon : 0.3um") +end + +# m1 +huge_m1 = m1.sized(-1.5).sized(1.5) +m1.width(0.14, euclidian).output("m1.1", "m1.1 : min. m1 width : 0.14um") +m1.isolated(0.14, euclidian).output("m1.2", "m1.2 : min. m1 spacing : 0.14um") +huge_m1.separation(m1, 0.28, euclidian).output("m1.3ab", "m1.3ab : min. 3um.m1 spacing m1 : 0.28um") +not_in_cell6 = layout(source.cell_obj).select("-s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b", "-s8fpls_pl8", "-s8fs_cmux4_fm") +not_in_cell6_m1 = not_in_cell6.input(68, 20) +not_in_cell6_m1.enclosing(mcon, 0.03, euclidian).output("m1.4", "m1.4 : min. m1 enclosure of mcon : 0.03um") +in_cell6 = layout(source.cell_obj).select("+s8cell_ee_plus_sseln_a", "+s8cell_ee_plus_sseln_b", "+s8cell_ee_plus_sselp_a", "+s8cell_ee_plus_sselp_b", "+s8fpls_pl8", "+s8fs_cmux4_fm") +in_cell6_m1 = in_cell6.input(68, 20) +in_cell6_m1.enclosing(mcon, 0.005, euclidian).output("m1.4a", "m1.4a : min. m1 enclosure of mcon for specific cells : 0.005um") +m1.with_area(0..0.083).output("m1.6", "m1.6 : min. m1 area : 0.083um²") +m1.holes.with_area(0..0.14).output("m1.7", "m1.7 : min. m1 holes area : 0.14um²") +if backend_flow = AL + mcon06 = mcon.interacting(poly.enclosing(m1, 0.06, euclidian).polygons) + mcon_edges_with_less_enclosure_m1 = m1.enclosing(mcon, 0.06, projection).second_edges + opposite4 = (mcon.edges - mcon_edges_with_less_enclosure_m1).width(0.17 + 1.dbu, projection).polygons + mcon06.not_interacting(opposite4).output("m1.5", "m1.5 : min. m1 enclosure of mcon of 2 opposite edges : 0.06um") + # rule m1.pd.1, rule m1.pd.2a, rule m1.pd.2b not coded +end +if bakend_flow = CU + m1.sized(-2.0).sized(2.0).output("m1.11", "m1.11 : max. m1 width after slotting : 4.0um") + # rule m1.12 not coded because inconsistent with m1.11 + # rule m1.13, m1.14, m1.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +end + +# via +#rule via.3 not coded +via.not(m1).output("via.4c.5c", "via.4c.5c : m1 must enclose all via") +if backend_flow = AL + via.not(areaid_mt).edges.without_length(0.15).output("via.1a", "via.1a : minimum/maximum width of via : 0.15um") + via.and(areaid_mt).not_interacting((via.and(areaid_mt).edges.without_length(0.15)).or(via.and(areaid_mt).edges.without_length(0.23)).or(via.and(areaid_mt).edges.without_length(0.28))).output("via.1b", "via.1b : minimum/maximum width of via in areaid.mt: 0.15um or 0.23um or 0.28um") + via.isolated(0.17, euclidian).output("via.2", "via.2 : min. via spacing : 0.17um") + m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.055, euclidian).output("via.4a", "via.4a : min. m1 enclosure of 0.15um via : 0.055um") + m1.enclosing(via.not_interacting(via.edges.without_length(0.23)), 0.03, euclidian).output("via.4b", "via.4b : min. m1 enclosure of 0.23um via : 0.03um") + via1_edges_with_less_enclosure_m1 = m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.085, projection).second_edges + opposite5 = (via.not_interacting(via.edges.without_length(0.15)).edges - via1_edges_with_less_enclosure_m1).width(0.15 + 1.dbu, projection).polygons + via.not_interacting(via.edges.without_length(0.15)).not_interacting(opposite5).output("via1.5a", "via1.5a : min. m1 enclosure of 0.15um via of 2 opposite edges : 0.085um") + via2_edges_with_less_enclosure_m1 = m1.enclosing(via.not_interacting(via.edges.without_length(0.23)), 0.06, projection).second_edges + opposite6 = (via.not_interacting(via.edges.without_length(0.23)).edges - via2_edges_with_less_enclosure_m1).width(0.23 + 1.dbu, projection).polygons + via.not_interacting(via.edges.without_length(0.23)).not_interacting(opposite6).output("via1.5b", "via1.5b : min. m1 enclosure of 0.23um via of 2 opposite edges : 0.06um") +end +if backend_flow = CU + via.not(areaid_mt).edges.without_length(0.18).output("via.11", "via.11 : minimum/maximum width of via : 0.18um") + via.isolated(0.13, euclidian).output("via.12", "via.12 : min. via spacing : 0.13um") + # rule via.13 not coded because not understandable + via1_edges_with_less_enclosure_m1 = m1.enclosing(via, 0.04, projection).second_edges + opposite5 = (via.edges - via1_edges_with_less_enclosure_m1).width(0.18 + 1.dbu, projection).polygons + via.not_interacting(opposite5).output("via1.14", "via1.14 : min. m1 enclosure of 0.04um via of 2 opposite edges : 0.04um") + # rules via.irdrop.1, via.irdrop.2, via.irdrop.3, via.irdrop.4 not coded because not understandable +end + +# m2 +huge_m2 = m2.sized(-1.5).sized(1.5) +m2.width(0.14, euclidian).output("m2.1", "m2.1 : min. m2 width : 0.14um") +m2.isolated(0.14, euclidian).output("m2.2", "m2.2 : min. m2 spacing : 0.14um") +huge_m2.separation(m2, 0.28, euclidian).output("m2.3ab", "m2.3ab : min. 3um.m2 spacing m2 : 0.28um") +# rule m2.3c not coded +m2.with_area(0..0.0676).output("m2.6", "m2.6 : min. m2 area : 0.0676um²") +m2.holes.with_area(0..0.14).output("m2.7", "m2.7 : min. m2 holes area : 0.14um²") +via.not(m2).output("m2.via", "m2.via : m2 must enclose via") +if backend_flow = AL + m2.enclosing(via, 0.055, euclidian).output("m2.4", "m2.4 : min. m2 enclosure of via : 0.055um") + via_edges_with_less_enclosure_m2 = m2.enclosing(via, 0.085, projection).second_edges + opposite7 = (via.edges - via_edges_with_less_enclosure_m2).width(0.14 + 1.dbu, projection).polygons + via.not_interacting(opposite7).output("m2.5", "m2.5 : min. m2 enclosure of via of 2 opposite edges : 0.085um") + # rule m2.pd.1, rule m2.pd.2a, rule m2.pd.2b not coded +end +if bakend_flow = CU + m2.sized(-2.0).sized(2.0).output("m2.11", "m2.11 : max. m2 width after slotting : 4.0um") + # rule m2.12 not coded because inconsistent with m2.11 + # rule m2.13, m2.14, m2.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +end + +# via2 +#rule via233 not coded +via2.not(m2).output("via2", "via2 : m2 must enclose all via2") +if backend_flow = AL + via2.not(areaid_mt).edges.without_length(0.2).output("via2.1a", "via2.1a : minimum/maximum width of via2 : 0.2um") + via2.and(areaid_mt).not_interacting((via2.and(areaid_mt).edges.without_length(0.2)).or(via2.and(areaid_mt).edges.without_length(1.2)).or(via2.and(areaid_mt).edges.without_length(1.5))).output("via2.1b", "via2.1b : minimum/maximum width of via2 in areaid.mt: 0.2um or 1.2um or 1.5um") + via2.isolated(0.2, euclidian).output("via2.2", "via2.2 : min. via2 spacing : 0.2um") + m2.enclosing(via2, 0.04, euclidian).output("via2.4", "via2.4 : min. m2 enclosure of via2 : 0.04um") + m2.enclosing(via2.not_interacting(via2.edges.without_length(1.5)), 0.14, euclidian).output("via2.4a", "via2.4a : min. m2 enclosure of 1.5um via2 : 0.14um") + via2_edges_with_less_enclosure_m2 = m2.enclosing(via2, 0.085, projection).second_edges + opposite8 = (via2.edges - via2_edges_with_less_enclosure_m2).width(0.2 + 1.dbu, projection).polygons + via2.not_interacting(opposite8).output("via2.5", "via2.5 : min. m2 enclosure of via2 of 2 opposite edges : 0.085um") +end +if backend_flow = CU + via2.edges.without_length(0.21).output("via2.11", "via2.11 : minimum/maximum width of via2 : 0.21um") + via2.isolated(0.18, euclidian).output("via2.12", "via2.12 : min. via2 spacing : 0.18um") + # rule via2.13 not coded because not understandable, or not clear + m2.enclosing(via2, 0.035, euclidian).output("via2.14", "via2.14 : min. m2 enclosure of via2 : 0.035um") + # rules via2.irdrop.1, via2.irdrop.2, via2.irdrop.3, via2.irdrop.4 not coded because not understandable +end + +# m3 +huge_m3 = m3.sized(-1.5).sized(1.5) +m3.width(0.3, euclidian).output("m3.1", "m3.1 : min. m3 width : 0.3um") +m3.isolated(0.3, euclidian).output("m3.2", "m3.2 : min. m3 spacing : 0.3um") +huge_m3.separation(m3, 0.4, euclidian).output("m3.3ab", "m3.3ab : min. 3um.m3 spacing m3 : 0.4um") +# rule m3.3c not coded +m3.with_area(0..0.24).output("m3.6", "m3.6 : min. m2 area : 0.24um²") +via2.not(m3).output("m3.via2", "m3.via2 : m3 must enclose via2") +if backend_flow = AL + m3.enclosing(via2, 0.065, euclidian).output("m3.4", "m3.4 : min. m3 enclosure of via2 : 0.065um") + via2_edges_with_less_enclosure_m3 = m3.enclosing(via2, 0.085, projection).second_edges + opposite9 = (via2.edges - via2_edges_with_less_enclosure_m3).width(0.3 + 1.dbu, projection).polygons + via2.not_interacting(opposite9).output("m3.5", "m3.5 : min. m3 enclosure of via2 of 2 opposite edges : 0.085um") + # rule m3.pd.1, rule m3.pd.2a, rule m3.pd.2b not coded +end +if bakend_flow = CU + m3.holes.with_area(0..0.2).output("m3.7", "m3.7 : min. m2 holes area : 0.2um²") + m3.sized(-2.0).sized(2.0).output("m3.11", "m3.11 : max. m3 width after slotting : 4.0um") + # rule m3.12 not coded because inconsistent with m3.11 + # rule m3.13, m3.14, m3.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +end + +# via3 +#rule via3.3 not coded +via3.not(m3).output("via3", "via3 : m3 must enclose all via3") +if backend_flow = AL + via3.not(areaid_mt).edges.without_length(0.2).output("via3.1a", "via3.1a : minimum/maximum width of via3 : 0.2um") + via3.and(areaid_mt).not_interacting((via3.and(areaid_mt).edges.without_length(0.2)).or(via3.and(areaid_mt).edges.without_length(0.8))).output("via3.1a", "via3.1a : minimum/maximum width of via3 in areaid.mt: 0.2um or 0.8um") + via3.isolated(0.2, euclidian).output("via3.2", "via3.2 : min. via3 spacing : 0.2um") + m3.enclosing(via3, 0.06, euclidian).output("via3.4", "via3.4 : min. m3 enclosure of via3 : 0.06um") + via3_edges_with_less_enclosure_m3 = m3.enclosing(via3, 0.09, projection).second_edges + opposite10 = (via3.edges - via3_edges_with_less_enclosure_m3).width(0.2 + 1.dbu, projection).polygons + via3.not_interacting(opposite10).output("via3.5", "via3.5 : min. m2 enclosure of via3 of 2 opposite edges : 0.09um") +end +if backend_flow = CU + via3.edges.without_length(0.21).output("via3.11", "via3.11 : minimum/maximum width of via3 : 0.21um") + via3.isolated(0.18, euclidian).output("via3.12", "via3.12 : min. via3 spacing : 0.18um") + m3.enclosing(via3, 0.055, euclidian).output("via3.13", "via3.13 : min. m3 enclosure of via3 : 0.055um") + # rule via3.14 not coded because not understandable, or not clear + # rules via3.irdrop.1, via3.irdrop.2, via3.irdrop.3, via3.irdrop.4 not coded because not understandable +end + +# nsm +nsm.width(3.0, euclidian).output("nsm.1", "nsm.1 : min. nsm width : 3.0um") +nsm.isolated(4.0, euclidian).output("nsm.2", "nsm.2 : min. nsm spacing : 4.0um") +nsm.enclosing(diff, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of diff : 3.0um") +nsm.enclosing(tap, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of tap : 3.0um") +nsm.enclosing(poly, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of poly : 3.0um") +nsm.enclosing(li, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of li : 3.0um") +nsm.enclosing(m1, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m1 : 3.0um") +nsm.enclosing(m2, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m2 : 3.0um") +nsm.enclosing(m3, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m3 : 3.0um") +nsm.enclosing(m4, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m4 : 3.0um") +nsm.enclosing(m5, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m5 : 3.0um") +nsm.enclosing(cfom, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of cfom : 3.0um") +if backend_flow = AL + nsm.separation(diff, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to diff : 1.0um") + nsm.separation(tap, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to tap : 1.0um") + nsm.separation(poly, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to poly : 1.0um") + nsm.separation(li, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to li : 1.0um") + nsm.separation(m1, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m1 : 1.0um") + nsm.separation(m2, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m2 : 1.0um") + nsm.separation(m3, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m3 : 1.0um") + nsm.separation(m4, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m4 : 1.0um") + nsm.separation(m5, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m5 : 1.0um") + nsm.separation(cfom, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to cfom : 1.0um") +end + +# m4 +huge_m4 = m4.sized(-1.5).sized(1.5) +m4.width(0.3, euclidian).output("m4.1", "m4.1 : min. m4 width : 0.3um") +m4.isolated(0.3, euclidian).output("m4.2", "m4.2 : min. m4 spacing : 0.3um") +m4.with_area(0..0.24).output("m4.4", "m4.4 : min. m2 area : 0.24um²") +huge_m4.separation(m4, 0.4, euclidian).output("m4.5ab", "m4.5ab : min. 3um.m4 spacing m4 : 0.4um") +via3.not(m4).output("m4.via3", "m4.via3 : m4 must enclose via3") +if backend_flow = AL + m4.enclosing(via3, 0.065, euclidian).output("m4.3", "m4.3 : min. m4 enclosure of via3 : 0.065um") + via3_edges_with_less_enclosure_m4 = m4.enclosing(via2, 0.085, projection).second_edges + opposite9 = (via3.edges - via3_edges_with_less_enclosure_m4).width(0.3 + 1.dbu, projection).polygons + via3.not_interacting(opposite9).output("m4.5", "m4.5 : min. m4 enclosure of via3 of 2 opposite edges : 0.085um") + # rule m4.pd.1, rule m4.pd.2a, rule m4.pd.2b not coded +end +if bakend_flow = CU + m4.holes.with_area(0..0.2).output("m4.7", "m4.7 : min. m2 holes area : 0.2um²") + m4.sized(-5.0).sized(5.0).output("m4.11", "m4.11 : max. m4 width after slotting : 10.0um") + # rule m4.12 not coded because inconsistent with m4.11 + # rule m4.13, m4.14, m4.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 + m4.enclosing(via3, 0.06, euclidian).output("m4.15", "m4.15 : min. m4 enclosure of via3 : 0.06um") +end + +# via4 +via4.edges.without_length(0.8).output("via4.1a", "via4.1a : minimum/maximum width of via4 : 0.8um") +via4.isolated(0.8, euclidian).output("via4.2", "via4.2 : min. via4 spacing : 0.8um") +#rule via4.3 not coded +m4.enclosing(via4, 0.19, euclidian).output("via4.4", "via4.4 : min. m4 enclosure of via4 : 0.19um") +via4.not(m4).output("via4", "via4 : m4 must enclose all via4") +if backend_flow = CU + # rules via4.irdrop.1, via4.irdrop.2, via4.irdrop.3, via4.irdrop.4 not coded because not understandable +end + +# m5 +m5.width(1.6, euclidian).output("m5.1", "m5.1 : min. m5 width : 1.6um") +m5.isolated(1.6, euclidian).output("m5.2", "m5.2 : min. m5 spacing : 1.6um") +via4.not(m5).output("m5.via4", "m5.via4 : m5 must enclose via4") +m5.enclosing(via4, 0.31, euclidian).output("m5.3", "m4.3 : min. m5 enclosure of via4 : 0.31um") + +# pad +pad.isolated(1.27, euclidian).output("pad.2", "pad.2 : min. pad spacing : 1.27um") + +end #BEOL + +if FEOL +info("FEOL section") + +# mf +mf.not_interacting(mf.edges.without_length(0.8)).output("mf.1", "mf.1 : minimum/maximum width of fuse : 0.8um") +mf.not_interacting(mf.edges.without_length(7.2)).output("mf.2", "mf.2 : minimum/maximum length of fuse : 7.2um") +mf.isolated(1.96, euclidian).output("mf.3", "mf.3 : min. fuse center spacing : 2.76um") +# fuses need more clarification on fuse_shield, fuse layers ... + +# hvi +hvi.width(0.6, euclidian).output("hvi.1", "hvi.1 : min. hvi width : 0.6um") +hvi.isolated(0.7, euclidian).output("hvi.2", "hvi.2 : min. hvi spacing, merge if less : 0.7um") +hvi.and(tunm).output("hvi.4", "hvi.4 : hvi must not overlapp tunm") +hvi.and(nwell).separation(nwell, 2.0, euclidian).output("hvnwell.8", "hvnwelli.8 : min. hvnwel spacing to nwell : 2.0") +areaid_hl.not(hvi).output("hvnwel.9", "hvnwell.9 : hvi must overlapp hvnwell") +# rule hvnell.10 not coded +diff.not(psdm.and(diff_rs)).and(hvi).width(0.29, euclidian).output("hvdifftap.14", "hvdifftap.14 : min. diff inside hvi width : 0.29um") +diff.and(psdm.and(diff_rs)).and(hvi).width(0.15, euclidian).output("hvdifftap.14a", "hvdifftap.14a : min. p+diff resistor inside hvi width : 0.15um") +diff.and(hvi).isolated(0.3, euclidian).output("hvdifftap.15a", "hvdifftap.15a : min. diff inside hvi spacing : 0.3um") +diff.and(hvi).and(nsdm).separation(diff.and(hvi).and(psdm), 0.37, euclidian).polygons.without_area(0).output("hvdifftap.15b", "hvdifftap.15b : min. n+diff inside hvi spacing to p+diff inside hvi except abutting: 0.37um") +tap.and(hvi).edges.and(diff).without_length(0.7).output("hvdifftap.16", "hvdifftap.16 : min. tap inside hvi abuttng diff : 0.7um") +hvi.and(nwell).enclosing(diff, 0.33, euclidian).output("hvdifftap.17", "hvdifftap.17 : min. hvnwell enclosure of p+diff : 0.33um") +hvi.and(nwell).separation(diff, 0.43, euclidian).output("hvdifftap.18", "hvdifftap.18 : min. hvnwell spacing to n+diff : 0.43um") +hvi.and(nwell).enclosing(tap, 0.33, euclidian).output("hvdifftap.19", "hvdifftap.19 : min. hvnwell enclosure of n+tap : 0.33um") +hvi.and(nwell).separation(tap, 0.43, euclidian).output("hvdifftap.20", "hvdifftap.20 : min. hvnwell spacing to p+tap : 0.43um") +hvi.and(diff).edges.not(diff.edges).output("hvdifftap.21", "hvdifftap.21 : diff must not straddle hvi") +hvi.and(tap).edges.not(tap.edges).output("hvdifftap.21", "hvdifftap.21 : tap must not straddle hvi") +hvi.enclosing(difftap, 0.18, euclidian).output("hvdifftap.22", "hvdifftap.22 : min. hvi enclosure of diff or tap : 0.18um") +hvi.separation(difftap, 0.18, euclidian).output("hvdifftap.23", "hvdifftap.23 : min. hvi spacing to diff or tap : 0.18um") +hvi.and(diff).not(nwell).separation(nwell, 0.43, euclidian).output("hvdifftap.24", "hvdifftap.24 : min. hv n+diff spacing to nwell : 0.43um") +diff.and(hvi).not(nwell).isolated(1.07, euclidian).polygons.and(tap).output("hvdifftap.25", "hvdifftap.25 : min. n+diff inside hvi spacing accros p+tap : 1.07um") +diff.not(poly).edges.and(gate.and(hvi).edges).space(0.35, euclidian).output("hvpoly.13", "hvpoly.13: min. hvi gate length : 0.5um") +hvi.and(poly).edges.not(poly.edges).output("hvpoly.14", "hvpoly.14 : poly must not straddle hvi") + +# hvntm +hvntm.width(0.7, euclidian).output("hvntm.1", "hvntm.1 : min. hvntm width : 0.7um") +hvntm.isolated(0.7, euclidian).output("hvntm.2", "hvntm.2 : min. hvntm spacing : 0.7um") +hvntm.enclosing(diff.and(nwell).and(hvi), 0.185, euclidian).output("hvntm.3", "hvntm.3 : min. hvntm enclosure of hv n+diff : 0.185um") +hvntm.separation(diff.not(nwell).not(hvi), 0.185, euclidian).output("hvntm.4", "hvntm.4 : min. hvntm spacing to n+diff : 0.185um") +hvntm.separation(diff.and(nwell).not(hvi), 0.185, euclidian).output("hvntm.5", "hvntm.5 : min. hvntm spacing to p+diff : 0.185um") +hvntm.separation(tap.not(nwell).not(hvi), 0.185, euclidian).polygons.without_area(0).output("hvntm.6a", "hvntm.6a : min. hvntm spacing to p+tap : 0.185um") +hvntm.and(areaid_ce).output("hvntm.9", "hvntm.9 : hvntm must not overlapp areaid.ce") + +# denmos +poly.not_interacting(pwde).interacting(areaid_en).width(1.055, projection).output("denmos.1", "denmos.1 : min. de_nfet gate width : 1.055um") +diff.not_interacting(pwde).enclosing(poly.interacting(areaid_en), 0.28, projection).polygons.without_area(0).output("denmos.2", "denmos.2 : min. de_nfet source ouside poly width : 0.28um") +diff.not_interacting(pwde).and(poly.interacting(areaid_en)).width(0.925, projection).output("denmos.3", "denmos.3 : min. de_nfet source inside poly width : 0.925um") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).width(0.17, euclidian).output("denmos.4", "denmos.4 : min. de_nfet drain width : 0.17um") +nwell.not_interacting(pwde).and(poly.interacting(areaid_en)).width(0.225, projection).polygons.or(nwell.and(poly.interacting(areaid_en)).sized(-0.1125).sized(0.1125)).output("denmos.5", "denmos.5 : min. de_nfet source inside nwell width : 0.225m") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).separation(diff.interacting(poly.interacting(areaid_en)), 1.585, projection).output("denmos.6", "denmos.6 : min. de_nfet source spacing to drain : 1.585um") +nwell.not_interacting(pwde).and(poly.and(diff).interacting(areaid_en)).edges.without_length(5.0, nil).output("denmos.7", "denmos.7 : min. de_nfet channel width : 5.0um") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("denmos.8", "denmos.8 : 90deg. not allowed for de_nfet drain") +nwell.not_interacting(pwde).interacting(areaid_en).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("denmos.9a", "denmos.9a : 90deg. not allowed for de_nfet nwell") +nwell.not_interacting(pwde).interacting(areaid_en).edges.with_angle(45).without_length(0.607..0.609).output("denmos.9a", "denmos.9a : 45deg. bevels of de_nfet nwell should be 0.43um from corners") +nwell.not_interacting(pwde).interacting(areaid_en).edges.with_angle(135).without_length(0.607..0.609).output("denmos.9a", "denmos.9a : 45deg. bevels of de_nfet nwell should be 0.43um from corners") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(45).without_length(0.7..0.71).output("denmos.9b", "denmos.9b : 45deg. bevels of de_nfet drain should be 0.05um from corners") +diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(135).without_length(0.7..0.71).output("denmos.9b", "denmos.9b : 45deg. bevels of de_nfet drain should be 0.05um from corners") +nwell.not_interacting(pwde).enclosing(diff.interacting(areaid_en).not_interacting(poly), 0.66, euclidian).output("denmos.10", "denmos.10 : min. nwell enclosure of de_nfet drain : 0.66um") +nwell.not_interacting(pwde).interacting(areaid_en).separation(tap.not(nwell), 0.86, euclidian).output("denmos.11", "denmos.11 : min. de_nfet nwell spacing to tap : 0.86um") +nwell.not_interacting(pwde).interacting(areaid_en).isolated(2.4, euclidian).output("denmos.12", "denmos.12 : min. de_nfet nwell : 2.4um") +nsdm.not_interacting(pwde).enclosing(diff.interacting(areaid_en).interacting(poly), 0.13, euclidian).output("denmos.13", "denmos.13 : min. nsdm enclosure of de_nfet source : 0.13um") + +# depmos +poly.interacting(pwde).interacting(areaid_en).width(1.05, projection).output("depmos.1", "depmos.1 : min. de_pfet gate width : 1.05um") +diff.interacting(pwde).enclosing(poly.interacting(areaid_en), 0.28, projection).polygons.without_area(0).output("depmos.2", "depmos.2 : min. de_pfet source ouside poly width : 0.28um") +diff.interacting(pwde).and(poly.interacting(areaid_en)).width(0.92, projection).output("depmos.3", "depmos.3 : min. de_pfet source inside poly width : 0.92um") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).width(0.17, euclidian).output("depmos.4", "depmos.4 : min. de_pfet drain width : 0.17um") +pwde.not(nwell).and(poly.interacting(areaid_en)).width(0.26, projection).polygons.or(pwde.not(nwell).and(poly.interacting(areaid_en)).sized(-0.13).sized(0.13)).output("depmos.5", "depmos.5 : min. de_pfet source inside nwell width : 0.26m") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).separation(diff.interacting(poly.interacting(areaid_en)), 1.19, projection).output("depmos.6", "depmos.6 : min. de_pfet source spacing to drain : 1.19um") +nwell.interacting(pwde).and(poly.and(diff).interacting(areaid_en)).edges.without_length(5.0, nil).output("depmos.7", "depmos.7 : min. de_pfet channel width : 5.0um") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("depmos.8", "depmos.8 : 90deg. not allowed for de_pfet drain") +pwde.not(nwell).interacting(areaid_en).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("depmos.9a", "depmos.9a : 90deg. not allowed for de_pfet pwell") +pwde.not(nwell).interacting(areaid_en).edges.with_angle(45).without_length(0.607..0.609).output("depmos.9a", "depmos.9a : 45deg. bevels of de_pfet pwell should be 0.43um from corners") +pwde.not(nwell).interacting(areaid_en).edges.with_angle(135).without_length(0.607..0.609).output("depmos.9a", "depmos.9a : 45deg. bevels of de_pfet pwell should be 0.43um from corners") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(45).without_length(0.7..0.71).output("depmos.9b", "depmos.9b : 45deg. bevels of de_pfet drain should be 0.05um from corners") +diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(135).without_length(0.7..0.71).output("depmos.9b", "depmos.9b : 45deg. bevels of de_pfet drain should be 0.05um from corners") +nwell.interacting(pwde).separation(diff.interacting(areaid_en).not_interacting(poly), 0.86, euclidian).output("depmos.10", "depmos.10 : min. pwell enclosure of de_pfet drain : 0.86um") +pwde.not(nwell).interacting(areaid_en).separation(tap.and(nwell), 0.66, euclidian).output("depmos.11", "depmos.11 : min. de_pfet pwell spacing to tap : 0.66um") +psdm.interacting(pwde).enclosing(diff.interacting(areaid_en).interacting(poly), 0.13, euclidian).output("depmos.12", "depmos.12 : min. psdm enclosure of de_pfet source : 0.13um") + +# extd +areaid_en.and(difftap).edges.not(difftap.edges).output("extd.1", "extd.1 : difftap must not straddle areaid.en") +difftap.interacting(areaid_en).not(poly).with_area(0).output("extd.2", "extd.2 : poly must not overlapp entirely difftap in areaid.en") +# rules extd.4, extd.5, extd.6, extd.7 not coded because specific to some cells + +# vhvi +# rules vhvi.vhv.1, vhvi.vhv.2, vhvi.vhv.3, vhvi.vhv.4, vhvi.vhv.5, vhvi.vhv.6 not coded +vhvi.width(0.02, euclidian).output("vhvi.1", "vhvi.1 : min. vhvi width : 0.02um") +vhvi.and(areaid_ce).output("vhvi.2", "vhvi.2 : vhvi must not overlap areaid.ce") +vhvi.and(hvi).output("vhvi.3", "vhvi.3 : vhvi must not overlap hvi") +# rules vhvi.4, vhvi.6 not coded +vhvi.and(diff).edges.not(diff.edges).output("vhvi.5", "vhvi.5 : vhvi must not straddle diff") +vhvi.and(tap).edges.not(tap.edges).output("vhvi.5", "vhvi.5 : vhvi must not straddle tap") +vhvi.and(poly).edges.not(poly.edges).output("vhvi.7", "vhvi.7 : vhvi must not straddle poly") + +nwell.and(vhvi).separation(nwell, 2.5, euclidian).output("hv.nwell.1", "hv.nwell.1 : min. vhvi nwell spacing to nwell : 2.5um") +diff.and(vhvi).isolated(0.3, euclidian).output("hv.diff.1", "hv.diff.1 : min. vhvi diff spacing : 0.3um") +nwell.interacting(diff.and(vhvi)).separation(diff.not(nwell), 0.43, euclidian).output("hv.diff.2", "hv.diff.2 : min. vhvi nwell spacing n+diff : 0.43um") +diff.and(vhvi).not(nwell).separation(nwell, 0.55, euclidian).output("hv.diff.3a", "hv.diff.3a : min. vhvi n+diff spacing nwell : 0.55um") +# rule hv.diff.3b not coded +poly.and(vhvi).not(diff).separation(diff, 0.3, euclidian).polygons.without_area(0).output("hv.poly.2", "hv.poly.2 : min. vhvi poly spacing to diff : 0.3um") +poly.and(vhvi).not(diff).separation(nwell, 0.55, euclidian).polygons.without_area(0).output("hv.poly.3", "hv.poly.3 : min. vhvi poly spacing to nwell : 0.55um") +nwell.enclosing(poly.and(vhvi).not(diff), 0.3, euclidian).polygons.without_area(0).output("hv.poly.4", "hv.poly.4 : min. nwell enclosure of vhvi poly : 0.3um") +#poly.and(vhvi).enclosing(diff.interacting(areaid_en), 0.16, projection).polygons.without_area(0).output("hv.poly.6", "hv.poly.6 : min. poly enclosure of hvfet gate : 0.16um") +# rule hv.poly.7 not coded + +# uhvi +uhvi.and(diff).edges.not(diff.edges).output("uhvi.1", "uhvi.1 : diff must not straddle uhvi") +uhvi.and(tap).edges.not(tap.edges).output("uhvi.1", "uhvi.1 : tap must not straddle uhvi") +uhvi.and(poly).edges.not(poly.edges).output("uhvi.2", "uhvi.2 : poly must not straddle uhvi") +pwbm.not(uhvi).output("uhvi.3", "uhvi.3 : uhvi must not enclose pwbm") +uhvi.and(dnwell).edges.not(dnwell.edges).output("uhvi.4", "uhvi.4 : dnwell must not straddle uhvi") +areaid_en20.not(uhvi).output("uhvi.5", "uhvi.5 : uhvi must not enclose areaid.en20") +#dnwell.not(uhvi).output("uhvi.6", "uhvi.6 : uhvi must not enclose dnwell") +natfet.not(uhvi).output("uhvi.7", "uhvi.7 : uhvi must not enclose natfet") + +# pwell_res +pwell_rs.width(2.65).output("pwres.2", "pwres.2 : min. pwell resistor width : 2.65um") +pwell_rs.sized(-2.65).sized(2.65).output("pwres.2", "pwres.2 : max. pwell resistor width : 2.65um") +pwell_rs.interacting(pwell_rs.edges.with_length(2.651,26.499)).output("pwres.3", "pwres.3 : min. pwell resistor length : 26.5um") +pwell_rs.interacting(pwell_rs.edges.with_length(265.0, nil)).output("pwres.4", "pwres.4 : max. pwell resistor length : 265um") +tap.interacting(pwell_rs).separation(nwell, 0.22, euclidian).output("pwres.5", "pwres.5 : min. pwell resistor tap spacing to nwell : 0.22um") +tap.interacting(pwell_rs).and(tap.sized(0.22).and(nwell)).output("pwres.5", "pwres.5 : max. pwell resistor tap spacing to nwell : 0.22um") +tap.interacting(pwell_rs).width(0.53).output("pwres.6", "pwres.6 : min. width of tap inside pwell resistor : 0.53um") +tap.interacting(pwell_rs).sized(-0.265).sized(0.265).output("pwres.6", "pwres.6 : max. width of tap inside pwell resistor : 0.53um") +# rules pwres.7a, pwres.7b not coded +pwell_rs.and(diff).output("pwres.8", "pwres.8 : diff not allowed inside pwell resistor") +pwell_rs.and(poly).output("pwres.8", "pwres.8 : poly not allowed inside pwell resistor") +# rules pwres.9, pwres.10 not coded + +# rf_diode +areaid_re.with_angle(0 .. 90).output("rfdiode.1", "rfdiode.1 : non 90 degree angle areaid.re") +areaid_re.not(nwell).or(nwell.interacting(areaid_re).not(areaid_re)).output("rfdiode.2", "rfdiode.2 : areaid.re must coincide rf nwell diode") +# rule rfdiode.3 not coded + +end #FEOL + +if OFFGRID +info("OFFGRID-ANGLES section") + +dnwell.ongrid(0.005).output("dnwell_OFFGRID", "x.1b : OFFGRID vertex on dnwell") +dnwell.with_angle(0 .. 45).output("dnwell_angle", "x.3a : non 45 degree angle dnwell") +nwell.ongrid(0.005).output("nwell_OFFGRID", "x.1b : OFFGRID vertex on nwell") +nwell.with_angle(0 .. 45).output("nwell_angle", "x.3a : non 45 degree angle nwell") +pwbm.ongrid(0.005).output("pwbm_OFFGRID", "x.1b : OFFGRID vertex on pwbm") +pwbm.with_angle(0 .. 45).output("pwbm_angle", "x.3a : non 45 degree angle pwbm") +pwde.ongrid(0.005).output("pwde_OFFGRID", "x.1b : OFFGRID vertex on pwde") +pwde.with_angle(0 .. 45).output("pwde_angle", "x.3a : non 45 degree angle pwde") +hvtp.ongrid(0.005).output("hvtp_OFFGRID", "x.1b : OFFGRID vertex on hvtp") +hvtp.with_angle(0 .. 45).output("hvtp_angle", "x.3a : non 45 degree angle hvtp") +hvtr.ongrid(0.005).output("hvtr_OFFGRID", "x.1b : OFFGRID vertex on hvtr") +hvtr.with_angle(0 .. 45).output("hvtr_angle", "x.3a : non 45 degree angle hvtr") +lvtn.ongrid(0.005).output("lvtn_OFFGRID", "x.1b : OFFGRID vertex on lvtn") +lvtn.with_angle(0 .. 45).output("lvtn_angle", "x.3a : non 45 degree angle lvtn") +ncm.ongrid(0.005).output("ncm_OFFGRID", "x.1b : OFFGRID vertex on ncm") +ncm.with_angle(0 .. 45).output("ncm_angle", "x.3a : non 45 degree angle ncm") +diff.ongrid(0.005).output("diff_OFFGRID", "x.1b : OFFGRID vertex on diff") +tap.ongrid(0.005).output("tap_OFFGRID", "x.1b : OFFGRID vertex on tap") +diff.not(areaid_en.and(uhvi)).with_angle(0 .. 90).output("diff_angle", "x.2 : non 90 degree angle diff") +diff.and(areaid_en.and(uhvi)).with_angle(0 .. 45).output("diff_angle", "x.2c : non 45 degree angle diff") +tap.not(areaid_en.and(uhvi)).with_angle(0 .. 90).output("tap_angle", "x.2 : non 90 degree angle tap") +tap.and(areaid_en.and(uhvi)).with_angle(0 .. 45).output("tap_angle", "x.2c : non 45 degree angle tap") +tunm.ongrid(0.005).output("tunm_OFFGRID", "x.1b : OFFGRID vertex on tunm") +tunm.with_angle(0 .. 45).output("tunm_angle", "x.3a : non 45 degree angle tunm") +poly.ongrid(0.005).output("poly_OFFGRID", "x.1b : OFFGRID vertex on poly") +poly.with_angle(0 .. 90).output("poly_angle", "x.2 : non 90 degree angle poly") +rpm.ongrid(0.005).output("rpm_OFFGRID", "x.1b : OFFGRID vertex on rpm") +rpm.with_angle(0 .. 45).output("rpm_angle", "x.3a : non 45 degree angle rpm") +npc.ongrid(0.005).output("npc_OFFGRID", "x.1b : OFFGRID vertex on npc") +npc.with_angle(0 .. 45).output("npc_angle", "x.3a : non 45 degree angle npc") +nsdm.ongrid(0.005).output("nsdm_OFFGRID", "x.1b : OFFGRID vertex on nsdm") +nsdm.with_angle(0 .. 45).output("nsdm_angle", "x.3a : non 45 degree angle nsdm") +psdm.ongrid(0.005).output("psdm_OFFGRID", "x.1b : OFFGRID vertex on psdm") +psdm.with_angle(0 .. 45).output("psdm_angle", "x.3a : non 45 degree angle psdm") +licon.ongrid(0.005).output("licon_OFFGRID", "x.1b : OFFGRID vertex on licon") +licon.with_angle(0 .. 90).output("licon_angle", "x.2 : non 90 degree angle licon") +li.ongrid(0.005).output("li_OFFGRID", "x.1b : OFFGRID vertex on li") +li.with_angle(0 .. 45).output("li_angle", "x.3a : non 45 degree angle li") +mcon.ongrid(0.005).output("ct_OFFGRID", "x.1b : OFFGRID vertex on mcon") +mcon.with_angle(0 .. 90).output("ct_angle", "x.2 : non 90 degree angle mcon") +vpp.ongrid(0.005).output("vpp_OFFGRID", "x.1b : OFFGRID vertex on vpp") +vpp.with_angle(0 .. 45).output("vpp_angle", "x.3a : non 45 degree angle vpp") +m1.ongrid(0.005).output("m1_OFFGRID", "x.1b : OFFGRID vertex on m1") +m1.with_angle(0 .. 45).output("m1_angle", "x.3a : non 45 degree angle m1") +via.ongrid(0.005).output("via_OFFGRID", "x.1b : OFFGRID vertex on via") +via.with_angle(0 .. 90).output("via_angle", "x.2 : non 90 degree angle via") +m2.ongrid(0.005).output("m2_OFFGRID", "x.1b : OFFGRID vertex on m2") +m2.with_angle(0 .. 45).output("m2_angle", "x.3a : non 45 degree angle m2") +via2.ongrid(0.005).output("via2_OFFGRID", "x.1b : OFFGRID vertex on via2") +via2.with_angle(0 .. 90).output("via2_angle", "x.2 : non 90 degree angle via2") +m3.ongrid(0.005).output("m3_OFFGRID", "x.1b : OFFGRID vertex on m3") +m3.with_angle(0 .. 45).output("m3_angle", "x.3a : non 45 degree angle m3") +via3.ongrid(0.005).output("via3_OFFGRID", "x.1b : OFFGRID vertex on via3") +via3.with_angle(0 .. 90).output("via3_angle", "x.2 : non 90 degree angle via3") +nsm.ongrid(0.005).output("nsm_OFFGRID", "x.1b : OFFGRID vertex on nsm") +nsm.with_angle(0 .. 45).output("nsm_angle", "x.3a : non 45 degree angle nsm") +m4.ongrid(0.005).output("m4_OFFGRID", "x.1b : OFFGRID vertex on m4") +m4.with_angle(0 .. 45).output("m4_angle", "x.3a : non 45 degree angle m4") +via4.ongrid(0.005).output("via4_OFFGRID", "x.1b : OFFGRID vertex on via4") +via4.with_angle(0 .. 90).output("via4_angle", "x.2 : non 90 degree angle via4") +m5.ongrid(0.005).output("m5_OFFGRID", "x.1b : OFFGRID vertex on m5") +m5.with_angle(0 .. 45).output("m5_angle", "x.3a : non 45 degree angle m5") +pad.ongrid(0.005).output("pad_OFFGRID", "x.1b : OFFGRID vertex on pad") +pad.with_angle(0 .. 45).output("pad_angle", "x.3a : non 45 degree angle pad") +mf.ongrid(0.005).output("mf_OFFGRID", "x.1b : OFFGRID vertex on mf") +mf.with_angle(0 .. 90).output("mf_angle", "x.2 : non 90 degree angle mf") +hvi.ongrid(0.005).output("hvi_OFFGRID", "x.1b : OFFGRID vertex on hvi") +hvi.with_angle(0 .. 45).output("hvi_angle", "x.3a : non 45 degree angle hvi") +hvntm.ongrid(0.005).output("hvntm_OFFGRID", "x.1b : OFFGRID vertex on hvntm") +hvntm.with_angle(0 .. 45).output("hvntm_angle", "x.3a : non 45 degree angle hvntm") +vhvi.ongrid(0.005).output("vhvi_OFFGRID", "x.1b : OFFGRID vertex on vhvi") +vhvi.with_angle(0 .. 45).output("vhvi_angle", "x.3a : non 45 degree angle vhvi") +uhvi.ongrid(0.005).output("uhvi_OFFGRID", "x.1b : OFFGRID vertex on uhvi") +uhvi.with_angle(0 .. 45).output("uhvi_angle", "x.3a : non 45 degree angle uhvi") +pwell_rs.ongrid(0.005).output("pwell_rs_OFFGRID", "x.1b : OFFGRID vertex on pwell_rs") +pwell_rs.with_angle(0 .. 45).output("pwell_rs_angle", "x.3a : non 45 degree angle pwell_rs") +areaid_re.ongrid(0.005).output("areaid_re_OFFGRID", "x.1b : OFFGRID vertex on areaid.re") + +end #OFFGRID + diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.lylvs b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.lylvs new file mode 100755 index 00000000..3663572f --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.lylvs @@ -0,0 +1,220 @@ + + + + + lvs + + + + false + false + + true + lvs_scripts + tools_menu.lvs.end + dsl + lvs-dsl-xml + +# Extraction for SKY130 +# +############################ + +#report_netlist("report.txt") + +# optionnal for a batch launch : klayout -b -rd input=my_layout.gds -rd report=my_report.lyrdb -rd schematic=reference_netlist.cir -rd target_netlist=extracted_netlist.cir -r sky130.lvs +if $input + source($input) +end + +# true: use net names instead of numbers +# false: use numbers for nets +spice_with_net_names = true + +# true: put in comments with details +# false: no comments +spice_with_comments = true + +# Write extracted netlist to extracted.cir using a special +# writer delegate + + +if $target_netlist + target_netlist($target_netlist) +else + # target_netlist("netlist.cir", write_spice(spice_with_net_names, spice_with_comments), "Generated by Klayout on : #{Time.now.strftime("%d/%m/%Y %H:%M")}") + target_netlist(File.join(File.dirname(RBA::CellView::active.filename), source.cell_name+"_extracted.spice"),write_spice(spice_with_net_names, spice_with_comments),"Extracted by KLayout on : #{Time.now.strftime("%d/%m/%Y %H:%M")}") +end + +# Hierarchical mode +deep +# Use 4 CPU cores +threads(4) +# Print details +verbose(true) + + +# layers definitions +######################## +BOUND = polygons(235, 4) +DNWELL = polygons(64, 18) +PWRES = polygons(64, 13) +NWELL = polygons(64, 20) +NWELLTXT = input(64, 5) +NWELLPIN = polygons(64, 16) +SUBTXT = input(122, 5) +SUBPIN = input(64, 59) +DIFF = polygons(65, 20) +TAP = polygons(65, 44) +PSDM = polygons(94, 20) +NSDM = polygons(93, 44) +LVTN = polygons(125, 44) +HVTR = polygons(18, 20) +HVTP = polygons(78, 44) +SONOS = polygons(80, 20) +COREID = polygons(81, 2) +STDCELL = polygons(81, 4) +NPNID = polygons(82, 20) +PNPID = polygons(82, 44) +RPM = polygons(86, 20) +URPM = polygons(79, 20) +LDNTM = polygons(11, 44) +HVNTM = polygons(125, 20) +POLY = polygons(66, 20) +POLYTXT = input(66, 5) +POLYPIN = polygons(66, 16) +HVI = polygons(75, 20) +LICON = polygons(66, 44) +NPC = polygons(95, 20) +DIFFRES = polygons(65, 13) +POLYRES = polygons(66, 13) +POLYSHO = polygons(66, 15) +DIODE = polygons(81, 23) +LI = polygons(67, 20) +LITXT = input(67, 5) +LIPIN = polygons(67, 16) +LIRES = polygons(67, 13) +MCON = polygons(67, 44) +MET1 = polygons(68, 20) +MET1TXT = input(68, 5) +MET1PIN = polygons(68, 16) +MET1RES = polygons(68, 13) +VIA1 = polygons(68, 44) +MET2 = polygons(69, 20) +MET2TXT = input(69, 5) +MET2PIN = polygons(69, 16) +MET2RES = polygons(69, 13) +VIA2 = polygons(69, 44) +MET3 = polygons(70, 20) +MET3TXT = input(70, 5) +MET3PIN = polygons(70, 16) +MET3RES = polygons(70, 13) +VIA3 = polygons(70, 44) +MET4 = polygons(71, 20) +MET4TXT = input(71, 5) +MET4PIN = polygons(71, 16) +MET4RES = polygons(71, 13) +VIA4 = polygons(71, 44) +MET5 = polygons(72, 20) +MET5TXT = input(72, 5) +MET5PIN = polygons(72, 16) +MET5RES = polygons(72, 13) +RDL = polygons(74, 20) +RDLTXT = input(74, 5) +RDLPIN = polygons(74, 16) +GLASS = polygons(76, 20) +CAPM = polygons(89, 44) +CAPM2 = polygons(97, 44) +LOWTAPD = polygons(81, 14) +FILLOBSM1 = polygons(62, 24) +FILLOBSM2 = polygons(105, 52) +FILLOBSM3 = polygons(107, 24) +FILLOBSM4 = polygons(112, 4) +NCM = polygons(92, 44) + +# Bulk layer for terminal provisioning +SUB = polygons(236, 0) +# SUB = polygon_layer + +# Computed layers +PDIFF = DIFF & NWELL & PSDM +NTAP = TAP & NWELL & NSDM +PGATE = PDIFF & POLY +PSD = PDIFF - PGATE +STD_PGATE = PGATE - HVTP - NCM - HVI +HVT_PGATE = PGATE & HVTP - NCM - HVI +HV5_PGATE = PGATE - HVTP - NCM & HVI + +NDIFF = DIFF - NWELL & NSDM +PTAP = TAP - NWELL & PSDM +NGATE = NDIFF & POLY +NSD = NDIFF - NGATE +STD_NGATE = NGATE - NCM - LVTN - HVI +LVT_NGATE = NGATE - NCM & LVTN - HVI +HV5_NGATE = NGATE - NCM - LVTN & HVI +HV5NA_NGATE = NGATE - NCM & LVTN & HVI + +# drawing to physical +device_scaling(1000000) + +# PMOS transistor device extraction +extract_devices(mos4("pfet_01v8"), { "SD" => PSD, "G" => STD_PGATE, "tS" => PSD, "tD" => PSD, "tG" => POLY, "W" => NWELL }) +extract_devices(mos4("pfet_01v8_hvt"), { "SD" => PSD, "G" => HVT_PGATE, "tS" => PSD, "tD" => PSD, "tG" => POLY, "W" => NWELL }) +extract_devices(mos4("pfet_g5v0d10v5"), { "SD" => PSD, "G" => HV5_PGATE, "tS" => PSD, "tD" => PSD, "tG" => POLY, "W" => NWELL }) + +# NMOS transistor device extraction +extract_devices(mos4("nfet_01v8"), { "SD" => NSD, "G" => STD_NGATE, "tS" => NSD, "tD" => NSD, "tG" => POLY, "W" => SUB }) +extract_devices(mos4("nfet_01v8_lvt"), { "SD" => NSD, "G" => LVT_NGATE, "tS" => NSD, "tD" => NSD, "tG" => POLY, "W" => SUB }) +extract_devices(mos4("nfet_g5v0d10v5"), { "SD" => NSD, "G" => HV5_NGATE, "tS" => NSD, "tD" => NSD, "tG" => POLY, "W" => SUB }) +extract_devices(mos4("nfet_01v8_nvt"), { "SD" => NSD, "G" => HV5NA_NGATE, "tS" => NSD, "tD" => NSD, "tG" => POLY, "W" => SUB }) + + +# Define connectivity for netlist extraction + +# Inter-layer +connect(SUB, PTAP) +connect(NWELL, NTAP) +connect(LICON, PTAP) +connect(LICON, NTAP) +connect(PSD, LICON) +connect(NSD, LICON) +connect(POLY, LICON) +connect(LICON, LI) +connect(LI, MCON) +connect(MCON, MET1) +connect(MET1,VIA1) +connect(VIA1, MET2) +connect(MET2, VIA2) +connect(VIA2, MET3) +connect(MET3, VIA3) +connect(VIA3, MET4) +connect(MET4, VIA4) +connect(VIA4, MET5) +# Attaching labels +connect(SUB, SUBTXT) +connect(SUB, SUBPIN) +connect(NWELL, NWELLTXT) +connect(POLY, POLYTXT) +connect(LI, LITXT) +connect(MET1, MET1TXT) +connect(MET2, MET2TXT) +connect(MET3, MET3TXT) +connect(MET4, MET4TXT) +connect(MET5, MET5TXT) + +# Global +connect_global(SUB, "VNB") + +# Actually performs the extraction +netlist # ... not really required + +# Flatten cells which are present in one netlist only +# align +# SIMPLIFICATION of the netlist +netlist.make_top_level_pins +netlist.combine_devices +netlist.purge +netlist.purge_nets +netlist.simplify +puts netlist.to_s + + \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.lyp b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.lyp new file mode 100755 index 00000000..27935a37 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.lyp @@ -0,0 +1,8498 @@ + + + + #ccccd9 + #ccccd9 + 0 + 0 + C7 + C0 + true + true + false + 1 + false + false + 0 + prBoundary.boundary - 235/4 + 235/4@1 + + + #00ffff + #00ffff + 0 + 0 + C19 + C0 + true + true + false + 1 + false + false + 0 + pwell.drawing - 64/44 + 64/44@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C37 + C0 + true + false + false + 1 + false + false + 0 + pwell.pin - 122/16 + 122/16@1 + + + #9900e6 + #9900e6 + 0 + 0 + C1 + C0 + true + false + true + 1 + false + false + 0 + pwell.label - 64/59 + 64/59@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + pwell.res - 64/13 + 64/13@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + pwell.cut - 64/14 + 64/14@1 + + + #ffffff + #96c8ff + 0 + 0 + C37 + C0 + true + true + false + 1 + false + false + 0 + pwelliso.pin - 44/16 + 44/16@1 + + + #9900e6 + #9900e6 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + pwelliso.label - 44/5 + 44/5@1 + + + #00cc66 + #00cc66 + 0 + 0 + C19 + C0 + true + true + false + 1 + false + false + 0 + nwell.drawing - 64/20 + 64/20@1 + + + #ff00ff + #ff00ff + 0 + 0 + C2 + C0 + true + true + false + 1 + false + false + 0 + nwell.net - 84/23 + 84/23@1 + + + #268c6b + #268c6b + 0 + 0 + C35 + C0 + true + true + false + 1 + false + false + 0 + nwell.pin - 64/16 + 64/16@1 + + + #333399 + #333399 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + nwell.label - 64/5 + 64/5@1 + + + #c8ffc8 + #c8ffc8 + 0 + 0 + C46 + C0 + true + false + false + 1 + false + false + 0 + dnwell.drawing - 64/18 + 64/18@1 + + + #00ffff + #00ffff + 0 + 0 + C6 + C0 + true + true + false + 1 + false + false + 0 + vhvi.drawing - 74/21 + 74/21@1 + + + #00ff00 + #00ff00 + 0 + 0 + C33 + C0 + true + false + false + 1 + false + false + 0 + diff.drawing - 65/20 + 65/20@1 + + + #00ff00 + #00ff00 + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + diff.res - 65/13 + 65/13@1 + + + #00ff00 + #00ff00 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + diff.cut - 65/14 + 65/14@1 + + + #268c6b + #268c6b + 0 + 0 + C35 + C0 + false + true + false + 1 + false + false + 0 + diff.pin - 65/16 + 65/16@1 + + + #c8ffc8 + #c8ffc8 + 0 + 0 + C1 + C0 + false + true + false + 1 + false + false + 0 + diff.label - 65/6 + 65/6@1 + + + #00ff00 + #00ff00 + 0 + 0 + C5 + C0 + false + true + false + 1 + false + false + 0 + diff.net - 65/23 + 65/23@1 + + + #00ff00 + #00ff00 + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + diff.boundary - 65/4 + 65/4@1 + + + #9900e6 + #9900e6 + 0 + 0 + C35 + C0 + true + true + false + 1 + false + false + 0 + diff.hv - 65/8 + 65/8@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C33 + C0 + true + false + false + 1 + false + false + 0 + tap.drawing - 65/44 + 65/44@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C6 + C0 + false + true + false + 1 + false + false + 0 + tap.pin - 65/48 + 65/48@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C5 + C0 + false + true + false + 1 + false + false + 0 + tap.net - 65/41 + 65/41@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + tap.boundary - 65/60 + 65/60@1 + + + #fff464 + #fff464 + 0 + 0 + C1 + C0 + false + true + false + 1 + false + false + 0 + tap.label - 65/5 + 65/5@1 + + + #9900e6 + #9900e6 + 0 + 0 + C21 + C0 + true + false + false + 1 + false + false + 0 + psdm.drawing - 94/20 + 94/20@1 + + + #e61f0d + #e61f0d + 0 + 0 + C20 + C0 + true + false + false + 1 + false + false + 0 + nsdm.drawing - 93/44 + 93/44@1 + + + #ff0000 + #ff0000 + 0 + 0 + C40 + C0 + true + false + false + 1 + false + false + 0 + poly.drawing - 66/20 + 66/20@1 + + + #ff8000 + #ff8000 + 0 + 0 + C37 + C0 + true + true + false + 1 + false + false + 0 + poly.pin - 66/16 + 66/16@1 + + + #ff0000 + #ff0000 + 0 + 0 + I1 + C0 + true + false + false + 1 + false + false + 0 + poly.res - 66/13 + 66/13@1 + + + #ff0000 + #ff0000 + 0 + 0 + C1 + C0 + true + false + false + 1 + false + false + 0 + poly.cut - 66/14 + 66/14@1 + + + #ff0000 + #ff0000 + 0 + 0 + I1 + C0 + true + false + false + 1 + false + false + 0 + poly.gate - 66/9 + 66/9@1 + + + #ffafaf + #ffafaf + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + poly.label - 66/5 + 66/5@1 + + + #ff0000 + #ff0000 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + poly.boundary - 66/4 + 66/4@1 + + + #ff0000 + #ff0000 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + poly.probe - 66/25 + 66/25@1 + + + #ff0000 + #ff0000 + 0 + 0 + C35 + C0 + true + true + false + 1 + false + false + 0 + poly.short - 66/15 + 66/15@1 + + + #ff0000 + #ff0000 + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + poly.net - 66/23 + 66/23@1 + + + #ff0000 + #ff0000 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + poly.model - 66/83 + 66/83@1 + + + #00cc66 + #00cc66 + 0 + 0 + C49 + C0 + true + true + false + 1 + false + false + 0 + ldntm.drawing - 11/44 + 11/44@1 + + + #96c8ff + #ffffff + 0 + 0 + C15 + C0 + true + false + false + 1 + false + false + 0 + lvtn.drawing - 125/44 + 125/44@1 + + + #ff8000 + #ffffff + 0 + 0 + C14 + C0 + true + false + false + 1 + false + false + 0 + hvtp.drawing - 78/44 + 78/44@1 + + + #ff0000 + #e61f0d + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + hvtr.drawing - 18/20 + 18/20@1 + + + #9900e6 + #9900e6 + 0 + 0 + C40 + C0 + true + true + false + 1 + false + false + 0 + tunm.drawing - 80/20 + 80/20@1 + + + #ffffcc + #ffffcc + 0 + 0 + C22 + C0 + true + true + false + 1 + false + false + 0 + licon1.drawing - 66/44 + 66/44@1 + + + #ffffcc + #ffffcc + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + licon1.boundary - 66/60 + 66/60@1 + + + #ffe6bf + #c8ffff + 0 + 0 + C6 + C0 + false + true + false + 1 + false + false + 0 + licon1.pin - 66/58 + 66/58@1 + + + #ffffcc + #ffffcc + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + licon1.net - 66/41 + 66/41@1 + + + #bf4026 + #bf4026 + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + npc.drawing - 95/20 + 95/20@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + li1.drawing - 67/20 + 67/20@1 + + + #bf4026 + #bf4026 + 0 + 0 + C45 + C0 + true + true + false + 1 + false + false + 0 + li1.pin - 67/16 + 67/16@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + I1 + C0 + false + true + false + 1 + false + false + 0 + li1.res - 67/13 + 67/13@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C1 + C0 + false + true + false + 1 + false + false + 0 + li1.cut - 67/14 + 67/14@1 + + + #bf4026 + #bf4026 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + li1.label - 67/5 + 67/5@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C52 + C0 + true + true + false + 1 + false + false + 0 + li1.net - 67/23 + 67/23@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + li1.boundary - 67/4 + 67/4@1 + + + #bf4026 + #bf4026 + 0 + 0 + C52 + C0 + true + true + false + 1 + false + false + 0 + li1.blockage - 67/10 + 67/10@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C35 + C0 + true + false + false + 1 + false + false + 0 + li1.short - 67/15 + 67/15@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + li1.probe - 67/25 + 67/25@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + mcon.drawing - 67/44 + 67/44@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + mcon.boundary - 67/60 + 67/60@1 + + + #ffffcc + #d9e6ff + 0 + 0 + C6 + C0 + false + true + false + 1 + false + false + 0 + mcon.pin - 67/48 + 67/48@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + mcon.net - 67/41 + 67/41@1 + + + #0000ff + #0000ff + 0 + 0 + C7 + C0 + true + true + false + 1 + false + false + 0 + met1.drawing - 68/20 + 68/20@1 + + + #0000ff + #0000ff + 0 + 0 + I1 + C0 + false + true + false + 1 + false + false + 0 + met1.res - 68/13 + 68/13@1 + + + #0000ff + #0000ff + 0 + 0 + C1 + C0 + false + true + false + 1 + false + false + 0 + met1.cut - 68/14 + 68/14@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C6 + C0 + true + true + false + 1 + false + false + 0 + met1.pin - 68/16 + 68/16@1 + + + #96c8ff + #96c8ff + 0 + 0 + C1 + C0 + true + true + true + 1 + false + false + 0 + met1.label - 68/5 + 68/5@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + met1.net - 68/23 + 68/23@1 + + + #0000ff + #0000ff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + met1.boundary - 68/4 + 68/4@1 + + + #0000ff + #0000ff + 0 + 0 + C52 + C0 + true + true + false + 1 + false + false + 0 + met1.blockage - 68/10 + 68/10@1 + + + #0000ff + #0000ff + 0 + 0 + C35 + C0 + true + false + false + 1 + false + false + 0 + met1.short - 68/15 + 68/15@1 + + + #0000ff + #0000ff + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + met1.probe - 68/25 + 68/25@1 + + + #0000ff + #0000ff + 0 + 0 + C24 + C0 + false + true + false + 1 + false + false + 0 + met1.option1 - 68/32 + 68/32@1 + + + #0000ff + #0000ff + 0 + 0 + C25 + C0 + false + true + false + 1 + false + false + 0 + met1.option2 - 68/33 + 68/33@1 + + + #0000ff + #0000ff + 0 + 0 + C26 + C0 + false + true + false + 1 + false + false + 0 + met1.option3 - 68/34 + 68/34@1 + + + #0000ff + #0000ff + 0 + 0 + C27 + C0 + false + true + false + 1 + false + false + 0 + met1.option4 - 68/35 + 68/35@1 + + + #0000ff + #0000ff + 0 + 0 + C28 + C0 + false + true + false + 1 + false + false + 0 + met1.option5 - 68/36 + 68/36@1 + + + #0000ff + #0000ff + 0 + 0 + C29 + C0 + false + true + false + 1 + false + false + 0 + met1.option6 - 68/37 + 68/37@1 + + + #0000ff + #0000ff + 0 + 0 + C30 + C0 + false + true + false + 1 + false + false + 0 + met1.option7 - 68/38 + 68/38@1 + + + #0000ff + #0000ff + 0 + 0 + C31 + C0 + false + true + false + 1 + false + false + 0 + met1.option8 - 68/39 + 68/39@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + via.drawing - 68/44 + 68/44@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + via.boundary - 68/60 + 68/60@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + via.net - 68/41 + 68/41@1 + + + #ae7dff + #ae7dff + 0 + 0 + C6 + C0 + false + true + false + 1 + false + false + 0 + via.pin - 68/58 + 68/58@1 + + + #ff00ff + #ff00ff + 0 + 0 + C36 + C0 + true + true + false + 1 + false + false + 0 + met2.drawing - 69/20 + 69/20@1 + + + #ff00ff + #ff00ff + 0 + 0 + I1 + C0 + false + true + false + 1 + false + false + 0 + met2.res - 69/13 + 69/13@1 + + + #ff00ff + #ff00ff + 0 + 0 + C1 + C0 + false + true + false + 1 + false + false + 0 + met2.cut - 69/14 + 69/14@1 + + + #ff00ff + #ff00ff + 0 + 0 + C44 + C0 + true + true + false + 1 + false + false + 0 + met2.pin - 69/16 + 69/16@1 + + + #ffc8ff + #ffc8ff + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + met2.label - 69/5 + 69/5@1 + + + #ff00ff + #ff00ff + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + met2.net - 69/23 + 69/23@1 + + + #ff00ff + #ff00ff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + met2.boundary - 69/4 + 69/4@1 + + + #ff00ff + #ff00ff + 0 + 0 + C52 + C0 + true + true + false + 1 + false + false + 0 + met2.blockage - 69/10 + 69/10@1 + + + #ff00ff + #ff00ff + 0 + 0 + C35 + C0 + true + false + false + 1 + false + false + 0 + met2.short - 69/15 + 69/15@1 + + + #ff00ff + #ff00ff + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + met2.probe - 69/25 + 69/25@1 + + + #ff00ff + #ff00ff + 0 + 0 + C24 + C0 + false + true + false + 1 + false + false + 0 + met2.option1 - 69/32 + 69/32@1 + + + #ff00ff + #ff00ff + 0 + 0 + C25 + C0 + false + true + false + 1 + false + false + 0 + met2.option2 - 69/33 + 69/33@1 + + + #ff00ff + #ff00ff + 0 + 0 + C26 + C0 + false + true + false + 1 + false + false + 0 + met2.option3 - 69/34 + 69/34@1 + + + #ff00ff + #ff00ff + 0 + 0 + C27 + C0 + false + true + false + 1 + false + false + 0 + met2.option4 - 69/35 + 69/35@1 + + + #ff00ff + #ff00ff + 0 + 0 + C28 + C0 + false + true + false + 1 + false + false + 0 + met2.option5 - 69/36 + 69/36@1 + + + #ff00ff + #ff00ff + 0 + 0 + C29 + C0 + false + true + false + 1 + false + false + 0 + met2.option6 - 69/37 + 69/37@1 + + + #ff00ff + #ff00ff + 0 + 0 + C30 + C0 + false + true + false + 1 + false + false + 0 + met2.option7 - 69/38 + 69/38@1 + + + #ff00ff + #ff00ff + 0 + 0 + C31 + C0 + false + true + false + 1 + false + false + 0 + met2.option8 - 69/39 + 69/39@1 + + + #ff8000 + #ff8000 + 0 + 0 + I1 + C0 + true + true + false + 3 + false + false + 0 + via2.drawing - 69/44 + 69/44@1 + + + #ff8000 + #ff8000 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + via2.boundary - 69/60 + 69/60@1 + + + #ff8000 + #ff8000 + 0 + 0 + C6 + C0 + false + true + false + 1 + false + false + 0 + via2.pin - 69/58 + 69/58@1 + + + #ff8000 + #ff8000 + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + via2.net - 69/41 + 69/41@1 + + + #00ffff + #00ffff + 0 + 0 + C48 + C0 + true + true + false + 1 + false + false + 0 + met3.drawing - 70/20 + 70/20@1 + + + #00ffff + #00ffff + 0 + 0 + I1 + C0 + false + true + false + 1 + false + false + 0 + met3.res - 70/13 + 70/13@1 + + + #00ffff + #00ffff + 0 + 0 + C1 + C0 + false + true + false + 1 + false + false + 0 + met3.cut - 70/14 + 70/14@1 + + + #00ffff + #00ffff + 0 + 0 + C33 + C0 + true + true + false + 1 + false + false + 0 + met3.pin - 70/16 + 70/16@1 + + + #c8ffff + #c8ffff + 0 + 0 + C1 + C0 + true + true + true + 1 + false + false + 0 + met3.label - 70/5 + 70/5@1 + + + #00ffff + #00ffff + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + met3.net - 70/23 + 70/23@1 + + + #00ffff + #00ffff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + met3.boundary - 70/4 + 70/4@1 + + + #00ffff + #00ffff + 0 + 0 + C52 + C0 + true + true + false + 1 + false + false + 0 + met3.blockage - 70/10 + 70/10@1 + + + #00ffff + #00ffff + 0 + 0 + C35 + C0 + true + true + false + 1 + false + false + 0 + met3.short - 70/15 + 70/15@1 + + + #00ffff + #00ffff + 0 + 0 + I1 + C0 + false + true + false + 1 + false + false + 0 + met3.fuse - 70/17 + 70/17@1 + + + #00ffff + #00ffff + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + met3.probe - 70/25 + 70/25@1 + + + #00ffff + #00ffff + 0 + 0 + C24 + C0 + false + true + false + 1 + false + false + 0 + met3.option1 - 70/32 + 70/32@1 + + + #00ffff + #00ffff + 0 + 0 + C25 + C0 + false + true + false + 1 + false + false + 0 + met3.option2 - 70/33 + 70/33@1 + + + #00ffff + #00ffff + 0 + 0 + C26 + C0 + false + true + false + 1 + false + false + 0 + met3.option3 - 70/34 + 70/34@1 + + + #00ffff + #00ffff + 0 + 0 + C27 + C0 + false + true + false + 1 + false + false + 0 + met3.option4 - 70/35 + 70/35@1 + + + #00ffff + #00ffff + 0 + 0 + C28 + C0 + false + true + false + 1 + false + false + 0 + met3.option5 - 70/36 + 70/36@1 + + + #00ffff + #00ffff + 0 + 0 + C29 + C0 + false + true + false + 1 + false + false + 0 + met3.option6 - 70/37 + 70/37@1 + + + #00ffff + #00ffff + 0 + 0 + C30 + C0 + false + true + false + 1 + false + false + 0 + met3.option7 - 70/38 + 70/38@1 + + + #00ffff + #00ffff + 0 + 0 + C31 + C0 + false + true + false + 1 + false + false + 0 + met3.option8 - 70/39 + 70/39@1 + + + #268c6b + #268c6b + 0 + 0 + I1 + C0 + true + true + false + 3 + false + false + 0 + via3.drawing - 70/44 + 70/44@1 + + + #268c6b + #268c6b + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + via3.boundary - 70/60 + 70/60@1 + + + #268c6b + #268c6b + 0 + 0 + C6 + C0 + false + true + false + 1 + false + false + 0 + via3.pin - 70/48 + 70/48@1 + + + #268c6b + #268c6b + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + via3.net - 70/41 + 70/41@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C15 + C0 + true + true + false + 1 + false + false + 0 + met4.drawing - 71/20 + 71/20@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + I1 + C0 + false + true + false + 1 + false + false + 0 + met4.res - 71/13 + 71/13@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C1 + C0 + false + true + false + 1 + false + false + 0 + met4.cut - 71/14 + 71/14@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C33 + C0 + true + true + false + 1 + false + false + 0 + met4.pin - 71/16 + 71/16@1 + + + #ae7dff + #ae7dff + 0 + 0 + C1 + C0 + true + true + true + 1 + false + false + 0 + met4.label - 71/5 + 71/5@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + met4.net - 71/23 + 71/23@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + met4.boundary - 71/4 + 71/4@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C52 + C0 + true + true + false + 1 + false + false + 0 + met4.blockage - 71/10 + 71/10@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C35 + C0 + true + true + false + 1 + false + false + 0 + met4.short - 71/15 + 71/15@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + I1 + C0 + false + true + false + 1 + false + false + 0 + met4.fuse - 71/17 + 71/17@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + met4.probe - 71/25 + 71/25@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C24 + C0 + false + true + false + 1 + false + false + 0 + met4.option1 - 71/32 + 71/32@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C25 + C0 + false + true + false + 1 + false + false + 0 + met4.option2 - 71/33 + 71/33@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C26 + C0 + false + true + false + 1 + false + false + 0 + met4.option3 - 71/34 + 71/34@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C27 + C0 + false + true + false + 1 + false + false + 0 + met4.option4 - 71/35 + 71/35@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C28 + C0 + false + true + false + 1 + false + false + 0 + met4.option5 - 71/36 + 71/36@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C29 + C0 + false + true + false + 1 + false + false + 0 + met4.option6 - 71/37 + 71/37@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C30 + C0 + false + true + false + 1 + false + false + 0 + met4.option7 - 71/38 + 71/38@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C31 + C0 + false + true + false + 1 + false + false + 0 + met4.option8 - 71/39 + 71/39@1 + + + #ffff00 + #ffff00 + 0 + 0 + I1 + C0 + true + true + false + 3 + false + false + 0 + via4.drawing - 71/44 + 71/44@1 + + + #ffff00 + #ffff00 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + via4.boundary - 71/60 + 71/60@1 + + + #ffff00 + #ffff00 + 0 + 0 + C6 + C0 + false + true + false + 1 + false + false + 0 + via4.pin - 71/48 + 71/48@1 + + + #ffff00 + #ffff00 + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + via4.net - 71/41 + 71/41@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C41 + C0 + true + true + false + 1 + false + false + 0 + met5.drawing - 72/20 + 72/20@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + I1 + C0 + false + true + false + 1 + false + false + 0 + met5.res - 72/13 + 72/13@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C1 + C0 + false + true + false + 1 + false + false + 0 + met5.cut - 72/14 + 72/14@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C33 + C0 + true + true + false + 1 + false + false + 0 + met5.pin - 72/16 + 72/16@1 + + + #fff464 + #fff464 + 0 + 0 + C1 + C0 + true + true + true + 1 + false + false + 0 + met5.label - 72/5 + 72/5@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C5 + C0 + true + true + false + 1 + false + false + 0 + met5.net - 72/23 + 72/23@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + met5.boundary - 72/4 + 72/4@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C52 + C0 + true + true + false + 1 + false + false + 0 + met5.blockage - 72/10 + 72/10@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C35 + C0 + true + true + false + 1 + false + false + 0 + met5.short - 72/15 + 72/15@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + I1 + C0 + false + true + false + 1 + false + false + 0 + met5.fuse - 72/17 + 72/17@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + met5.probe - 72/25 + 72/25@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C24 + C0 + false + true + false + 1 + false + false + 0 + met5.option1 - 72/32 + 72/32@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C25 + C0 + false + true + false + 1 + false + false + 0 + met5.option2 - 72/33 + 72/33@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C26 + C0 + false + true + false + 1 + false + false + 0 + met5.option3 - 72/34 + 72/34@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C27 + C0 + false + true + false + 1 + false + false + 0 + met5.option4 - 72/35 + 72/35@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C28 + C0 + false + true + false + 1 + false + false + 0 + met5.option5 - 72/36 + 72/36@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C29 + C0 + false + true + false + 1 + false + false + 0 + met5.option6 - 72/37 + 72/37@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C30 + C0 + false + true + false + 1 + false + false + 0 + met5.option7 - 72/38 + 72/38@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C31 + C0 + false + true + false + 1 + false + false + 0 + met5.option8 - 72/39 + 72/39@1 + + + #00cc66 + #00cc66 + 0 + 0 + C49 + C0 + true + true + false + 1 + false + false + 0 + nsm.drawing - 61/20 + 61/20@1 + + + #ffffcc + #ffffcc + 0 + 0 + C19 + C0 + true + true + false + 1 + false + false + 0 + pad.drawing - 76/20 + 76/20@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + pad.label - 76/5 + 76/5@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C33 + C0 + true + true + false + 1 + false + false + 0 + pad.pin - 76/16 + 76/16@1 + + + #ff00ff + #ff00ff + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + pnp.drawing - 82/44 + 82/44@1 + + + #ffc8ff + #ffc8ff + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + pnp.label - 82/59 + 82/59@1 + + + #00ffff + #00ffff + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + npn.drawing - 82/20 + 82/20@1 + + + #c8ffff + #c8ffff + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + npn.label - 82/5 + 82/5@1 + + + #ffffff + #96c8ff + 0 + 0 + C37 + C0 + true + true + false + 1 + false + false + 0 + rpm.drawing - 86/20 + 86/20@1 + + + #ffffff + #c896ff + 0 + 0 + C37 + C0 + true + true + false + 1 + false + false + 0 + urpm.drawing - 79/20 + 79/20@1 + + + #9900e6 + #9900e6 + 0 + 0 + C4 + C0 + true + false + false + 1 + false + false + 0 + hvi.drawing - 75/20 + 75/20@1 + + + #ffb232 + #ffb232 + 0 + 0 + C0 + C0 + true + true + false + 3 + false + false + 0 + capacitor.drawing - 82/64 + 82/64@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C14 + C0 + true + false + false + 1 + false + false + 0 + ncm.drawing - 92/44 + 92/44@1 + + + #ff8000 + #ff8000 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + cncm.drawing - 96/44 + 96/44@1 + + + #ff0000 + #ff0000 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + cncm.mask - 17/0 + 17/0@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C19 + C1 + true + true + false + 1 + false + false + 0 + pmm.drawing - 85/44 + 85/44@1 + + + #bf4026 + #bf4026 + 0 + 0 + C39 + C0 + true + true + false + 1 + false + false + 0 + pmm2.drawing - 77/20 + 77/20@1 + + + #e61f0d + #e61f0d + 0 + 0 + C46 + C0 + true + true + false + 1 + false + false + 0 + rdl.drawing - 74/20 + 74/20@1 + + + #e61f0d + #e61f0d + 0 + 0 + C33 + C0 + true + true + false + 1 + false + false + 0 + rdl.pin - 74/16 + 74/16@1 + + + #ff6464 + #ff6464 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + rdl.label - 74/5 + 74/5@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + rdl.res - 74/13 + 74/13@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + rdl.cut - 74/14 + 74/14@1 + + + #e61f0d + #e61f0d + 0 + 0 + C35 + C0 + false + true + false + 1 + false + false + 0 + rdl.short - 74/15 + 74/15@1 + + + #e61f0d + #e61f0d + 0 + 0 + C24 + C0 + false + true + false + 1 + false + false + 0 + rdl.option1 - 89/32 + 89/32@1 + + + #e61f0d + #e61f0d + 0 + 0 + C25 + C0 + false + true + false + 1 + false + false + 0 + rdl.option2 - 89/33 + 89/33@1 + + + #e61f0d + #e61f0d + 0 + 0 + C26 + C0 + false + true + false + 1 + false + false + 0 + rdl.option3 - 89/34 + 89/34@1 + + + #e61f0d + #e61f0d + 0 + 0 + C27 + C0 + false + true + false + 1 + false + false + 0 + rdl.option4 - 89/35 + 89/35@1 + + + #e61f0d + #e61f0d + 0 + 0 + C28 + C0 + false + true + false + 1 + false + false + 0 + rdl.option5 - 89/36 + 89/36@1 + + + #e61f0d + #e61f0d + 0 + 0 + C29 + C0 + false + true + false + 1 + false + false + 0 + rdl.option6 - 89/37 + 89/37@1 + + + #e61f0d + #e61f0d + 0 + 0 + C30 + C0 + false + true + false + 1 + false + false + 0 + rdl.option7 - 89/38 + 89/38@1 + + + #e61f0d + #e61f0d + 0 + 0 + C31 + C0 + false + true + false + 1 + false + false + 0 + rdl.option8 - 89/39 + 89/39@1 + + + #ccccd9 + #333399 + 0 + 0 + C7 + C0 + true + true + false + 1 + false + false + 0 + ubm.drawing - 127/21 + 127/21@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C19 + C0 + true + true + false + 1 + false + false + 0 + bump.drawing - 127/22 + 127/22@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + inductor.drawing - 82/24 + 82/24@1 + + + #fff464 + #fff464 + 0 + 0 + C1 + C0 + true + true + false + 1 + false + false + 0 + inductor.label - 82/25 + 82/25@1 + + + #333399 + #ffffff + 0 + 0 + C24 + C0 + true + true + false + 1 + false + false + 0 + inductor.term1 - 82/26 + 82/26@1 + + + #333399 + #ffffff + 0 + 0 + C25 + C0 + true + true + false + 1 + false + false + 0 + inductor.term2 - 82/27 + 82/27@1 + + + #333399 + #ffffff + 0 + 0 + C26 + C0 + true + true + false + 1 + false + false + 0 + inductor.term3 - 82/28 + 82/28@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C19 + C0 + true + true + false + 1 + false + false + 0 + cfom.drawing - 22/20 + 22/20@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cfom.mask - 23/0 + 23/0@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C14 + C0 + true + false + false + 1 + false + false + 0 + cfom.maskAdd - 22/21 + 22/21@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C11 + C0 + true + false + false + 1 + false + false + 0 + cfom.maskDrop - 22/22 + 22/22@1 + + + #268c6b + #268c6b + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + cfom.waffleDrop - 22/24 + 22/24@1 + + + #ccccd9 + #ccccd9 + 0 + 0 + C19 + C0 + false + true + false + 1 + false + false + 0 + fom.dummy - 22/23 + 22/23@1 + + + #268c6b + #268c6b + 0 + 0 + C19 + C0 + false + true + false + 1 + false + false + 0 + cnwm.drawing - 109/44 + 109/44@1 + + + #268c6b + #268c6b + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cnwm.mask - 21/0 + 21/0@1 + + + #268c6b + #268c6b + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cnwm.maskAdd - 109/43 + 109/43@1 + + + #268c6b + #268c6b + 0 + 0 + C11 + C0 + false + true + false + 1 + false + false + 0 + cnwm.maskDrop - 109/42 + 109/42@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + cdnm.drawing - 110/20 + 110/20@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C17 + C0 + true + true + false + 1 + false + false + 0 + cdnm.mask - 48/0 + 48/0@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + cdnm.maskAdd - 110/21 + 110/21@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C3 + C0 + true + true + false + 1 + false + false + 0 + cdnm.maskDrop - 110/22 + 110/22@1 + + + #96c8ff + #ffffcc + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + clvtnm.drawing - 25/44 + 25/44@1 + + + #96c8ff + #ffffff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + clvtnm.mask - 25/0 + 25/0@1 + + + #96c8ff + #ffffff + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + clvtnm.maskAdd - 25/43 + 25/43@1 + + + #96c8ff + #0000ff + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + clvtnm.maskDrop - 25/42 + 25/42@1 + + + #ff8000 + #ffffcc + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + chvtpm.drawing - 88/44 + 88/44@1 + + + #ff8000 + #ffffff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + chvtpm.mask - 97/0 + 97/0@1 + + + #ff8000 + #ffffff + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + chvtpm.maskAdd - 97/43 + 97/43@1 + + + #ff8000 + #0000ff + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + chvtpm.maskDrop - 97/42 + 97/42@1 + + + #ff0000 + #d9e6ff + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + chvtrm.drawing - 98/44 + 98/44@1 + + + #ff0000 + #e61f0d + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + chvtrm.mask - 98/0 + 98/0@1 + + + #ff0000 + #e61f0d + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + chvtrm.maskAdd - 98/43 + 98/43@1 + + + #ff0000 + #d9e6ff + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + chvtrm.maskDrop - 98/42 + 98/42@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + ctunm.drawing - 96/20 + 96/20@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + ctunm.mask - 20/0 + 20/0@1 + + + #ffffff + #ffffff + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + ctunm.maskAdd - 96/21 + 96/21@1 + + + #ffffff + #ffffff + 0 + 0 + C3 + C0 + true + true + false + 1 + false + false + 0 + ctunm.maskDrop - 96/22 + 96/22@1 + + + #ff0000 + #ff0000 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + conom.drawing - 87/44 + 87/44@1 + + + #ff0000 + #ff0000 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + conom.mask - 88/0 + 88/0@1 + + + #ff0000 + #ff0000 + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + conom.maskAdd - 87/43 + 87/43@1 + + + #ff0000 + #ff0000 + 0 + 0 + C3 + C0 + true + true + false + 1 + false + false + 0 + conom.maskDrop - 87/42 + 87/42@1 + + + #00cc66 + #00cc66 + 0 + 0 + C19 + C0 + true + true + false + 1 + false + false + 0 + cnsdm.drawing - 29/20 + 29/20@1 + + + #00cc66 + #00cc66 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cnsdm.mask - 30/0 + 30/0@1 + + + #00cc66 + #00cc66 + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + cnsdm.maskAdd - 29/21 + 29/21@1 + + + #00cc66 + #00cc66 + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cnsdm.maskDrop - 29/22 + 29/22@1 + + + #ffff00 + #ffff00 + 0 + 0 + C19 + C0 + true + true + false + 1 + false + false + 0 + cpsdm.drawing - 31/20 + 31/20@1 + + + #ffff00 + #ffff00 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cpsdm.mask - 32/0 + 32/0@1 + + + #ffff00 + #ffff00 + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + cpsdm.maskAdd - 31/21 + 31/21@1 + + + #ffff00 + #ffff00 + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cpsdm.maskDrop - 31/22 + 31/22@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C19 + C0 + true + true + false + 1 + false + false + 0 + cntm.drawing - 26/20 + 26/20@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cntm.mask - 27/0 + 27/0@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cntm.maskAdd - 26/21 + 26/21@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C11 + C0 + false + true + false + 1 + false + false + 0 + cntm.maskDrop - 26/22 + 26/22@1 + + + #ffff00 + #ffff00 + 0 + 0 + C19 + C0 + true + false + false + 1 + false + false + 0 + hvntm.drawing - 125/20 + 125/20@1 + + + #fff5e6 + #fff5e6 + 0 + 0 + C19 + C0 + true + true + false + 1 + false + false + 0 + chvntm.drawing - 38/20 + 38/20@1 + + + #fff5e6 + #fff5e6 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + chvntm.mask - 39/0 + 39/0@1 + + + #fff5e6 + #fff5e6 + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + chvntm.maskAdd - 38/21 + 38/21@1 + + + #fff5e6 + #fff5e6 + 0 + 0 + C11 + C0 + false + true + false + 1 + false + false + 0 + chvntm.maskDrop - 38/22 + 38/22@1 + + + #00cc66 + #00cc66 + 0 + 0 + C19 + C0 + false + true + false + 1 + false + false + 0 + cldntm.drawing - 11/20 + 11/20@1 + + + #00cc66 + #00cc66 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cldntm.mask - 11/0 + 11/0@1 + + + #ff8000 + #ff8000 + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + clvom.drawing - 45/20 + 45/20@1 + + + #268c6b + #268c6b + 0 + 0 + C17 + C0 + true + true + false + 1 + false + false + 0 + clvom.mask - 46/0 + 46/0@1 + + + #268c6b + #268c6b + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + clvom.maskAdd - 45/21 + 45/21@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + clvom.maskDrop - 45/22 + 45/22@1 + + + #ff8000 + #ff8000 + 0 + 0 + C19 + C0 + false + true + false + 1 + false + false + 0 + cp1m.drawing - 33/44 + 33/44@1 + + + #ff8000 + #ff8000 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cp1m.mask - 28/0 + 28/0@1 + + + #ff8000 + #ff8000 + 0 + 0 + C14 + C0 + true + false + false + 1 + false + false + 0 + cp1m.maskAdd - 33/43 + 33/43@1 + + + #9900e6 + #9900e6 + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + cp1m.waffleDrop - 33/24 + 33/24@1 + + + #ff8000 + #ff8000 + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cp1m.maskDrop - 33/42 + 33/42@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + cli1m.drawing - 115/44 + 115/44@1 + + + #00ffff + #00ffff + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cli1m.mask - 56/0 + 56/0@1 + + + #00ffff + #00ffff + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + cli1m.maskAdd - 115/43 + 115/43@1 + + + #00ffff + #00ffff + 0 + 0 + C3 + C0 + true + true + false + 1 + false + false + 0 + cli1m.maskDrop - 115/42 + 115/42@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + clicm1.drawing - 106/44 + 106/44@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + clicm1.mask - 43/0 + 43/0@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + clicm1.maskAdd - 106/43 + 106/43@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C3 + C0 + true + true + false + 1 + false + false + 0 + clicm1.maskDrop - 106/42 + 106/42@1 + + + #0000ff + #0000ff + 0 + 0 + C19 + C0 + false + true + false + 1 + false + false + 0 + cmm1.drawing - 62/20 + 62/20@1 + + + #0000ff + #0000ff + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cmm1.mask - 36/0 + 36/0@1 + + + #0000ff + #0000ff + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cmm1.maskAdd - 62/21 + 62/21@1 + + + #0000ff + #0000ff + 0 + 0 + C11 + C0 + false + true + false + 1 + false + false + 0 + cmm1.maskDrop - 62/22 + 62/22@1 + + + #0000ff + #0000ff + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + cmm1.waffleDrop - 62/24 + 62/24@1 + + + #ffffcc + #ffffcc + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + cviam.drawing - 105/20 + 105/20@1 + + + #ffffcc + #ffffcc + 0 + 0 + C17 + C0 + true + true + false + 1 + false + false + 0 + cviam.mask - 40/0 + 40/0@1 + + + #ffffcc + #ffffcc + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cviam.maskAdd - 105/21 + 105/21@1 + + + #ffffcc + #ffffcc + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + cviam.maskDrop - 105/22 + 105/22@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C19 + C0 + false + true + false + 1 + false + false + 0 + cmm2.drawing - 105/44 + 105/44@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cmm2.mask - 41/0 + 41/0@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cmm2.maskAdd - 105/43 + 105/43@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C11 + C0 + false + true + false + 1 + false + false + 0 + cmm2.maskDrop - 105/42 + 105/42@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + cmm2.waffleDrop - 105/52 + 105/52@1 + + + #333399 + #333399 + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + cviam2.drawing - 108/20 + 108/20@1 + + + #333399 + #333399 + 0 + 0 + C17 + C0 + true + true + false + 1 + false + false + 0 + cviam2.mask - 44/0 + 44/0@1 + + + #333399 + #333399 + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cviam2.maskAdd - 108/21 + 108/21@1 + + + #333399 + #333399 + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + cviam2.maskDrop - 108/22 + 108/22@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C19 + C0 + false + true + false + 1 + false + false + 0 + cmm3.drawing - 107/20 + 107/20@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cmm3.mask - 34/0 + 34/0@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cmm3.maskAdd - 107/21 + 107/21@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + C11 + C0 + false + true + false + 1 + false + false + 0 + cmm3.maskDrop - 107/22 + 107/22@1 + + + #5e00e6 + #5e00e6 + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + cmm3.waffleDrop - 107/24 + 107/24@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + cnpc.drawing - 44/20 + 44/20@1 + + + #e61f0d + #e61f0d + 0 + 0 + C38 + C0 + true + true + false + 1 + false + false + 0 + cnpc.mask - 49/0 + 49/0@1 + + + #e61f0d + #e61f0d + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cnpc.maskAdd - 44/43 + 44/43@1 + + + #e61f0d + #e61f0d + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + cnpc.maskDrop - 44/42 + 44/42@1 + + + #268c6b + #268c6b + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + cviam3.drawing - 112/20 + 112/20@1 + + + #268c6b + #268c6b + 0 + 0 + C17 + C0 + true + true + false + 1 + false + false + 0 + cviam3.mask - 50/0 + 50/0@1 + + + #268c6b + #268c6b + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cviam3.maskAdd - 112/21 + 112/21@1 + + + #268c6b + #268c6b + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + cviam3.maskDrop - 112/22 + 112/22@1 + + + #00cc66 + #00cc66 + 0 + 0 + C19 + C0 + true + true + false + 1 + false + false + 0 + cnsm.mask - 22/0 + 22/0@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C19 + C0 + false + true + false + 1 + false + false + 0 + cpdm.drawing - 104/44 + 104/44@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cpdm.mask - 37/0 + 37/0@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cpdm.maskAdd - 104/43 + 104/43@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C11 + C0 + false + true + false + 1 + false + false + 0 + cpdm.maskDrop - 104/42 + 104/42@1 + + + #8c8ca6 + #0000ff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + cpmm.drawing - 91/44 + 91/44@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cpbo.mask - 99/0 + 99/0@1 + + + #00cc66 + #00cc66 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cmm4.mask - 51/0 + 51/0@1 + + + #00cc66 + #00cc66 + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + cmm4.maskAdd - 112/43 + 112/43@1 + + + #00cc66 + #00cc66 + 0 + 0 + C11 + C0 + true + true + false + 1 + false + false + 0 + cmm4.maskDrop - 112/42 + 112/42@1 + + + #00cc66 + #00cc66 + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + cmm4.waffleDrop - 112/4 + 112/4@1 + + + #00ffff + #00ffff + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + cviam4.drawing - 117/20 + 117/20@1 + + + #00ffff + #00ffff + 0 + 0 + C17 + C0 + true + true + false + 1 + false + false + 0 + cviam4.mask - 58/0 + 58/0@1 + + + #00ffff + #00ffff + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cviam4.maskAdd - 117/21 + 117/21@1 + + + #00ffff + #00ffff + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + cviam4.maskDrop - 117/22 + 117/22@1 + + + #ff8000 + #ff8000 + 0 + 0 + C13 + C0 + true + true + false + 1 + false + false + 0 + cmm5.mask - 59/0 + 59/0@1 + + + #ff8000 + #ff8000 + 0 + 0 + I1 + C0 + true + true + false + 1 + false + false + 0 + cmm5.waffleDrop - 117/4 + 117/4@1 + + + #0000ff + #0000ff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + target.drawing - 76/44 + 76/44@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + false + true + false + 1 + false + false + 0 + cctm1.drawing - 101/44 + 101/44@1 + + + #ffffff + #ffffff + 0 + 0 + C17 + C0 + true + true + false + 1 + false + false + 0 + cctm1.mask - 35/0 + 35/0@1 + + + #ffffff + #ffffff + 0 + 0 + C14 + C0 + false + true + false + 1 + false + false + 0 + cctm1.maskAdd - 101/43 + 101/43@1 + + + #ffffff + #ffffff + 0 + 0 + C3 + C0 + false + true + false + 1 + false + false + 0 + cctm1.maskDrop - 101/42 + 101/42@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + crpm.drawing - 53/44 + 53/44@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + crpm.mask - 96/0 + 96/0@1 + + + #ffffff + #ffffff + 0 + 0 + C14 + C0 + true + true + false + 1 + false + false + 0 + crpm.maskAdd - 53/43 + 53/43@1 + + + #ffffff + #ffffff + 0 + 0 + C3 + C0 + true + true + false + 1 + false + false + 0 + crpm.maskDrop - 53/42 + 53/42@1 + + + #e61f0d + #e61f0d + 0 + 0 + C46 + C0 + false + true + false + 1 + false + false + 0 + ccu1m.mask - 93/0 + 93/0@1 + + + #bf4026 + #bf4026 + 0 + 0 + C39 + C0 + false + true + false + 1 + false + false + 0 + cpmm2.mask - 94/0 + 94/0@1 + + + #ccccd9 + #333399 + 0 + 0 + C7 + C0 + false + true + false + 1 + false + false + 0 + cubm.mask - 100/0 + 100/0@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C19 + C0 + false + true + false + 1 + false + false + 0 + cbump.mask - 101/0 + 101/0@1 + + + #00bfff + #00bfff + 0 + 0 + C0 + C0 + true + true + false + 3 + false + false + 0 + overlap.drawing - 90/20 + 90/20@1 + + + #ff7f50 + #ff7f50 + 0 + 0 + C0 + C0 + true + true + false + 3 + false + false + 0 + overlap.boundary - 90/4 + 90/4@1 + + + #ff8000 + #ff8000 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.lowTapDensity - 81/14 + 81/14@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C0 + C0 + true + true + false + 3 + false + false + 0 + areaid.notCritSide - 81/15 + 81/15@1 + + + #adff2f + #adff2f + 0 + 0 + C2 + C0 + true + true + false + 3 + false + false + 0 + areaid.injection - 81/17 + 81/17@1 + + + #bebed8 + #bebed8 + 0 + 0 + C2 + C0 + true + true + false + 3 + false + false + 0 + areaid.rfdiode - 81/125 + 81/125@1 + + + #ffffff + #ffffff + 0 + 0 + C0 + C0 + true + true + false + 3 + false + false + 0 + areaid.seal - 81/1 + 81/1@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.core - 81/2 + 81/2@1 + + + #ffffcc + #ffffcc + 0 + 0 + C0 + C0 + true + true + false + 3 + false + false + 0 + areaid.frame - 81/3 + 81/3@1 + + + #d9cc00 + #d9cc00 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.esd - 81/19 + 81/19@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C0 + C0 + true + true + false + 3 + false + false + 0 + areaid.dieCut - 81/11 + 81/11@1 + + + #00ff00 + #00ff00 + 0 + 0 + C0 + C0 + true + true + false + 3 + false + false + 0 + areaid.moduleCut - 81/10 + 81/10@1 + + + #00ffff + #00ffff + 0 + 0 + C0 + C0 + true + true + false + 3 + false + false + 0 + areaid.frameRect - 81/12 + 81/12@1 + + + #333399 + #ccccd9 + 0 + 0 + C21 + C0 + true + true + false + 1 + false + false + 0 + areaid.substrateCut - 81/53 + 81/53@1 + + + #ffff00 + #ffff00 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.diode - 81/23 + 81/23@1 + + + #ff00ff + #ff00ff + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.standardc - 81/4 + 81/4@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C0 + C5 + true + true + false + 1 + false + false + 0 + areaid.deadZon - 81/50 + 81/50@1 + + + #ff8000 + #ff8000 + 0 + 0 + C0 + C5 + true + true + false + 1 + false + false + 0 + areaid.critCorner - 81/51 + 81/51@1 + + + #ffffcc + #ffffcc + 0 + 0 + C0 + C5 + true + true + false + 1 + false + false + 0 + areaid.critSid - 81/52 + 81/52@1 + + + #8c8ca6 + #c8ffc8 + 0 + 0 + C19 + C0 + true + true + false + 3 + false + false + 0 + areaid.opcDrop - 81/54 + 81/54@1 + + + #00bfff + #00ffe7 + 0 + 0 + C1 + C0 + true + true + false + 3 + false + false + 0 + areaid.waffleWindow - 81/13 + 81/13@1 + + + #daa520 + #daa520 + 0 + 0 + C0 + C0 + true + true + false + 3 + false + false + 0 + areaid.extendedDrain - 81/57 + 81/57@1 + + + #ffbff2 + #ffbff2 + 0 + 0 + C0 + C0 + true + true + false + 3 + false + false + 0 + areaid.lvNative - 81/60 + 81/60@1 + + + #9900e6 + #9900e6 + 0 + 0 + C0 + C0 + true + true + false + 3 + false + false + 0 + areaid.photo - 81/81 + 81/81@1 + + + #ff00ff + #00ff00 + 0 + 0 + C0 + C0 + true + true + false + 3 + false + false + 0 + areaid.etest - 81/101 + 81/101@1 + + + #ff0000 + #ff0000 + 0 + 0 + C0 + C0 + true + true + false + 3 + false + false + 0 + areaid.hvnwell - 81/63 + 81/63@1 + + + #9900e6 + #9900e6 + 0 + 0 + C0 + C0 + true + true + false + 3 + false + false + 0 + areaid.rdlprobepad - 81/27 + 81/27@1 + + + #00bfff + #00bfff + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.sigPadDiff - 81/6 + 81/6@1 + + + #c8ffc8 + #c8ffc8 + 0 + 0 + C0 + C0 + true + true + false + 3 + false + false + 0 + areaid.sigPadWell - 81/7 + 81/7@1 + + + #ff7f50 + #ff7f50 + 0 + 0 + C0 + C0 + true + false + false + 3 + false + false + 0 + areaid.sigPadMetNtr - 81/8 + 81/8@1 + + + #ff6464 + #ff6464 + 0 + 0 + C0 + C0 + true + true + false + 3 + false + false + 0 + areaid.analog - 81/79 + 81/79@1 + + + #ffff00 + #ffffff + 0 + 0 + C0 + C0 + true + true + false + 1 + false + false + 0 + prune.drawing - 84/44 + 84/44@1 + + + #0000ff + #0000ff + 0 + 0 + C0 + C0 + true + false + false + 1 + false + false + 0 + padCenter.drawing - 81/20 + 81/20@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C7 + C0 + true + true + false + 1 + false + false + 0 + met1.psa1 - 68/88 + 68/88@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C36 + C0 + true + true + false + 1 + false + false + 0 + met2.psa1 - 69/88 + 69/88@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C48 + C0 + true + true + false + 1 + false + false + 0 + met3.psa1 - 70/88 + 70/88@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C15 + C0 + true + true + false + 1 + false + false + 0 + met4.psa1 - 71/88 + 71/88@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C41 + C0 + true + true + false + 1 + false + false + 0 + met5.psa1 - 72/88 + 72/88@1 + + + #00ffe7 + #00ffe7 + 0 + 0 + C7 + C0 + true + true + false + 1 + false + false + 0 + met1.psa2 - 68/89 + 68/89@1 + + + #00ffe7 + #00ffe7 + 0 + 0 + C36 + C0 + true + true + false + 1 + false + false + 0 + met2.psa2 - 69/89 + 69/89@1 + + + #00ffe7 + #00ffe7 + 0 + 0 + C48 + C0 + true + true + false + 1 + false + false + 0 + met3.psa2 - 70/89 + 70/89@1 + + + #00ffe7 + #00ffe7 + 0 + 0 + C15 + C0 + true + true + false + 1 + false + false + 0 + met4.psa2 - 71/89 + 71/89@1 + + + #00ffe7 + #00ffe7 + 0 + 0 + C41 + C0 + true + true + false + 1 + false + false + 0 + met5.psa2 - 72/89 + 72/89@1 + + + #ffffcc + #ffffcc + 0 + 0 + C7 + C0 + true + true + false + 1 + false + false + 0 + met1.psa3 - 68/90 + 68/90@1 + + + #ffffcc + #ffffcc + 0 + 0 + C36 + C0 + true + true + false + 1 + false + false + 0 + met2.psa3 - 69/90 + 69/90@1 + + + #ffffcc + #ffffcc + 0 + 0 + C48 + C0 + true + true + false + 1 + false + false + 0 + met3.psa3 - 70/90 + 70/90@1 + + + #ffffcc + #ffffcc + 0 + 0 + C15 + C0 + true + true + false + 1 + false + false + 0 + met4.psa3 - 71/90 + 71/90@1 + + + #ffffcc + #ffffcc + 0 + 0 + C41 + C0 + true + true + false + 1 + false + false + 0 + met5.psa3 - 72/90 + 72/90@1 + + + #802626 + #802626 + 0 + 0 + C7 + C0 + true + true + false + 1 + false + false + 0 + met1.psa4 - 68/91 + 68/91@1 + + + #802626 + #802626 + 0 + 0 + C36 + C0 + true + true + false + 1 + false + false + 0 + met2.psa4 - 69/91 + 69/91@1 + + + #802626 + #802626 + 0 + 0 + C48 + C0 + true + true + false + 1 + false + false + 0 + met3.psa4 - 70/91 + 70/91@1 + + + #802626 + #802626 + 0 + 0 + C15 + C0 + true + true + false + 1 + false + false + 0 + met4.psa4 - 71/91 + 71/91@1 + + + #802626 + #802626 + 0 + 0 + C41 + C0 + true + true + false + 1 + false + false + 0 + met5.psa4 - 72/91 + 72/91@1 + + + #333399 + #333399 + 0 + 0 + C7 + C0 + true + true + false + 1 + false + false + 0 + met1.psa5 - 68/92 + 68/92@1 + + + #333399 + #333399 + 0 + 0 + C36 + C0 + true + true + false + 1 + false + false + 0 + met2.psa5 - 69/92 + 69/92@1 + + + #333399 + #333399 + 0 + 0 + C48 + C0 + true + true + false + 1 + false + false + 0 + met3.psa5 - 70/92 + 70/92@1 + + + #333399 + #333399 + 0 + 0 + C15 + C0 + true + true + false + 1 + false + false + 0 + met4.psa5 - 71/92 + 71/92@1 + + + #333399 + #333399 + 0 + 0 + C41 + C0 + true + true + false + 1 + false + false + 0 + met5.psa5 - 72/92 + 72/92@1 + + + #fa8072 + #fa8072 + 0 + 0 + C7 + C0 + true + true + false + 1 + false + false + 0 + met1.psa6 - 68/93 + 68/93@1 + + + #fa8072 + #fa8072 + 0 + 0 + C36 + C0 + true + true + false + 1 + false + false + 0 + met2.psa6 - 69/93 + 69/93@1 + + + #fa8072 + #fa8072 + 0 + 0 + C48 + C0 + true + true + false + 1 + false + false + 0 + met3.psa6 - 70/93 + 70/93@1 + + + #fa8072 + #fa8072 + 0 + 0 + C15 + C0 + true + true + false + 1 + false + false + 0 + met4.psa6 - 71/93 + 71/93@1 + + + #fa8072 + #fa8072 + 0 + 0 + C41 + C0 + true + true + false + 1 + false + false + 0 + met5.psa6 - 72/93 + 72/93@1 + + + #ff0000 + #ff0000 + 0 + 0 + C10 + C0 + true + true + false + 1 + false + false + 0 + rdl.psa1 - 74/88 + 74/88@1 + + + #0000ff + #0000ff + 0 + 0 + C10 + C0 + true + true + false + 1 + false + false + 0 + rdl.psa2 - 74/89 + 74/89@1 + + + #00cc66 + #00cc66 + 0 + 0 + C10 + C0 + true + true + false + 1 + false + false + 0 + rdl.psa3 - 74/90 + 74/90@1 + + + #ffffff + #ffffff + 0 + 0 + C10 + C0 + true + true + false + 1 + false + false + 0 + rdl.psa4 - 74/91 + 74/91@1 + + + #ffff00 + #ffff00 + 0 + 0 + C10 + C0 + true + true + false + 1 + false + false + 0 + rdl.psa5 - 74/92 + 74/92@1 + + + #bf4026 + #bf4026 + 0 + 0 + C10 + C0 + true + true + false + 1 + false + false + 0 + rdl.psa6 - 74/93 + 74/93@1 + + + #ffe6bf + #ffe6bf + 0 + 0 + C19 + C1 + false + true + false + 1 + false + false + 0 + blanking.drawing - 124/40 + 124/40@1 + + + #80a8ff + #80a8ff + 0 + 0 + I5 + + true + true + false + + false + false + 0 + via.label 5/1@1 + 5/1@1 + + + #80a8ff + #80a8ff + 0 + 0 + I9 + + true + true + false + + false + false + 0 + via.blockage 5/3@1 + 5/3@1 + + + #ff0080 + #ff0080 + 0 + 0 + I5 + + true + true + false + + false + false + 0 + via2.blockage 7/3@1 + 7/3@1 + + + #8000ff + #8000ff + 0 + 0 + I9 + + true + true + false + + false + false + 0 + via3.label 9/1@1 + 9/1@1 + + + #8000ff + #8000ff + 0 + 0 + I5 + + true + true + false + + false + false + 0 + via3.blockage 9/3@1 + 9/3@1 + + + #0080ff + #0080ff + 0 + 0 + I9 + + true + true + false + + false + false + 0 + via4.label 11/1@1 + 11/1@1 + + + #0080ff + #0080ff + 0 + 0 + I5 + + true + true + false + + false + false + 0 + via4.blockage 11/3@1 + 11/3@1 + + + #800057 + #800057 + 0 + 0 + I9 + + true + true + false + + false + false + 0 + rdlcon.drawing 13/0@1 + 13/0@1 + + + #0080ff + #0080ff + 0 + 0 + I5 + + true + true + false + + false + false + 0 + marker.error 83/6@1 + 83/6@1 + + + #0080ff + #0080ff + 0 + 0 + I9 + + true + true + false + + false + false + 0 + marker.warning 83/7@1 + 83/7@1 + + + #0080ff + #0080ff + 0 + 0 + C0 + + true + false + false + + false + false + 0 + text.drawing 83/44@1 + 83/44@1 + + + #008080 + #008080 + 0 + 0 + I9 + + true + true + false + + false + false + 0 + crrpm.mask 102/0@1 + 102/0@1 + + + #008080 + #008080 + 0 + 0 + I5 + + true + true + false + + false + false + 0 + rrpm.drawing 102/20@1 + 102/20@1 + + + #80ff8d + #80ff8d + 0 + 0 + C0 + + true + false + false + + false + false + 0 + prBoundary.drawing 235/0@1 + 235/0@1 + + + #ffae00 + #ffae00 + 0 + 0 + C0 + + true + true + false + + false + false + 0 + OUTLINE 236/0@1 + 236/0@1 + + GDS + + + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + + 1 + blank + + + + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + **************** + + 2 + solid + + + + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + + 3 + dots + + + + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + + 4 + hLine + + + + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + + 5 + vLine + + + + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + + 6 + cross + + + + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + + 7 + grid + + + + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + + 8 + slash + + + + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + + 9 + backSlash + + + + **......**...... + ..*.......*..... + ...**......**... + .....*.......*.. + ......**......** + *.......*....... + .**......**..... + ...*.......*.... + ....**......**.. + ......*.......*. + *......**......* + .*.......*...... + ..**......**.... + ....*.......*... + .....**......**. + .......*.......* + + 10 + hZigZag + + + + *....*....*..... + *.....*....*.... + .*....*.....*... + ..*....*....*... + ..*.....*....*.. + ...*....*.....*. + ....*....*....*. + ....*.....*....* + *....*....*..... + *.....*....*.... + .*....*.....*... + ..*....*....*... + ..*.....*....*.. + ...*....*.....*. + ....*....*....*. + ....*.....*....* + + 11 + vZigZag + + + + ................ + ................ + ...*****...***** + ...*...*...*...* + ...*...*...*...* + ****...*****...* + ................ + ................ + ................ + ................ + ...*****...***** + ...*...*...*...* + ...*...*...*...* + ****...*****...* + ................ + ................ + + 12 + hCurb + + + + .....*.......*.. + .....*.......*.. + .....*.......*.. + ..****....****.. + ..*.......*..... + ..*.......*..... + ..*.......*..... + ..****....****.. + .....*.......*.. + .....*.......*.. + .....*.......*.. + ..****....****.. + ..*.......*..... + ..*.......*..... + ..*.......*..... + ..****....****.. + + 13 + vCurb + + + + **************** + ..*.......*..... + ..*.......*..... + ..*.......*..... + **************** + ......*.......*. + ......*.......*. + ......*.......*. + **************** + ..*.......*..... + ..*.......*..... + ..*.......*..... + **************** + ......*.......*. + ......*.......*. + ......*.......*. + + 14 + brick + + + + ................ + ..*.......*..... + ..*.......*..... + ..*.......*..... + *****...*****... + ..*.......*..... + ..*.......*..... + ..*.......*..... + ................ + .....*.......*.. + .....*.......*.. + .....*.......*.. + ...*****...***** + .....*.......*.. + .....*.......*.. + .....*.......*.. + + 15 + dagger + + + + ................ + ..*............. + ..*............. + ..*............. + *****........... + ..*............. + ..*............. + ..*............. + ................ + .............*.. + .............*.. + .............*.. + ...........***** + .............*.. + .............*.. + .............*.. + + 16 + sparseDagger + + + + ................ + ..........*..... + ..........*..... + ..........*..... + ........*****... + ..........*..... + ..........*..... + ..........*..... + ................ + .....*.......... + .....*.......... + .....*.......... + ...*****........ + .....*.......... + .....*.......... + .....*.......... + + 17 + sparseDagger2 + + + + ................ + ....*........... + ...*.*.......... + ..*...*......... + .*.....*........ + *********....... + ................ + ................ + ................ + ...........*.... + ..........*.*... + .........*...*.. + ........*.....*. + .......********* + ................ + ................ + + 18 + triangle + + + + ................ + .*.....*.....*.. + ..*...**....*... + ...*.*.*...*.... + ....*..*..*..... + .....*.*.*...... + ......***....... + .......*........ + ......***....... + .....*.*.*...... + ....*..*..*..... + ...*...*...*.... + ..*....*....*... + .*..*******..*.. + ................ + ................ + + 19 + Xone + + + + ................ + .*....**.....*.. + ..*..*..*...*... + ...**....*.*.... + ....*....**..... + .....*...*...... + ......*.*....... + .......*........ + ......*.*....... + .....*...*...... + ....*.....*..... + ...**......*.... + ..*.*.......*... + .*..******...*.. + ................ + ................ + + 20 + Xtwo + + + + ................ + ................ + ......*.......*. + ................ + ................ + ................ + ..*.......*..... + ................ + ................ + ................ + ......*.......*. + ................ + ................ + ................ + ..*.......*..... + ................ + + 21 + spareDots + + + + ................ + ................ + ................ + ................ + ................ + ......*.......*. + ................ + ................ + ................ + ................ + ................ + ................ + ..*.......*..... + ................ + ................ + ................ + + 22 + spareDots21 + + + + ................ + ................ + ......*.......*. + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ..*.......*..... + ................ + ................ + ................ + ................ + ................ + + 23 + spareDots22 + + + + ****....****.... + ****....****.... + ****....****.... + ****....****.... + ....****....**** + ....****....**** + ....****....**** + ....****....**** + ****....****.... + ****....****.... + ****....****.... + ****....****.... + ....****....**** + ....****....**** + ....****....**** + ....****....**** + + 24 + checker + + + + ....****....**** + ....****....**** + ....****....**** + ....****....**** + ****....****.... + ****....****.... + ****....****.... + ****....****.... + ....****....**** + ....****....**** + ....****....**** + ....****....**** + ****....****.... + ****....****.... + ****....****.... + ****....****.... + + 25 + checker2 + + + + ................ + ................ + ................ + ................ + .......*........ + ......**........ + .......*........ + .......*........ + .......*........ + .......*........ + ......***....... + ................ + ................ + ................ + ................ + ................ + + 26 + one + + + + ................ + ................ + ................ + ................ + ................ + .......**....... + ......*..*...... + .........*...... + ........*....... + .......*........ + ......*......... + ......****...... + ................ + ................ + ................ + ................ + + 27 + two + + + + ................ + ................ + ................ + ................ + ................ + ......***....... + .....*...*...... + .........*...... + .......**....... + .........*...... + .....*...*...... + ......***....... + ................ + ................ + ................ + ................ + + 28 + three + + + + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + .............*.. + ............**.. + ...........*.*.. + ..........*..*.. + .........******. + .............*.. + .............*.. + ................ + + 29 + four + + + + ................ + ................ + ................ + ......***....... + .....*.......... + .....*.......... + .....***........ + ........*....... + ........*....... + .....***........ + ................ + ................ + ................ + ................ + ................ + ................ + + 30 + five + + + + ................ + ................ + ................ + ................ + .......***...... + ......*......... + ......*......... + ......****...... + ......*...*..... + ......*...*..... + .......***...... + ................ + ................ + ................ + ................ + ................ + + 31 + six + + + + ................ + ................ + ................ + .....******..... + ..........*..... + .........*...... + .........*...... + ........*....... + ........*....... + .......*........ + ......*......... + .....*.......... + ................ + ................ + ................ + ................ + + 32 + seven + + + + ................ + ................ + ................ + ................ + ......***....... + .....*...*...... + .....*...*...... + ......***....... + .....*...*...... + .....*...*...... + ......***....... + ................ + ................ + ................ + ................ + ................ + + 33 + eight + + + + *..............* + .*............*. + ..*..........*.. + ...*........*... + ....*......*.... + .....*....*..... + ......*..*...... + .......**....... + .......**....... + ......*..*...... + .....*....*..... + ....*......*.... + ...*........*... + ..*..........*.. + .*............*. + *..............* + + 34 + box45 + + + + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + .*.*.*.*.*.*.*.* + *.*.*.*.*.*.*.*. + + 35 + gray50 + + + + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + + 36 + gray25 + + + + .*.*.*...*.*.*.. + ................ + ...*...*...*...* + ................ + .*...*.*.*...*.* + ................ + ...*...*...*...* + ................ + .*.*.*...*.*.*.. + ................ + ...*...*...*...* + ................ + .*...*.*.*...*.* + ................ + ...*...*...*...* + ................ + + 37 + snow + + + + ..*.......*..... + ...*.......*.... + ....*.......*... + .....*.......*.. + ......*.......*. + .......*.......* + *.......*....... + .*.......*...... + ..*.......*..... + ...*.......*.... + ....*.......*... + .....*.......*.. + ......*.......*. + .......*.......* + *.......*....... + .*.......*...... + + 38 + backSlash2 + + + + *.....*.*.....*. + .*...*...*...*.. + ..*.*.....*.*... + ...*...*...*...* + ..*.*.....*.*... + .*...*...*...*.. + *.....*.*.....*. + ...*...*...*...* + *.....*.*.....*. + .*...*...*...*.. + ..*.*.....*.*... + ...*...*...*...* + ..*.*.....*.*... + .*...*...*...*.. + *.....*.*.....*. + ...*...*...*...* + + 39 + lattice + + + + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + + 40 + smallChecker + + + + ....*........... + ...*.*.......... + ..*...*......... + .*.....*........ + *.......*....... + .*.......*...... + ..*.......*..... + ...*.......*.... + ....*.......*... + .....*.......*.. + ......*.......*. + .......*.......* + ........*.....*. + .........*...*.. + ..........*.*... + ...........*.... + + 41 + slantBox + + + + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + + 42 + slash2 + + + + ...*.......*.... + ..*.......*..... + .*.......*...... + *.......*....... + .......*.......* + ......*.......*. + .....*.......*.. + ....*.......*... + ...*.......*.... + ..*.......*..... + .*.......*...... + *.......*....... + .......*.......* + ......*.......*. + .....*.......*.. + ....*.......*... + + 43 + bigSlash + + + + ****....****.... + *..*....*..*.... + *..*....*..*.... + ****....****.... + ................ + ................ + ................ + ................ + ****....****.... + *..*....*..*.... + *..*....*..*.... + ****....****.... + ................ + ................ + ................ + ................ + + 44 + boxes + + + + ..**......**.... + .*..*....*..*... + *....*..*....*.. + *....*..*....*.. + .*..*....*..*... + ..**......**.... + ................ + ................ + ..**......**.... + .*..*....*..*... + *....*..*....*.. + *....*..*....*.. + .*..*....*..*... + ..**......**.... + ................ + ................ + + 45 + circles + + + + .**..**..**..**. + ...*...*...*...* + *...*...*...*... + .**..**..**..**. + .**..**..**..**. + *...*...*...*... + ...*...*...*...* + .**..**..**..**. + .**..**..**..**. + ...*...*...*...* + *...*...*...*... + .**..**..**..**. + .**..**..**..**. + *...*...*...*... + ...*...*...*...* + .**..**..**..**. + + 46 + zigzag + + + + ................ + *.*.*.*.*.*.*.*. + ................ + ...*....*....*.. + ................ + *.*.*.*.*.*.*.*. + ................ + ...*....*....*.. + ................ + *.*.*.*.*.*.*.*. + ................ + ...*....*....*.. + ................ + *.*.*.*.*.*.*.*. + ................ + ...*....*....*.. + + 47 + lightMesh + + + + ...............* + ..............*. + .............*.. + ............*... + ...........*.... + ..........*..... + .........*...... + ........*....... + .......*........ + ......*......... + .....*.......... + ....*........... + ...*............ + ..*............. + .*.............. + *............... + + 48 + hugeSlash + + + + *............... + .*.............. + ..*............. + ...*............ + ....*........... + .....*.......... + ......*......... + .......*........ + ........*....... + .........*...... + ..........*..... + ...........*.... + ............*... + .............*.. + ..............*. + ...............* + + 49 + hugeSlash2 + + + + *.........*..... + .....*.......... + ..*.........*... + .......*........ + ....*.........*. + .*.......*...... + ......*......... + ...*.......*.... + ........*....... + .....*.......*.. + *.........*..... + .......*........ + ..*.........*... + .........*...... + ....*.........*. + ...........*.... + + 50 + curve + + + + ....*....*....*. + ..*............. + *.......*....... + .............*.. + .......*........ + ............*... + .....*.......... + ...*.......*.... + *............... + ................ + .........*...... + ................ + ......*........* + ...*............ + *............*.. + ..........*..... + + 51 + curve2 + + + + ...........*.... + ..........*.*... + .........*...*.. + ........*.....*. + .........*...*.. + ..........*.*... + ...........*.... + ................ + ................ + ...*............ + ..*.*........... + .*...*.......... + *.....*......... + .*...*.......... + ..*.*........... + ...*............ + + 52 + diams + + + + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ...*............ + ..*.*........... + .*...*.......... + *.....*......... + .*...*.......... + ..*.*........... + ...*............ + + 53 + sparsediam + + + + .......*.......* + ......*......... + .....*.......... + ................ + ................ + ................ + .*.............. + *............... + .......*.......* + ..............*. + .............*.. + ................ + ................ + ................ + .........*...... + ........*....... + + 54 + rain + + + + * + + 55 + + + + *** + 1 + solid + + + ****.. + 2 + dashed + + + *.. + 3 + dots + + + ***..*.. + 4 + dashDot + + + **.. + 5 + shortDash + + + ****..**.. + 6 + doubleDash + + + *... + 7 + hidden + + + + 8 + + + diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.lyt b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.lyt new file mode 100755 index 00000000..8e56918e --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A.lyt @@ -0,0 +1,135 @@ + + + sky130A + SkyWater 130nm technology + + 0.005 + $(appdata_path)/tech/sky130A + /home/xrex/.klayout/tech/sky130A + sky130A.lyp + true + + + 1 + true + true + + + true + layer_map() + true + true + + + true + layer_map('areaid.analog : 81/79';'areaid.core : 81/2';'areaid.critCorner : 81/51';'areaid.critSid : 81/52';'areaid.deadZon : 81/50';'areaid.dieCut : 81/11';'areaid.diode : 81/23';'areaid.esd : 81/19';'areaid.etest : 81/101';'areaid.extendedDrain : 81/57';'areaid.frame : 81/3';'areaid.frameRect : 81/12';'areaid.hvnwell : 81/63';'areaid.injection : 81/17';'areaid.lowTapDensity : 81/14';'areaid.lvNative : 81/60';'areaid.moduleCut : 81/10';'areaid.notCritSide : 81/15';'areaid.opcDrop : 81/54';'areaid.photo : 81/81';'areaid.rdlprobepad : 81/27';'areaid.rfdiode : 81/125';'areaid.seal : 81/1';'areaid.sigPadDiff : 81/6';'areaid.sigPadMetNtr : 81/8';'areaid.sigPadWell : 81/7';'areaid.standardc : 81/4';'areaid.substrateCut : 81/53';'areaid.waffleWindow : 81/13';'blanking.drawing : 124/40';'bump.drawing : 127/22';'capacitor.drawing : 82/64';'cbump.mask : 101/0';'cctm1.drawing : 101/44';'cctm1.mask : 35/0';'cctm1.maskAdd : 101/43';'cctm1.maskDrop : 101/42';'ccu1m.mask : 93/0';'cdnm.drawing : 110/20';'cdnm.mask : 48/0';'cdnm.maskAdd : 110/21';'cdnm.maskDrop : 110/22';'cfom.drawing : 22/20';'cfom.mask : 23/0';'cfom.maskAdd : 22/21';'cfom.maskDrop : 22/22';'cfom.waffleDrop : 22/24';'chvntm.drawing : 38/20';'chvntm.mask : 39/0';'chvntm.maskAdd : 38/21';'chvntm.maskDrop : 38/22';'chvtpm.drawing : 88/44';'chvtpm.mask : 97/0';'chvtpm.maskAdd : 97/43';'chvtpm.maskDrop : 97/42';'chvtrm.drawing : 98/44';'chvtrm.mask : 98/0';'chvtrm.maskAdd : 98/43';'chvtrm.maskDrop : 98/42';'cldntm.drawing : 11/20';'cldntm.mask : 11/0';'cli1m.drawing : 115/44';'cli1m.mask : 56/0';'cli1m.maskAdd : 115/43';'cli1m.maskDrop : 115/42';'clicm1.drawing : 106/44';'clicm1.mask : 43/0';'clicm1.maskAdd : 106/43';'clicm1.maskDrop : 106/42';'clvom.drawing : 45/20';'clvom.mask : 46/0';'clvom.maskAdd : 45/21';'clvom.maskDrop : 45/22';'clvtnm.drawing : 25/44';'clvtnm.mask : 25/0';'clvtnm.maskAdd : 25/43';'clvtnm.maskDrop : 25/42';'cmm1.drawing : 62/20';'cmm1.mask : 36/0';'cmm1.maskAdd : 62/21';'cmm1.maskDrop : 62/22';'cmm1.waffleDrop : 62/24';'cmm2.drawing : 105/44';'cmm2.mask : 41/0';'cmm2.maskAdd : 105/43';'cmm2.maskDrop : 105/42';'cmm2.waffleDrop : 105/52';'cmm3.drawing : 107/20';'cmm3.mask : 34/0';'cmm3.maskAdd : 107/21';'cmm3.maskDrop : 107/22';'cmm3.waffleDrop : 107/24';'cmm4.mask : 51/0';'cmm4.maskAdd : 112/43';'cmm4.maskDrop : 112/42';'cmm4.waffleDrop : 112/4';'cmm5.mask : 59/0';'cmm5.waffleDrop : 117/4';'cncm.drawing : 96/44';'cncm.mask : 17/0';'cnpc.drawing : 44/20';'cnpc.mask : 49/0';'cnpc.maskAdd : 44/43';'cnpc.maskDrop : 44/42';'cnsdm.drawing : 29/20';'cnsdm.mask : 30/0';'cnsdm.maskAdd : 29/21';'cnsdm.maskDrop : 29/22';'cnsm.mask : 22/0';'cntm.drawing : 26/20';'cntm.mask : 27/0';'cntm.maskAdd : 26/21';'cntm.maskDrop : 26/22';'cnwm.drawing : 109/44';'cnwm.mask : 21/0';'cnwm.maskAdd : 109/43';'cnwm.maskDrop : 109/42';'conom.drawing : 87/44';'conom.mask : 88/0';'conom.maskAdd : 87/43';'conom.maskDrop : 87/42';'cp1m.drawing : 33/44';'cp1m.mask : 28/0';'cp1m.maskAdd : 33/43';'cp1m.maskDrop : 33/42';'cp1m.waffleDrop : 33/24';'cpbo.mask : 99/0';'cpdm.drawing : 104/44';'cpdm.mask : 37/0';'cpdm.maskAdd : 104/43';'cpdm.maskDrop : 104/42';'cpmm2.mask : 94/0';'cpmm.drawing : 91/44';'cpsdm.drawing : 31/20';'cpsdm.mask : 32/0';'cpsdm.maskAdd : 31/21';'cpsdm.maskDrop : 31/22';'crpm.drawing : 53/44';'crpm.mask : 96/0';'crpm.maskAdd : 53/43';'crpm.maskDrop : 53/42';'crrpm.mask : 102/0';'ctunm.drawing : 96/20';'ctunm.mask : 20/0';'ctunm.maskAdd : 96/21';'ctunm.maskDrop : 96/22';'cubm.mask : 100/0';'cviam2.drawing : 108/20';'cviam2.mask : 44/0';'cviam2.maskAdd : 108/21';'cviam2.maskDrop : 108/22';'cviam3.drawing : 112/20';'cviam3.mask : 50/0';'cviam3.maskAdd : 112/21';'cviam3.maskDrop : 112/22';'cviam4.drawing : 117/20';'cviam4.mask : 58/0';'cviam4.maskAdd : 117/21';'cviam4.maskDrop : 117/22';'cviam.drawing : 105/20';'cviam.mask : 40/0';'cviam.maskAdd : 105/21';'cviam.maskDrop : 105/22';'diff.boundary : 65/4';'diff.cut : 65/14';'diff.drawing : 65/20';'diff.hv : 65/8';'diff.label : 65/6';'diff.net : 65/23';'diff.pin : 65/16';'diff.res : 65/13';'dnwell.drawing : 64/18';'fom.dummy : 22/23';'hvi.drawing : 75/20';'hvntm.drawing : 125/20';'hvtp.drawing : 78/44';'hvtr.drawing : 18/20';'inductor.drawing : 82/24';'inductor.label : 82/25';'inductor.term1 : 82/26';'inductor.term2 : 82/27';'inductor.term3 : 82/28';'ldntm.drawing : 11/44';'li1.blockage : 67/10';'li1.boundary : 67/4';'li1.cut : 67/14';'li1.drawing : 67/20';'li1.label : 67/5';'li1.net : 67/23';'li1.pin : 67/16';'li1.probe : 67/25';'li1.res : 67/13';'li1.short : 67/15';'licon1.boundary : 66/60';'licon1.drawing : 66/44';'licon1.net : 66/41';'licon1.pin : 66/58';'lvtn.drawing : 125/44';'marker.error : 83/6';'marker.warning : 83/7';'mcon.boundary : 67/60';'mcon.drawing : 67/44';'mcon.blockage : 67/44';'mcon.net : 67/41';'mcon.pin : 67/48';'met1.blockage : 68/10';'met1.boundary : 68/4';'met1.cut : 68/14';'met1.drawing : 68/20';'met1.label : 68/5';'met1.net : 68/23';'met1.option1 : 68/32';'met1.option2 : 68/33';'met1.option3 : 68/34';'met1.option4 : 68/35';'met1.option5 : 68/36';'met1.option6 : 68/37';'met1.option7 : 68/38';'met1.option8 : 68/39';'met1.pin : 68/16';'met1.probe : 68/25';'met1.psa1 : 68/88';'met1.psa2 : 68/89';'met1.psa3 : 68/90';'met1.psa4 : 68/91';'met1.psa5 : 68/92';'met1.psa6 : 68/93';'met1.res : 68/13';'met1.short : 68/15';'met2.blockage : 69/10';'met2.boundary : 69/4';'met2.cut : 69/14';'met2.drawing : 69/20';'met2.label : 69/5';'met2.net : 69/23';'met2.option1 : 69/32';'met2.option2 : 69/33';'met2.option3 : 69/34';'met2.option4 : 69/35';'met2.option5 : 69/36';'met2.option6 : 69/37';'met2.option7 : 69/38';'met2.option8 : 69/39';'met2.pin : 69/16';'met2.probe : 69/25';'met2.psa1 : 69/88';'met2.psa2 : 69/89';'met2.psa3 : 69/90';'met2.psa4 : 69/91';'met2.psa5 : 69/92';'met2.psa6 : 69/93';'met2.res : 69/13';'met2.short : 69/15';'met3.blockage : 70/10';'met3.boundary : 70/4';'met3.cut : 70/14';'met3.drawing : 70/20';'met3.fuse : 70/17';'met3.label : 70/5';'met3.net : 70/23';'met3.option1 : 70/32';'met3.option2 : 70/33';'met3.option3 : 70/34';'met3.option4 : 70/35';'met3.option5 : 70/36';'met3.option6 : 70/37';'met3.option7 : 70/38';'met3.option8 : 70/39';'met3.pin : 70/16';'met3.probe : 70/25';'met3.psa1 : 70/88';'met3.psa2 : 70/89';'met3.psa3 : 70/90';'met3.psa4 : 70/91';'met3.psa5 : 70/92';'met3.psa6 : 70/93';'met3.res : 70/13';'met3.short : 70/15';'met4.blockage : 71/10';'met4.boundary : 71/4';'met4.cut : 71/14';'met4.drawing : 71/20';'met4.fuse : 71/17';'met4.label : 71/5';'met4.net : 71/23';'met4.option1 : 71/32';'met4.option2 : 71/33';'met4.option3 : 71/34';'met4.option4 : 71/35';'met4.option5 : 71/36';'met4.option6 : 71/37';'met4.option7 : 71/38';'met4.option8 : 71/39';'met4.pin : 71/16';'met4.probe : 71/25';'met4.psa1 : 71/88';'met4.psa2 : 71/89';'met4.psa3 : 71/90';'met4.psa4 : 71/91';'met4.psa5 : 71/92';'met4.psa6 : 71/93';'met4.res : 71/13';'met4.short : 71/15';'met5.blockage : 72/10';'met5.boundary : 72/4';'met5.cut : 72/14';'met5.drawing : 72/20';'met5.fuse : 72/17';'met5.label : 72/5';'met5.net : 72/23';'met5.option1 : 72/32';'met5.option2 : 72/33';'met5.option3 : 72/34';'met5.option4 : 72/35';'met5.option5 : 72/36';'met5.option6 : 72/37';'met5.option7 : 72/38';'met5.option8 : 72/39';'met5.pin : 72/16';'met5.probe : 72/25';'met5.psa1 : 72/88';'met5.psa2 : 72/89';'met5.psa3 : 72/90';'met5.psa4 : 72/91';'met5.psa5 : 72/92';'met5.psa6 : 72/93';'met5.res : 72/13';'met5.short : 72/15';'ncm.drawing : 92/44';'npc.drawing : 95/20';'npn.drawing : 82/20';'npn.label : 82/5';'nsdm.drawing : 93/44';'nsm.drawing : 61/20';'nwell.drawing : 64/20';'nwell.label : 64/5';'nwell.net : 84/23';'nwell.pin : 64/16';'overlap.boundary : 90/4';'overlap.drawing : 90/20';'pad.drawing : 76/20';'pad.label : 76/5';'pad.pin : 76/16';'padCenter.drawing : 81/20';'pmm2.drawing : 77/20';'pmm.drawing : 85/44';'pnp.drawing : 82/44';'pnp.label : 82/59';'poly.boundary : 66/4';'poly.cut : 66/14';'poly.drawing : 66/20';'poly.gate : 66/9';'poly.label : 66/5';'poly.model : 66/83';'poly.net : 66/23';'poly.pin : 66/16';'poly.probe : 66/25';'poly.res : 66/13';'poly.short : 66/15';'prBoundary.boundary : 235/4';'prBoundary.drawing : 235/0';'prune.drawing : 84/44';'psdm.drawing : 94/20';'pwell.cut : 64/14';'pwell.drawing : 64/44';'pwell.label : 64/59';'pwell.pin : 122/16';'pwell.res : 64/13';'pwelliso.label : 44/5';'pwelliso.pin : 44/16';'rdl.cut : 74/14';'rdl.drawing : 74/20';'rdl.label : 74/5';'rdl.option1 : 89/32';'rdl.option2 : 89/33';'rdl.option3 : 89/34';'rdl.option4 : 89/35';'rdl.option5 : 89/36';'rdl.option6 : 89/37';'rdl.option7 : 89/38';'rdl.option8 : 89/39';'rdl.pin : 74/16';'rdl.psa1 : 74/88';'rdl.psa2 : 74/89';'rdl.psa3 : 74/90';'rdl.psa4 : 74/91';'rdl.psa5 : 74/92';'rdl.psa6 : 74/93';'rdl.res : 74/13';'rdl.short : 74/15';'rpm.drawing : 86/20';'rrpm.drawing : 102/20';'tap.boundary : 65/60';'tap.drawing : 65/44';'tap.label : 65/5';'tap.net : 65/41';'tap.pin : 65/48';'target.drawing : 76/44';'text.drawing : 83/44';'tunm.drawing : 80/20';'ubm.drawing : 127/21';'vhvi.drawing : 74/21';'via2.boundary : 69/60';'via2.drawing : 69/44';'via2.net : 69/41';'via2.pin : 69/58';'via3.boundary : 70/60';'via3.drawing : 70/44';'via3.net : 70/41';'via3.pin : 70/48';'via4.boundary : 71/60';'via4.drawing : 71/44';'via4.net : 71/41';'via4.pin : 71/48';'via.boundary : 68/60';'via.drawing : 68/44';'via.net : 68/41';'via.pin : 68/58') + 0.005 + true + #1 + true + #1 + false + #1 + true + OUTLINE + true + PLACEMENT_BLK + true + REGIONS + true + .drawing + 0 + true + .pin + 2 + true + .blockage + 3 + true + .blockage + 4 + true + .label + 1 + true + .drawing + 0 + + + 0.005 + 1 + 100 + 100 + 0 + 0 + 0 + false + false + false + true + layer_map() + + + 0 + 0.005 + layer_map() + true + false + + + 1 + 0.005 + layer_map() + true + false + true + + + + + + + true + false + false + false + false + 8000 + 32000 + LIB + + + 2 + false + false + 1 + * + false + + + 0 + + + false + false + + + 0 + + true + + + + li1,67/44,met1 + met1,68/44,met2 + met2,69/44,met3 + met3,70/44,met4 + met4,71/44,met5 + li1='67/20+67/5+67/16' + met1='68/20+68/5+68/16' + met2='69/20+69/5+69/16' + met3='70/20+70/5+70/16' + met4='71/20+71/5+71/16' + met5='72/20-72/15+72/5+72/16' + + diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A_mr.drc b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A_mr.drc new file mode 100755 index 00000000..e9a03fc8 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A_mr.drc @@ -0,0 +1,580 @@ +# DRC for SKY130 according to : +# https://skywater-pdk.readthedocs.io/en/latest/rules/periphery.html +# https://skywater-pdk.readthedocs.io/en/latest/rules/layers.html +# +# Distributed under GNU GPLv3: https://www.gnu.org/licenses/ +# +# History : +# 2020-10-04 : v1.0 : initial release +# +########################################################################################## + +# optionnal for a batch launch : klayout -b -rd input=my_layout.gds -rd report=sky130_drc.txt -r drc_sky130.drc +if $input + source($input, $top_cell) +end + +if $report + report("SKY130 DRC runset", $report) +else + report("SKY130 DRC runset", File.join(File.dirname(RBA::CellView::active.filename), "sky130_drc.txt")) +end + +AL = true # do not change +CU = false # do not change +# choose betwen only one of AL or CU back-end flow here : +backend_flow = AL + +# enable / disable rule groups +if $feol + FEOL = true # front-end-of-line checks +else + FEOL = false # front-end-of-line checks +end +if $beol + BEOL = true # back-end-of-line checks +else + BEOL = false # back-end-of-line checks +end +if $offgrid + OFFGRID = true # manufacturing grid/angle checks +else + OFFGRID = false # manufacturing grid/angle checks +end + +# klayout setup +######################## +# use a tile size of 1mm - not used in deep mode- +# tiles(1000.um) +# use a tile border of 10 micron: +# tile_borders(1.um) +#no_borders + +# hierachical +deep + +if $thr + threads($thr) +else + threads(4) +end + +# if more inof is needed, set true +# verbose(true) +verbose(true) + +# layers definitions +######################## + +# all except purpose (datatype) 5 -- label and 44 -- via +li_wildcard = "67/20" +mcon_wildcard = "67/44" + +m1_wildcard = "68/20" +via_wildcard = "68/44" + +m2_wildcard = "69/20" +via2_wildcard = "69/44" + +m3_wildcard = "70/20" +via3_wildcard = "70/44" + +m4_wildcard = "71/20" +via4_wildcard = "71/44" + +m5_wildcard = "72/20" + +diff = input(65, 20) +tap = polygons(65, 44) +nwell = polygons(64, 20) +dnwell = polygons(64, 18) +pwbm = polygons(19, 44) +pwde = polygons(124, 20) +natfet = polygons(124, 21) +hvtr = polygons(18, 20) +hvtp = polygons(78, 44) +ldntm = polygons(11, 44) +hvi = polygons(75, 20) +tunm = polygons(80, 20) +lvtn = polygons(125, 44) +poly = polygons(66, 20) +hvntm = polygons(125, 20) +nsdm = polygons(93, 44) +psdm = polygons(94, 20) +rpm = polygons(86, 20) +urpm = polygons(79, 20) +npc = polygons(95, 20) +licon = polygons(66, 44) + +li = polygons(li_wildcard) +mcon = polygons(mcon_wildcard) + +m1 = polygons(m1_wildcard) +via = polygons(via_wildcard) + +m2 = polygons(m2_wildcard) +via2 = polygons(via2_wildcard) + +m3 = polygons(m3_wildcard) +via3 = polygons(via3_wildcard) + +m4 = polygons(m4_wildcard) +via4 = polygons(via4_wildcard) + +m5 = polygons(m5_wildcard) + +pad = polygons(76, 20) +nsm = polygons(61, 20) +capm = polygons(89, 44) +cap2m = polygons(97, 44) +vhvi = polygons(74, 21) +uhvi = polygons(74, 22) +npn = polygons(82, 20) +inductor = polygons(82, 24) +vpp = polygons(82, 64) +pnp = polygons(82, 44) +lvs_prune = polygons(84, 44) +ncm = polygons(92, 44) +padcenter = polygons(81, 20) +mf = polygons(76, 44) +areaid_sl = polygons(81, 1) +areaid_ce = polygons(81, 2) +areaid_fe = polygons(81, 3) +areaid_sc = polygons(81, 4) +areaid_sf = polygons(81, 6) +areaid_sw = polygons(81, 7) +areaid_sr = polygons(81, 8) +areaid_mt = polygons(81, 10) +areaid_dt = polygons(81, 11) +areaid_ft = polygons(81, 12) +areaid_ww = polygons(81, 13) +areaid_ld = polygons(81, 14) +areaid_ns = polygons(81, 15) +areaid_ij = polygons(81, 17) +areaid_zr = polygons(81, 18) +areaid_ed = polygons(81, 19) +areaid_de = polygons(81, 23) +areaid_rd = polygons(81, 24) +areaid_dn = polygons(81, 50) +areaid_cr = polygons(81, 51) +areaid_cd = polygons(81, 52) +areaid_st = polygons(81, 53) +areaid_op = polygons(81, 54) +areaid_en = polygons(81, 57) +areaid_en20 = polygons(81, 58) +areaid_le = polygons(81, 60) +areaid_hl = polygons(81, 63) +areaid_sd = polygons(81, 70) +areaid_po = polygons(81, 81) +areaid_it = polygons(81, 84) +areaid_et = polygons(81, 101) +areaid_lvt = polygons(81, 108) +areaid_re = polygons(81, 125) +areaid_ag = polygons(81, 79) +poly_rs = polygons(66, 13) +diff_rs = polygons(65, 13) +pwell_rs = polygons(64, 13) +li_rs = polygons(67, 13) +cfom = polygons(22, 20) + + +# Define a new custom function that selects polygons by their number of holes: +# It will return a new layer containing those polygons with min to max holes. +# max can be nil to omit the upper limit. +class DRC::DRCLayer + def with_holes(min, max) + new_data = RBA::Region::new + self.data.each do |p| + if p.holes >= (min || 0) && (!max || p.holes <= max) + new_data.insert(p) + end + end + DRC::DRCLayer::new(@engine, new_data) + end +end + +# DRC section +######################## +log("DRC section") + +if FEOL +log("FEOL section") +gate = diff & poly + +# dnwell +log("dnwell") +dnwell.width(3.0, euclidian).output("dnwell.2", "dnwell.2 : min. dnwell width : 3.0um") + + +# nwell +log("nwell") +nwell.width(0.84, euclidian).output("nwell.1", "nwell.1 : min. nwell width : 0.84um") +nwell.isolated(1.27, euclidian).output("nwell.2a", "nwell.2a : min. nwell spacing (merged if less) : 1.27um") + +# hvtp +log("hvtp") +hvtp.width(0.38, euclidian).output("hvtp.1", "hvtp.1 : min. hvtp width : 0.38um") +hvtp.isolated(0.38, euclidian).output("hvtp.2", "hvtp.2 : min. hvtp spacing : 0.38um") + +# hvtr +log("htvr") +hvtr.width(0.38, euclidian).output("hvtr.1", "hvtr.1 : min. hvtr width : 0.38um") +hvtr.isolated(0.38, euclidian).output("hvtr.2", "hvtr.2 : min. hvtr spacing : 0.38um") +hvtr.and(hvtp).output("hvtr.2_a", "hvtr.2_a : hvtr must not overlap hvtp") + +# lvtn +log("lvtn") +lvtn.width(0.38, euclidian).output("lvtn.1a", "lvtn.1a : min. lvtn width : 0.38um") +lvtn.isolated(0.38, euclidian).output("lvtn.2", "lvtn.2 : min. lvtn spacing : 0.38um") + +# ncm +log("ncm") +ncm.width(0.38, euclidian).output("ncm.1", "ncm.1 : min. ncm width : 0.38um") +ncm.isolated(0.38, euclidian).output("ncm.2a", "ncm.2a : min. ncm spacing : 0.38um") + +# diff-tap +log("diff-tap") +difftap = diff.or(tap) +diff_width = diff.rectangles.width(0.15, euclidian).polygons +diff_cross_areaid_ce = diff_width.edges.outside_part(areaid_ce).not(diff_width.outside(areaid_ce).edges) +diff_cross_areaid_ce.output("difftap.1", "difftap.1 : min. diff width across areaid:ce : 0.15um") + +diff.outside(areaid_ce).width(0.15, euclidian).output("difftap.1_a", "difftap.1_a : min. diff width in periphery : 0.15um") + +tap_width = tap.rectangles.width(0.15, euclidian).polygons +tap_cross_areaid_ce = tap_width.edges.outside_part(areaid_ce).not(tap_width.outside(areaid_ce).edges) +tap_cross_areaid_ce.output("difftap.1_b", "difftap.1_b : min. tap width across areaid:ce : 0.15um") + +tap.outside(areaid_ce).width(0.15, euclidian).output("difftap.1_c", "difftap.1_c : min. tap width in periphery : 0.15um") + +difftap.space(0.27, euclidian).output("difftap.3", "difftap.3 : min. difftap spacing : 0.27um") + +# tunm +log("tunm") +tunm.width(0.41, euclidian).output("tunm.1", "tunm.1 : min. tunm width : 0.41um") +tunm.space(0.5, euclidian).output("tunm.2", "tunm.2 : min. tunm spacing : 0.5um") + +# poly +log("poly") +poly.width(0.15, euclidian).output("poly.1a", "poly.1a : min. poly width : 0.15um") + +# updated for sram - jeffdi +#poly.isolated(0.21, euclidian).output("poly.2", "poly.2 : min. poly spacing : 0.21um") +poly.not(areaid_ce).space(0.21, euclidian).output("poly.2", "poly.2 : min. poly spacing : 0.21um") + + +# rpm +log("rpm") +rpm.width(1.27, euclidian).output("rpm.1a", "rpm.1a : min. rpm width : 1.27um") +rpm.isolated(0.84, euclidian).output("rpm.2", "rpm.2 : min. rpm spacing : 0.84um") + +# urpm +log("urpm") +urpm.width(1.27, euclidian).output("urpm.1a", "urpm.1a : min. rpm width : 1.27um") +urpm.isolated(0.84, euclidian).output("urpm.2", "urpm.2 : min. rpm spacing : 0.84um") + +# npc +log("npc") +npc.width(0.27, euclidian).output("npc.1", "npc.1 : min. npc width : 0.27um") +npc.space(0.27, euclidian).output("npc.2", "npc.2 : min. npc spacing, should be mnually merge if less : 0.27um") + +# licon +log("licon") +xfom = difftap.not(poly) +licon1ToXfom = licon.interacting(licon.and(xfom)) +licon1ToXfom_PERI = licon1ToXfom.not(areaid_ce) + +licon.non_rectangles.output("licon.1", "licon.1 : licon should be rectangle") +licon.not(rpm.or(urpm)).edges.without_length(0.17).output("licon.1_a/b", "licon.1_a/b : minimum/maximum width of licon : 0.17um") +#licon.and(poly.interacting(poly_rs).and(rpm.or(urpm))).not_interacting((licon.and(poly.interacting(poly_rs).and(rpm)).edges.with_length(0.19)).or(licon.and(poly.interacting(poly_rs).and(rpm)).edges.with_length(2.0))).output("licon.1b/c", "licon.1b/c : minimum/maximum width/length of licon inside poly resistor : 2.0/0.19um") +#licon.and(diff_or_tap).separation(npc, 0.09, euclidian).output("licon.13", "licon.13 : min. difftap licon spacing to npc : 0.09um") +licon1ToXfom_PERI.separation(npc, 0.09, euclidian).output("licon.13", "licon.13 : min. difftap licon spacing to npc : 0.09um") +licon1ToXfom_PERI.and(npc).output("licon.13_a", "licon.13_a : licon of diffTap in periphery must not overlap npc") +licon.interacting(poly).and(licon.interacting(difftap)).output("licon.17", "licon.17 : Licons may not overlap both poly and (diff or tap)") + +# CAPM +log("capm") +m3_bot_plate = (capm.and(m3)).sized(0.14) +capm.width(1.0, euclidian).output("capm.1", "capm.1 : min. capm width : 1.0um") +capm.space(0.84, euclidian).output("capm.2a", "capm.2a : min. capm spacing : 0.84um") +m3.interacting(capm).isolated(1.2, euclidian).output("capm.2b", "capm.2b : min. capm spacing : 1.2um") +m3_bot_plate.isolated(1.2, euclidian).output("capm.2b_a", "capm.2b_a : min. spacing of m3_bot_plate : 1.2um") +capm.and(m3).enclosing(m3, 0.14, euclidian).output("capm.3", "capm.3 : min. capm and m3 enclosure of m3 : 0.14um") +m3.enclosing(capm, 0.14, euclidian).output("capm.3_a", "capm.3_a : min. m3 enclosure of capm : 0.14um") +capm.enclosing(via3, 0.14, euclidian).output("capm.4", "capm.4 : min. capm enclosure of via3 : 0.14um") +capm.separation(via3, 0.14, euclidian).output("capm.5", "capm.5 : min. capm spacing to via3 : 0.14um") + +# CAP2M +log("cap2m") +m4_bot_plate = (cap2m.and(m4)).sized(0.14) +cap2m.width(1.0, euclidian).output("cap2m.1", "cap2m.1 : min. cap2m width : 1.0um") +cap2m.isolated(0.84, euclidian).output("cap2m.2a", "cap2m.2a : min. cap2m spacing : 0.84um") +m4.interacting(cap2m).isolated(1.2, euclidian).output("cap2m.2b", "cap2m.2b : min. cap2m spacing : 1.2um") +# This rule has false positive errors +m4_bot_plate.isolated(1.2, euclidian).output("cap2m.2b_a", "cap2m.2b_a : min. spacing of m4_bot_plate : 1.2um") +cap2m.and(m4).enclosing(m4, 0.14, euclidian).output("cap2m.3", "cap2m.3 : min. m4 enclosure of cap2m : 0.14um") +cap2m.enclosing(via4, 0.2, euclidian).output("cap2m.4", "cap2m.4 : min. cap2m enclosure of via4 : 0.14um") +cap2m.separation(via4, 0.2, euclidian).output("cap2m.5", "cap2m.5 : min. cap2m spacing to via4 : 0.14um") + +end #FEOL + +if BEOL +log("BEOL section") + +# li +log("li") + +# currently-unused: + +# update for sram - jeffdi +linotace = li.not(areaid_ce) +linotace.width(0.17, euclidian).output("li.1", "li.1 : min. li width : 0.17um") + +# updated for sram - jeffdi +linotace.space(0.17, euclidian).output("li.3", "li.3 : min. li spacing : 0.17um") + +licon_peri = licon.not(areaid_ce) +li_edges_with_less_enclosure = li.enclosing(licon_peri, 0.08, not_opposite, projection).second_edges +error_corners = li_edges_with_less_enclosure.width(angle_limit(100.0), 1.dbu) +li_interact = licon_peri.interacting(error_corners.polygons(1.dbu)) +li_interact.output("li.5", "li.5 : min. li enclosure of licon of 2 opposite edges : 0.08um") + +li.with_area(0..0.0561).output("li.6", "li.6 : min. li area : 0.0561um²") + +# ct +log("mcon") +mconnotace = mcon.not(areaid_ce) + +mconnotace.edges.without_length(0.17).output("ct.1", "ct.1 : minimum/maximum width of mcon : 0.17um") + +mcon.space(0.19, euclidian).output("ct.2", "ct.2 : min. mcon spacing : 0.19um") + +#updated for sram - jeffdi +mconnotace.not(li).output("ct.4", "ct.4 : mcon should covered by li") + +# m1 +log("m1") +m1.width(0.14, euclidian).output("m1.1", "m1.1 : min. m1 width : 0.14um") + +huge_m1 = m1.sized(-1.5).sized(1.5).snap(0.005) & m1 +non_huge_m1 = m1.edges - huge_m1 +huge_m1 = huge_m1.edges.outside_part(m1.merged) + +non_huge_m1.space(0.14, euclidian).output("m1.2", "m1.2 : min. m1 spacing : 0.14um") + +(huge_m1.separation(non_huge_m1, 0.28, euclidian) + huge_m1.space(0.28, euclidian)).output("m1.3ab", "m1.3ab : min. 3um.m1 spacing m1 : 0.28um") + +not_in_cell6 = layout(source.cell_obj).select("-s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b", "-s8fpls_pl8", "-s8fs_cmux4_fm") +not_in_cell6_m1 = not_in_cell6.input(m1_wildcard) + + + +#updated for sram - jeffdi +not_in_cell6_m1.enclosing(mconnotace, 0.03, euclidian).output("791_m1.4", "791_m1.4 : min. m1 enclosure of mcon : 0.03um") +mconnotace.not(m1).output("m1.4", "m1.4 : mcon periphery must be enclosed by m1") +in_cell6 = layout(source.cell_obj).select("+s8cell_ee_plus_sseln_a", "+s8cell_ee_plus_sseln_b", "+s8cell_ee_plus_sselp_a", "+s8cell_ee_plus_sselp_b", "+s8fpls_pl8", "+s8fs_cmux4_fm") +in_cell6_m1 = in_cell6.input(m1_wildcard) +in_cell6_m1.enclosing(mcon, 0.005, euclidian).output("m1.4a", "m1.4a : min. m1 enclosure of mcon for specific cells : 0.005um") + +m1.with_area(0..0.083).output("m1.6", "m1.6 : min. m1 area : 0.083um²") + +m1.holes.with_area(0..0.14).output("m1.7", "m1.7 : min. m1 with holes area : 0.14um²") + +if backend_flow = AL + mcon06 = mcon.interacting(poly.enclosing(m1, 0.06, euclidian).polygons) + mcon_edges_with_less_enclosure_m1 = m1.enclosing(mcon, 0.06, projection).second_edges + opposite4 = (mcon.edges - mcon_edges_with_less_enclosure_m1).width(0.17 + 1.dbu, projection).polygons + mcon06.not_interacting(opposite4).output("m1.5", "m1.5 : min. m1 enclosure of mcon of 2 opposite edges : 0.06um") +end +# via +log("via") +if backend_flow = AL + ringVIA = via.drc(with_holes > 0) + rectVIA = via.not(ringVIA) + via_not_mt = rectVIA.not(areaid_mt) + + via_not_mt.non_rectangles.output("via.1a", "via.1a : via outside of moduleCut should be rectangular") + via_not_mt.width(0.15, euclidian).output("via.1a_a", "via.1a_a : min. width of via outside of moduleCut : 0.15um") + via_not_mt.edges.without_length(nil, 0.15 + 1.dbu).output("via.1a_b", "via.1a_b : maximum length of via : 0.15um") + + via.space(0.17, euclidian).output("via.2", "via.2 : min. via spacing : 0.17um") + + ringVIA.width(0.2, euclidian).output("via.3", "via.3 : min. width of ring-shaped via : 0.2um") + ringVIA.drc(width >= 0.205).output("via.3", "via.3 : max. width of ring-shaped via : 0.205um") + + ringVIA.not(areaid_sl).output("via.3_b", "via.3_b: ring-shaped via must be enclosed by areaid_sl") + + m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.055, euclidian).output("via.4a", "via.4a : min. m1 enclosure of 0.15um via : 0.055um") + via.squares.edges.with_length(0.15).not(m1).output("via.4a_a", "via.4a_a : via must be enclosed by met1") + + via1_edges_with_less_enclosure_m1 = m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.085, projection).second_edges + opposite5 = (via.not_interacting(via.edges.without_length(0.15)).edges - via1_edges_with_less_enclosure_m1).width(0.15 + 1.dbu, projection).polygons + via.not_interacting(via.edges.without_length(0.15)).not_interacting(opposite5).output("via.5a", "via.5a : min. m1 enclosure of 0.15um via of 2 opposite edges : 0.085um") +end + +# m2 +log("m2") +m2.width(0.14, euclidian).output("m2.1", "m2.1 : min. m2 width : 0.14um") + +huge_m2 = m2.sized(-1.5).sized(1.5).snap(0.005) & m2 +non_huge_m2 = m2.edges - huge_m2 +huge_m2 = huge_m2.edges.outside_part(m2.merged) +via_outside_periphery = via.not(areaid_ce) + +non_huge_m2.space(0.14, euclidian).output("m2.2", "m2.2 : min. m2 spacing : 0.14um") + +(huge_m2.separation(non_huge_m2, 0.28, euclidian) + huge_m2.space(0.28, euclidian)).output("m2.3ab", "m2.3ab : min. 3um.m2 spacing m2 : 0.28um") + +# rule m2.3c not coded +m2.with_area(0..0.0676).output("m2.6", "m2.6 : min. m2 area : 0.0676um²") +m2.holes.with_area(0..0.14).output("m2.7", "m2.7 : min. m2 holes area : 0.14um²") + +if backend_flow = AL + m2.enclosing(via, 0.055, euclidian).output("m2.4", "m2.4 : min. m2 enclosure of via : 0.055um") + + via_outside_periphery.not(m2).output("m2.4_a", "m2.4_a : via in periphery must be enclosed by met2") + + + via_edges_with_less_enclosure_m2 = m2.enclosing(via, 0.085, projection).second_edges + error_corners = via_edges_with_less_enclosure_m2.width(angle_limit(100.0), 1.dbu) + via_interact = via.interacting(error_corners.polygons(1.dbu)) + via_interact.output("m2.5", "m2.5 : min. m2 enclosure of via of 2 opposite edges : 0.085um") + + #via_edges_with_less_enclosure_m2 = m2.enclosing(via, 0.085, projection).second_edges + #opposite7 = (via.edges - via_edges_with_less_enclosure_m2).width(0.2 + 1.dbu, projection).polygons + #via.not_interacting(opposite7).output("m2.5", "m2.5 : min. m2 enclosure of via of 2 opposite edges : 0.085um") +end + +# via2 +log("via2") +if backend_flow = AL + ringVIA2 = via2.drc(with_holes > 0) + rectVIA2 = via2.not(ringVIA2) + via2_not_mt = rectVIA2.not(areaid_mt) + via2_not_mt.non_rectangles.output("via2.1a", "via2.1a : via2 outside of moduleCut should be rectangular") + via2_not_mt.width(0.2, euclidian).output("via2.1a_a", "via2.1a_a : min. width of via2 outside of moduleCut : 0.2um") + via2_not_mt.edges.without_length(nil, 0.2 + 1.dbu).output("via2.1a_b", "via2.1a_b : maximum length of via2 : 0.2um") + #via2.not(areaid_mt).edges.without_length(0.2).output("via2.1a", "via2.1a : minimum/maximum width of via2 : 0.2um") + via2.space(0.2, euclidian).output("via2.2", "via2.2 : min. via2 spacing : 0.2um") + ringVIA2.width(0.2, euclidian).output("via2.3", "via2.3 : min. width of ring-shaped via2 : 0.2um") + ringVIA2.drc(width >= 0.205).output("via2.3", "via2.3 : max. width of ring-shaped via2 : 0.205um") + ringVIA2.not(areaid_sl).output("via2.3_b", "via2.3_b: ring-shaped via2 must be enclosed by areaid_sl") + m2.enclosing(via2, 0.04, euclidian).output("via2.4", "via2.4 : min. m2 enclosure of via2 : 0.04um") + #m2.enclosing(via2.not_interacting(via2.edges.without_length(1.5)), 0.14, euclidian).output("via2.4a", "via2.4a : min. m2 enclosure of 1.5um via2 : 0.14um") + via2.not(m2).output("via2.4_a", "via2.4_a : via must be enclosed by met2") + + via2_edges_with_less_enclosure = m2.enclosing(via2, 0.085, projection).second_edges + error_corners = via2_edges_with_less_enclosure.width(angle_limit(100.0), 1.dbu) + via2_interact = via2.interacting(error_corners.polygons(1.dbu)) + via2_interact.output("via2.5", "via2.5 : min. m3 enclosure of via2 of 2 opposite edges : 0.085um") +end + +# m3 +log("m3") +m3.width(0.3, euclidian).output("m3.1", "m3.1 : min. m3 width : 0.3um") + +huge_m3 = m3.sized(-1.5).sized(1.5).snap(0.005) & m3 +non_huge_m3 = m3.edges - huge_m2 +huge_m3 = huge_m3.edges.outside_part(m3.merged) + +non_huge_m3.space(0.3, euclidian).output("m3.2", "m3.2 : min. m3 spacing : 0.3um") + +(huge_m3.separation(non_huge_m3, 0.4, euclidian) + huge_m3.space(0.4, euclidian)).output("m3.3cd", "m3.3cd : min. 3um.m3 spacing m3 : 0.4um") + +if backend_flow = AL + m3.enclosing(via2, 0.065, euclidian).output("m3.4", "m3.4 : min. m3 enclosure of via2 : 0.065um") + via2.not(m3).output("m3.4_a", "m3.4_a : via2 must be enclosed by met3") +end + +# via3 +log("via3") +if backend_flow = AL + + ringVIA3 = via3.drc(with_holes > 0) + rectVIA3 = via3.not(ringVIA3) + via3_not_mt = rectVIA3.not(areaid_mt) + via3_not_mt.non_rectangles.output("via3.1", "via3.1 : via3 outside of moduleCut should be rectangular") + via3_not_mt.width(0.2, euclidian).output("via3.1_a", "via3.1_a : min. width of via3 outside of moduleCut : 0.2um") + via3_not_mt.edges.without_length(nil, 0.2 + 1.dbu).output("via3.1_b", "via3.1_b : maximum length of via3 : 0.2um") + + #via3.not(areaid_mt).edges.without_length(0.2).output("via3.1a", "via3.1a : minimum/maximum width of via3 : 0.2um") + via3.space(0.2, euclidian).output("via3.2", "via3.2 : min. via3 spacing : 0.2um") + m3.enclosing(via3, 0.06, euclidian).output("via3.4", "via3.4 : min. m3 enclosure of via3 : 0.06um") + rectVIA3.not(m3).output("via3.4_a", "via3.4_a : non-ring via3 must be enclosed by met3") + + via_edges_with_less_enclosure = m3.enclosing(via3, 0.09, projection).second_edges + error_corners = via_edges_with_less_enclosure.width(angle_limit(100.0), 1.dbu) + via3_interact = via3.interacting(error_corners.polygons(1.dbu)) + via3_interact.output("via3.5", "via3.5 : min. m3 enclosure of via3 of 2 opposite edges : 0.09um") +end + +# m4 +log("m4") +m4.width(0.3, euclidian).output("m4.1", "m4.1 : min. m4 width : 0.3um") + +huge_m4 = m4.sized(-1.5).sized(1.5).snap(0.005) & m4 +non_huge_m4 = m4.edges - huge_m4 +huge_m4 = huge_m4.edges.outside_part(m4.merged) + +non_huge_m4.space(0.3, euclidian).output("m4.2", "m4.2 : min. m4 spacing : 0.3um") + +m4.with_area(0..0.240).output("m4.4a", "m4.4a : min. m4 area : 0.240um²") + +(huge_m4.separation(non_huge_m4, 0.4, euclidian) + huge_m4.space(0.4, euclidian)).output("m4.5ab", "m4.5ab : min. 3um.m4 spacing m4 : 0.4um") + +if backend_flow = AL + m4.enclosing(via3, 0.065, euclidian).output("m4.3", "m4.3 : min. m4 enclosure of via3 : 0.065um") + via3.not(m4).output("m4.3_a", "m4.3_a : via3 must be enclosed by met4") +end + +# via4 +log("via4") +ringVIA4 = via4.drc(with_holes > 0) +rectVIA4 = via4.not(ringVIA4) +via4_not_mt = rectVIA4.not(areaid_mt) +via4_not_mt.non_rectangles.output("via4.1", "via4.1 : via4 outside of moduleCut should be rectangular") +via4_not_mt.width(0.8, euclidian).output("via4.1_a", "via4.1_a : min. width of via4 outside of moduleCut : 0.8um") +via4_not_mt.edges.without_length(nil, 0.8 + 1.dbu).output("via4.1_b", "via4.1_b : maximum length of via4 : 0.8um") + +#via4.edges.without_length(0.8).output("via4.1", "via4.1 : minimum/maximum width of via4 : 0.8um") +via4.space(0.8, euclidian).output("via4.2", "via4.2 : min. via4 spacing : 0.8um") +ringVIA4.width(0.2, euclidian).output("via4.3", "via4.3 : min. width of ring-shaped via4 : 0.2um") +ringVIA4.drc(width >= 0.205).output("via4.3", "via4.3 : max. width of ring-shaped via4 : 0.205um") +ringVIA4.not(areaid_sl).output("via4.3_b", "via4.3_b: ring-shaped via4 must be enclosed by areaid_sl") +m4.enclosing(via4, 0.19, euclidian).output("via4.4", "via4.4 : min. m4 enclosure of via4 : 0.19um") +rectVIA4.not(m4).output("via4.4_a", "via4.4_a : m4 must enclose all via4") + +# m5 +log("m5") +m5.width(1.6, euclidian).output("m5.1", "m5.1 : min. m5 width : 1.6um") + +m5.space(1.6, euclidian).output("m5.2", "m5.2 : min. m5 spacing : 1.6um") + +# via4.not(m5).output("m5.via4", "m5.via4 : m5 must enclose via4") +m5.enclosing(via4, 0.31, euclidian).output("m5.3", "m5.3 : min. m5 enclosure of via4 : 0.31um") +via4.not(m5).output("m5.3_a", "m5.3_a : min. m5 enclosure of via4 : 0.31um") + +m5.with_area(0..4.0).output("m5.4", "m5.4 : min. m5 area : 4.0um²") + +# pad +log("pad") +pad.isolated(1.27, euclidian).output("pad.2", "pad.2 : min. pad spacing : 1.27um") + +end #BEOL + +if FEOL +log("FEOL section") + +# hvi +log("hvi") +hvi_peri = hvi.not(areaid_ce) +hvi_peri.width(0.6, euclidian).output("hvi.1", "hvi.1 : min. hvi width : 0.6um") +hvi_peri.isolated(0.7, euclidian).output("hvi.2a", "hvi.2a : min. hvi spacing : 0.7um") + +# hvntm +log("hvntm") +hvntm_peri = hvntm.not(areaid_ce) +hvntm_peri.width(0.7, euclidian).output("hvntm.1", "hvntm.1 : min. hvntm width : 0.7um") +hvntm_peri.space(0.7, euclidian).output("hvntm.2", "hvntm.2 : min. hvntm spacing : 0.7um") + +end #FEOL diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A_mr.lydrc b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A_mr.lydrc new file mode 100755 index 00000000..c24c65eb --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A_mr.lydrc @@ -0,0 +1,995 @@ + + + + + drc + + + + false + false + + true + drc_scripts + tools_menu.drc.end + dsl + drc-dsl-xml + # +# DRC for SKY130 according to : +# https://skywater-pdk.readthedocs.io/en/latest/rules/periphery.html +# https://skywater-pdk.readthedocs.io/en/latest/rules/layers.html +# +# Distributed under GNU GPLv3: https://www.gnu.org/licenses/ +# +# History : +# 2020-10-04 : v1.0 : initial release +# +########################################################################################## + +# optionnal for a batch launch : klayout -b -rd input=my_layout.gds -rd report=sky130_drc.txt -r drc_sky130.drc +if $input + source($input, $top_cell) +end + +if $report + report("SKY130 DRC runset", $report) +else + report("SKY130 DRC runset", File.join(File.dirname(RBA::CellView::active.filename), "sky130_drc.txt")) +end + +AL = true # do not change +CU = false # do not change +# choose betwen only one of AL or CU back-end flow here : +backend_flow = AL + +# enable / disable rule groups +if $feol + FEOL = true # front-end-of-line checks +else + FEOL = false # front-end-of-line checks +end +if $beol + BEOL = true # back-end-of-line checks +else + BEOL = false # back-end-of-line checks +end +if $offgrid + OFFGRID = true # manufacturing grid/angle checks +else + OFFGRID = false # manufacturing grid/angle checks +end + +# klayout setup +######################## +# use a tile size of 1mm - not used in deep mode- +tiles(1000.um) +# use a tile border of 10 micron: +tile_borders(1.um) +#no_borders + +# hierachical +deep + +if $thr + threads($thr) +else + threads(4) +end + +# if more inof is needed, set true +# verbose(true) +verbose(true) + +# layers definitions +######################## + +# all except purpose (datatype) 5 -- label and 44 -- via +li_wildcard = "67/20" +mcon_wildcard = "67/44" + +m1_wildcard = "68/20" +via_wildcard = "68/44" + +m2_wildcard = "69/20" +via2_wildcard = "69/44" + +m3_wildcard = "70/20" +via3_wildcard = "70/44" + +m4_wildcard = "71/20" +via4_wildcard = "71/44" + +m5_wildcard = "72/20" + +diff = input(65, 20) +tap = polygons(65, 44) +nwell = polygons(64, 20) +dnwell = polygons(64, 18) +pwbm = polygons(19, 44) +pwde = polygons(124, 20) +natfet = polygons(124, 21) +hvtr = polygons(18, 20) +hvtp = polygons(78, 44) +ldntm = polygons(11, 44) +hvi = polygons(75, 20) +tunm = polygons(80, 20) +lvtn = polygons(125, 44) +poly = polygons(66, 20) +hvntm = polygons(125, 20) +nsdm = polygons(93, 44) +psdm = polygons(94, 20) +rpm = polygons(86, 20) +urpm = polygons(79, 20) +npc = polygons(95, 20) +licon = polygons(66, 44) + +li = polygons(li_wildcard) +mcon = polygons(mcon_wildcard) + +m1 = polygons(m1_wildcard) +via = polygons(via_wildcard) + +m2 = polygons(m2_wildcard) +via2 = polygons(via2_wildcard) + +m3 = polygons(m3_wildcard) +via3 = polygons(via3_wildcard) + +m4 = polygons(m4_wildcard) +via4 = polygons(via4_wildcard) + +m5 = polygons(m5_wildcard) + +pad = polygons(76, 20) +nsm = polygons(61, 20) +capm = polygons(89, 44) +cap2m = polygons(97, 44) +vhvi = polygons(74, 21) +uhvi = polygons(74, 22) +npn = polygons(82, 20) +inductor = polygons(82, 24) +vpp = polygons(82, 64) +pnp = polygons(82, 44) +lvs_prune = polygons(84, 44) +ncm = polygons(92, 44) +padcenter = polygons(81, 20) +mf = polygons(76, 44) +areaid_sl = polygons(81, 1) +areaid_ce = polygons(81, 2) +areaid_fe = polygons(81, 3) +areaid_sc = polygons(81, 4) +areaid_sf = polygons(81, 6) +areaid_sw = polygons(81, 7) +areaid_sr = polygons(81, 8) +areaid_mt = polygons(81, 10) +areaid_dt = polygons(81, 11) +areaid_ft = polygons(81, 12) +areaid_ww = polygons(81, 13) +areaid_ld = polygons(81, 14) +areaid_ns = polygons(81, 15) +areaid_ij = polygons(81, 17) +areaid_zr = polygons(81, 18) +areaid_ed = polygons(81, 19) +areaid_de = polygons(81, 23) +areaid_rd = polygons(81, 24) +areaid_dn = polygons(81, 50) +areaid_cr = polygons(81, 51) +areaid_cd = polygons(81, 52) +areaid_st = polygons(81, 53) +areaid_op = polygons(81, 54) +areaid_en = polygons(81, 57) +areaid_en20 = polygons(81, 58) +areaid_le = polygons(81, 60) +areaid_hl = polygons(81, 63) +areaid_sd = polygons(81, 70) +areaid_po = polygons(81, 81) +areaid_it = polygons(81, 84) +areaid_et = polygons(81, 101) +areaid_lvt = polygons(81, 108) +areaid_re = polygons(81, 125) +areaid_ag = polygons(81, 79) +poly_rs = polygons(66, 13) +diff_rs = polygons(65, 13) +pwell_rs = polygons(64, 13) +li_rs = polygons(67, 13) +cfom = polygons(22, 20) + + +# Define a new custom function that selects polygons by their number of holes: +# It will return a new layer containing those polygons with min to max holes. +# max can be nil to omit the upper limit. +class DRC::DRCLayer + def with_holes(min, max) + new_data = RBA::Region::new + self.data.each do |p| + if p.holes >= (min || 0) && (!max || p.holes <= max) + new_data.insert(p) + end + end + DRC::DRCLayer::new(@engine, new_data) + end +end + +# DRC section +######################## +log("DRC section") + +if FEOL +log("FEOL section") +gate = diff & poly + +# dnwell +log("dnwell") +dnwell.width(3.0, euclidian).output("dnwell.2", "dnwell.2 : min. dnwell width : 3.0um") +# dnwell.not(uhvi).not(areaid_po).isolated(6.3, euclidian).output("dnwell.3", "dnwell.3 : min. dnwell spacing : 6.3um") +# dnwell.and(pnp).output("dnwell.4", "dnwell.4 : dnwell must not overlap pnp") +# dnwell.and(psdm).edges.not(psdm.edges).output("dnwell.5", "p+ must not straddle dnwell") +# # dnwell.6 rue not coded + +# nwell +log("nwell") +nwell.width(0.84, euclidian).output("nwell.1", "nwell.1 : min. nwell width : 0.84um") +nwell.isolated(1.27, euclidian).output("nwell.2a", "nwell.2a : min. nwell spacing (merged if less) : 1.27um") +# rule nwell.4 is suitable for digital cells +#nwell.not(uhvi).not(areaid_en20).not_interacting(tap.and(licon).and(li)).output("nwell.4", "nwell4 : all nwell exempt inside uhvi must contain a n+tap") +# nwell.enclosing(dnwell.not(uhvi).not(areaid_po), 0.4, euclidian).output("nwell.5", "nwell.5 : min. nwell enclosing dnwell exempt unside uhvi : 0.4um") +# dnwell.enclosing(nwell.not(uhvi), 1.03, euclidian).output("nwell.6", "nwell.6 : min. dnwell enclosing nwell exempt unside uhvi : 1.03um") +# dnwell.separation(nwell, 4.5, euclidian).output("nwell.7", "nwell.7 : min. dnwell separation nwell : 4.5um") + +# pwbm +# pwbm.not(uhvi).output("pwbm", "pwbm must be inside uhvi") +# dnwell.and(uhvi).edges.not(pwbm).output("pwbm.4", "pwbm.4 : dnwell inside uhvi must be enclosed by pwbm") + +# pwde +# pwde.not(pwbm).output("pwdem.3", "pwdem.3 : pwde must be inside pwbm") +# pwde.not(uhvi).output("pwdem.4", "pwdem.4 : pwde must be inside uhvi") +# pwde.not(dnwell).output("pwdem.5", "pwdem.5 : pwde must be inside dnwell") + +# hvtp +log("hvtp") +#hvtp.not(nwell).output("hvtp", "hvtp must inside nwell") +hvtp.width(0.38, euclidian).output("hvtp.1", "hvtp.1 : min. hvtp width : 0.38um") +hvtp.isolated(0.38, euclidian).output("hvtp.2", "hvtp.2 : min. hvtp spacing : 0.38um") +# hvtp.enclosing(gate.and(psdm), 0.18, euclidian).output("hvtp.3", "hvtp.3 : min. hvtp enclosure of pfet gate : 0.18um") +# hvtp.separation(gate.and(psdm), 0.18, euclidian).output("hvtp.4", "hvtp.4 : min. hvtp spacing pfet gate: 0.18um") +# hvtp.with_area(0..0.265).output("hvtp.5", "hvtp.5 : min. hvtp area : 0.265um²") + +# hvtr +log("htvr") +hvtr.width(0.38, euclidian).output("hvtr.1", "hvtr.1 : min. hvtr width : 0.38um") +hvtr.isolated(0.38, euclidian).output("hvtr.2", "hvtr.2 : min. hvtr spacing : 0.38um") + +# lvtn +log("lvtn") +# lvtn.width(0.38, euclidian).output("lvtn.1", "lvtn.1 : min. lvtn width : 0.38um") +lvtn.isolated(0.38, euclidian).output("lvtn.2", "lvtn.2 : min. lvtn spacing : 0.38um") +# lvtn.separation(diff.and(poly).not(uhvi), 0.18, euclidian).output("lvtn.3a", "lvtn.3a : min. lvtn spacing to gate : 0.18um") +# lvtn.separation(diff.and(nwell).not(poly), 0.235, projection).output("lvtn.3b", "lvtn.3b : min. lvtn spacing to pfet s/d : 0.18um") +# lvtn.enclosing(gate.not(uhvi), 0.18, euclidian).output("lvtn.4b", "lvtn.4b : min. lvtn enclosing to gate : 0.18um") +# lvtn.separation(hvtp, 0.38, euclidian).output("lvtn.9", "lvtn.9 : min. lvtn spacing hvtp : 0.38um") +# nwell.not_interacting(gate.and(nwell.not(hvi).not(areaid_ce))).enclosing(lvtn.not(uhvi), 0.18, euclidian).polygons.without_area(0).output("lvtn.4b", "lvtn.4b : min. lvtn enclosure of gate : 0.18um") +# lvtn.separation(nwell.inside(areaid_ce), 0.38, euclidian).output("lvtn.12", "lvtn.12 : min. lvtn spacing nwell inside areaid.ce : 0.38um") +# lvtn.with_area(0..0.265).output("lvtn.13", "lvtn.13 : min. lvtn area : 0.265um²") + +# ncm +log("ncm") +# ncm.and(tap.and(nwell).or(diff.not(nwell))).output("ncm.x.3", "ncm.x.3 : ncm must not overlap n+diff") +ncm.width(0.38, euclidian).output("ncm.1", "ncm.1 : min. ncm width : 0.38um") +# ncm.isolated(0.38, euclidian).output("ncm.2", "ncm.2 : min. ncm spacing manual merge if smaller : 0.38um") +# ncm.enclosing(diff.and(nwell), 0.18, euclidian).output("ncm.3", "ncm.3 : min. ncm enclosure of p+diff : 0.18um") +# ncm.separation(lvtn.and(diff), 0.23, euclidian).output("ncm.5", "ncm.5 : min. ncm spacing lvtn diff : 0.23um") +# ncm.separation(diff.not(nwell), 0.2, euclidian).output("ncm.6", "ncm.6 : min. ncm spacing nfet : 0.2um") +# ncm.with_area(0..0.265).output("ncm.7", "ncm.13 : min. ncm area : 0.265um²") + +# diff-tap +log("diff-tap") +difftap = diff + tap + +# TODO: this rule needs to be reviewed to address sram +# this rule appears to be incorrect - it is flagging errors not identified by the Calibre MR deck +# difftap.width(0.15, euclidian).output("difftap.1", "difftap.1 : min. difftap width : 0.15um") + +# not_in_cell1 = layout(source.cell_obj).select("s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b", "-s8fpls_pl8", "-s8fpls_rdrv4", "-s8fpls_rdrv4f", "-s8fpls_rdrv8") +# not_in_cell1_diff = not_in_cell1.input(65, 20) +# not_in_cell1_diff.not(areaid_sc).not(poly).edges.and(gate.edges).with_length(0,0.42).output("difftap.2", "difftap.2: min. gate (exempt areaid.sc) width : 0.42um") +# diff.and(areaid_sc).not(poly).edges.and(gate.edges).with_length(0,0.36).output("difftap.2", "difftap.2: min. gate inside areaid.sc width : 0.36um") +difftap.isolated(0.27, euclidian).output("difftap.3", "difftap.3 : min. difftap spacing : 0.27um") +# tap.edges.and(diff.edges).with_length(0,0.29).output("difftap.4", "difftap.4 : min. tap bound by diffusion : 0.29um") +# tap.edges.and(diff.edges).space(0.4, projection).output("difftap.5", "difftap.5 : min. tap bound by 2 diffusions : 0.4um") +# (tap.edges.and(diff.edges)).extended(0.01, 0.01, 0, 0, false).not(tap.and(diff)).and(diff.or(tap)).output("difftap.6", "difftap.6 : diff and tap not allowed to extend beyong their abutting ege") +# tap.edges.not_interacting(diff.edges).separation(diff.edges, 0.13, euclidian).output("difftap.7", "difftap.7 : min. diff/tap spacing to non-coincident diff edge : 0.13um") +# diff.edges.not_interacting(tap.edges).separation(tap.edges, 0.13, euclidian).output("difftap.7", "difftap.7 : min. diff/tap spacing to non-coincident tap edge : 0.13um") +# nwell.enclosing(diff.not(uhvi).and(psdm), 0.18, euclidian).output("difftap.8", "difftap.8 : min. p+diff enclosure by nwell : 0.18um") +# diff.not(uhvi).and(nsdm).separation(nwell, 0.34, euclidian).output("difftap.9", "difftap.9 : min. n+diff spacing to nwell : 0.34um") +# nwell.enclosing(tap.not(uhvi).and(nsdm), 0.18, euclidian).output("difftap.10", "difftap.10 : min. n+tap enclosure by nwell : 0.18um") +# tap.not(uhvi).and(psdm).separation(nwell, 0.13, euclidian).output("difftap.11", "difftap.11 : min. p+tap spacing to nwell : 0.13um") + +# tunm +log("tunm") +tunm.width(0.41, euclidian).output("tunm.1", "tunm.1 : min. tunm width : 0.41um") +tunm.isolated(0.5, euclidian).output("tunm.2", "tunm.2 : min. tunm spacing : 0.5um") +# tunm.enclosing(gate, 0.095, euclidian).output("tunm.3", "tunm.3 : min. tunm beyond gate : 0.095um") +# tunm.separation(gate.not_interacting(tunm), 0.095, euclidian).output("tunm.4", "tunm.4 : min. tunm spacing to gate outside tunm: 0.095um") +# gate.and(tunm).edges.not(gate.edges).output("tunm.5", "tunm.5 : gate must not straddle tunm") +# tunm.not(dnwell).output("tunm.6a", "tunm.6a : tunm not allowed outside dnwell") +# tunm.with_area(0..0.672).output("tunm.7", "tunm.7 : min. tunm area : 0.672um²") + +# poly +log("poly") +poly.width(0.15, euclidian).output("poly.1a", "poly.1a : min. poly width : 0.15um") +# poly.not(diff).edges.and(gate.and(lvtn).edges).space(0.35, euclidian).output("poly.1b", "poly.1b: min. lvtn gate width : 0.35um") + +# updated for sram - jeffdi +#poly.isolated(0.21, euclidian).output("poly.2", "poly.2 : min. poly spacing : 0.21um") +poly.not(areaid_ce).isolated(0.21, euclidian).output("poly.2", "poly.2 : min. poly spacing : 0.21um") + +# poly.and(rpm.or(urpm).or(poly_rs)).width(0.33, euclidian).output("poly.3", "poly.3 : min. poly resistor width : 0.33um") +# poly.not(gate).separation(diff, 0.075, projection).polygons.without_area(0).output("poly.4", "poly.4 : min. poly on field spacing to diff : 0.075um") +# poly.not(gate).separation(tap, 0.055, euclidian).output("poly.5", "poly.5 : min. poly on field spacing to tap : 0.055um") +# gate.separation(tap, 0.3, projection).polygons.and(diff).output("poly.6", "poly.6 : min. gate spacing to tap : 0.3um") +# diff.enclosing(gate, 0.25, projection).polygons.without_area(0).output("poly.7", "poly.7 : min. source/drain length : 0.25um") +# poly.enclosing(gate, 0.13, projection).polygons.without_area(0).output("poly.8", "poly.8 : min. poly extention gate (endcap) : 0.13um") +# poly.and(rpm.or(urpm).or(poly_rs)).separation(poly.or(difftap), 0.48, euclidian).polygons.without_area(0).output("poly.9", "poly.9 : min. poly resistor space to poly or diff/tap : 0.48um") +# diff.merged.edges.end_segments(0.01).and(poly).output("poly.10", "poly.10 : poly must not overlap diff corner") +# gate.with_angle(0 .. 90).output("poly.11", "poly.11 : non 90 degree angle gate") +# not_in_cell3 = layout(source.cell_obj).select("s8fgvr_n_fg2") +# not_in_cell3_poly = not_in_cell3.input(66, 20) +# not_in_cell3_poly.not(hvi).not(nwell.not(hvi)).and(tap).output("poly.12", "poly.12 : poly must not overlap tap") +# poly.and(diff_rs).output("poly.15", "poly.15 : poly must not overlap diff resistor") + +# rpm +log("rpm") +rpm.width(1.27, euclidian).output("rpm.1a", "rpm.1a : min. rpm width : 1.27um") +rpm.isolated(0.84, euclidian).output("rpm.2", "rpm.2 : min. rpm spacing : 0.84um") +# rpm.enclosing(poly.and(poly_rs).and(psdm), 0.2, euclidian).output("rpm.3", "rpm.3 : min. rpm enclosure of poly resistor : 0.2um") +# psdm.enclosing(poly.and(poly_rs).and(rpm), 0.11, euclidian).output("rpm.4", "rpm.4 : min. psdm enclosure of poly resistor : 0.11um") +# npc.enclosing(poly.and(poly_rs).and(rpm), 0.095, euclidian).output("rpm.5", "rpm.5 : min. npc enclosure of poly resistor : 0.095um") +# rpm.separation(nsdm, 0.2, euclidian).output("rpm.6", "rpm.6 : min. rpm spacing nsdm: 0.2um") +# rpm.separation(poly, 0.2, euclidian).output("rpm.7", "rpm.7 : min. rpm spacing poly: 0.2um") +# rpm.and(poly).edges.not(poly.edges).output("rpm.8", "rpm.8 : poly must not straddle rpm") +# poly.and(poly_rs).and(rpm).separation(hvntm, 0.185, euclidian).output("rpm.9", "rpm.9 : min. poly resistor spacing hvntm: 0.185um") +# rpm.and(pwbm).output("rpm.10", "rpm.107 : min. rpm spacing pwbm: na") + +# varac +# varac = poly & tap & (nwell - hvi) - areaid_ce +# tap.not(poly).edges.and(varac.edges).space(0.18, euclidian).output("varac.1", "varac.1: min. varac channel length : 0.18um") +# tap.and(poly).edges.and(varac.edges).space(1.0, euclidian).output("varac.2", "varac.2: min. varac channel wdth : 1.0um") +# varac.separation(hvtp, 0.18, euclidian).output("varac.3", "varac.3: min. varac channel space to hvtp : 0.18um") +# varac.separation(licon.and(tap), 0.25, euclidian).output("varac.4", "varac.4: min. varac channel space to licon on tap : 0.25um") +# nwell.enclosing(poly.overlapping(varac), 0.15, euclidian).output("varac.5", "varac.5: min. nwell enclosure of poly overlapping varac channel : 0.15um") +# tap.overlapping(varac).separation(difftap, 0.27, euclidian).polygons.without_area(0).output("varac.6", "varac.6: min. varac channel tap space to difftap : 0.27um") +# nwell.overlapping(varac).and(diff.and(nwell)).output("varac.7", "varac.7: nwell overlapping varac channel must not overlap p+diff") + +# photo +# photodiode = dnwell & areaid_po +# photodiode.edges.without_length(3.0).output("photo.2", "photo.2 : minimum/maximum width of photodiode : 3.0um") +# photodiode.isolated(5.0, euclidian).output("photo.3", "photo.3 : mini. photodiode spacing : 5.0um") +# photodiode.separation(dnwell, 5.3, euclidian).output("photo.4", "photo.4 : mini. photodiode spacing to dnwell : 5.3um") +# areaid_po.not(dnwell).output("photo.5.6", "photo.5.6 : photodiode edges must coincide areaid.po and enclosed by dnwell") +# photodiode.not(tap.not(nwell).holes).output("photo.7", "photo.7 : photodiode must be enclosed by p+tap ring") +# photodiode.and(nwell).edges.without_length(0.84).output("photo.8", "photo.8 : minimum/maximum width of nwell inside photodiode : 0.84um") +# areaid_po.edges.and(photodiode.and(nwell).sized(1.08)).without_length(12.0).output("photo.9", "photo.9 : minimum/maximum enclosure of nwell by photodiode : 1.08um") +# photodiode.and(tap).edges.without_length(0.41).output("photo.10", "photo.10 : minimum/maximum width of tap inside photodiode : 0.41um") + +# npc +log("npc") +npc.width(0.27, euclidian).output("npc.1", "npc.1 : min. npc width : 0.27um") +npc.isolated(0.27, euclidian).output("npc.2", "npc.2 : min. npc spacing, should be mnually merge if less : 0.27um") +# npc.separation(gate, 0.09, euclidian).output("npc.4", "npc.4 : min. npc spacing to gate : 0.09um") + +# nsdm/psdm +# npsdm = nsdm + psdm +# nsdm.width(0.38, euclidian).output("nsdm.1", "nsdm.1 : min. nsdm width : 0.38um") +# psdm.width(0.38, euclidian).output("psdm.1", "psdm.1 : min. psdm width : 0.38um") +# nsdm.isolated(0.38, euclidian).output("n/psdm.1", "n/psdm.1 : min. nsdm spacing, should be mnually merge if less : 0.38um") +# psdm.isolated(0.38, euclidian).output("n/psdm.1", "n/psdm.1 : min. psdm spacing, should be mnually merge if less : 0.38um") +# npsdm.enclosing(diff, 0.125, euclidian).polygons.not(tap.sized(0.125)).output("n/psdm.5a", "n/psdm.5a : min. n/psdm enclosure diff except butting edge : 0.125um") +# npsdm.enclosing(tap, 0.125, euclidian).polygons.not(diff.sized(0.125)).output("n/psdm.5b", "n/psdm.5b : min. n/psdm enclosure tap except butting edge : 0.125um") +# tap.edges.and(diff.edges).not(npsdm).output("n/psdm.6", "n/psdm.6 : min. n/psdm enclosure of butting edge : 0.0um") +# nsdm.and(difftap).separation(psdm.and(difftap), 0.13, euclidian).polygons.without_area(0).output("n/psdm.7", "n/psdm.7 : min. nsdm diff spacing to psdm diff except butting edge : 0.13um") +# diff.and((nsdm.and(nwell)).or(psdm.not(nwell))).output("n/psdm.8", "n/psdm.8 : diff should be the opposite type of well/substrate underneath") +# tap.and((nsdm.not(nwell)).or(psdm.and(nwell))).output("n/psdm.8", "n/psdm.8 : tap should be the same type of well/substrate underneath") +# tap.and(diff).without_area(0).output("tap and diff", "tap and diff must not overlap") +# nsdm.with_area(0..0.265).output("n/psdm.10a", "n/psdm.10a : min. nsdm area : 0.265um²") +# psdm.with_area(0..0.265).output("n/psdm.10b", "n/psdm.10b : min. psdm area : 0.265um²") + +# licon +log("licon") +licon.not(poly.interacting(poly_rs).and(rpm)).edges.without_length(0.17).output("licon.1", "licon.1 : minimum/maximum width of licon : 0.17um") +licon.and(poly.interacting(poly_rs).and(rpm)).not_interacting((licon.and(poly.interacting(poly_rs).and(rpm)).edges.with_length(0.19)).or(licon.and(poly.interacting(poly_rs).and(rpm)).edges.with_length(2.0))).output("licon.1b/c", "licon.1b/c : minimum/maximum width/length of licon inside poly resistor : 2.0/0.19um") +# licon.isolated(0.17, euclidian).output("licon.2", "licon.2 : min. licon spacing : 0.17um") +# licon.and(poly.interacting(poly_rs).and(rpm)).edges.with_length(0.19).space(0.35, euclidian).output("licon.2b", "licon.2b : min. licon 0.19um edge on resistor spacing : 0.35um") +# licon.interacting(licon.and(poly.interacting(poly_rs).and(rpm)).edges.with_length(2.0)).separation(licon.and(poly.interacting(poly_rs).and(rpm)), 0.51, euclidian).output("licon.2c", "licon.2c : min. licon 2.0um edge on resistor spacing : 0.51um") +# licon.and(poly.interacting(poly_rs).and(rpm)).separation(licon.not(poly.interacting(poly_rs).and(rpm)), 0.51, euclidian).output("licon.2d", "licon.2d : min. licon on resistor spacing other licon : 0.51um") +# rule licon.3 not coded +# licon.not(li).not(poly.or(diff).or(tap)).output("licon.4", "licon.4 : min. licon must overlap li and (poly or tap or diff)") +# diff.enclosing(licon, 0.04, euclidian).output("licon.5", "licon.5 : min. diff enclosure of licon : 0.04um") +# tap.edges.and(diff.edges).separation(licon.and(tap).edges, 0.06, euclidian).output("licon.6", "licon.6 : min. abutting edge spacing to licon tap : 0.06um") +# licon_edges_with_less_enclosure_tap = tap.enclosing(licon, 0.12, projection).second_edges +# opposite1 = (licon.edges - licon_edges_with_less_enclosure_tap).width(0.17 + 1.dbu, projection).polygons +# licon.not_interacting(opposite1).output("licon.7", "licon.7 : min. tap enclosure of licon by one of 2 opposite edges : 0.12um") +# poly.enclosing(licon, 0.05, euclidian).output("licon.8", "licon.8 : min. poly enclosure of licon : 0.05um") +# licon008 = licon.interacting(poly.enclosing(licon, 0.08, euclidian).polygons) +# licon_edges_with_less_enclosure_poly = poly.enclosing(licon, 0.08, projection).second_edges +# opposite2 = (licon.edges - licon_edges_with_less_enclosure_poly).width(0.17 + 1.dbu, projection).polygons +# licon008.not_interacting(opposite2).output("licon.8a", "licon.8a : min. poly enclosure of licon by one of 2 opposite edges : 0.08um") +# # rule licon.9 not coded +# licon.and(tap.and(nwell.not(hvi))).separation(varac, 0.25, euclidian).output("licon.10", "licon.10 : min. licon spacing to varac channel : 0.25um") +# not_in_cell4 = layout(source.cell_obj).select("-s8fs_gwdlvx4", "-s8fs_gwdlvx8", "-s8fs_hvrsw_x4", "-s8fs_hvrsw8", "-s8fs_hvrsw264", "-s8fs_hvrsw520", "-s8fs_rdecdrv", "-s8fs_rdec8”, “s8fs_rdec32", "-s8fs_rdec264", "-s8fs_rdec520") +# not_in_cell4_licon = not_in_cell4.input(66, 44) +# not_in_cell4_licon.and(diff.or(tap)).separation(gate.not(areaid_sc), 0.055, euclidian).output("licon.11", "licon.11 : min. licon spacing to gate : 0.055um") +# licon.and(diff.or(tap)).separation(gate.and(areaid_sc), 0.05, euclidian).output("licon.11a", "licon.11a : min. licon spacing to gate inside areaid.sc : 0.05um") +# in_cell4 = layout(source.cell_obj).select("+s8fs_gwdlvx4", "+s8fs_gwdlvx8", "+s8fs_hvrsw_x4", "+s8fs_hvrsw8", "+s8fs_hvrsw264", "+s8fs_hvrsw520") +# in_cell4_licon = in_cell4.input(66, 44) +# in_cell4_licon.and(diff.or(tap)).separation(gate, 0.04, euclidian).output("licon.11c", "licon.11c : min. licon spacing to gate for specific cells: 0.04um") +# # rules 11.b , 11.d not coded +# diff.interacting(gate).not(diff.interacting(gate).width(5.7, euclidian).polygons).output("licon.12", "licon.12 : max. sd width without licon : 5.7um") +licon.and(diff.or(tap)).separation(npc, 0.09, euclidian).output("licon.13", "licon.13 : min. difftap licon spacing to npc : 0.09um") +# licon.and(poly).separation(diff.or(tap), 0.19, euclidian).output("licon.14", "licon.14 : min. poly licon spacing to difftap : 0.19um") +# npc.enclosing(licon.and(poly), 0.1, euclidian).output("licon.15", "licon.15 : min. npc enclosure of poly-licon : 0.1um") +# rule licon.16 not applicable for the diff for the nmos of a nand gates or the pmos of a nor gates +#diff.not(gate).not_interacting(licon).output("licon.16", "licon.16 : diff must enclose one licon") +# tap.not(uhvi).not_interacting(licon).output("licon.16", "licon.16 : tap must enclose one licon") + +# this rule appears to be incorrect - it is flagging errors not identified by the Calibre MR deck +# poly.and(tap).edges.not(tap.edges).output("licon.17", "licon.17 : tap must not straddle poly") + +# npc.not_interacting(licon.and(poly)).output("licon.18", "licon.18 : npc mut enclosed one poly-licon") + +# vpp +log("vpp") +# vpp.width(1.43, euclidian).output("vpp.1", "vpp.1 : min. vpp width : 1.43um") +# # rules 1.b, 1.c not coded +# vpp.and(poly.or(difftap)).output("vpp.3", "vpp.3 : vpp must not overlapp poly or diff or tap") +# vpp.and(nwell).edges.not(vpp.edges).output("vpp.4", "vpp.4 : vpp must not straddle nwell") +# vpp.and(dnwell).edges.not(vpp.edges).output("vpp.4", "vpp.4 : vpp must not straddle dnwell") +# vpp.and(poly.or(li).or(m1).or(m2)).separation(poly.or(li).or(m1).or(m2), 1.5, euclidian).polygons.with_area(2.25,nil).output("vpp.5", "vpp.5 : min. vpp spacing to poly or li or m1 or m2 : 1.5um") +# vpp.with_area(0..area(vpp.and(m3))*0.25).output("vpp.5a", "vpp.5a : max. m3 density in vpp : 0.25") +# vpp.with_area(0..area(vpp.and(m4))*0.3).output("vpp.5b", "vpp.5b : max. m4 density in vpp : 0.3") +# vpp.with_area(0..area(vpp.and(m5))*0.4).output("vpp.5c", "vpp.5c : max. m5 density in vpp : 0.4") +# nwell.enclosing(vpp, 1.5, euclidian).output("vpp.8", "vpp.8 : nwell enclosure of vpp : 1.5") +# vpp.separation(nwell, 1.5, euclidian).polygons.without_area(0).output("vpp.9", "vpp.9 : vpp spacing to nwell : 1.5") +# # rule vpp.10 not coded +# # rule vpp.11 not coded because moscap is not defined properly by any gds layer +# # rules vpp.12a, 12b, 12c not coded because specific to one cell +# if backend_flow = CU +# m1.separation(vpp.and(m1), 0.16, euclidian).polygons.without_area(0).output("vpp.13", "vpp.13 : m1 spacing to m1inside vpp : 0.16") +# end + +# CAPM +log("capm") +capm.width(1.0, euclidian).output("capm.1", "capm.1 : min. capm width : 1.0um") +capm.isolated(0.84, euclidian).output("capm.2a", "capm.2a : min. capm spacing : 0.84um") +m2.interacting(capm).isolated(1.2, euclidian).output("capm.2b", "capm.2b : min. capm spacing : 1.2um") +m2.enclosing(capm, 0.14, euclidian).output("capm.3", "capm.3 : min. m2 enclosure of capm : 0.14um") +capm.enclosing(via2, 0.14, euclidian).output("capm.4", "capm.4 : min. capm enclosure of via2 : 0.14um") +capm.separation(via2, 0.14, euclidian).output("capm.5", "capm.5 : min. capm spacing to via2 : 0.14um") +# capm.sized(-20.0).sized(20.0).output("capm.6", "capm.6 : max. capm lenght/width : 20um") +# capm.with_angle(0 .. 90).output("capm.7", "capm.7 : capm not rectangle") +# capm.separation(via, 0.14, euclidian).polygons.without_area(0).output("capm.8", "capm.8 : min. capm spacing to via : 0.14um") +# capm.and(nwell).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle nwell") +# capm.and(diff).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle diff") +# capm.and(tap).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle tap") +# capm.and(poly).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle poly") +# capm.and(li).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle li") +# capm.and(m1).edges.not(capm.edges).output("capm.10", "capm.10 : capm must not straddle m1") +# capm.separation(m2.not_interacting(capm), 0.14, euclidian).output("capm.11", "capm.11 : min. capm spacing to m2 not overlapping capm : 0.5um") + +end #FEOL + +if BEOL +log("BEOL section") + +# li +log("li") + +# currently-unused: +# not_in_cell5 = source.select("-s8rf2_xcmvpp_hd5_*") +# not_in_cell5_li = not_in_cell5.polygons(li_wildcard) + +# update for sram - jeffdi +# not_in_cell5_li.width(0.17, euclidian).output("li.1", "li.1 : min. li width : 0.17um") +linotace = li.not(areaid_ce) +linotace.width(0.17, euclidian).output("li.1", "li.1 : min. li width : 0.17um") + +# in_cell5_li = li - not_in_cell5_li +# in_cell5_li.width(0.14, euclidian).output("li.1a", "li.1a : min. li width for the cells s8rf2_xcmvpp_hd5_* : 0.14um") + +# rule li.2 not coded + +# updated for sram - jeffdi +linotace.space(0.17, euclidian).output("li.3", "li.3 : min. li spacing : 0.17um") +#not_in_cell5_li.space(0.17, euclidian).output("li.3", "li.3 : min. li spacing : 0.17um") + +# in_cell5_li.space(0.14, euclidian).output("li.3a", "li.3a : min. li spacing for the cells s8rf2_xcmvpp_hd5_* : 0.14um") + +# TODO: this next rule is hanging - it also needs to me updated to support sram +# licon08 = licon.interacting(li.enclosing(licon, 0.08, euclidian).polygons) +licon_edges_with_less_enclosure_li = li.enclosing(licon, 0.08, projection).second_edges +opposite3 = (licon.edges - licon_edges_with_less_enclosure_li).width(0.17 + 1.dbu, projection).polygons +# licon08.not_interacting(opposite3).output("li.5", "li.5 : min. li enclosure of licon of 2 opposite edges : 0.08um") + +li.with_area(0..0.0561).output("li.6", "li.6 : min. li area : 0.0561um²") + +# ct +log("mcon") +mcon.edges.without_length(0.17).output("ct.1", "ct.1 : minimum/maximum width of mcon : 0.17um") +mcon.space(0.19, euclidian).output("ct.2", "ct.2 : min. mcon spacing : 0.19um") +# rule ct.3 not coded + +#updated for sram - jeffdi +#mcon.not(li).output("ct.4", "ct.4 : mcon should covered by li") +mconnotace = mcon.not(areaid_ce) +mconnotace.not(li).output("ct.4", "ct.4 : mcon should covered by li") + +# if backend_flow = CU +# li.interacting(li.and(m1).not(mcon).with_holes(1,10)).enclosing(mcon, 0.2, euclidian).output("ct.irdrop.1", "ct.irdrop.1 : min. li enclsoure of 1..10 mcon : 0.2um") +# li.interacting(li.and(m1).not(mcon).with_holes(11,100)).enclosing(mcon, 0.3, euclidian).output("ct.irdrop.2", "ct.irdrop.2 : min. li enclsoure of 11..100 mcon : 0.3um") +# end +# + +# m1 +log("m1") +m1.width(0.14, euclidian).output("m1.1", "m1.1 : min. m1 width : 0.14um") + +huge_m1 = m1.sized(-1.5).sized(1.5) +non_huge_m1 = m1 - huge_m1 + +non_huge_m1.space(0.14, euclidian).output("m1.2", "m1.2 : min. m1 spacing : 0.14um") + +(huge_m1.separation(non_huge_m1, 0.28, euclidian) + huge_m1.space(0.28, euclidian)).output("m1.3ab", "m1.3ab : min. 3um.m1 spacing m1 : 0.28um") + +not_in_cell6 = layout(source.cell_obj).select("-s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b", "-s8fpls_pl8", "-s8fs_cmux4_fm") +not_in_cell6_m1 = not_in_cell6.input(m1_wildcard) + +#updated for sram - jeffdi +not_in_cell6_m1.enclosing(mconnotace, 0.03, euclidian).output("m1.4", "m1.4 : min. m1 enclosure of mcon : 0.03um") +in_cell6 = layout(source.cell_obj).select("+s8cell_ee_plus_sseln_a", "+s8cell_ee_plus_sseln_b", "+s8cell_ee_plus_sselp_a", "+s8cell_ee_plus_sselp_b", "+s8fpls_pl8", "+s8fs_cmux4_fm") +in_cell6_m1 = in_cell6.input(m1_wildcard) +in_cell6_m1.enclosing(mcon, 0.005, euclidian).output("m1.4a", "m1.4a : min. m1 enclosure of mcon for specific cells : 0.005um") + +m1.with_area(0..0.083).output("m1.6", "m1.6 : min. m1 area : 0.083um²") +m1.holes.with_area(0..0.14).output("m1.7", "m1.7 : min. m1 holes area : 0.14um²") +if backend_flow = AL + mcon06 = mcon.interacting(poly.enclosing(m1, 0.06, euclidian).polygons) + mcon_edges_with_less_enclosure_m1 = m1.enclosing(mcon, 0.06, projection).second_edges + opposite4 = (mcon.edges - mcon_edges_with_less_enclosure_m1).width(0.17 + 1.dbu, projection).polygons + mcon06.not_interacting(opposite4).output("m1.5", "m1.5 : min. m1 enclosure of mcon of 2 opposite edges : 0.06um") + # rule m1.pd.1, rule m1.pd.2a, rule m1.pd.2b not coded +end +#if bakend_flow = CU +# m1.sized(-2.0).sized(2.0).output("m1.11", "m1.11 : max. m1 width after slotting : 4.0um") +# # rule m1.12 not coded because inconsistent with m1.11 +# # rule m1.13, m1.14, m1.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +#end + +# via +log("via") +#rule via.3 not coded +# via.not(m1).output("via.4c.5c", "via.4c.5c : m1 must enclose all via") +if backend_flow = AL + via.not(areaid_mt).edges.without_length(0.15).output("via.1a", "via.1a : minimum/maximum width of via : 0.15um") + # via.and(areaid_mt).not_interacting((via.and(areaid_mt).edges.without_length(0.15)).or(via.and(areaid_mt).edges.without_length(0.23)).or(via.and(areaid_mt).edges.without_length(0.28))).output("via.1b", "via.1b : minimum/maximum width of via in areaid.mt: 0.15um or 0.23um or 0.28um") + via.isolated(0.17, euclidian).output("via.2", "via.2 : min. via spacing : 0.17um") + m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.055, euclidian).output("via.4a", "via.4a : min. m1 enclosure of 0.15um via : 0.055um") + # m1.enclosing(via.not_interacting(via.edges.without_length(0.23)), 0.03, euclidian).output("via.4b", "via.4b : min. m1 enclosure of 0.23um via : 0.03um") + via1_edges_with_less_enclosure_m1 = m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.085, projection).second_edges + opposite5 = (via.not_interacting(via.edges.without_length(0.15)).edges - via1_edges_with_less_enclosure_m1).width(0.15 + 1.dbu, projection).polygons + via.not_interacting(via.edges.without_length(0.15)).not_interacting(opposite5).output("via1.5a", "via1.5a : min. m1 enclosure of 0.15um via of 2 opposite edges : 0.085um") + via2_edges_with_less_enclosure_m1 = m1.enclosing(via.not_interacting(via.edges.without_length(0.23)), 0.06, projection).second_edges + opposite6 = (via.not_interacting(via.edges.without_length(0.23)).edges - via2_edges_with_less_enclosure_m1).width(0.23 + 1.dbu, projection).polygons + # via.not_interacting(via.edges.without_length(0.23)).not_interacting(opposite6).output("via1.5b", "via1.5b : min. m1 enclosure of 0.23um via of 2 opposite edges : 0.06um") +end +# if backend_flow = CU + # via.not(areaid_mt).edges.without_length(0.18).output("via.11", "via.11 : minimum/maximum width of via : 0.18um") + # via.isolated(0.13, euclidian).output("via.12", "via.12 : min. via spacing : 0.13um") + # rule via.13 not coded because not understandable + # via1_edges_with_less_enclosure_m1 = m1.enclosing(via, 0.04, projection).second_edges + # opposite5 = (via.edges - via1_edges_with_less_enclosure_m1).width(0.18 + 1.dbu, projection).polygons + # via.not_interacting(opposite5).output("via1.14", "via1.14 : min. m1 enclosure of 0.04um via of 2 opposite edges : 0.04um") + # rules via.irdrop.1, via.irdrop.2, via.irdrop.3, via.irdrop.4 not coded because not understandable +# end + +# m2 +log("m2") +m2.width(0.14, euclidian).output("m2.1", "m2.1 : min. m2 width : 0.14um") + +huge_m2 = m2.sized(-1.5).sized(1.5) +non_huge_m2 = m2 - huge_m2 + +non_huge_m2.space(0.14, euclidian).output("m2.2", "m2.2 : min. m2 spacing : 0.14um") + +(huge_m2.separation(non_huge_m2, 0.28, euclidian) + huge_m2.space(0.28, euclidian)).output("m2.3ab", "m2.3ab : min. 3um.m2 spacing m2 : 0.28um") + +# rule m2.3c not coded +m2.with_area(0..0.0676).output("m2.6", "m2.6 : min. m2 area : 0.0676um²") +m2.holes.with_area(0..0.14).output("m2.7", "m2.7 : min. m2 holes area : 0.14um²") +# via.not(m2).output("m2.via", "m2.via : m2 must enclose via") +if backend_flow = AL + m2.enclosing(via, 0.055, euclidian).output("m2.4", "m2.4 : min. m2 enclosure of via : 0.055um") + via_edges_with_less_enclosure_m2 = m2.enclosing(via, 0.085, projection).second_edges + opposite7 = (via.edges - via_edges_with_less_enclosure_m2).width(0.2 + 1.dbu, projection).polygons + via.not_interacting(opposite7).output("m2.5", "m2.5 : min. m2 enclosure of via of 2 opposite edges : 0.085um") + # rule m2.pd.1, rule m2.pd.2a, rule m2.pd.2b not coded +end +# if bakend_flow = CU + # m2.sized(-2.0).sized(2.0).output("m2.11", "m2.11 : max. m2 width after slotting : 4.0um") + # rule m2.12 not coded because inconsistent with m2.11 + # rule m2.13, m2.14, m2.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +# end + +# via2 +log("via2") +#rule via233 not coded +# via2.not(m2).output("via2", "via2 : m2 must enclose all via2") +if backend_flow = AL + via2.not(areaid_mt).edges.without_length(0.2).output("via2.1a", "via2.1a : minimum/maximum width of via2 : 0.2um") + # via2.and(areaid_mt).not_interacting((via2.and(areaid_mt).edges.without_length(0.2)).or(via2.and(areaid_mt).edges.without_length(1.2)).or(via2.and(areaid_mt).edges.without_length(1.5))).output("via2.1b", "via2.1b : minimum/maximum width of via2 in areaid.mt: 0.2um or 1.2um or 1.5um") + via2.isolated(0.2, euclidian).output("via2.2", "via2.2 : min. via2 spacing : 0.2um") + m2.enclosing(via2, 0.04, euclidian).output("via2.4", "via2.4 : min. m2 enclosure of via2 : 0.04um") + m2.enclosing(via2.not_interacting(via2.edges.without_length(1.5)), 0.14, euclidian).output("via2.4a", "via2.4a : min. m2 enclosure of 1.5um via2 : 0.14um") + via2_edges_with_less_enclosure_m2 = m2.enclosing(via2, 0.085, projection).second_edges + opposite8 = (via2.edges - via2_edges_with_less_enclosure_m2).width(0.2 + 1.dbu, projection).polygons + via2.not_interacting(opposite8).output("via2.5", "via2.5 : min. m2 enclosure of via2 of 2 opposite edges : 0.085um") +end +# if backend_flow = CU + # via2.edges.without_length(0.21).output("via2.11", "via2.11 : minimum/maximum width of via2 : 0.21um") + # via2.isolated(0.18, euclidian).output("via2.12", "via2.12 : min. via2 spacing : 0.18um") + # rule via2.13 not coded because not understandable, or not clear + # m2.enclosing(via2, 0.035, euclidian).output("via2.14", "via2.14 : min. m2 enclosure of via2 : 0.035um") + # rules via2.irdrop.1, via2.irdrop.2, via2.irdrop.3, via2.irdrop.4 not coded because not understandable +# end + +# m3 +log("m3") +m3.width(0.3, euclidian).output("m3.1", "m3.1 : min. m3 width : 0.3um") + +huge_m3 = m3.sized(-1.5).sized(1.5) +non_huge_m3 = m3 - huge_m3 + +non_huge_m3.space(0.3, euclidian).output("m3.2", "m3.2 : min. m3 spacing : 0.3um") + +# (huge_m3.separation(non_huge_m3, 0.4, euclidian) + huge_m3.space(0.4, euclidian)).output("m3.3ab", "m3.3ab : min. 3um.m3 spacing m3 : 0.4um") + +# rule m3.3c not coded +# m3.with_area(0..0.24).output("m3.6", "m3.6 : min. m2 area : 0.24um²") +# via2.not(m3).output("m3.via2", "m3.via2 : m3 must enclose via2") +if backend_flow = AL + m3.enclosing(via2, 0.065, euclidian).output("m3.4", "m3.4 : min. m3 enclosure of via2 : 0.065um") + # via2_edges_with_less_enclosure_m3 = m3.enclosing(via2, 0.085, projection).second_edges + # m3.5 N/A + # opposite9 = (via2.edges - via2_edges_with_less_enclosure_m3).width(0.3 + 1.dbu, projection).polygons + # via2.not_interacting(opposite9).output("m3.5", "m3.5 : min. m3 enclosure of via2 of 2 opposite edges : 0.085um") + # rule m3.pd.1, rule m3.pd.2a, rule m3.pd.2b not coded +end +# if bakend_flow = CU + # m3.holes.with_area(0..0.2).output("m3.7", "m3.7 : min. m2 holes area : 0.2um²") + # m3.sized(-2.0).sized(2.0).output("m3.11", "m3.11 : max. m3 width after slotting : 4.0um") + # rule m3.12 not coded because inconsistent with m3.11 + # rule m3.13, m3.14, m3.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 +# end + +# via3 +log("via3") +#rule via3.3 not coded +# via3.not(m3).output("via3", "via3 : m3 must enclose all via3") +if backend_flow = AL + via3.not(areaid_mt).edges.without_length(0.2).output("via3.1a", "via3.1a : minimum/maximum width of via3 : 0.2um") + via3.and(areaid_mt).not_interacting((via3.and(areaid_mt).edges.without_length(0.2)).or(via3.and(areaid_mt).edges.without_length(0.8))).output("via3.1a", "via3.1a : minimum/maximum width of via3 in areaid.mt: 0.2um or 0.8um") + via3.isolated(0.2, euclidian).output("via3.2", "via3.2 : min. via3 spacing : 0.2um") + m3.enclosing(via3, 0.06, euclidian).output("via3.4", "via3.4 : min. m3 enclosure of via3 : 0.06um") + via3_edges_with_less_enclosure_m3 = m3.enclosing(via3, 0.09, projection).second_edges + opposite10 = (via3.edges - via3_edges_with_less_enclosure_m3).width(0.2 + 1.dbu, projection).polygons + via3.not_interacting(opposite10).output("via3.5", "via3.5 : min. m2 enclosure of via3 of 2 opposite edges : 0.09um") +end +# if backend_flow = CU + # via3.edges.without_length(0.21).output("via3.11", "via3.11 : minimum/maximum width of via3 : 0.21um") + # via3.isolated(0.18, euclidian).output("via3.12", "via3.12 : min. via3 spacing : 0.18um") + # m3.enclosing(via3, 0.055, euclidian).output("via3.13", "via3.13 : min. m3 enclosure of via3 : 0.055um") + # rule via3.14 not coded because not understandable, or not clear + # rules via3.irdrop.1, via3.irdrop.2, via3.irdrop.3, via3.irdrop.4 not coded because not understandable +# end + +# m4 +log("m4") +m4.width(0.3, euclidian).output("m4.1", "m4.1 : min. m4 width : 0.3um") + +huge_m4 = m4.sized(-1.5).sized(1.5) +non_huge_m4 = m4 - huge_m4 + +non_huge_m4.space(0.3, euclidian).output("m4.2", "m4.2 : min. m4 spacing : 0.3um") + +(huge_m4.separation(non_huge_m4, 0.4, euclidian) + huge_m4.space(0.4, euclidian)).output("m4.5ab", "m4.5ab : min. 3um.m4 spacing m4 : 0.4um") + +# m4.with_area(0..0.24).output("m4.4", "m4.4 : min. m2 area : 0.24um²") +# via3.not(m4).output("m4.via3", "m4.via3 : m4 must enclose via3") +if backend_flow = AL + m4.enclosing(via3, 0.065, euclidian).output("m4.3", "m4.3 : min. m4 enclosure of via3 : 0.065um") + # m4.5 doesn't exist + # via3_edges_with_less_enclosure_m4 = m4.enclosing(via2, 0.085, projection).second_edges + # opposite9 = (via3.edges - via3_edges_with_less_enclosure_m4).width(0.3 + 1.dbu, projection).polygons + # via3.not_interacting(opposite9).output("m4.5", "m4.5 : min. m4 enclosure of via3 of 2 opposite edges : 0.085um") + # rule m4.pd.1, rule m4.pd.2a, rule m4.pd.2b not coded +end +if bakend_flow = CU + # m4.holes.with_area(0..0.2).output("m4.7", "m4.7 : min. m2 holes area : 0.2um²") + # m4.sized(-5.0).sized(5.0).output("m4.11", "m4.11 : max. m4 width after slotting : 10.0um") + # rule m4.12 not coded because inconsistent with m4.11 + # rule m4.13, m4.14, m4.14a not coded : see : https://www.klayout.de/forum/discussion/comment/6759 + # m4.enclosing(via3, 0.06, euclidian).output("m4.15", "m4.15 : min. m4 enclosure of via3 : 0.06um") +end + +# via4 +log("via4") +via4.edges.without_length(0.8).output("via4.1a", "via4.1a : minimum/maximum width of via4 : 0.8um") +via4.isolated(0.8, euclidian).output("via4.2", "via4.2 : min. via4 spacing : 0.8um") +#rule via4.3 not coded +m4.enclosing(via4, 0.19, euclidian).output("via4.4", "via4.4 : min. m4 enclosure of via4 : 0.19um") +via4.not(m4).output("via4", "via4 : m4 must enclose all via4") +if backend_flow = CU + # rules via4.irdrop.1, via4.irdrop.2, via4.irdrop.3, via4.irdrop.4 not coded because not understandable +end + +# m5 +log("m5") +m5.width(1.6, euclidian).output("m5.1", "m5.1 : min. m5 width : 1.6um") + +m5.space(1.6, euclidian).output("m5.2", "m5.2 : min. m5 spacing : 1.6um") + +# via4.not(m5).output("m5.via4", "m5.via4 : m5 must enclose via4") +m5.enclosing(via4, 0.31, euclidian).output("m5.3", "m4.3 : min. m5 enclosure of via4 : 0.31um") + +# nsm +# nsm.width(3.0, euclidian).output("nsm.1", "nsm.1 : min. nsm width : 3.0um") +# nsm.isolated(4.0, euclidian).output("nsm.2", "nsm.2 : min. nsm spacing : 4.0um") +# nsm.enclosing(diff, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of diff : 3.0um") +# nsm.enclosing(tap, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of tap : 3.0um") +# nsm.enclosing(poly, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of poly : 3.0um") +# nsm.enclosing(li, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of li : 3.0um") +# nsm.enclosing(m1, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m1 : 3.0um") +# nsm.enclosing(m2, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m2 : 3.0um") +# nsm.enclosing(m3, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m3 : 3.0um") +# nsm.enclosing(m4, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m4 : 3.0um") +# nsm.enclosing(m5, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of m5 : 3.0um") +# nsm.enclosing(cfom, 3.0, euclidian).output("nsm.4", "nsm.4 : min. nsm enclosure of cfom : 3.0um") +# if backend_flow = AL +# nsm.separation(diff, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to diff : 1.0um") +# nsm.separation(tap, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to tap : 1.0um") +# nsm.separation(poly, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to poly : 1.0um") +# nsm.separation(li, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to li : 1.0um") +# nsm.separation(m1, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m1 : 1.0um") +# nsm.separation(m2, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m2 : 1.0um") +# nsm.separation(m3, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m3 : 1.0um") +# nsm.separation(m4, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m4 : 1.0um") +# nsm.separation(m5, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to m5 : 1.0um") +# nsm.separation(cfom, 1.0, euclidian).output("nsm.3", "nsm.3 : min. nsm spacing to cfom : 1.0um") +# end + +# pad +log("pad") +pad.isolated(1.27, euclidian).output("pad.2", "pad.2 : min. pad spacing : 1.27um") + +end #BEOL + +if FEOL +log("FEOL section") + +# mf +#mf.not_interacting(mf.edges.without_length(0.8)).output("mf.1", "mf.1 : minimum/maximum width of fuse : 0.8um") +#mf.not_interacting(mf.edges.without_length(7.2)).output("mf.2", "mf.2 : minimum/maximum length of fuse : 7.2um") +#mf.isolated(1.96, euclidian).output("mf.3", "mf.3 : min. fuse center spacing : 2.76um") +# fuses need more clarification on fuse_shield, fuse layers ... + +# hvi +log("hvi") +hvi.width(0.6, euclidian).output("hvi.1", "hvi.1 : min. hvi width : 0.6um") +# hvi.isolated(0.7, euclidian).output("hvi.2", "hvi.2 : min. hvi spacing, merge if less : 0.7um") +# hvi.and(tunm).output("hvi.4", "hvi.4 : hvi must not overlapp tunm") +# hvi.and(nwell).separation(nwell, 2.0, euclidian).output("hvnwell.8", "hvnwelli.8 : min. hvnwel spacing to nwell : 2.0") +# areaid_hl.not(hvi).output("hvnwel.9", "hvnwell.9 : hvi must overlapp hvnwell") +# rule hvnell.10 not coded +# diff.not(psdm.and(diff_rs)).and(hvi).width(0.29, euclidian).output("hvdifftap.14", "hvdifftap.14 : min. diff inside hvi width : 0.29um") +# diff.and(psdm.and(diff_rs)).and(hvi).width(0.15, euclidian).output("hvdifftap.14a", "hvdifftap.14a : min. p+diff resistor inside hvi width : 0.15um") +# diff.and(hvi).isolated(0.3, euclidian).output("hvdifftap.15a", "hvdifftap.15a : min. diff inside hvi spacing : 0.3um") +# diff.and(hvi).and(nsdm).separation(diff.and(hvi).and(psdm), 0.37, euclidian).polygons.without_area(0).output("hvdifftap.15b", "hvdifftap.15b : min. n+diff inside hvi spacing to p+diff inside hvi except abutting: 0.37um") +# tap.and(hvi).edges.and(diff).without_length(0.7).output("hvdifftap.16", "hvdifftap.16 : min. tap inside hvi abuttng diff : 0.7um") +# hvi.and(nwell).enclosing(diff, 0.33, euclidian).output("hvdifftap.17", "hvdifftap.17 : min. hvnwell enclosure of p+diff : 0.33um") +# hvi.and(nwell).separation(diff, 0.43, euclidian).output("hvdifftap.18", "hvdifftap.18 : min. hvnwell spacing to n+diff : 0.43um") +# hvi.and(nwell).enclosing(tap, 0.33, euclidian).output("hvdifftap.19", "hvdifftap.19 : min. hvnwell enclosure of n+tap : 0.33um") +# hvi.and(nwell).separation(tap, 0.43, euclidian).output("hvdifftap.20", "hvdifftap.20 : min. hvnwell spacing to p+tap : 0.43um") +# hvi.and(diff).edges.not(diff.edges).output("hvdifftap.21", "hvdifftap.21 : diff must not straddle hvi") +# hvi.and(tap).edges.not(tap.edges).output("hvdifftap.21", "hvdifftap.21 : tap must not straddle hvi") +# hvi.enclosing(difftap, 0.18, euclidian).output("hvdifftap.22", "hvdifftap.22 : min. hvi enclosure of diff or tap : 0.18um") +# hvi.separation(difftap, 0.18, euclidian).output("hvdifftap.23", "hvdifftap.23 : min. hvi spacing to diff or tap : 0.18um") +# hvi.and(diff).not(nwell).separation(nwell, 0.43, euclidian).output("hvdifftap.24", "hvdifftap.24 : min. hv n+diff spacing to nwell : 0.43um") +# diff.and(hvi).not(nwell).isolated(1.07, euclidian).polygons.and(tap).output("hvdifftap.25", "hvdifftap.25 : min. n+diff inside hvi spacing accros p+tap : 1.07um") +# diff.not(poly).edges.and(gate.and(hvi).edges).space(0.35, euclidian).output("hvpoly.13", "hvpoly.13: min. hvi gate length : 0.5um") +# hvi.and(poly).edges.not(poly.edges).output("hvpoly.14", "hvpoly.14 : poly must not straddle hvi") + +# hvntm +log("hvntm") +hvntm.width(0.7, euclidian).output("hvntm.1", "hvntm.1 : min. hvntm width : 0.7um") +hvntm.isolated(0.7, euclidian).output("hvntm.2", "hvntm.2 : min. hvntm spacing : 0.7um") +# hvntm.enclosing(diff.and(nwell).and(hvi), 0.185, euclidian).output("hvntm.3", "hvntm.3 : min. hvntm enclosure of hv n+diff : 0.185um") +# hvntm.separation(diff.not(nwell).not(hvi), 0.185, euclidian).output("hvntm.4", "hvntm.4 : min. hvntm spacing to n+diff : 0.185um") +# hvntm.separation(diff.and(nwell).not(hvi), 0.185, euclidian).output("hvntm.5", "hvntm.5 : min. hvntm spacing to p+diff : 0.185um") +# hvntm.separation(tap.not(nwell).not(hvi), 0.185, euclidian).polygons.without_area(0).output("hvntm.6a", "hvntm.6a : min. hvntm spacing to p+tap : 0.185um") +# hvntm.and(areaid_ce).output("hvntm.9", "hvntm.9 : hvntm must not overlapp areaid.ce") + +# denmos +# poly.not_interacting(pwde).interacting(areaid_en).width(1.055, projection).output("denmos.1", "denmos.1 : min. de_nfet gate width : 1.055um") +# diff.not_interacting(pwde).enclosing(poly.interacting(areaid_en), 0.28, projection).polygons.without_area(0).output("denmos.2", "denmos.2 : min. de_nfet source ouside poly width : 0.28um") +# diff.not_interacting(pwde).and(poly.interacting(areaid_en)).width(0.925, projection).output("denmos.3", "denmos.3 : min. de_nfet source inside poly width : 0.925um") +# diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).width(0.17, euclidian).output("denmos.4", "denmos.4 : min. de_nfet drain width : 0.17um") +# nwell.not_interacting(pwde).and(poly.interacting(areaid_en)).width(0.225, projection).polygons.or(nwell.and(poly.interacting(areaid_en)).sized(-0.1125).sized(0.1125)).output("denmos.5", "denmos.5 : min. de_nfet source inside nwell width : 0.225m") +# diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).separation(diff.interacting(poly.interacting(areaid_en)), 1.585, projection).output("denmos.6", "denmos.6 : min. de_nfet source spacing to drain : 1.585um") +# nwell.not_interacting(pwde).and(poly.and(diff).interacting(areaid_en)).edges.without_length(5.0, nil).output("denmos.7", "denmos.7 : min. de_nfet channel width : 5.0um") +# diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("denmos.8", "denmos.8 : 90deg. not allowed for de_nfet drain") +# nwell.not_interacting(pwde).interacting(areaid_en).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("denmos.9a", "denmos.9a : 90deg. not allowed for de_nfet nwell") +# nwell.not_interacting(pwde).interacting(areaid_en).edges.with_angle(45).without_length(0.607..0.609).output("denmos.9a", "denmos.9a : 45deg. bevels of de_nfet nwell should be 0.43um from corners") +# nwell.not_interacting(pwde).interacting(areaid_en).edges.with_angle(135).without_length(0.607..0.609).output("denmos.9a", "denmos.9a : 45deg. bevels of de_nfet nwell should be 0.43um from corners") +# diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(45).without_length(0.7..0.71).output("denmos.9b", "denmos.9b : 45deg. bevels of de_nfet drain should be 0.05um from corners") +# diff.not_interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(135).without_length(0.7..0.71).output("denmos.9b", "denmos.9b : 45deg. bevels of de_nfet drain should be 0.05um from corners") +# nwell.not_interacting(pwde).enclosing(diff.interacting(areaid_en).not_interacting(poly), 0.66, euclidian).output("denmos.10", "denmos.10 : min. nwell enclosure of de_nfet drain : 0.66um") +# nwell.not_interacting(pwde).interacting(areaid_en).separation(tap.not(nwell), 0.86, euclidian).output("denmos.11", "denmos.11 : min. de_nfet nwell spacing to tap : 0.86um") +# nwell.not_interacting(pwde).interacting(areaid_en).isolated(2.4, euclidian).output("denmos.12", "denmos.12 : min. de_nfet nwell : 2.4um") +# nsdm.not_interacting(pwde).enclosing(diff.interacting(areaid_en).interacting(poly), 0.13, euclidian).output("denmos.13", "denmos.13 : min. nsdm enclosure of de_nfet source : 0.13um") + +# depmos +# poly.interacting(pwde).interacting(areaid_en).width(1.05, projection).output("depmos.1", "depmos.1 : min. de_pfet gate width : 1.05um") +# diff.interacting(pwde).enclosing(poly.interacting(areaid_en), 0.28, projection).polygons.without_area(0).output("depmos.2", "depmos.2 : min. de_pfet source ouside poly width : 0.28um") +# diff.interacting(pwde).and(poly.interacting(areaid_en)).width(0.92, projection).output("depmos.3", "depmos.3 : min. de_pfet source inside poly width : 0.92um") +# diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).width(0.17, euclidian).output("depmos.4", "depmos.4 : min. de_pfet drain width : 0.17um") +# pwde.not(nwell).and(poly.interacting(areaid_en)).width(0.26, projection).polygons.or(pwde.not(nwell).and(poly.interacting(areaid_en)).sized(-0.13).sized(0.13)).output("depmos.5", "depmos.5 : min. de_pfet source inside nwell width : 0.26m") +# diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).separation(diff.interacting(poly.interacting(areaid_en)), 1.19, projection).output("depmos.6", "depmos.6 : min. de_pfet source spacing to drain : 1.19um") +# nwell.interacting(pwde).and(poly.and(diff).interacting(areaid_en)).edges.without_length(5.0, nil).output("depmos.7", "depmos.7 : min. de_pfet channel width : 5.0um") +# diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("depmos.8", "depmos.8 : 90deg. not allowed for de_pfet drain") +# pwde.not(nwell).interacting(areaid_en).edges.without_angle(45).without_angle(135).without_angle(225).without_angle(315).output("depmos.9a", "depmos.9a : 90deg. not allowed for de_pfet pwell") +# pwde.not(nwell).interacting(areaid_en).edges.with_angle(45).without_length(0.607..0.609).output("depmos.9a", "depmos.9a : 45deg. bevels of de_pfet pwell should be 0.43um from corners") +# pwde.not(nwell).interacting(areaid_en).edges.with_angle(135).without_length(0.607..0.609).output("depmos.9a", "depmos.9a : 45deg. bevels of de_pfet pwell should be 0.43um from corners") +# diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(45).without_length(0.7..0.71).output("depmos.9b", "depmos.9b : 45deg. bevels of de_pfet drain should be 0.05um from corners") +# diff.interacting(pwde).interacting(areaid_en).not_interacting(poly).edges.with_angle(135).without_length(0.7..0.71).output("depmos.9b", "depmos.9b : 45deg. bevels of de_pfet drain should be 0.05um from corners") +# nwell.interacting(pwde).separation(diff.interacting(areaid_en).not_interacting(poly), 0.86, euclidian).output("depmos.10", "depmos.10 : min. pwell enclosure of de_pfet drain : 0.86um") +# pwde.not(nwell).interacting(areaid_en).separation(tap.and(nwell), 0.66, euclidian).output("depmos.11", "depmos.11 : min. de_pfet pwell spacing to tap : 0.66um") +# psdm.interacting(pwde).enclosing(diff.interacting(areaid_en).interacting(poly), 0.13, euclidian).output("depmos.12", "depmos.12 : min. psdm enclosure of de_pfet source : 0.13um") + +# extd +# areaid_en.and(difftap).edges.not(difftap.edges).output("extd.1", "extd.1 : difftap must not straddle areaid.en") +# difftap.interacting(areaid_en).not(poly).with_area(0).output("extd.2", "extd.2 : poly must not overlapp entirely difftap in areaid.en") +# rules extd.4, extd.5, extd.6, extd.7 not coded because specific to some cells + +# vhvi +# rules vhvi.vhv.1, vhvi.vhv.2, vhvi.vhv.3, vhvi.vhv.4, vhvi.vhv.5, vhvi.vhv.6 not coded +# vhvi.width(0.02, euclidian).output("vhvi.1", "vhvi.1 : min. vhvi width : 0.02um") +# vhvi.and(areaid_ce).output("vhvi.2", "vhvi.2 : vhvi must not overlap areaid.ce") +# vhvi.and(hvi).output("vhvi.3", "vhvi.3 : vhvi must not overlap hvi") +# # rules vhvi.4, vhvi.6 not coded +# vhvi.and(diff).edges.not(diff.edges).output("vhvi.5", "vhvi.5 : vhvi must not straddle diff") +# vhvi.and(tap).edges.not(tap.edges).output("vhvi.5", "vhvi.5 : vhvi must not straddle tap") +# vhvi.and(poly).edges.not(poly.edges).output("vhvi.7", "vhvi.7 : vhvi must not straddle poly") + +# nwell.and(vhvi).separation(nwell, 2.5, euclidian).output("hv.nwell.1", "hv.nwell.1 : min. vhvi nwell spacing to nwell : 2.5um") +# diff.and(vhvi).isolated(0.3, euclidian).output("hv.diff.1", "hv.diff.1 : min. vhvi diff spacing : 0.3um") +# nwell.interacting(diff.and(vhvi)).separation(diff.not(nwell), 0.43, euclidian).output("hv.diff.2", "hv.diff.2 : min. vhvi nwell spacing n+diff : 0.43um") +# diff.and(vhvi).not(nwell).separation(nwell, 0.55, euclidian).output("hv.diff.3a", "hv.diff.3a : min. vhvi n+diff spacing nwell : 0.55um") +# # rule hv.diff.3b not coded +# poly.and(vhvi).not(diff).separation(diff, 0.3, euclidian).polygons.without_area(0).output("hv.poly.2", "hv.poly.2 : min. vhvi poly spacing to diff : 0.3um") +# poly.and(vhvi).not(diff).separation(nwell, 0.55, euclidian).polygons.without_area(0).output("hv.poly.3", "hv.poly.3 : min. vhvi poly spacing to nwell : 0.55um") +# nwell.enclosing(poly.and(vhvi).not(diff), 0.3, euclidian).polygons.without_area(0).output("hv.poly.4", "hv.poly.4 : min. nwell enclosure of vhvi poly : 0.3um") +# poly.and(vhvi).enclosing(diff.interacting(areaid_en), 0.16, projection).polygons.without_area(0).output("hv.poly.6", "hv.poly.6 : min. poly enclosure of hvfet gate : 0.16um") +# rule hv.poly.7 not coded + +# uhvi +# uhvi.and(diff).edges.not(diff.edges).output("uhvi.1", "uhvi.1 : diff must not straddle uhvi") +# uhvi.and(tap).edges.not(tap.edges).output("uhvi.1", "uhvi.1 : tap must not straddle uhvi") +# uhvi.and(poly).edges.not(poly.edges).output("uhvi.2", "uhvi.2 : poly must not straddle uhvi") +# pwbm.not(uhvi).output("uhvi.3", "uhvi.3 : uhvi must not enclose pwbm") +# uhvi.and(dnwell).edges.not(dnwell.edges).output("uhvi.4", "uhvi.4 : dnwell must not straddle uhvi") +# areaid_en20.not(uhvi).output("uhvi.5", "uhvi.5 : uhvi must not enclose areaid.en20") +# #dnwell.not(uhvi).output("uhvi.6", "uhvi.6 : uhvi must not enclose dnwell") +# natfet.not(uhvi).output("uhvi.7", "uhvi.7 : uhvi must not enclose natfet") + +# pwell_res +# pwell_rs.width(2.65).output("pwres.2", "pwres.2 : min. pwell resistor width : 2.65um") +# pwell_rs.sized(-2.65).sized(2.65).output("pwres.2", "pwres.2 : max. pwell resistor width : 2.65um") +# pwell_rs.interacting(pwell_rs.edges.with_length(2.651,26.499)).output("pwres.3", "pwres.3 : min. pwell resistor length : 26.5um") +# pwell_rs.interacting(pwell_rs.edges.with_length(265.0, nil)).output("pwres.4", "pwres.4 : max. pwell resistor length : 265um") +# tap.interacting(pwell_rs).separation(nwell, 0.22, euclidian).output("pwres.5", "pwres.5 : min. pwell resistor tap spacing to nwell : 0.22um") +# tap.interacting(pwell_rs).and(tap.sized(0.22).and(nwell)).output("pwres.5", "pwres.5 : max. pwell resistor tap spacing to nwell : 0.22um") +# tap.interacting(pwell_rs).width(0.53).output("pwres.6", "pwres.6 : min. width of tap inside pwell resistor : 0.53um") +# tap.interacting(pwell_rs).sized(-0.265).sized(0.265).output("pwres.6", "pwres.6 : max. width of tap inside pwell resistor : 0.53um") +# # rules pwres.7a, pwres.7b not coded +# pwell_rs.and(diff).output("pwres.8", "pwres.8 : diff not allowed inside pwell resistor") +# pwell_rs.and(poly).output("pwres.8", "pwres.8 : poly not allowed inside pwell resistor") +# rules pwres.9, pwres.10 not coded + +# rf_diode +# areaid_re.with_angle(0 .. 90).output("rfdiode.1", "rfdiode.1 : non 90 degree angle areaid.re") +# areaid_re.not(nwell).or(nwell.interacting(areaid_re).not(areaid_re)).output("rfdiode.2", "rfdiode.2 : areaid.re must coincide rf nwell diode") +# rule rfdiode.3 not coded + +end #FEOL + +if OFFGRID +log("OFFGRID-ANGLES section") + +dnwell.ongrid(0.005).output("dnwell_OFFGRID", "x.1b : OFFGRID vertex on dnwell") +dnwell.with_angle(0 .. 45).output("dnwell_angle", "x.3a : non 45 degree angle dnwell") +nwell.ongrid(0.005).output("nwell_OFFGRID", "x.1b : OFFGRID vertex on nwell") +nwell.with_angle(0 .. 45).output("nwell_angle", "x.3a : non 45 degree angle nwell") +pwbm.ongrid(0.005).output("pwbm_OFFGRID", "x.1b : OFFGRID vertex on pwbm") +pwbm.with_angle(0 .. 45).output("pwbm_angle", "x.3a : non 45 degree angle pwbm") +pwde.ongrid(0.005).output("pwde_OFFGRID", "x.1b : OFFGRID vertex on pwde") +pwde.with_angle(0 .. 45).output("pwde_angle", "x.3a : non 45 degree angle pwde") +hvtp.ongrid(0.005).output("hvtp_OFFGRID", "x.1b : OFFGRID vertex on hvtp") +hvtp.with_angle(0 .. 45).output("hvtp_angle", "x.3a : non 45 degree angle hvtp") +hvtr.ongrid(0.005).output("hvtr_OFFGRID", "x.1b : OFFGRID vertex on hvtr") +hvtr.with_angle(0 .. 45).output("hvtr_angle", "x.3a : non 45 degree angle hvtr") +lvtn.ongrid(0.005).output("lvtn_OFFGRID", "x.1b : OFFGRID vertex on lvtn") +lvtn.with_angle(0 .. 45).output("lvtn_angle", "x.3a : non 45 degree angle lvtn") +ncm.ongrid(0.005).output("ncm_OFFGRID", "x.1b : OFFGRID vertex on ncm") +ncm.with_angle(0 .. 45).output("ncm_angle", "x.3a : non 45 degree angle ncm") +diff.ongrid(0.005).output("diff_OFFGRID", "x.1b : OFFGRID vertex on diff") +tap.ongrid(0.005).output("tap_OFFGRID", "x.1b : OFFGRID vertex on tap") +diff.not(areaid_en.and(uhvi)).with_angle(0 .. 90).output("diff_angle", "x.2 : non 90 degree angle diff") +diff.and(areaid_en.and(uhvi)).with_angle(0 .. 45).output("diff_angle", "x.2c : non 45 degree angle diff") +tap.not(areaid_en.and(uhvi)).with_angle(0 .. 90).output("tap_angle", "x.2 : non 90 degree angle tap") +tap.and(areaid_en.and(uhvi)).with_angle(0 .. 45).output("tap_angle", "x.2c : non 45 degree angle tap") +tunm.ongrid(0.005).output("tunm_OFFGRID", "x.1b : OFFGRID vertex on tunm") +tunm.with_angle(0 .. 45).output("tunm_angle", "x.3a : non 45 degree angle tunm") +poly.ongrid(0.005).output("poly_OFFGRID", "x.1b : OFFGRID vertex on poly") +poly.with_angle(0 .. 90).output("poly_angle", "x.2 : non 90 degree angle poly") +rpm.ongrid(0.005).output("rpm_OFFGRID", "x.1b : OFFGRID vertex on rpm") +rpm.with_angle(0 .. 45).output("rpm_angle", "x.3a : non 45 degree angle rpm") +npc.ongrid(0.005).output("npc_OFFGRID", "x.1b : OFFGRID vertex on npc") +npc.with_angle(0 .. 45).output("npc_angle", "x.3a : non 45 degree angle npc") +nsdm.ongrid(0.005).output("nsdm_OFFGRID", "x.1b : OFFGRID vertex on nsdm") +nsdm.with_angle(0 .. 45).output("nsdm_angle", "x.3a : non 45 degree angle nsdm") +psdm.ongrid(0.005).output("psdm_OFFGRID", "x.1b : OFFGRID vertex on psdm") +psdm.with_angle(0 .. 45).output("psdm_angle", "x.3a : non 45 degree angle psdm") +licon.ongrid(0.005).output("licon_OFFGRID", "x.1b : OFFGRID vertex on licon") +licon.with_angle(0 .. 90).output("licon_angle", "x.2 : non 90 degree angle licon") +li.ongrid(0.005).output("li_OFFGRID", "x.1b : OFFGRID vertex on li") +li.with_angle(0 .. 45).output("li_angle", "x.3a : non 45 degree angle li") +mcon.ongrid(0.005).output("ct_OFFGRID", "x.1b : OFFGRID vertex on mcon") +mcon.with_angle(0 .. 90).output("ct_angle", "x.2 : non 90 degree angle mcon") +vpp.ongrid(0.005).output("vpp_OFFGRID", "x.1b : OFFGRID vertex on vpp") +vpp.with_angle(0 .. 45).output("vpp_angle", "x.3a : non 45 degree angle vpp") +m1.ongrid(0.005).output("m1_OFFGRID", "x.1b : OFFGRID vertex on m1") +m1.with_angle(0 .. 45).output("m1_angle", "x.3a : non 45 degree angle m1") +via.ongrid(0.005).output("via_OFFGRID", "x.1b : OFFGRID vertex on via") +via.with_angle(0 .. 90).output("via_angle", "x.2 : non 90 degree angle via") +m2.ongrid(0.005).output("m2_OFFGRID", "x.1b : OFFGRID vertex on m2") +m2.with_angle(0 .. 45).output("m2_angle", "x.3a : non 45 degree angle m2") +via2.ongrid(0.005).output("via2_OFFGRID", "x.1b : OFFGRID vertex on via2") +via2.with_angle(0 .. 90).output("via2_angle", "x.2 : non 90 degree angle via2") +m3.ongrid(0.005).output("m3_OFFGRID", "x.1b : OFFGRID vertex on m3") +m3.with_angle(0 .. 45).output("m3_angle", "x.3a : non 45 degree angle m3") +via3.ongrid(0.005).output("via3_OFFGRID", "x.1b : OFFGRID vertex on via3") +via3.with_angle(0 .. 90).output("via3_angle", "x.2 : non 90 degree angle via3") +nsm.ongrid(0.005).output("nsm_OFFGRID", "x.1b : OFFGRID vertex on nsm") +nsm.with_angle(0 .. 45).output("nsm_angle", "x.3a : non 45 degree angle nsm") +m4.ongrid(0.005).output("m4_OFFGRID", "x.1b : OFFGRID vertex on m4") +m4.with_angle(0 .. 45).output("m4_angle", "x.3a : non 45 degree angle m4") +via4.ongrid(0.005).output("via4_OFFGRID", "x.1b : OFFGRID vertex on via4") +via4.with_angle(0 .. 90).output("via4_angle", "x.2 : non 90 degree angle via4") +m5.ongrid(0.005).output("m5_OFFGRID", "x.1b : OFFGRID vertex on m5") +m5.with_angle(0 .. 45).output("m5_angle", "x.3a : non 45 degree angle m5") +pad.ongrid(0.005).output("pad_OFFGRID", "x.1b : OFFGRID vertex on pad") +pad.with_angle(0 .. 45).output("pad_angle", "x.3a : non 45 degree angle pad") +mf.ongrid(0.005).output("mf_OFFGRID", "x.1b : OFFGRID vertex on mf") +mf.with_angle(0 .. 90).output("mf_angle", "x.2 : non 90 degree angle mf") +hvi.ongrid(0.005).output("hvi_OFFGRID", "x.1b : OFFGRID vertex on hvi") +hvi.with_angle(0 .. 45).output("hvi_angle", "x.3a : non 45 degree angle hvi") +hvntm.ongrid(0.005).output("hvntm_OFFGRID", "x.1b : OFFGRID vertex on hvntm") +hvntm.with_angle(0 .. 45).output("hvntm_angle", "x.3a : non 45 degree angle hvntm") +vhvi.ongrid(0.005).output("vhvi_OFFGRID", "x.1b : OFFGRID vertex on vhvi") +vhvi.with_angle(0 .. 45).output("vhvi_angle", "x.3a : non 45 degree angle vhvi") +uhvi.ongrid(0.005).output("uhvi_OFFGRID", "x.1b : OFFGRID vertex on uhvi") +uhvi.with_angle(0 .. 45).output("uhvi_angle", "x.3a : non 45 degree angle uhvi") +pwell_rs.ongrid(0.005).output("pwell_rs_OFFGRID", "x.1b : OFFGRID vertex on pwell_rs") +pwell_rs.with_angle(0 .. 45).output("pwell_rs_angle", "x.3a : non 45 degree angle pwell_rs") +areaid_re.ongrid(0.005).output("areaid_re_OFFGRID", "x.1b : OFFGRID vertex on areaid.re") + +end #OFFGRID + diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A_mr_opt.drc b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A_mr_opt.drc new file mode 100755 index 00000000..c4e8faf5 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/sky130A_mr_opt.drc @@ -0,0 +1,808 @@ +# Run script : klayout -rd input= -rd report= -rd summary_file= -rd thr= -rd tiles= -rd feol=1 -rd beol=1 -z -r sky130A_mr_opt.drc + +if $input + inp = source($input, $top_cell) +end + +lay = inp.layout + +if $report + report("SKY130 DRC runset", $report) +else + report("SKY130 DRC runset", File.join(File.dirname(RBA::CellView::active.filename), "sky130_drc.txt")) +end + +AL = true # do not change +CU = false # do not change +# choose betwen only one of AL or CU back-end flow here : +backend_flow = AL + +# enable / disable rule groups +if $feol == "0" + FEOL = false # front-end-of-line checks +else + FEOL = true # front-end-of-line checks +end +if $beol == "0" + BEOL = false # back-end-of-line checks +else + BEOL = true # back-end-of-line checks +end +if $offgrid == "0" + OFFGRID = false # manufacturing grid/angle checks +else + OFFGRID = true # manufacturing grid/angle checks +end + + +# klayout setup +######################## +def log_modes() + deepP = is_deep? + tiledP = is_tiled? + log("... deep:#{deepP} tiled:#{tiledP}") +end + +# if going back & forth between deep <=> tiles() need to reset tile-size & borders +def Tiled() + if $tiles + tiles($tiles.to_f) + else + tiles(200.um) + end + tile_borders(3.um) +end + +# Note: deep: should be used very selectively. +# In deep-mode: plain cmds outside (typically before) TP.execute, don't participate +# in ordinary multithreaded tiling (but do participate in, the lesser, hier-based multithreading). +# And... even for flat tiling (in or out of TP.execute), we still must avoid certain operations, +# like interacting. +# BUT: believe enclosing() is not one of those cmds. +# Expensive part of li.5 are two enclosing stmts: Make sure those are done in flat tiling mode! +# +# Cannot just change to flat/tiling (for all pre-TP commands) since: some of those are interacting, +# i.e. of the variety that cannot be tiled. + +if $thr + threads($thr) +else + threads(8) +end + +# if more inof is needed, set true +verbose(true) + +inputs = Array.new +outputs = Array.new + + +$tp = RBA::TilingProcessor::new +if $tiles + $tp.tile_size($tiles.to_f, $tiles.to_f) + tiles($tiles.to_f) +else + $tp.tile_size(200, 200) + tiles(200.um) +end +if $thr + $tp.threads = $thr.to_i +else + $tp.threads = 8 +end +$tp.dbu = lay.dbu +$tp.tile_border(3,3) + tile_borders(3.um) +$count = 0 + +# hierachical. Note: using tiles() just to set tile-size also turns-off deep mode. So set deep *after* tiles(). +#Tiled(); log_modes() + +def drc_check(output, inputs, script) + + $tp.output("output_#{$count}", output.last[:data].data) + inputs.each do |inp| + $tp.input(inp[:name], inp[:layer].data) + end + $tp.queue("_output(output_#{$count}, #{script})") + $count = $count + 1 + +end + +# layers definitions +######################## + +# all except purpose (datatype) 5 -- label and 44 -- via +li_wildcard = "67/20" +mcon_wildcard = "67/44" + +m1_wildcard = "68/20" +via_wildcard = "68/44" + +m2_wildcard = "69/20" +via2_wildcard = "69/44" + +m3_wildcard = "70/20" +via3_wildcard = "70/44" + +m4_wildcard = "71/20" +via4_wildcard = "71/44" + +m5_wildcard = "72/20" + +diff = input(65, 20) +tap = polygons(65, 44) +nwell = polygons(64, 20) +dnwell = polygons(64, 18) +pwbm = polygons(19, 44) +pwde = polygons(124, 20) +natfet = polygons(124, 21) +hvtr = polygons(18, 20) +hvtp = polygons(78, 44) +ldntm = polygons(11, 44) +hvi = polygons(75, 20) +tunm = polygons(80, 20) +lvtn = polygons(125, 44) +poly = polygons(66, 20) +hvntm = polygons(125, 20) +nsdm = polygons(93, 44) +psdm = polygons(94, 20) +rpm = polygons(86, 20) +urpm = polygons(79, 20) +npc = polygons(95, 20) +licon = polygons(66, 44) + +li = polygons(li_wildcard) +mcon = polygons(mcon_wildcard) + +m1 = polygons(m1_wildcard) +via = polygons(via_wildcard) + +m2 = polygons(m2_wildcard) +via2 = polygons(via2_wildcard) + +m3 = polygons(m3_wildcard) +via3 = polygons(via3_wildcard) + +m4 = polygons(m4_wildcard) +via4 = polygons(via4_wildcard) + +m5 = polygons(m5_wildcard) + +pad = polygons(76, 20) +nsm = polygons(61, 20) +capm = polygons(89, 44) +cap2m = polygons(97, 44) +vhvi = polygons(74, 21) +uhvi = polygons(74, 22) +npn = polygons(82, 20) +inductor = polygons(82, 24) +vpp = polygons(82, 64) +pnp = polygons(82, 44) +lvs_prune = polygons(84, 44) +ncm = polygons(92, 44) +padcenter = polygons(81, 20) +mf = polygons(76, 44) +areaid_sl = polygons(81, 1) +areaid_ce = polygons(81, 2) +areaid_fe = polygons(81, 3) +areaid_sc = polygons(81, 4) +areaid_sf = polygons(81, 6) +areaid_sw = polygons(81, 7) +areaid_sr = polygons(81, 8) +areaid_mt = polygons(81, 10) +areaid_dt = polygons(81, 11) +areaid_ft = polygons(81, 12) +areaid_ww = polygons(81, 13) +areaid_ld = polygons(81, 14) +areaid_ns = polygons(81, 15) +areaid_ij = polygons(81, 17) +areaid_zr = polygons(81, 18) +areaid_ed = polygons(81, 19) +areaid_de = polygons(81, 23) +areaid_rd = polygons(81, 24) +areaid_dn = polygons(81, 50) +areaid_cr = polygons(81, 51) +areaid_cd = polygons(81, 52) +areaid_st = polygons(81, 53) +areaid_op = polygons(81, 54) +areaid_en = polygons(81, 57) +areaid_en20 = polygons(81, 58) +areaid_le = polygons(81, 60) +areaid_hl = polygons(81, 63) +areaid_sd = polygons(81, 70) +areaid_po = polygons(81, 81) +areaid_it = polygons(81, 84) +areaid_et = polygons(81, 101) +areaid_lvt = polygons(81, 108) +areaid_re = polygons(81, 125) +areaid_ag = polygons(81, 79) +poly_rs = polygons(66, 13) +diff_rs = polygons(65, 13) +pwell_rs = polygons(64, 13) +li_rs = polygons(67, 13) +cfom = polygons(22, 20) + +# Define a new custom function that selects polygons by their number of holes: +# It will return a new layer containing those polygons with min to max holes. +# max can be nil to omit the upper limit. +#class DRC::DRCLayer +# def with_holes(min, max) +# new_data = RBA::Region::new +# self.data.each do |p| +# if p.holes >= (min || 0) && (!max || p.holes <= max) +# new_data.insert(p) +# end +# end +# DRC::DRCLayer::new(@engine, new_data) +# end +#end + +# DRC section +######################## +log("DRC section") +out = polygon_layer +out_edge = polygon_layer + +#/////////////////////////////////////////// +# FRONT-END checks +#/////////////////////////////////////////// +if FEOL +log("FEOL section") + +deep; log_modes() +m2_interact_capm = m2.interacting(capm) +Tiled(); log_modes() + +# dnwell +drc_check(outputs.push({category: "dnwell.2", description: "dnwell.2 : min. dnwell width : 3.0um", data: out}), Array.new.push({name: "dnwell", layer: dnwell}), "dnwell.width_check(3/#{lay.dbu})") + +# nwell +out = polygon_layer +drc_check(outputs.push({category: "nwell.1", description: "nwell.1 : min. nwell width : 0.84um", data: out}), Array.new.push({name: "nwell", layer: nwell}), "nwell.width_check(0.84/#{lay.dbu})") + +deep; log_modes() +nwell.isolated(1.27, euclidian).output("nwell.2a", "nwell.2a : min. nwell spacing (merged if less) : 1.27um") +Tiled(); log_modes() + +# hvtp +out = polygon_layer +drc_check(outputs.push({category: "hvtp.1", description: "hvtp.1 : min. hvtp width : 0.38um", data: out}), Array.new.push({name: "hvtp", layer: hvtp}), "hvtp.width_check(0.38/#{lay.dbu})") + +deep; log_modes() +hvtp.isolated(0.38, euclidian).output("hvtp.2", "hvtp.2 : min. hvtp spacing : 0.38um") +Tiled(); log_modes() + +# hvtr +out = polygon_layer +drc_check(outputs.push({category: "hvtr.1", description: "hvtr.1 : min. hvtr width : 0.38um", data: out}), Array.new.push({name: "hvtr", layer: hvtr}), "hvtr.width_check(0.38/#{lay.dbu})") + +deep; log_modes() +hvtr.isolated(0.38, euclidian).output("hvtr.2", "hvtr.2 : min. hvtr spacing : 0.38um") +Tiled(); log_modes() + +# lvtn +out = polygon_layer +drc_check(outputs.push({category: "lvtn.1a", description: "lvtn.1a : min. lvtn width : 0.38um", data: out}), Array.new.push({name: "lvtn", layer: lvtn}), "lvtn.width_check(0.38/#{lay.dbu})") + +deep; log_modes() +lvtn.isolated(0.38, euclidian).output("lvtn.2", "lvtn.2 : min. lvtn spacing : 0.38um") +Tiled(); log_modes() + +# ncm +out = polygon_layer +drc_check(outputs.push({category: "ncm.1", description: "ncm.1 : min. ncm width : 0.38um", data: out}), Array.new.push({name: "ncm", layer: ncm}), " ncm.width_check(0.38/#{lay.dbu})") + +deep; log_modes() +ncm.isolated(0.38, euclidian).output("ncm.2a", "ncm.2a : min. ncm spacing : 0.38um") +Tiled(); log_modes() + +# diff-tap +deep; log_modes() + diff_width = diff.rectangles.width(0.15, euclidian).polygons + diff_cross_areaid_ce = diff_width.edges.outside_part(areaid_ce).not(diff_width.outside(areaid_ce).edges) + diff_cross_areaid_ce.output("difftap.1", "difftap.1 : min. diff width across areaid:ce : 0.15um") +Tiled(); log_modes() + +out = polygon_layer +drc_check(outputs.push({category: "difftap.1_a", description: "difftap.1_a : min. diff width across areaid:ce : 0.15um", data: out}), Array.new.push({name: "diff", layer: diff}, {name: "areaid_ce", layer: areaid_ce}), "diff.outside(areaid_ce).width_check(0.15/#{lay.dbu})") + +deep; log_modes() + tap_width = tap.rectangles.width(0.15, euclidian).polygons + tap_cross_areaid_ce = tap_width.edges.outside_part(areaid_ce).not(tap_width.outside(areaid_ce).edges) + tap_cross_areaid_ce.output("difftap.1_a", "difftap.1_a : min. tap width across areaid:ce : 0.15um") +Tiled(); log_modes() + +out = polygon_layer +drc_check(outputs.push({category: "difftap.1_c", description: "difftap.1_c : min. diff width across areaid:ce : 0.15um", data: out}), Array.new.push({name: "tap", layer: tap}, {name: "areaid_ce", layer: areaid_ce}), "tap.outside(areaid_ce).width_check(0.15/#{lay.dbu})") + +out = polygon_layer +drc_check(outputs.push({category: "difftap.1_c", description: "difftap.1_c : min. diff width across areaid:ce : 0.15um", data: out}), Array.new.push({name: "tap", layer: tap}, {name: "diff", layer: diff}), "(diff + tap).space_check(0.27/#{lay.dbu})") + +# tunm +out = polygon_layer +drc_check(outputs.push({category: "tunm.1", description: "tunm.1 : min. tunm width : 0.41um", data: out}), Array.new.push({name: "tunm", layer: tunm}), "tunm.width_check(0.41/#{lay.dbu})") + +out = polygon_layer +drc_check(outputs.push({category: "tunm.2", description: "tunm.2 : min. tunm spacing : 0.5um", data: out}), Array.new.push({name: "tunm", layer: tunm}), "tunm.space_check(0.5/#{lay.dbu})") + +#tunm.isolated(0.5, euclidian).output("tunm.2", "tunm.2 : min. tunm spacing : 0.5um") + +# poly +out = polygon_layer +drc_check(outputs.push({category: "poly.1a", description: "poly.1a : min. poly width : 0.15um", data: out}), Array.new.push({name: "poly", layer: poly}), "poly.width_check(0.15/#{lay.dbu})") + +deep; log_modes() +poly.not(areaid_ce).isolated(0.21, euclidian).output("poly.2", "poly.2 : min. poly spacing : 0.21um") +Tiled(); log_modes() + +# rpm +out = polygon_layer +drc_check(outputs.push({category: "rpm.1a", description: "rpm.1a : min. rpm width : 1.27um", data: out}), Array.new.push({name: "rpm", layer: rpm}), "rpm.width_check(1.27/#{lay.dbu})") + +deep; log_modes() +rpm.isolated(0.84, euclidian).output("rpm.2", "rpm.2 : min. rpm spacing : 0.84um") +Tiled(); log_modes() + +# npc +out = polygon_layer +drc_check(outputs.push({category: "npc.1", description: "npc.1 : min. npc width : 0.27um", data: out}), Array.new.push({name: "npc", layer: npc}), "npc.width_check(0.27/#{lay.dbu})") + +deep; log_modes() +npc.isolated(0.27, euclidian).output("npc.2", "npc.2 : min. npc spacing, should be mnually merge if less : 0.27um") +Tiled(); log_modes() + +# licon +difftap = diff.or(tap) +xfom = difftap.not(poly) +licon1ToXfom = licon.interacting(licon.and(xfom)) +licon1ToXfom_PERI = licon1ToXfom.not(areaid_ce) + +out = polygon_layer +drc_check(outputs.push({category: "licon.1", description: "licon.1 : licon should be rectangle", data: out}), Array.new.push({name: "licon", layer: licon}), "licon.non_rectangles") + +out = polygon_layer +drc_check(outputs.push({category: "licon.1_a/b", description: "licon.1_a/b : minimum/maximum width of licon : 0.17um", data: out}), Array.new.push({name: "licon", layer: licon}, {name: "rpm", layer: rpm}, {name: "urpm", layer: urpm}), "(licon - (rpm | urpm)).edges.with_length(0.17/#{lay.dbu}, true)") + +deep; log_modes() + licon1ToXfom_PERI.separation(npc, 0.09, euclidian).output("licon.13", "licon.13 : min. difftap licon spacing to npc : 0.09um") +Tiled(); log_modes() + +out = polygon_layer +drc_check(outputs.push({category: "licon.13_a", description: "licon.13_a : licon.13 : licon of diffTap in periphery must not overlap npc", data: out}), Array.new.push({name: "licon1ToXfom_PERI", layer: licon1ToXfom_PERI}, {name: "npc", layer: npc}), "licon1ToXfom_PERI & npc") + +deep; log_modes() + licon.interacting(poly).and(licon.interacting(difftap)).output("licon.17", "licon.17 : Licons may not overlap both poly and (diff or tap)") +Tiled(); log_modes() + +# CAPM +deep; log_modes() + m3_bot_plate = (capm.and(m3)).sized(0.14) +Tiled(); log_modes() + +out = polygon_layer +drc_check(outputs.push({category: "capm.1", description: "capm.1 : min. capm width : 1.0um", data: out}), Array.new.push({name: "capm", layer: capm}), "capm.width_check(1.0/#{lay.dbu})") + +out = polygon_layer +drc_check(outputs.push({category: "capm.2a", description: "capm.2a : min. capm spacing : 0.84um", data: out}), Array.new.push({name: "capm", layer: capm}), "capm.space_check(0.84/#{lay.dbu})") + +#capm.isolated(0.84, euclidian).output("capm.2a", "capm.2a : min. capm spacing : 0.84um") + +m3.interacting(capm).isolated(1.2, euclidian).output("capm.2b", "capm.2b : min. capm spacing : 1.2um") + +m3_bot_plate.isolated(1.2, euclidian).output("capm.2b_a", "capm.2b_a : min. spacing of m3_bot_plate : 1.2um") + +deep; log_modes() + capm.and(m3).enclosing(m3, 0.14, euclidian).output("capm.3", "capm.3 : min. capm and m3 enclosure of m3 : 0.14um") + m3.enclosing(capm, 0.14, euclidian).output("capm.3_a", "capm.3_a : min. m3 enclosure of capm : 0.14um") +Tiled(); log_modes() + +out = polygon_layer +drc_check(outputs.push({category: "capm.4", description: "capm.4 : min. capm enclosure of via3 : 0.14um", data: out}), Array.new.push({name: "capm", layer: capm}, {name: "via3", layer: via3}), "capm.enclosing_check(via3, 0.14/#{lay.dbu})") + +out = polygon_layer +drc_check(outputs.push({category: "capm.5", description: "capm.5 : min. capm spacing to via3 : 0.14um", data: out}), Array.new.push({name: "capm", layer: capm}, {name: "via3", layer: via3}), "capm.separation_check(via3, 0.14/#{lay.dbu})") + +# CAP2M +deep; log_modes() + m4_bot_plate = (cap2m.and(m4)).sized(0.14) +Tiled(); log_modes() + +out = polygon_layer +drc_check(outputs.push({category: "cap2m.1", description: "cap2m.1 : min. cap2m width : 1.0um", data: out}), Array.new.push({name: "cap2m", layer: cap2m}), "cap2m.width_check(1.0/#{lay.dbu})") + +out = polygon_layer +drc_check(outputs.push({category: "cap2m.2a", description: "cap2m.2a : min. cap2m spacing : 0.84um", data: out}), Array.new.push({name: "cap2m", layer: cap2m}), "cap2m.space_check(0.84/#{lay.dbu})") + +#cap2m.isolated(0.84, euclidian).output("cap2m.2a", "cap2m.2a : min. cap2m spacing : 0.84um") + +deep; log_modes() + m4.interacting(cap2m).isolated(1.2, euclidian).output("cap2m.2b", "cap2m.2b : min. cap2m spacing : 1.2um") + m4_bot_plate.space(1.2, euclidian).output("cap2m.2b_a", "cap2m.2b_a : min. spacing of m4_bot_plate : 1.2um") +Tiled(); log_modes() + +out = polygon_layer +drc_check(outputs.push({category: "cap2m.3", description: "cap2m.3 : min. cap2m and m4 enclosure of m4 : 0.14um", data: out}), Array.new.push({name: "m4", layer: m4}, {name: "cap2m", layer: cap2m}), "(cap2m & m4).enclosing_check(cap2m, 0.14/#{lay.dbu})") + +out = polygon_layer +drc_check(outputs.push({category: "cap2m.4", description: "cap2m.4 : min. cap2m enclosure of via4 : 0.14um", data: out}), Array.new.push({name: "cap2m", layer: cap2m}, {name: "via4", layer: via4}), "cap2m.enclosing_check(via4, 0.14/#{lay.dbu})") + +out = polygon_layer +drc_check(outputs.push({category: "cap2m.5", description: "cap2m.5 : min. cap2m spacing to via4 : 0.14um", data: out}), Array.new.push({name: "cap2m", layer: cap2m}, {name: "via4", layer: via4}), "cap2m.separation_check(via4, 0.14/#{lay.dbu})") + + +# hvi +hvi_peri = hvi.not(areaid_ce) + +out = polygon_layer +drc_check(outputs.push({category: "hvi.1", description: "hvi.1 : min. hvi width : 0.6um", data: out}), Array.new.push({name: "hvi_peri", layer: hvi_peri}), "hvi_peri.width_check(0.6/#{lay.dbu})") + +deep; log_modes() + hvi_peri.isolated(0.7, euclidian).output("hvi.2a", "hvi.2a : min. hvi spacing : 0.7um") +Tiled(); log_modes() + +# hvntm +hvntm_peri = hvntm.not(areaid_ce) +out = polygon_layer +drc_check(outputs.push({category: "hvntm.1", description: "hvntm.1 : min. hvntm width : 0.7um", data: out}), Array.new.push({name: "hvntm_peri", layer: hvntm_peri}), "hvntm_peri.width_check(0.7/#{lay.dbu})") + +deep; log_modes() + hvntm_peri.isolated(0.7, euclidian).output("hvntm.2", "hvntm.2 : min. hvntm spacing : 0.7um") +Tiled(); log_modes() + +log("FEOL queued, executing the rules...") + +$tp.execute("DRC") + +log("FEOL rule execution done") + +end #FEOL + +#/////////////////////////////////////////// +# BACK-END checks +#/////////////////////////////////////////// + +if BEOL +log("BEOL section") + +Tiled(); log_modes() + +# li +linotace = li.not(areaid_ce) +out = polygon_layer +drc_check(outputs.push({category: "li.1", description: "li.1 : min. li width : 0.17um", data: out}), Array.new.push({name: "linotace", layer: linotace}), "linotace.width_check(0.17/#{lay.dbu})") + +out = polygon_layer +drc_check(outputs.push({category: "li.3", description: "li.3 : min. li spacing : 0.17um", data: out}), Array.new.push({name: "linotace", layer: linotace}), "linotace.space_check(0.17/#{lay.dbu})") + +deep; log_modes() + licon_peri = licon.not(areaid_ce) + li_edges_with_less_enclosure = li.enclosing(licon_peri, 0.08, not_opposite, projection).second_edges + error_corners = li_edges_with_less_enclosure.width(angle_limit(100.0), 1.dbu) + li_interact = licon_peri.interacting(error_corners.polygons(1.dbu)) + li_interact.output("li.5", "li.5 : min. li enclosure of licon of 2 opposite edges : 0.08um") +Tiled(); log_modes() + +li.with_area(0..0.0561).output("li.6", "li.6 : min. li area : 0.0561um²") + +# ct +mconnotace = mcon.not(areaid_ce) + +out = polygon_layer +drc_check(outputs.push({category: "ct.1", description: "ct.1 : minimum/maximum width of mcon : 0.17um", data: out}), Array.new.push({name: "mconnotace", layer: mconnotace}), "mconnotace.edges.with_length(0.17/#{lay.dbu}, true)") + +out = polygon_layer +drc_check(outputs.push({category: "ct.2", description: "ct.2 : min. mcon spacing : 0.19um", data: out}), Array.new.push({name: "mcon", layer: mcon}), "mcon.space_check(0.19/#{lay.dbu})") + +out = polygon_layer +drc_check(outputs.push({category: "ct.4", description: "ct.4 : mcon should covered by li", data: out}), Array.new.push({name: "mconnotace", layer: mconnotace}, {name: "li", layer: li}), "mconnotace - li") + +# m1 +out = polygon_layer +drc_check(outputs.push({category: "m1.1", description: "m1.1 : min. m1 width : 0.14um", data: out}), Array.new.push({name: "m1", layer: m1}), "m1.width_check(0.14/#{lay.dbu})") + +deep; log_modes() + huge_m1 = m1.sized(-1.5).sized(1.5).snap(0.005) & m1 + non_huge_m1 = m1.edges - huge_m1 + huge_m1 = huge_m1.edges.outside_part(m1.merged) +Tiled(); log_modes() + +out = polygon_layer +drc_check(outputs.push({category: "m1.2", description: "m1.2 : min. m1 spacing : 0.14um", data: out}), Array.new.push({name: "non_huge_m1", layer: non_huge_m1}), "non_huge_m1.space_check(0.14/#{lay.dbu})") + +out = polygon_layer +drc_check(outputs.push({category: "m1.3ab", description: "m1.3ab : min. 3um.m1 spacing m1 : 0.28um", data: out}), Array.new.push({name: "non_huge_m1", layer: non_huge_m1}, {name: "huge_m1", layer: huge_m1}), "huge_m1.separation_check(non_huge_m1, 0.28/#{lay.dbu}) + huge_m1.space_check(0.28/#{lay.dbu})") + +deep; log_modes() + not_in_cell6 = layout(source.cell_obj).select("-s8cell_ee_plus_sseln_a", "-s8cell_ee_plus_sseln_b", "-s8cell_ee_plus_sselp_a", "-s8cell_ee_plus_sselp_b", "-s8fpls_pl8", "-s8fs_cmux4_fm") + not_in_cell6_m1 = not_in_cell6.input(m1_wildcard) +Tiled(); log_modes() + +out = polygon_layer +drc_check(outputs.push({category: "791_m1.4", description: "791_m1.4 : min. m1 enclosure of mcon : 0.03um", data: out}), Array.new.push({name: "not_in_cell6_m1", layer: not_in_cell6_m1}, {name: "mconnotace", layer: mconnotace}), "not_in_cell6_m1.enclosing_check(mconnotace, 0.03/#{lay.dbu})") + +out = polygon_layer +drc_check(outputs.push({category: "m1.4", description: "m1.4 : mcon periphery must be enclosed by m1", data: out}), Array.new.push({name: "mconnotace", layer: mconnotace}, {name: "m1", layer: m1}), "mconnotace - m1") + +deep; log_modes() + in_cell6 = layout(source.cell_obj).select("+s8cell_ee_plus_sseln_a", "+s8cell_ee_plus_sseln_b", "+s8cell_ee_plus_sselp_a", "+s8cell_ee_plus_sselp_b", "+s8fpls_pl8", "+s8fs_cmux4_fm") + in_cell6_m1 = in_cell6.input(m1_wildcard) +Tiled(); log_modes() + +out = polygon_layer +drc_check(outputs.push({category: "m1.4a", description: "m1.4a : min. m1 enclosure of mcon for specific cells : 0.005um", data: out}), Array.new.push({name: "mcon", layer: mcon}, {name: "in_cell6_m1", layer: in_cell6_m1}), "in_cell6_m1.enclosing_check(mcon, 0.005/#{lay.dbu})") + +m1.with_area(0..0.083).output("m1.6", "m1.6 : min. m1 area : 0.083um²") +m1.holes.with_area(0..0.14).output("m1.7", "m1.7 : min. m1 holes area : 0.14um²") + + +if backend_flow = AL + + + poly_inclosing_m1 = poly.enclosing(m1, 0.06, euclidian).polygons + mcon_edges_with_less_enclosure_m1 = m1.enclosing(mcon, 0.06, projection).second_edges + opposite4 = (mcon.edges - mcon_edges_with_less_enclosure_m1).width(0.17 + 1.dbu, projection).polygons + + deep; log_modes() # say if we are is_deep? and is_tiled? + mcon06 = mcon.interacting(poly_inclosing_m1) + mcon06.not_interacting(opposite4).output("m1.5", "m1.5 : min. m1 enclosure of mcon of 2 opposite edges : 0.06um") + Tiled(); log_modes() # say if we are is_deep? and is_tiled? + +end + +# areaid_mt +#drc_check(outputs.push({category: "areaid_mt", description: "areaid_mt rules not supported", data: out}), Array.new.push({name: "areaid_mt", layer: areaid_mt}), "areaid_mt") + + +# via +out = polygon_layer +drc_check(outputs.push({category: "via.3", description: "via.3 : Only min. square vias are allowed", data: out}), Array.new.push({name: "via", layer: via}), "via.non_squares") + +if backend_flow = AL + ringVIA = via.drc(with_holes > 0) + rectVIA = via.not(ringVIA) + via_not_mt = rectVIA.not(areaid_mt) + + out = polygon_layer + drc_check(outputs.push({category: "via.1a", description: "via.1a : via outside of moduleCut should be rectangular", data: out}), Array.new.push({name: "via_not_mt", layer: via_not_mt}), "via_not_mt.non_rectangles") + + out = polygon_layer + drc_check(outputs.push({category: "via.1a_a", description: "via.1a_a : minimum width of via : 0.15um", data: out}), Array.new.push({name: "via_not_mt", layer: via_not_mt}), "via_not_mt.width_check(0.15/#{lay.dbu})") + + out = polygon_layer + drc_check(outputs.push({category: "via.1a_b", description: "via.1a_b : maximum length of via : 0.15um", data: out}), Array.new.push({name: "via_not_mt", layer: via_not_mt}), "via_not_mt.edges.with_length(0.15/#{lay.dbu}, true)") + + via.isolated(0.17, euclidian).output("via.2", "via.2 : min. via spacing : 0.17um") + + ringVIA.drc(0.2.um < width <= 0.205.um).output("via.3/_a", "via.3/_a : min./max width of ring-shaped via : 0.2um/0.205um") + out = polygon_layer + drc_check(outputs.push({category: "via.3_b", description: "via.3_b : ring-shaped via must be enclosed by areaid_sl", data: out}), Array.new.push({name: "ringVIA", layer: ringVIA}, {name: "areaid_sl", layer: areaid_sl}), "ringVIA - areaid_sl") + + deep; log_modes() + m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.055, euclidian).output("via.4a", "via.4a : min. m1 enclosure of 0.15um via : 0.055um") + Tiled(); log_modes() + out = polygon_layer + drc_check(outputs.push({category: "via.4a_a", description: "via.4a_a : via must be enclosed by met1", data: out}), Array.new.push({name: "via", layer: via}, {name: "m1", layer: m1}), "(via.squares.edges.with_length(0.15/#{lay.dbu}, false)) - m1") + + + via_not_interacting_via = via.not_interacting(via.edges.without_length(0.15)) + via1_edges_with_less_enclosure_m1 = m1.enclosing(via_not_interacting_via, 0.085, projection).second_edges + opposite5 = (via_not_interacting_via.edges - via1_edges_with_less_enclosure_m1).width(0.15 + 1.dbu, projection).polygons + via_without_length = via.edges.without_length(0.15) + + via1_edges_with_less_enclosure_m1 = m1.enclosing(via.not_interacting(via.edges.without_length(0.15)), 0.085, projection).second_edges + opposite5 = (via.not_interacting(via.edges.without_length(0.15)).edges - via1_edges_with_less_enclosure_m1).width(0.15 + 1.dbu, projection).polygons + via.not_interacting(via.edges.without_length(0.15)).not_interacting(opposite5).output("via.5a", "via.5a : min. m1 enclosure of 0.15um via of 2 opposite edges : 0.085um") +end + +# m2 +deep; log_modes() + huge_m2 = m2.sized(-1.5).sized(1.5).snap(0.005) & m2 + non_huge_m2 = m2.edges - huge_m2 + huge_m2 = huge_m2.edges.outside_part(m2.merged) + via_outside_periphery = via.not(areaid_ce) +Tiled(); log_modes() + +out = polygon_layer +drc_check(outputs.push({category: "m2.1", description: "m2.1 : min. m2 width : 0.14um", data: out}), Array.new.push({name: "m2", layer: m2}), "m2.width_check(0.14/#{lay.dbu})") + +out = polygon_layer +drc_check(outputs.push({category: "m2.2", description: "m2.2 : min. m2 spacing : 0.14um", data: out}), Array.new.push({name: "non_huge_m2", layer: non_huge_m2}), "non_huge_m2.space_check(0.14/#{lay.dbu})") + +out = polygon_layer +drc_check(outputs.push({category: "m2.3ab", description: "m2.3ab : min. 3um.m2 spacing m2 : 0.28um", data: out}), Array.new.push({name: "huge_m2", layer: huge_m2}, {name: "non_huge_m2", layer: non_huge_m2}), "(huge_m2.separation_check(non_huge_m2, 0.28/#{lay.dbu}) + huge_m2.space_check(0.28/#{lay.dbu}))") + +m2.with_area(0..0.0676).output("m2.6", "m2.6 : min. m2 area : 0.0676um²") +m2.holes.with_area(0..0.14).output("m2.7", "m2.7 : min. m2 holes area : 0.14um²") + + +if backend_flow = AL + deep; log_modes() + m2.enclosing(via, 0.055, euclidian).output("m2.4", "m2.4 : min. m2 enclosure of via : 0.055um") + via_outside_periphery.not(m2).output("m2.4_a", "m2.4_a : via in periphery must be enclosed by met2") + Tiled(); log_modes() + + via_edges_with_less_enclosure_m2 = m2.enclosing(via, 0.085, projection).second_edges + opposite7 = (via.edges - via_edges_with_less_enclosure_m2).width(0.2 + 1.dbu, projection).polygons + + deep; log_modes() + via.not_interacting(opposite7).output("m2.5", "m2.5 : min. m2 enclosure of via of 2 opposite edges : 0.085um") + Tiled(); log_modes() + +end + +# via2 +out = polygon_layer +drc_check(outputs.push({category: "via2.3", description: "via2.3 : Only min. square vias are allowed", data: out}), Array.new.push({name: "via2", layer: via2}), "via2.non_squares") + +if backend_flow = AL + ringVIA2 = via2.drc(with_holes > 0) + rectVIA2 = via2.not(ringVIA2) + via2_not_mt = rectVIA2.not(areaid_mt) + out = polygon_layer + drc_check(outputs.push({category: "via2.1a", description: "via2.1a : via2 outside of moduleCut should be rectangular", data: out}), Array.new.push({name: "via2_not_mt", layer: via2_not_mt}), "via2_not_mt.non_rectangles") + + out = polygon_layer + drc_check(outputs.push({category: "via2.1a_a", description: "via2.1a_a : minimum width of via2 : 0.2um", data: out}), Array.new.push({name: "via2_not_mt", layer: via2_not_mt}), "via2_not_mt.width_check(0.2/#{lay.dbu})") + + out = polygon_layer + drc_check(outputs.push({category: "via2.1a_b", description: "via2.1a_b : minimum/maximum width of via2 : 0.2um", data: out}), Array.new.push({name: "via2_not_mt", layer: via2_not_mt}), "via2_not_mt.edges.with_length(0.2/#{lay.dbu}, true)") + + via2.isolated(0.2, euclidian).output("via2.2", "via2.2 : min. via2 spacing : 0.2um") + + ringVIA2.drc(0.2.um < width <= 0.205.um).output("via2.3/_a", "via2.3/_a : min./max width of ring-shaped via2 : 0.2um/0.205um") + out = polygon_layer + drc_check(outputs.push({category: "via2.3_b", description: "via2.3_b : ring-shaped via2 must be enclosed by areaid_sl", data: out}), Array.new.push({name: "ringVIA2", layer: ringVIA2}, {name: "areaid_sl", layer: areaid_sl}), "ringVIA2 - areaid_sl") + + deep; log_modes() + m2.enclosing(via2, 0.04, euclidian).output("via2.4", "via2.4 : min. m2 enclosure of via2 : 0.04um") + Tiled(); log_modes() + out = polygon_layer + drc_check(outputs.push({category: "via.4_a", description: "via.4_a : via must be enclosed by met2", data: out}), Array.new.push({name: "via2", layer: via2}, {name: "m2", layer: m2}), "via2 - m1") + + deep; log_modes() + via2_edges_with_less_enclosure = m2.enclosing(via2, 0.085, projection).second_edges + error_corners = via2_edges_with_less_enclosure.width(angle_limit(100.0), 1.dbu) + via2_interact = via2.interacting(error_corners.polygons(1.dbu)) + via2_interact.output("via2.5", "via2.5 : min. m3 enclosure of via2 of 2 opposite edges : 0.085um") + Tiled(); log_modes() +end + +# m3 +deep; log_modes() + huge_m3 = m3.sized(-1.5).sized(1.5).snap(0.005) & m3 + non_huge_m3 = m3.edges - huge_m2 + huge_m3 = huge_m3.edges.outside_part(m3.merged) +Tiled(); log_modes() + +out = polygon_layer +drc_check(outputs.push({category: "m3.1", description: "m3.1 : min. m3 width : 0.3um", data: out}), Array.new.push({name: "m3", layer: m3}), "m3.width_check(0.3/#{lay.dbu})") + +out = polygon_layer +drc_check(outputs.push({category: "m3.2", description: "m3.2 : min. m3 spacing : 0.3um", data: out}), Array.new.push({name: "m3", layer: m3}), "non_huge_m3.space_check(0.3/#{lay.dbu})") + +out = polygon_layer +drc_check(outputs.push({category: "m3.3cd", description: "m3.3cd : min. 4um.m3 spacing m3 : 0.4um", data: out}), Array.new.push({name: "huge_m3", layer: huge_m3}, {name: "non_huge_m3", layer: non_huge_m3}), "(huge_m3.separation_check(non_huge_m3, 0.4/#{lay.dbu}) + huge_m3.space_check(0.4/#{lay.dbu}))") + +if backend_flow = AL + deep; log_modes() + m3.enclosing(via2, 0.065, euclidian).output("m3.4", "m3.4 : min. m3 enclosure of via2 : 0.065um") + via2.not(m3).output("m3.4_a", "m3.4_a : via2 must be enclosed by met3") + Tiled(); log_modes() +end + +# via3 +if backend_flow = AL + ringVIA3 = via3.drc(with_holes > 0) + rectVIA3 = via3.not(ringVIA3) + via3_not_mt = rectVIA3.not(areaid_mt) + + out = polygon_layer + drc_check(outputs.push({category: "via3.1", description: "via3.1 : via3 outside of moduleCut should be rectangular", data: out}), Array.new.push({name: "via3_not_mt", layer: via3_not_mt}), "via3_not_mt.non_rectangles") + + out = polygon_layer + drc_check(outputs.push({category: "via3.1_a", description: "via3.1_a : minimum width of via3 : 0.2um", data: out}), Array.new.push({name: "via3_not_mt", layer: via3_not_mt}), "via3_not_mt.width_check(0.2/#{lay.dbu})") + + out = polygon_layer + drc_check(outputs.push({category: "via3.1_b", description: "via3.1_b : minimum/maximum width of via3 : 0.2um", data: out}), Array.new.push({name: "via3_not_mt", layer: via3_not_mt}), "via3_not_mt.edges.with_length(0.2/#{lay.dbu}, true)") + + via3.isolated(0.2, euclidian).output("via3.2", "via3.2 : min. via3 spacing : 0.2um") + + deep; log_modes() + m3.enclosing(via3, 0.06, euclidian).output("via3.4", "via3.4 : min. m3 enclosure of via3 : 0.06um") + Tiled(); log_modes() + + out = polygon_layer + drc_check(outputs.push({category: "via3.4_a", description: "via3.4_a : non-ring via3 must be enclosed by met3", data: out}), Array.new.push({name: "rectVIA3", layer: rectVIA3}, {name: "m3", layer: m3}), "rectVIA3 - m3") + + deep; log_modes() + via_edges_with_less_enclosure = m3.enclosing(via3, 0.09, projection).second_edges + error_corners = via_edges_with_less_enclosure.width(angle_limit(100.0), 1.dbu) + via3_interact = via3.interacting(error_corners.polygons(1.dbu)) + via3_interact.output("via3.5", "via3.5 : min. m3 enclosure of via3 of 2 opposite edges : 0.09um") + Tiled(); log_modes() + +end + +# m4 +deep; log_modes() + huge_m4 = m4.sized(-1.5).sized(1.5).snap(0.005) & m4 + non_huge_m4 = m4.edges - huge_m4 + huge_m4 = huge_m4.edges.outside_part(m4.merged) +Tiled(); log_modes() + +out = polygon_layer +drc_check(outputs.push({category: "m4.1", description: "m4.1 : min. m4 width : 0.3um", data: out}), Array.new.push({name: "m4", layer: m4}), "m4.width_check(0.3/#{lay.dbu})") + +out = polygon_layer +drc_check(outputs.push({category: "m4.2", description: "m4.2 : min. m4 spacing : 0.3um", data: out}), Array.new.push({name: "m4", layer: m4}), "non_huge_m4.space_check(0.3/#{lay.dbu})") + +deep; log_modes() + m4.with_area(0..0.240).output("m4.4a", "m4.4a : min. m4 area : 0.240um²") +Tiled(); log_modes() + +out = polygon_layer +drc_check(outputs.push({category: "m4.5ab", description: "m4.5ab : min. 3um.m4 spacing m4 : 0.4um", data: out}), Array.new.push({name: "huge_m4", layer: huge_m4}, {name: "non_huge_m4", layer: non_huge_m4}), "huge_m4.separation_check(non_huge_m4, 0.4/#{lay.dbu}) + huge_m4.space_check(0.4/#{lay.dbu})") + +if backend_flow = AL + deep; log_modes() + m4.enclosing(via3, 0.065, euclidian).output("m4.3", "m4.3 : min. m4 enclosure of via3 : 0.065um") + via3.not(m4).output("m4.3_a", "m4.3_a : via3 must be enclosed by met4") + Tiled(); log_modes() +end + +# via4 +ringVIA4 = via4.drc(with_holes > 0) +rectVIA4 = via4.not(ringVIA4) +via4_not_mt = rectVIA4.not(areaid_mt) + +out = polygon_layer +drc_check(outputs.push({category: "via4.1", description: "via4.1 : via4 outside of moduleCut should be rectangular", data: out}), Array.new.push({name: "via4_not_mt", layer: via4_not_mt}), "via4_not_mt.non_rectangles") + +out = polygon_layer +drc_check(outputs.push({category: "via4.1_a", description: "via4.1_a : min. width of via4 outside of moduleCut : 0.8um", data: out}), Array.new.push({name: "via4_not_mt", layer: via4_not_mt}), "via4_not_mt.width_check(0.8/#{lay.dbu})") + +out = polygon_layer +drc_check(outputs.push({category: "via4.1_b", description: "via4.1_b : maximum length of via4 : 0.8um", data: out}), Array.new.push({name: "via4_not_mt", layer: via4_not_mt}), "via4_not_mt.edges.with_length(0.8/#{lay.dbu}, true)") + +via4.isolated(0.8, euclidian).output("via4.2", "via4.2 : min. via4 spacing : 0.8um") + +ringVIA4.drc(0.2.um < width <= 0.205.um).output("via4.3", "via4.3 : min./max width of ring-shaped via4 : 0.2um/0.205um") +out = polygon_layer +drc_check(outputs.push({category: "via4.3_b", description: "via4.3_b : ring-shaped via4 must be enclosed by areaid_sl", data: out}), Array.new.push({name: "ringVIA4", layer: ringVIA4}), "ringVIA4 - areaid_sl") + +deep; log_modes() + m4.enclosing(via4, 0.19, euclidian).output("via4.4", "via4.4 : min. m4 enclosure of via4 : 0.19um") + via4.not(m4).output("via4.4_a", "via4.4_a : m4 must enclose all via4") +Tiled(); log_modes() + +# m5 +out = polygon_layer +drc_check(outputs.push({category: "m5.1", description: "m5.1 : min. m5 width : 1.6um", data: out}), Array.new.push({name: "m5", layer: m5}), "m5.width_check(1.6/#{lay.dbu})") + +out = polygon_layer +drc_check(outputs.push({category: "m5.2", description: "m5.2 : min. m5 spacing : 1.6um", data: out}), Array.new.push({name: "m5", layer: m5}), "m5.space_check(1.6/#{lay.dbu})") + +deep; log_modes() + m5.enclosing(via4, 0.31, euclidian).output("m5.3", "m5.3 : min. m5 enclosure of via4 : 0.31um") + via4.not(m5).output("m5.3_a", "m5.3_a : min. m5 enclosure of via4 : 0.31um") +Tiled(); log_modes() + +m5.with_area(0..4.0).output("m5.4", "m5.4 : min. m5 area : 4.0um²") + +# pad +deep; log_modes() + pad.isolated(1.27, euclidian).output("pad.2", "pad.2 : min. pad spacing : 1.27um") +Tiled(); log_modes() + +log("BEOL queued, executing the rules...") + +$tp.execute("DRC") + +log("BEOL execution done") + +end #BEOL + +outputs.each do |outs| + outs[:data].output(outs[:category], outs[:description]) +end diff --git a/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/test_suite.sh b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/test_suite.sh new file mode 100755 index 00000000..329546ea --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/tech/sky130A/test_suite.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +: ${1?"Usage: $0 gds input file"} +: ${2?"Usage: $0 report name"} + +threads=(200 150 100 50 25 20 15 10 8 4 2 1) +tiles=(1000 800 600 400 200 100 50 10) + +echo "design, report, start_date, end_date, threads, tiles" >> test_suite.csv + +for thr in ${threads[@]}; do + for tile in ${tiles[@]}; do + start=$(date +"%r") + /ciic/tools/bin/klayout -rd input=$1 -rd report=$2.$thr.$tile -rd thr=$thr -rd tiles=$tile -rd beol=1 -rd feol=1 -zz -r sky130A_mr_opt.drc + end=$(date +"%r") + echo "start: $start \nend: $end" + + echo "$1, $2.$thr.$tile, $start, $end, $thr, $tile" >> test_suite.csv + done +done diff --git a/images/foss-asic-tools/addons/sak/klayout/xor.drc b/images/foss-asic-tools/addons/sak/klayout/xor.drc new file mode 100755 index 00000000..1c451bea --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/xor.drc @@ -0,0 +1,42 @@ +# A general XOR script +# (https://www.klayout.de/forum/discussion/100/xor-vs-diff-tool) +# This script uses KLayout's DRC language to implement a generic +# XOR between two layouts. The name of the layouts is given +# in $a and $b. + +# For layout-to-layout XOR with multiple cores, run this script with +# ./klayout -r xor.drc -rd thr=NUM_CORES -rd top_cell=TOP_CELL_NAME -rd a=a.gds -rd b=b.gds -rd ol=xor.gds -zz +# (replace NUM_CORES by the desired number of cores to utilize + +# enable timing output +verbose + +# set up input a +a = source($a, $top_cell) + +# set up input b +b = source($b, $top_cell) + +$o && $ext != "gds" && report("XOR #{$a} vs. #{$b}", $o) +$ol && $ext == "gds" && target($ol, $co || "XOR") + +$thr && threads($thr) || threads(8) + +# collect all common layers +layers = {} +[ a.layout, b.layout ].each do |ly| + ly.layer_indices.each do |li| + i = ly.get_info(li) + layers[i.to_s] = i + end +end + +# perform the XOR's +layers.keys.sort.each do |l| + i = layers[l] + info("--- Running XOR for #{l} ---") + x = a.input(l) ^ b.input(l) + info("XOR differences: #{x.data.size}") + $o && $ext != "gds" && x.output(l, "XOR results for layer #{l} #{i.name}") + $ol && $ext == "gds" && x.output(i.layer, i.datatype, i.name) +end diff --git a/images/foss-asic-tools/addons/sak/klayout/xor.sh b/images/foss-asic-tools/addons/sak/klayout/xor.sh new file mode 100755 index 00000000..b58d0dd6 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/xor.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +: ${1?"Usage: $0 file1.gds file2.gds output.gds|markers.xml"} +: ${2?"Usage: $0 file1.gds file2.gds output.gds|markers.xml"} +: ${3?"Usage: $0 file1.gds file2.gds output.gds|markers.xml"} +: ${4?"Usage: $0 file1.gds file2.gds output.gds|markers.xml"} + + +echo "First Layout: $1" +echo "Second Layout: $2" +echo "Design Name: $3" +echo "Output GDS will be: $4" + +start=$(date +"%r") +xvfb-run -a klayout -r $(dirname $0)/xor_opt.drc \ + -rd top_cell=$3 \ + -rd a=$1 \ + -rd b=$2 \ + -rd output=$4 \ + -rd thr=8 + # -rd ol=$4 \ + # -rd o=$4 \ + # -rd ext=${4##*.} \ + # -zz +end=$(date +"%r") +echo "start: $start \nend:$end" diff --git a/images/foss-asic-tools/addons/sak/klayout/xor_opt.drc b/images/foss-asic-tools/addons/sak/klayout/xor_opt.drc new file mode 100755 index 00000000..f1e7aa1c --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout/xor_opt.drc @@ -0,0 +1,65 @@ +# A general XOR script +# (https://www.klayout.de/forum/discussion/100/xor-vs-diff-tool) +# This script uses KLayout's DRC language to implement a generic +# XOR between two layouts. The name of the layouts is given +# in $a and $b. + +# For layout-to-layout XOR with multiple cores, run this script with +# ./klayout -r xor.drc -rd thr=NUM_CORES -rd top_cell=TOP_CELL_NAME -rd a=a.gds -rd b=b.gds -rd ol=xor.gds -zz +# (replace NUM_CORES by the desired number of cores to utilize + +# enable timing output +verbose + +# set up input a +a = source($a, $top_cell) +$lay_a = a.layout +#$lay_a.flatten($lay_a.top_cell().cell_index, 1, false) + +# set up input b +b = source($b, $top_cell) +$lay_b = b.layout +#$lay_b.flatten($lay_b.top_cell().cell_index, 1, false) + +outputs = Array.new + +$tp = RBA::TilingProcessor::new +$tp.tile_size(500, 500) +$tp.threads = $thr.to_i +$tp.dbu = $lay_a.dbu + +$count = 0 + +o = RBA::Layout::new +cell = o.create_cell($top_cell.to_s) +cell_ind = cell.cell_index() + +def xor(output, layer_i) + + $tp.output("output_#{$count}", output[$count][:data].data) + $tp.input("a1", $lay_a, $lay_a.top_cell().cell_index, layer_i ) + $tp.input("a2", $lay_b, $lay_b.top_cell().cell_index, layer_i ) + $tp.queue("_output(output_#{$count}, a1 ^ a2)") + $count = $count + 1 + +end + +# collect all common layers +layers = {} +[ a.layout, b.layout ].each do |ly| + ly.layer_indices.each do |li| + i = ly.get_info(li) + out = polygon_layer + xor(outputs.push({"layer": i, "data": out}), i) + end +end + + +$tp.execute("XOR") + +puts "Writing gds output file" + +outputs.each do |outs| + cell.shapes(o.layer(outs[:layer])).insert(outs[:data].data) +end +o.write($output) \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/klayout_pip_drc_checks/klayout_pypi_cell_freshness.py b/images/foss-asic-tools/addons/sak/klayout_pip_drc_checks/klayout_pypi_cell_freshness.py new file mode 100755 index 00000000..94034f63 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout_pip_drc_checks/klayout_pypi_cell_freshness.py @@ -0,0 +1,128 @@ +#!/bin/python3.8 +import os +import gc +import argparse +import re +import logging +import sys +from pathlib import Path + +import coloredlogs +import klayout.db as pya +import klayout.rdb as rdb +from termcolor import colored + +# Needed for script wide deep mode analysis +global_dss = None + + +def cell_xor(cella, cellb, flat): + violation_region = pya.Region() + # To have all possible layers between the two cells + for layer_info in set([*cella.layout().layer_infos(), *cellb.layout().layer_infos()]): + cella_layer = cella.begin_shapes_rec(cella.layout().layer(layer_info.layer, layer_info.datatype)) + cellb_layer = cellb.begin_shapes_rec(cellb.layout().layer(layer_info.layer, layer_info.datatype)) + if not flat: + violation_region.insert(pya.Region(cella_layer, global_dss) ^ pya.Region(cellb_layer, global_dss)) + else: + violation_region.insert(pya.Region(cella_layer) ^ pya.Region(cellb_layer)) + del cella_layer + del cellb_layer + gc.collect() + return violation_region + +def cell_freshness_check(layout_path, pdk_root, break_on_single_rotten_cell, flat, check_sram_cells, close_matching, markers_output_file): + report = rdb.ReportDatabase("Cell Freshness Check") + layout_ut = pya.Layout() + layout_ut.read(str(layout_path)) + sky130A_pdk_layouts_list = [] + for path in list((pdk_root / 'sky130A/libs.ref/').rglob('*.gds')): + if not check_sram_cells and 'sram' in path.name: + continue + else: + sky130A_pdk_cells_layout = pya.Layout() + sky130A_pdk_cells_layout.read(str(path)) + sky130A_pdk_layouts_list.append(sky130A_pdk_cells_layout) + + sky130A_pdk_cells = {} + for asky130A_pdk_layout in sky130A_pdk_layouts_list: + for sky130A_pdk_cell in asky130A_pdk_layout.top_cells(): + sky130A_pdk_cells[sky130A_pdk_cell.name] = sky130A_pdk_cell + layout_ut_cells = {layout_ut_cell.name: layout_ut_cell for layout_ut_cell in layout_ut.each_cell()} + + test_matches = {} + # This is needed because some tools add some prefixes to the cell name while writing gds (example: magic) + if close_matching: + for layout_ut_cell in layout_ut_cells.values(): + for sky130A_pdk_cell in sky130A_pdk_cells.values(): + # This workaround exists specifically for magic to adhere to some prefix addition to cell name + # TODO: might need removal later on + if sky130A_pdk_cell.name == layout_ut_cell.name or re.match(layout_ut_cell.name, rf".*_{sky130A_pdk_cell.name}$"): + test_matches[layout_ut_cell] = sky130A_pdk_cell + else: + for layout_ut_cell in layout_ut_cells.values(): + if layout_ut_cell.name in sky130A_pdk_cells: + test_matches[layout_ut_cell] = sky130A_pdk_cells[layout_ut_cell.name] + + #TODO:remove all prints in favor of logging + rotten_cells = {} + fresh_cells = {} + logging.info(f"{'sky130 pdk':<50}{layout_path.stem:<70}EQUIVALENT") + logging.info(f"{'':_<130}") + for layout_ut_cell, sky130A_pdk_cell in test_matches.items(): + logging.root.handlers[0].terminator = "" + logging.info(f"{sky130A_pdk_cell.name:<50}{layout_ut_cell.name:<70}") + logging.root.handlers[0].terminator ="\n" + difference = cell_xor(cella=sky130A_pdk_cell, cellb=layout_ut_cell, flat=flat) + if difference.is_empty(): + logging.info(colored("YES", "green")) + fresh_cells[layout_ut_cell.name] = layout_ut_cell + else: + logging.error(colored("NO", "red")) + rotten_cells[layout_ut_cell.name] = layout_ut_cell + category_inst = report.create_category(f"PDK {sky130A_pdk_cell.name} compared to {layout_path.name} {layout_ut_cell.name}") + report.create_items(report.create_cell(layout_ut_cell.name).rdb_id(), category_inst.rdb_id(), + pya.CplxTrans(layout_ut_cell.layout().dbu), difference) + if break_on_single_rotten_cell: + break + # delete cell to free memory + del layout_ut_cell + del sky130A_pdk_cell + gc.collect() + logging.info( f"""\n{'Summary':_^130}\n + sky130A_pdk + {len(sky130A_pdk_cells):^30} sky130 cells + {len([sky130A_pdk_cell for sky130A_pdk_cell in sky130A_pdk_cells.values() if sky130A_pdk_cell.is_ghost_cell()]):^30} sky130 ghost cells + {layout_path.stem} + {len(layout_ut_cells):^30} cells + {len(rotten_cells):^30} Rotten sky130 Cells + {len(fresh_cells):^30} Fresh sky130 Cells + {len(layout_ut_cells) - len(fresh_cells) - len(rotten_cells):^30} Not-Tested Cells + {len([layout_ut_cell for layout_ut_cell in layout_ut_cells.values() if layout_ut_cell.is_ghost_cell()]):^30} ghost cells""") + if markers_output_file: + report.save(str(markers_output_file)) + return len(rotten_cells) == 0 + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("-l", "--layout_path", required=True, type=Path, help="Layout path") + parser.add_argument("-p", "--pdk_root", required=True, type=Path, help="PDK root directory") + parser.add_argument("-b", "--break_on_single_rotten_cell", action="store_true", default=False, required=False, + help="if specified the check exits on a single violation instead of running the check on all cells") + parser.add_argument("-f", "--flat", action="store_true", default=False, required=False, + help="enable flat mode analysis (instead of hierarchical)") + parser.add_argument("-s", "--check_sram_cells", action="store_true", default=False, required=False, + help="Run cell equivalency on ram cells, which are huge(very slow)") + parser.add_argument("-c", "--close_matching", action="store_true", default=False, required=False, + help="Comparison done between cells with names the resemble each other (as opposed to exactly matching which is default) ") + parser.add_argument("-m", "--markers_output_file", required=False, type=Path, help="violating shapes markers file path") + args = parser.parse_args() + + logging.basicConfig(level=logging.DEBUG, format=f"%(message)s", stream=sys.stdout) + if not args.flat: + # To enable faster analysis + global_dss = pya.DeepShapeStore() + # global_dss.threads = 4 + # global_dss.threads = os.cpu_count() + cell_freshness_check(Path(args.layout_path).absolute(), Path(args.pdk_root).absolute(), args.break_on_single_rotten_cell, + args.flat, args.check_sram_cells, args.close_matching, args.markers_output_file) diff --git a/images/foss-asic-tools/addons/sak/klayout_pip_drc_checks/klayout_pypi_nonoverlapping.py b/images/foss-asic-tools/addons/sak/klayout_pip_drc_checks/klayout_pypi_nonoverlapping.py new file mode 100755 index 00000000..8aaac36f --- /dev/null +++ b/images/foss-asic-tools/addons/sak/klayout_pip_drc_checks/klayout_pypi_nonoverlapping.py @@ -0,0 +1,83 @@ +#!/bin/python3.8 +import klayout.db as pya +import klayout.rdb as rdb +import argparse +import time +import gc +from termcolor import colored +from pprint import pprint +from pathlib import Path + +class Material: + def __init__(self, name, bottom, list_of_tops): + self.name = name + self.bottom = bottom + self.list_of_tops = list_of_tops + +def mark_metal_purpose_not_overlapping_drawing(layout_path, markers_output_file, flat): + layout_ut = pya.Layout() + layout_ut.read(str(layout_path)) + report = rdb.ReportDatabase(str(markers_output_file)) + rdb_top_cell = report.create_cell(layout_ut.top_cell().name) + + if not flat: + dss = pya.DeepShapeStore() + materials = [ + Material("nwell", bottom=pya.LayerInfo(64,20), list_of_tops=[pya.LayerInfo(64,16),pya.LayerInfo(64,5)]), + Material("diff", bottom=pya.LayerInfo(65,20), list_of_tops=[pya.LayerInfo(65,16),pya.LayerInfo(65,6)]), + Material("tap", bottom=pya.LayerInfo(65,44), list_of_tops=[pya.LayerInfo(65,48),pya.LayerInfo(65,5)]), + Material("poly", bottom=pya.LayerInfo(66,20), list_of_tops=[pya.LayerInfo(66,16),pya.LayerInfo(66,5)]), + Material("licon1", bottom=pya.LayerInfo(66,44), list_of_tops=[pya.LayerInfo(66,58)]), + Material("li1", bottom=pya.LayerInfo(67,20), list_of_tops=[pya.LayerInfo(67,16),pya.LayerInfo(67,5)]), + Material("mcon", bottom=pya.LayerInfo(67,44), list_of_tops=[pya.LayerInfo(67,48)]), + Material("met1", bottom=pya.LayerInfo(68,20), list_of_tops=[pya.LayerInfo(68,16),pya.LayerInfo(68,5)]), + Material("via", bottom=pya.LayerInfo(68,44), list_of_tops=[pya.LayerInfo(68,58)]), + Material("met2", bottom=pya.LayerInfo(69,20), list_of_tops=[pya.LayerInfo(69,16),pya.LayerInfo(69,5)]), + Material("via2", bottom=pya.LayerInfo(69,44), list_of_tops=[pya.LayerInfo(69,58)]), + Material("met3", bottom=pya.LayerInfo(70,20), list_of_tops=[pya.LayerInfo(70,16),pya.LayerInfo(70,5)]), + Material("via3", bottom=pya.LayerInfo(70,44), list_of_tops=[pya.LayerInfo(70,48)]), + Material("met4", bottom=pya.LayerInfo(71,20), list_of_tops=[pya.LayerInfo(71,16),pya.LayerInfo(71,5)]), + Material("via4", bottom=pya.LayerInfo(71,44), list_of_tops=[pya.LayerInfo(71,48)]), + Material("met5", bottom=pya.LayerInfo(72,20), list_of_tops=[pya.LayerInfo(72,16),pya.LayerInfo(72,5)]), + Material("pad", bottom=pya.LayerInfo(76,20), list_of_tops=[pya.LayerInfo(76,5),pya.LayerInfo(76,16)]), + Material("pnp", bottom=pya.LayerInfo(82,44), list_of_tops=[pya.LayerInfo(82,59)]), + Material("npn", bottom=pya.LayerInfo(82,20), list_of_tops=[pya.LayerInfo(82,5)]), + Material("rdl", bottom=pya.LayerInfo(74,20), list_of_tops=[pya.LayerInfo(74,16),pya.LayerInfo(74,5)]), + Material("inductor", bottom=pya.LayerInfo(82,24), list_of_tops=[pya.LayerInfo(82,25)])] + + for amaterial in materials: + print(f"{amaterial.name}") + for atop in amaterial.list_of_tops: + if not flat: + layer_top = pya.Region(layout_ut.top_cell().begin_shapes_rec(layout_ut.layer(atop.layer, atop.datatype)), dss) + layer_bot = pya.Region(layout_ut.top_cell().begin_shapes_rec(layout_ut.layer(amaterial.bottom.layer, amaterial.bottom.datatype)), dss) + else: + layer_top = pya.Region(layout_ut.top_cell().begin_shapes_rec(layout_ut.layer(atop.layer, atop.datatype))) + layer_bot = pya.Region(layout_ut.top_cell().begin_shapes_rec(layout_ut.layer(amaterial.bottom.layer, amaterial.bottom.datatype))) + + msg = f"{atop.layer}/{atop.datatype} over {amaterial.bottom.layer}/{amaterial.bottom.datatype}" + print(f"{msg:>40} ", end="") + violating_region = layer_top - layer_bot + + if violating_region.is_empty(): + print(colored(f"{'SUCCESS':^50}", "green")) + else: + print(colored(f"{'FAILURE':^50}", "red")) + category_inst = report.create_category(f"{atop.layer}/{atop.datatype}") + report.create_items(rdb_top_cell.rdb_id(), category_inst.rdb_id(), pya.CplxTrans(layout_ut.dbu), violating_region) + del violating_region + del layer_top + gc.collect() + del layer_bot + gc.collect() + report.save(str(markers_output_file)) + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("-l", "--layout_path", required=True, type=Path, help="Layout path") + parser.add_argument("-m", "--markers_output_file", required=True, type=Path, help="Violating shapes markers file path") + parser.add_argument("-f", "--flat", required=False, action="store_true", help="Specify flat mode analysis (versus deep), default: False") + args = parser.parse_args() + layout_path = Path(args.layout_path).absolute() + markers_output_file = Path(args.markers_output_file).absolute() + mark_metal_purpose_not_overlapping_drawing(layout_path, markers_output_file, args.flat) diff --git a/images/foss-asic-tools/addons/sak/magic/README.md b/images/foss-asic-tools/addons/sak/magic/README.md new file mode 100755 index 00000000..daa5515d --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/README.md @@ -0,0 +1,3 @@ +# What is this? + +Core scripts are doing the actual work, scripts under ../scripts are the ones that should be used. \ No newline at end of file diff --git a/images/foss-asic-tools/addons/sak/magic/antenna-check-gds.sh b/images/foss-asic-tools/addons/sak/magic/antenna-check-gds.sh new file mode 100755 index 00000000..2d1a5ec6 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/antenna-check-gds.sh @@ -0,0 +1,30 @@ +#!/bin/sh +export MAGIC=/ef/apps/ocd/magic/8.3.179-202106141345/bin/magic +export MAGTYPE=maglef; +export PDKPATH=$PDK_ROOT/sky130A ; + +$MAGIC -dnull -noconsole -rcfile $PDKPATH/libs.tech/magic/sky130A.magicrc < [ default is /results/] + +export TARGET_DIR=$1 +export DESIGN_NAME=$2 +export PDK_ROOT=$3 +export OUT_DIR=${4:-$TARGET_DIR/results/} + + +if ! [[ -d "$OUT_DIR" ]] +then + mkdir $OUT_DIR +fi +bash $SAK/magic/magic-drc.sh $TARGET_DIR $DESIGN_NAME $PDK_ROOT "def" "sky130A" $OUT_DIR $SAK/magic/tcl diff --git a/images/foss-asic-tools/addons/sak/magic/drc-gds-full-EFS8A.sh b/images/foss-asic-tools/addons/sak/magic/drc-gds-full-EFS8A.sh new file mode 100755 index 00000000..ecbb774c --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/drc-gds-full-EFS8A.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +export GDS_FILE_PATH=$1 +export CELL_NAME=$2 +export PDK_ROOT=/ef/tech/SW/ +export PDKPATH=/ef/tech/SW/EFS8A/ +export VERSION="current" +export OUT_DIR=./results.drc.$2 + +if ! [[ -d "$OUT_DIR" ]] +then + mkdir $OUT_DIR +fi + +cd $OUT_DIR + +# magicGdrc -T $PDKPATH/libs.tech/magic/$VERSION/EFS8A.tech -I vendorimport -S 'drc(full)' -l $OUT_DIR/$2.drc.out -km $OUT_DIR/$2.drc.km ../$GDS_FILE_PATH $CELL_NAME + +magicGdrc -T $PDKPATH/libs.tech/magic/$VERSION/EFS8A.tech -I vendorimport -S 'drc(fast)' -l $2.drc.out -km $2.drc.km $GDS_FILE_PATH $CELL_NAME + +cd .. + +echo "#############################################" +echo "Check the results in" "$OUT_DIR" +echo "#############################################" + +<< COMMENT + +usage: [ -T techfilePath ] [-S ] [-I ] [-km FILE_NAME] [-l FILE_NAME] [-L FILE_NAME] gdsFileName [topCellName] + -T if given, must be very first + -S if given, changes from techfile's default/1st drc style (perhaps "drc(fast)") to named style, for example: -S "drc(full)" + -I if given, changes from techfile's default/1st cifinput style (perhaps "vendorimport" or "import(exact)") to named style, for example: -I "import(magic)" + -path-sub do 'gds path subcell yes' (default:no). Make unique subcell for each path: cut #tiles cost of angles. + -poly-sub do 'gds polygon subcell yes' (default:no). Make unique subcell for each polygon: cut #tiles cost of angles. + -pps Short hand, equivalent to giving both: -path-sub -poly-sub + + Error tabulation: By default (slowest, most detail): Report table of counts-by-errorString for all cells. + Stdout logs a pareto of error-type by count unless disabled for some/all cells by below; topcell last. + -tt Table of counts-by-errorString for ONLY topcell; and just lumped total error count per subcell. + -tc Just lumped error counts per cell including topcell (fastest, least detail). + Cells NOT tabulating count-by-errorString can't appear in other output error files: feedback(*.drtcl), -l, -km. + For lumped error counts, overlapped error shapes from unique error-types are merged further reducing count. + + cell-type +-- (default) --+-- option -tt --+-- option -tc + subcell | count-by-errorString | lumped-error-count | lumped-error-count + topcell | count-by-errorString | count-by-errorString | lumped-error-count + + -km if given, write to FILE_NAME EVERY individual error bbox (MICRONS) in klayout Marker database(XML) format (suggest *.lyrdb) + -l if given, enumerates EVERY individual error bbox (MICRONS) to FILE_NAME, emulates /ef/efabless/lib/magic/tcl/drc.tcl + -L same as -l above, but outputs bbox-es in LAMBDA coordinates, not microns + -nf Do NOT write *.drtcl per-cell feedback files. Can be source-ed in magic and step thru: feedback find. + + NOTES: Without explicit tech-file option: the ./.magicrc or ./magic_setup and ~/.magicrc may load a default tech-file. + Therefore the tech-file used CAN depend on whether your CWD is ~/design//mag when running this script. + Since no *.mag are loaded by this script: the cell search path defined by any init files has no impact. + Since about 8.3.68, magic may generate error-type "See error definition in the subcell". There typically are + redundancies of errors across the hierarchy anyway (but with tech-file err-strings), this seems another form. + +example, just list all styles: by causing an error which provokes usage report: + magicGdrc -T /ef/tech/XFAB/EFXH035B/libs.tech/magic/current/EFXH035B.tech +example, same but run in a ~/design/*/mag/ dir, so techfile set by ./.magicrc (else magic's builtin minimum.tech): + magicGdrc +example, run GDS drc, explicit: tech, cif-istyle, drc-style: + magicGdrc -T /ef/tech/SW/EFS8A/libs.tech/magic/current/EFS8A.tech -I vendorimport -S 'drc(full)' /tmp/mytop.gds mytopcell +example, run GDS drc, default tech & styles, write klayout marker database, no per-cell *.drtcl feedback files: + magicGdrc -km /tmp/mytop.lyrdb -nf /tmp/mytop.gds mytopcell +example, same but make subcells for paths & polygons + magicGdrc -km /tmp/mytop.lyrdb -nf -pps /tmp/mytop.gds mytopcell +example, run GDS drc, no feedback (*.drtcl), only lumped/merged err-count for all cells + magicGdrc -tc /tmp/mytop.gds mytopcell +example, run GDS drc, no feedback (*.drtcl), lumped/merged err-count for subcells, detail errors for topcell + magicGdrc -nf -tt /tmp/mytop.gds mytopcell + +magicGdrc: tech-name: minimum -version: 0.0 {Minimum technology file structure} -filename: /ef/efabless/lib/magic/sys/minimum.tech -lambda 1 1 +info: magicGdrc: drc styles available: default + +ERROR: magicGdrc: Insufficient number of arguments, need gdsFileName [topCellName] + +COMMENT + + diff --git a/images/foss-asic-tools/addons/sak/magic/drc-gds-sky130A.sh b/images/foss-asic-tools/addons/sak/magic/drc-gds-sky130A.sh new file mode 100755 index 00000000..ace943d6 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/drc-gds-sky130A.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# SPDX-License-Identifier: Apache-2.0 + + +export MAGTYPE=mag ; +export PDKPATH=$PDK_ROOT=~/foss/pdks ; + +magic -dnull -noconsole -rcfile $PDKPATH/libs.tech/magic/current/sky130A.magicrc < [ default is /results/] + +export TARGET_DIR=$1 +export DESIGN_NAME=$2 +export PDK_ROOT=$3 +export OUT_DIR=${4:-$TARGET_DIR/results/} +export TCL_CALL_PATH=$(pwd)/core_scripts + +if ! [[ -d "$OUT_DIR" ]] +then + mkdir $OUT_DIR +fi + +bash $SAK/magic/magic-drc.sh $TARGET_DIR $DESIGN_NAME $PDK_ROOT "gds" "sky130A" $OUT_DIR $SAK/magic/tcl diff --git a/images/foss-asic-tools/addons/sak/magic/drc-mag-full-EFS8A.sh b/images/foss-asic-tools/addons/sak/magic/drc-mag-full-EFS8A.sh new file mode 100755 index 00000000..5859f4c5 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/drc-mag-full-EFS8A.sh @@ -0,0 +1,95 @@ +#!/bin/bash +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +export MAG_FILE_PATH=$1 +export PDK_ROOT=/ef/tech/SW/ +export PDKPATH=/ef/tech/SW/EFS8A/ +export VERSION="current" +export OUT_DIR=./results.drc.$2 + +#if ! [[ -d "$OUT_DIR" ]] +#then +# mkdir $OUT_DIR +#fi + +#cd $OUT_DIR + +# magicDrc -T $PDKPATH/libs.tech/magic/$VERSION/EFS8A.tech -I vendorimport -S 'drc(full)' -l $OUT_DIR/$2.drc.out -km $OUT_DIR/$2.drc.km ../$MAG_FILE_PATH $CELL_NAME + +# magicDrc -T $PDKPATH/libs.tech/magic/$VERSION/EFS8A.tech -I vendorimport -S 'drc(fast)' -l $2.drc.out -km $2.drc.km ../$MAG_FILE_PATH $CELL_NAME + +magicDrc -T $PDKPATH/libs.tech/magic/$VERSION/EFS8A.tech -S 'drc(fast)' -l $2.drc.out $MAG_FILE_PATH + +#cd .. + +#echo "#############################################" +#echo "Check the results in" "$OUT_DIR" +#echo "#############################################" + +<< COMMENT + +usage: [ -T techfilePath ] [-S ] [-I ] [-km FILE_NAME] [-l FILE_NAME] [-L FILE_NAME] gdsFileName [topCellName] + -T if given, must be very first + -S if given, changes from techfile's default/1st drc style (perhaps "drc(fast)") to named style, for example: -S "drc(full)" + -I if given, changes from techfile's default/1st cifinput style (perhaps "vendorimport" or "import(exact)") to named style, for example: -I "import(magic)" + -path-sub do 'gds path subcell yes' (default:no). Make unique subcell for each path: cut #tiles cost of angles. + -poly-sub do 'gds polygon subcell yes' (default:no). Make unique subcell for each polygon: cut #tiles cost of angles. + -pps Short hand, equivalent to giving both: -path-sub -poly-sub + + Error tabulation: By default (slowest, most detail): Report table of counts-by-errorString for all cells. + Stdout logs a pareto of error-type by count unless disabled for some/all cells by below; topcell last. + -tt Table of counts-by-errorString for ONLY topcell; and just lumped total error count per subcell. + -tc Just lumped error counts per cell including topcell (fastest, least detail). + Cells NOT tabulating count-by-errorString can't appear in other output error files: feedback(*.drtcl), -l, -km. + For lumped error counts, overlapped error shapes from unique error-types are merged further reducing count. + + cell-type +-- (default) --+-- option -tt --+-- option -tc + subcell | count-by-errorString | lumped-error-count | lumped-error-count + topcell | count-by-errorString | count-by-errorString | lumped-error-count + + -km if given, write to FILE_NAME EVERY individual error bbox (MICRONS) in klayout Marker database(XML) format (suggest *.lyrdb) + -l if given, enumerates EVERY individual error bbox (MICRONS) to FILE_NAME, emulates /ef/efabless/lib/magic/tcl/drc.tcl + -L same as -l above, but outputs bbox-es in LAMBDA coordinates, not microns + -nf Do NOT write *.drtcl per-cell feedback files. Can be source-ed in magic and step thru: feedback find. + + NOTES: Without explicit tech-file option: the ./.magicrc or ./magic_setup and ~/.magicrc may load a default tech-file. + Therefore the tech-file used CAN depend on whether your CWD is ~/design//mag when running this script. + Since no *.mag are loaded by this script: the cell search path defined by any init files has no impact. + Since about 8.3.68, magic may generate error-type "See error definition in the subcell". There typically are + redundancies of errors across the hierarchy anyway (but with tech-file err-strings), this seems another form. + +example, just list all styles: by causing an error which provokes usage report: + magicGdrc -T /ef/tech/XFAB/EFXH035B/libs.tech/magic/current/EFXH035B.tech +example, same but run in a ~/design/*/mag/ dir, so techfile set by ./.magicrc (else magic's builtin minimum.tech): + magicGdrc +example, run GDS drc, explicit: tech, cif-istyle, drc-style: + magicGdrc -T /ef/tech/SW/EFS8A/libs.tech/magic/current/EFS8A.tech -I vendorimport -S 'drc(full)' /tmp/mytop.gds mytopcell +example, run GDS drc, default tech & styles, write klayout marker database, no per-cell *.drtcl feedback files: + magicGdrc -km /tmp/mytop.lyrdb -nf /tmp/mytop.gds mytopcell +example, same but make subcells for paths & polygons + magicGdrc -km /tmp/mytop.lyrdb -nf -pps /tmp/mytop.gds mytopcell +example, run GDS drc, no feedback (*.drtcl), only lumped/merged err-count for all cells + magicGdrc -tc /tmp/mytop.gds mytopcell +example, run GDS drc, no feedback (*.drtcl), lumped/merged err-count for subcells, detail errors for topcell + magicGdrc -nf -tt /tmp/mytop.gds mytopcell + +magicGdrc: tech-name: minimum -version: 0.0 {Minimum technology file structure} -filename: /ef/efabless/lib/magic/sys/minimum.tech -lambda 1 1 +info: magicGdrc: drc styles available: default + +ERROR: magicGdrc: Insufficient number of arguments, need gdsFileName [topCellName] + +COMMENT + + diff --git a/images/foss-asic-tools/addons/sak/magic/drc-mag-sky130A.sh b/images/foss-asic-tools/addons/sak/magic/drc-mag-sky130A.sh new file mode 100755 index 00000000..5790ca5f --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/drc-mag-sky130A.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# SPDX-License-Identifier: Apache-2.0 + +# To call: ./drc-mag-sky130A.sh [ default is /results/] + +export TARGET_DIR=$1 +export DESIGN_NAME=$2 +export PDK_ROOT=$3 +export OUT_DIR=${4:-$TARGET_DIR/results/} + + +if ! [[ -d "$OUT_DIR" ]] +then + mkdir $OUT_DIR +fi +bash $SAK/magic/magic-drc.sh $TARGET_DIR $DESIGN_NAME $PDK_ROOT "mag" "sky130A" $OUT_DIR $SAK/magic/tcl diff --git a/images/foss-asic-tools/addons/sak/magic/erase_box.sh b/images/foss-asic-tools/addons/sak/magic/erase_box.sh new file mode 100755 index 00000000..41ceb651 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/erase_box.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +: ${1?"Usage: $0 file.gds llx lly urx ury"} +: ${2?"Usage: $0 file.gds llx lly urx ury"} +: ${3?"Usage: $0 file.gds llx lly urx ury"} +: ${4?"Usage: $0 file.gds llx lly urx ury"} +: ${5?"Usage: $0 file.gds llx lly urx ury"} +: ${PDK_ROOT?"You need to export PDK_ROOT"} + + +export PDK=sky130A + +export MAGIC_MAGICRC=$PDK_ROOT/$PDK/libs.tech/magic/$PDK.magicrc + +MAGTYPE=mag magic -rcfile $MAGIC_MAGICRC -dnull -noconsole < [ default is /results/] + +export TARGET_DIR=$1 +export DESIGN_NAME=$2 +export PDK_ROOT=$3 +export OUT_DIR=${4:-$TARGET_DIR/results/} +export TCL_CALL_PATH=$(pwd)/core_scripts + +if ! [[ -d "$OUT_DIR" ]] +then + mkdir $OUT_DIR +fi + +bash $SAK/magic/magic-ext.sh $TARGET_DIR $DESIGN_NAME $PDK_ROOT "def" "sky130A" $OUT_DIR $SAK/magic diff --git a/images/foss-asic-tools/addons/sak/magic/ext-gds-sky130A.sh b/images/foss-asic-tools/addons/sak/magic/ext-gds-sky130A.sh new file mode 100755 index 00000000..edda60b3 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/ext-gds-sky130A.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# SPDX-License-Identifier: Apache-2.0 + +# To call: ./ext-gds-sky130A.sh [ default is /results/] + +export TARGET_DIR=$1 +export DESIGN_NAME=$2 +export PDK_ROOT=$3 +export OUT_DIR=${4:-$TARGET_DIR/results/} + + +if ! [[ -d "$OUT_DIR" ]] +then + mkdir $OUT_DIR +fi + +bash $SAK/magic/magic-ext.sh $TARGET_DIR $DESIGN_NAME $PDK_ROOT "gds" "sky130A" $OUT_DIR $SAK/magic/tcl diff --git a/images/foss-asic-tools/addons/sak/magic/ext-mag-sky130A.sh b/images/foss-asic-tools/addons/sak/magic/ext-mag-sky130A.sh new file mode 100755 index 00000000..f40e2111 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/ext-mag-sky130A.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# SPDX-License-Identifier: Apache-2.0 + +# To call: ./ext-mag-sky130A.sh [ default is /results/] + +export TARGET_DIR=$1 +export DESIGN_NAME=$2 +export PDK_ROOT=$3 +export OUT_DIR=${4:-$TARGET_DIR/results/} + + +if ! [[ -d "$OUT_DIR" ]] +then + mkdir $OUT_DIR +fi + +bash $SAK/magic/magic-ext.sh $TARGET_DIR $DESIGN_NAME $PDK_ROOT "mag" "sky130A" $OUT_DIR $SAK/magic/tcl diff --git a/images/foss-asic-tools/addons/sak/magic/gds2mag-te.sh b/images/foss-asic-tools/addons/sak/magic/gds2mag-te.sh new file mode 100755 index 00000000..2c50ae8e --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/gds2mag-te.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# SPDX-FileCopyrightText: 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# SPDX-License-Identifier: Apache-2.0 + +export MAGTYPE=mag ; +export PDKPATH=$PDK_ROOT/sky130A ; +export MAGIC=magic + + +$MAGIC -rcfile $PDKPATH/libs.tech/magic/current/sky130A.magicrc -dnull -noconsole << EOF +drc off +box 0 0 0 0 +load vtop.mag -force +drc off +gds readonly true +gds rescale false +gds read ${cellname}.gds +cellname rename ${cellname} vtmp +load vtmp +select top cell +set pname [lindex [cellname list children] 0] +cellname rename \\\$pname ${cellname} +select cell \\\${pname}_0 +identify ${cellname}_0 +writeall force ${cellname} +quit -noprompt +EOF diff --git a/images/foss-asic-tools/addons/sak/magic/gds2mag.sh b/images/foss-asic-tools/addons/sak/magic/gds2mag.sh new file mode 100755 index 00000000..64a76eae --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/gds2mag.sh @@ -0,0 +1,36 @@ +#!/bin/sh +# SPDX-FileCopyrightText: 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# SPDX-License-Identifier: Apache-2.0 + +export MAGTYPE=mag ; +export PDKPATH=$PDK_ROOT/sky130A ; +export MAGIC=magic + + +$MAGIC -rcfile $PDKPATH/libs.tech/magic/current/sky130A.magicrc -dnull -noconsole << EOF +#------------------------------------------------------ +drc off +#---------------------------------gds polygon subcell true +gds warning default +gds readonly true +gds rescale false +#---------------------------------tech unlock * +gds read $1 +load ${1%.gds} +#---------------------------------readspice ${1%.gds}.sp +cellname delete "(UNNAMED)" +writeall force +quit -noprompt +EOF diff --git a/images/foss-asic-tools/addons/sak/magic/gdsMergeall.drc b/images/foss-asic-tools/addons/sak/magic/gdsMergeall.drc new file mode 100755 index 00000000..e8520db5 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/gdsMergeall.drc @@ -0,0 +1,193 @@ +#!/bin/bash +# usage: gdsMergeall.drc [-f] [-t ] [-T ] +# +# For each layer: merge shapes. To eliminate/drop zero-area boundarys (fatal to some tools). +# Usually input & output file-size are close, perhaps output a little smaller. +# +# WARNING: output has ALL TEXT STRIPPED/REMOVED (i.e. text not propagated from in to out). +# WARNING: paths are converted to polygons. +# +# Intent is (default) deep-mode retains hier. as much as possible, just +# merging each layer of each cell "in-place". +# +# Exit status (does not work in klayout 0.23.11; does in 0.24 and later): +# 1 : I/O error or other internal error (uncaught exceptions). +# 2...127 : means 1... rules did flag error(s). If over 126 rules had errors, status is 127 max. +# That is this # is the how many rule-types had non-zero errors, NOT total errors count. +# 0 : no rules flagged errors. +# If process dies thru signal, exit status is 128+SIGNUM, so that range is reserved. +# i.e. if kernel oom-killer sends kill -9: status=137. +# +# Runs klayout (in batch). +# (klayout requirement is this script-name *must* end in .drc). +# +# Shebang for: no outer ruby interpreter; generalize arg passing to script. +# for-bash: re-quote args, to import from an env-var +x=%{ + [[ "$1" == "--version" || "$1" == "-v" ]] && exec klayout -b -v # pass-thru -v + + export _M0= + for i in "$@" ; do _M0="$_M0${_M0:+,}\"${i//\"/\\\"}\""; done + exec klayout -b -r "$0" -rd tag="$_M0" + # tag= is NOT USED, cosmetic: So process-listing shows the arguments, and a + # user can distinguish one process from another, despite running same klayout-script. +} +# for-ruby: + +argv=eval("[ #{ENV["_M0"]} ]") # re-parse args from env-var +# puts "argv.size=#{argv.size}" +# argv.each{ |v| puts v } + + thisScript = $0 + prog="gdsMergeall.drc" + usage = "Usage: #{prog} [options] " + usage += "\n WARNING: output has ALL TEXT STRIPPED/REMOVED (i.e. text not propagated from in to out)." + usage += "\n WARNING: output has paths converted to polygons." + require 'optparse' + + argSum = argv.join(' ') + if argv.empty? + argv << '--help' + end + + o = {:flat=>false, :thread=>4, :tile=>0} + OptionParser.new do |opts| + opts.banner = usage + opts.on("-f", "flat mode, default is deep (in absence of tiling). Not recommended.") do + o[:flat] = true + end + opts.on("-T TILE_SIZE", "enable tiling (disables deep) AND sets tile-size in um; default 0 (no tiling). Not recommended.") do |tile| + o[:flat] = true + o[:tile] = tile.to_f + end + opts.on("-t THREADS", "threads for deep or tiled (not flat), default 4. Give 0 to get from cmd: nproc") do |thr| + o[:thread] = thr.to_i + end + + opts.on("-v", "--version", "version: pass-thru, JUST show klayout version") do + exec "klayout -b -v" + end + opts.on("--help", "show usage") do + puts opts + exit 1 + end + opts.on("--usage", "show usage") do + puts opts + exit 1 + end + end.parse!(argv) # default constant ARGV? Doesn't work here: not true ruby. + # "!" on end of parse: argv parameter is MODIFIED by OptionParser to delete the processed options. + + if argv.length != 2 + puts "ERROR, not 2 arguments. #{usage}" + exit 1 + end +f = argv[0] +# c = argv[1] +fout = argv[1] + +# if f == "" || fout == "" || c == "" +if f == "" || fout == "" + puts "ERROR: insufficient arguments. #{usage}" + exit 1 +end + +# include RBA +begin + +if o[:flat] + flat # flat, with or without tiling +else + deep +end + +if o[:thread] == 0 + o[:thread]=`nproc` +end + +if o[:tile] > 0 + tiles(o[:tile]) + # no border + # tile_borders(0) + no_borders +end + +threads(o[:thread]) +deepP = is_deep? +tiledP = is_tiled? + +# title = "Sky130Apin1.drc, input=#{f}, topcell=#{c}" +title = "gdsMergeall.drc, input=#{f}" +# puts "Running Sky130Apin1.drc on file=#{f}, topcell=#{c}, output to #{fout}" +puts "Running Sky130Apin1.drc on file=#{f}, output to #{fout}" +puts " args: #{ENV["_M0"]}" +puts " deep:#{deepP} tiled:#{tiledP} threads:#{o[:thread]}" + +STDOUT.flush + +# source(f, c) +s = source(f) +layout = s.layout +target(fout) + +$errs = 0 +$totals = 0 +$rules = 0 +layers = 0 + +# verbose input(), flag if its empty. description is a string. +def inputVerb(layn, typen, desc) + ly = input(layn, typen) + isEmpty(ly, desc) + return ly +end + +def isEmpty(layer, desc) + if layer.is_empty? + puts "--EMPTY : #{desc}" + else + puts "data : #{desc}" + end +end + +# loop over all layer-purpose-pairs found in input-layout: +# Merge it and write merged results to output. + +STDERR.flush +layout.layer_indices.each { |layer_id| + layers += 1 + layer_info = layout.get_info(layer_id) + lpp = layer_info.to_s + # puts "checking #{lpp} ..." + input(lpp).merged.output(lpp) +} + +puts "#{$errs} errors, #{layers} layers processed." + +# if we roll-over to 256, exit-status seen by shell is zero. +# uncaught I/O errors will yield (built-in) exit status of 1. +if $errs > 0 + $errs = $errs + 1 +end +if $errs > 127 + $errs = 127 +end + +# experimental: report own peak process-stats. BUT: output-file isn't really written +# until we exit (during exit). So these results are not 100% accurate. +# VmHWM: max-resident-size, VmPeak: max virtual-size. +# don't need: pid=Process.pid +if File.readable?("/proc/self/status") + puts File.foreach("/proc/self/status").grep(/^(VmPeak|VmHWM)/) +end + +end # end begin + +# does not work (to set exit-status) in 0.23.11. Does work in 0.24.2, 0.27. +exit $errs + +# +# emacs syntax-mode: +# Local Variables: +# mode:ruby +# End: diff --git a/images/foss-asic-tools/addons/sak/magic/gdsSky130Apin1.drc b/images/foss-asic-tools/addons/sak/magic/gdsSky130Apin1.drc new file mode 100755 index 00000000..db75251c --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/gdsSky130Apin1.drc @@ -0,0 +1,356 @@ +#!/bin/bash +# usage: gdsSky130Apin1.drc [-p] [-f] [-T ] +# +# Flag pin.not(drawing) for all known pin/label layers in sky130A. +# WARNING: if markerFile is RELATIVE-PATH it is written in SAME-DIR as input-GDS. +# +# pwell & pwelliso not checked by default. Believe labelling pwell without drawn pwell is legal. +# +# TODO?: are results correct if deep mode, for pin & drawing in different hier. levels? +# +# Exit status (does not work in klayout 0.23.11; does in 0.24 and later): +# 1 : I/O error or other internal error (uncaught exceptions). +# 2...127 : means 1... rules did flag error(s). If over 126 rules had errors, status is 127 max. +# That is this # is the how many rule-types had non-zero errors, NOT total errors count. +# 0 : no rules flagged errors. +# If process dies thru signal, exit status is 128+SIGNUM, so that range is reserved. +# i.e. if kernel oom-killer sends kill -9: status=137. +# +# Runs klayout (in batch) to do partial/crude layer grid checks; output to a MarkerDB (*.lyrdb) +# Crude because no partitioning is done, to enforce unique grid requirements by areaid. +# +# Script starts as regular ruby, then exec's via klayout passing self to it. +# (klayout requirement is this script-name *must* end in .drc). +# +# Known reasons why mult. klayout-versions produce non-identical output: +# 1. In some earlier versions (than 0.27), markerReport may state "wrong" generator: +# :/built-in-macros/drc.lym +# the "better" generator would look like: +# drc: script='/gdsSky130Apin1.drc' +# 2. When errors are flagged, the ordering of errors may differ between klayout versions. +# +# Shebang for: no outer ruby interpreter; generalize arg passing to script. +# for-bash: re-quote args, to import from an env-var +x=%{ + [[ "$1" == "--version" || "$1" == "-v" ]] && exec klayout -b -v # pass-thru -v + + export _M0= + for i in "$@" ; do _M0="$_M0${_M0:+,}\"${i//\"/\\\"}\""; done + exec klayout -b -r "$0" -rd tag="$_M0" + # tag= is NOT USED, cosmetic: So process-listing shows the arguments, and a + # user can distinguish one process from another, despite running same klayout-script. +} +# for-ruby: + +argv=eval("[ #{ENV["_M0"]} ]") # re-parse args from env-var +# puts "argv.size=#{argv.size}" +# argv.each{ |v| puts v } + + thisScript = $0 + prog="gdsSky130Apin1.drc" + usage = "Usage: #{prog} [options] " + usage += "\n WARNING: relative-path markerFile is written relative to input gdsFile." + usage += "\n pwell & pwelliso NOT-checked by default: Substrate without nwell is a pwell" + usage += "\n and can be labelled (*without* pwell:drawing)." + require 'optparse' + + argSum = argv.join(' ') + if argv.empty? + argv << '--help' + end + + o = {:flat=>false, :thread=>4, :tile=>0, :pwell=>false} + OptionParser.new do |opts| + opts.banner = usage + opts.on("-f", "flat mode, default is deep (in absence of tiling)") do + o[:flat] = true + end + opts.on("-p", "check pwell & pwelliso; not recommended") do + o[:pwell] = true + end + opts.on("-T TILE_SIZE", "enable tiling (disables deep) AND sets tile-size in um; default 0 (no tiling)") do |tile| + o[:flat] = true + o[:tile] = tile.to_f + end + opts.on("-t THREADS", "threads for deep or tiled (not flat), default 4. Give 0 to get from cmd: nproc") do |thr| + o[:thread] = thr.to_i + end + + opts.on("-v", "--version", "version: pass-thru, JUST show klayout version") do + exec "klayout -b -v" + end + opts.on("--help", "show usage") do + puts opts + exit 1 + end + opts.on("--usage", "show usage") do + puts opts + exit 1 + end + end.parse!(argv) # default constant ARGV? Doesn't work here: not true ruby. + # "!" on end of parse: argv parameter is MODIFIED by OptionParser to delete the processed options. + + if argv.length != 3 + puts "ERROR, not 3 arguments. #{usage}" + puts " To list available top-cells: gdsTopcells " + exit 1 + end +f = argv[0] +c = argv[1] +fout = argv[2] + +if f == "" || fout == "" || c == "" + puts "ERROR: insufficient arguments. #{usage}" + puts " To list available top-cells: gdsTopcells " + exit 1 +end + +# include RBA +begin + +if o[:flat] + flat # flat, with or without tiling +else + deep +end + +if o[:thread] == 0 + o[:thread]=`nproc` +end + +if o[:tile] > 0 + tiles(o[:tile]) + # no border + # tile_borders(0) + no_borders +end + + +threads(o[:thread]) +deepP = is_deep? +tiledP = is_tiled? + +title = "Sky130Apin1.drc, input=#{f}, topcell=#{c}" +puts "Running Sky130Apin1.drc on file=#{f}, topcell=#{c}, output to #{fout}" +puts " args: #{ENV["_M0"]}" +puts " deep:#{deepP} tiled:#{tiledP} threads:#{o[:thread]}" + +STDOUT.flush + +source(f, c) +report(title, fout) + +# $ruleHeader = "Checks with errors:" +$ruleHeader = "--- #err|description, table for cell: %s" % [c] +$didHeader = false +$errs = 0 +$totals = 0 +$rules = 0 + +# +# Direct rule checks like: +# m2.width(1.5).output("m2 width < 1.5") +# write to report() but don't give opportunity to count/print which rules did flag. +# Instead: +# rule(m2.width(1.5), "m2 width < 1.5") +# +# Wish to use direct-form, and just tabulate/post-process report after the fact. +# This form (empty or not) still does not nicely report/summarize error-count per-rule. + +# Return value not meaningful if the is_empty? fails (in 0.26.9 or earlier). +# +def rule(marker, msg) + $rules = $rules + 1 + empty = false + size = -1 + emptyFails = false + + # test if marker is empty. + # marker.is_empty? : works in 0.27, not 0.26 and earlier. + # marker.size : does not work in any so far. + # marker.bbox appears universal, works in klayout versions 0.23.11 ... 0.27. + # In case it fails, catch exception and revert to less information in our stdout. + begin + size = marker.data.size + empty = (size == 0) + # works all versions: size = marker.data.size + # works all versions: empty = marker.bbox.to_s == "()" + # fails pre 0.27: empty = marker.is_empty? + rescue StandardError => e + # when can't determine which rules flagged errors, signal not to summarize. + emptyFails = true + empty = false + size = -1 + if $errs >= 0 + $errs = -8 + end + if ($errs & 1) == 0 + puts "turned off marker empty detect..." + end + $errs = $errs | 1 + end + if ! empty + marker.output(msg) + if ! emptyFails + if $errs == 0 && ! $didHeader + puts $ruleHeader + $didHeader = true + end + $errs = $errs + 1 + $totals = $totals + size + puts "%8d %s" % [size, msg] + return 1 + end + end + return 0 +end + +# call like: +# +# pinCheck( "met1", 68,20, 68,16, 68, 5 ) +# +# where 68,20 is met1/drawing, and purposes 16 & 5 are pin,label +# +# It is an error if called: +# ... with less than 5 args, i.e. MUST have at least one non-drawing layer-purpose-pair. +# e.g.: pinCheck( "met1", 68,20 ) +# ... with an odd number of arguments after the first three. +# e.g.: pinCheck( "met1", 68,20, 68 ) +# e.g.: pinCheck( "met1", 68,20, 68,16, 68 ) +# +# Variations: +# pinCheck: do the regular AndNot pin check +# pinSkip: do not do the check, but still report on which lpps have data vs empty. +def pinCheck(name, layn, typen, *nonMaskLpps) + pinCheckIf(true, name, layn, typen, *nonMaskLpps) +end +def pinSkip(name, layn, typen, *nonMaskLpps) + pinCheckIf(false, name, layn, typen, *nonMaskLpps) +end +def pinCheckIf(checkp, name, layn, typen, *nonMaskLpps) + if nonMaskLpps.length == 0 || nonMaskLpps.length % 2 != 0 + STDERR.puts "pinCheck called with empty or odd-number of args for non-drawing layer-purpose-pairs." + exit 1 + end + + lyfmt = "%22s" + lyfmt2 = "%12s" + + ly = polygons(layn, typen) # get main drawing + drpair = "#{layn}/#{typen}" + # isEmpty(ly, name) + lye = (ly.is_empty?) ? "EMP" : "dat" + sumry = [ lyfmt % "#{name}:#{drpair}/#{lye}" ] + + nonMaskLpps.each_slice(2) {|lay, typ| + l2 = polygons(lay, typ) + l2e = (l2.is_empty?) ? "EMP" : "dat" + sumry += [ lyfmt2 % "#{lay}/#{typ}/#{l2e}" ] + + msg = "#{lay}/#{typ}: #{name}, pin/label not-over drawing:#{drpair}" + if checkp + rule( l2.not(ly), msg ) + end + } + if checkp + mode = " " + else + mode = "NO-Check" + end + # force header output (if not yet done) + if ! $didHeader + puts $ruleHeader + $didHeader = true + end + puts ("%8s ---- " % mode) + sumry.join(" ") + +end + +# verbose input(), flag if its empty. description is a string. +def inputVerb(layn, typen, desc) + ly = input(layn, typen) + isEmpty(ly, desc) + return ly +end + +def isEmpty(layer, desc) + if layer.is_empty? + puts "--EMPTY : #{desc}" + else + puts "data : #{desc}" + end +end + +# check all layer-purpose-pairs found in input-layout: +# Report ALL that are pin-purpose. + +#? should these be checked against pwell/drawing: pwelliso_pin - 44/16 pwelliso_label - 44/5 + pinCheckIf(o[:pwell], + "pwell", 64,44, 122,16, 64,59, 44,16, 44,5) + pinCheck( "nwell", 64,20, 64,16, 64,5) + pinCheck( "diff", 65,20, 65,16, 65,6) + pinCheck( "tap", 65,44, 65,48, 65,5) + pinCheck( "poly", 66,20, 66,16, 66,5) + pinCheck( "licon1", 66,44, 66,58) + pinCheck( "li1", 67,20, 67,16, 67,5) + pinCheck( "mcon", 67,44, 67,48) + pinCheck( "met1", 68,20, 68,16, 68,5) + pinCheck( "via", 68,44, 68,58) + pinCheck( "met2", 69,20, 69,16, 69,5) + pinCheck( "via2", 69,44, 69,58) + pinCheck( "met3", 70,20, 70,16, 70,5) + pinCheck( "via3", 70,44, 70,48) + pinCheck( "met4", 71,20, 71,16, 71,5) + pinCheck( "via4", 71,44, 71,48) + pinCheck( "met5", 72,20, 72,16, 72,5) + pinCheck( "pad", 76,20, 76,5, 76,16) + pinCheck( "pnp", 82,44, 82,59) + pinCheck( "npn", 82,20, 82,5) + pinCheck( "rdl", 74,20, 74,16, 74,5) + pinCheck( "inductor", 82,24, 82,25) + +end +# How to tabulate as-if-flat "error-counts by error-message" from current report()? +# In old versions, we can't seem to determine here if a check flagged errors ($errs == -1). +if $errs >= 0 + puts "%8d total error(s) among %d error type(s), %d checks, cell: %s" % [$totals, $errs, $rules, c] + # puts "#{$errs} of #{$rules} checks have errors" +else + puts "#{$rules} checks" + $errs = 0 # so exit status == 0. +end +puts "Writing report..." + +# if we roll-over to 256, exit-status seen by shell is zero. +# uncaught I/O errors will yield (built-in) exit status of 1. +if $errs > 0 + $errs = $errs + 1 +end +if $errs > 127 + $errs = 127 +end + +# experimental: report own peak process-stats. BUT: report-file isn't really written +# until we exit (during exit). So these results are not 100% accurate. +# VmHWM: max-resident-size, VmPeak: max virtual-size. +# don't need: pid=Process.pid +if File.readable?("/proc/self/status") + puts File.foreach("/proc/self/status").grep(/^(VmPeak|VmHWM)/) +end + +# does not work (to set exit-status) in 0.23.11. +# Does work in 0.24.2, 0.27! +exit $errs + +# For 0.23.11 we could set exit-status as below, but: +# if we do: the report() does not get written! +# +# for exit! we'd lose buffered output unless we flush: +# STDOUT.flush +# STDERR.flush +# Kernel.exit!($errs) +# +# emacs syntax-mode: +# Local Variables: +# mode:ruby +# End: diff --git a/images/foss-asic-tools/addons/sak/magic/gdsSky130Asub1.drc b/images/foss-asic-tools/addons/sak/magic/gdsSky130Asub1.drc new file mode 100755 index 00000000..e30aa78a --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/gdsSky130Asub1.drc @@ -0,0 +1,413 @@ +#!/bin/bash +# usage: gdsSky130Asub1.drc +# +# totals are reported twice: 1st for just the (subset of) MR-rules, +# and lastly again for the grand-total: including BOTH MR-rules & non-MR-rules. +# +# Exit status (does not work in klayout 0.23.11; does in 0.24 and later): +# 1 : I/O error or other internal error (uncaught exceptions). +# 2...127 : means 1... rules did flag error(s). If over 126 rules had errors, status is 127 max. +# That is this # is the how many rule-types had non-zero errors, NOT total errors count. +# 0 : no rules flagged errors. +# If process dies thru signal, exit status is 128+SIGNUM, so that range is reserved. +# i.e. if kernel oom-killer sends kill -9: status=137. +# +# Runs klayout (in batch) to do partial/crude layer grid checks; output to a MarkerDB (*.lyrdb) +# Crude because no partitioning is done, to enforce unique grid requirements by areaid. +# +# Script starts as regular ruby, then exec's via klayout passing self to it. +# (klayout requirement is this script-name *must* end in .drc). +# +# Known reasons why mult. klayout-versions produce non-identical output: +# 1. In some earlier versions (than 0.27), markerReport may state "wrong" generator: +# :/built-in-macros/drc.lym +# the "better" generator would look like: +# drc: script='/gdsSky130Asub1.drc' +# 2. When errors are flagged, the ordering of errors may differ between klayout versions. +# +# Shebang for: no outer ruby interpreter; generalize arg passing to script. +# for-bash: re-quote args, to import from an env-var +x=%{ + [[ "$1" == "--version" || "$1" == "-v" ]] && exec klayout -b -v # pass-thru -v + + export _M0= + for i in "$@" ; do _M0="$_M0${_M0:+,}\"${i//\"/\\\"}\""; done + exec klayout -b -r "$0" +} +# for-ruby: + +argv=eval("[ #{ENV["_M0"]} ]") # re-parse args from env-var +# puts "argv.size=#{argv.size}" +# argv.each{ |v| puts v } + + thisScript = $0 + prog="gdsSky130Asub1.drc" + usage = "Usage: #{prog} [options] " + require 'optparse' + + argSum = argv.join(' ') + if argv.empty? + argv << '--help' + end + + o = {:flat=>false, :thread=>4} + OptionParser.new do |opts| + opts.banner = usage + opts.on("-f", "flat mode, default is deep") do + o[:flat] = true + end + opts.on("-t THREADS", "threads for deep (not flat) mode, default 4. Give 0 to get from cmd: nproc") do |thr| + o[:thread] = thr.to_i + end + + opts.on("-v", "--version", "version: pass-thru, JUST show klayout version") do + exec "klayout -b -v" + end + opts.on("--help", "show usage") do + puts opts + exit 1 + end + opts.on("--usage", "show usage") do + puts opts + exit 1 + end + end.parse!(argv) # default constant ARGV? Doesn't work here: not true ruby. + # "!" on end of parse: argv parameter is MODIFIED by OptionParser to delete the processed options. + + if argv.length != 3 + puts "ERROR, not 3 arguments. #{usage}" + puts " To list available top-cells: gdsTopcells " + exit 1 + end +f = argv[0] +c = argv[1] +fout = argv[2] + +if f == "" || fout == "" || c == "" + puts "ERROR: insufficient arguments. #{usage}" + puts " To list available top-cells: gdsTopcells " + exit 1 +end + +# include RBA +begin + +if o[:flat] + flat +else + deep +end + +if o[:thread] == 0 + o[:thread]=`nproc` +end + +threads(o[:thread]) +deepP = is_deep? +tiledP = is_tiled? + +title = "Sky130Asub1.drc, input=#{f}, topcell=#{c}" +puts "Running Sky130Asub1.drc on file=#{f}, topcell=#{c}, output to #{fout}" +puts " deep:#{deepP} tiled:#{tiledP} threads:#{o[:thread]}" +STDOUT.flush + +source(f, c) +report(title, fout) + +# $ruleHeader = "Checks with errors:" +$ruleHeader = "--- #err|description, table for cell: %s" % [c] +$errs = 0 +$totals = 0 +$rules = 0 +$errs_mr = 0 +$totals_mr = 0 +$rules_mr = 0 + +# +# Direct rule checks like: +# m2.width(1.5).output("m2 width < 1.5") +# write to report() but don't give opportunity to count/print which rules did flag. +# Instead: +# rule(m2.width(1.5), "m2 width < 1.5") +# +# Wish to use direct-form, and just tabulate/post-process report after the fact. +# This form (empty or not) still does not nicely report/summarize error-count per-rule. + +# Return value not meaningful if the is_empty? fails (in 0.26.9 or earlier). +# +def rule_mr(marker, msg) + rule_work(true, marker, msg) +end +def rule(marker, msg) + rule_work(false, marker, msg) +end +def rule_work(isMR, marker, msg) + $rules += 1 + if isMR + $rules_mr += 1 + end + empty = false + size = -1 + emptyFails = false + + # test if marker is empty. + # marker.is_empty? : works in 0.27, not 0.26 and earlier. + # marker.size : does not work in any so far. + # marker.bbox appears universal, works in klayout versions 0.23.11 ... 0.27. + # In case it fails, catch exception and revert to less information in our stdout. + begin + size = marker.data.size + empty = (size == 0) + # works all versions: size = marker.data.size + # works all versions: empty = marker.bbox.to_s == "()" + # fails pre 0.27: empty = marker.is_empty? + rescue StandardError => e + # when can't determine which rules flagged errors, signal not to summarize. + emptyFails = true + empty = false + size = -1 + if $errs >= 0 + $errs = -8 + end + if ($errs & 1) == 0 + puts "turned off marker empty detect..." + end + $errs = $errs | 1 + end + if ! empty + marker.output(msg) + if ! emptyFails + if $errs == 0 + puts $ruleHeader + end + $errs += 1 + $totals += size + if isMR + $errs_mr += 1 + $totals_mr += size + end + + puts "%8d %s" % [size, msg] + return 1 + end + end + return 0 +end + +# verbose input(), flag if its empty. description is a string. +def inputVerb(layn, typen, desc) + ly = input(layn, typen) + isEmpty(ly, desc) + return ly +end + +def isEmpty(layer, desc) + if layer.is_empty? + puts "--EMPTY : #{desc}" + else + puts "data : #{desc}" + end +end + +# 1a +# g1 = 0.001 +# were 1a: 0.001, but that's not so per error reports back from skywater +# p1 = input(66, 20) +# m1 = input(68, 20) +# v1 = input(68, 44) +# m2 = inputVerb(69, 20, "m2 - 69/20") + +# 1b +g5 = 0.005 +# v2 = input(69, 44) +# m3 = input(70, 20) +# v3 = input(70, 44) +# m4 = input(71, 20) +# v4 = input(71, 44) +# m5 = input(72, 20) + +# were 1a: 0.001, but that's not so per error reports back from skywater +# p1.ongrid(g5).output("p1-grid5", "poly off-grid #{g5}") +# m1.ongrid(g5).output("m1-grid5", "met1 off-grid #{g5}") +# v1.ongrid(g5).output("v1-grid5", "via1 off-grid #{g5}") +# m2.ongrid(g5).output("m2-grid5", "met2 off-grid #{g5}") + +# v2.ongrid(g5).output("v2-grid5", "via2 off-grid #{g5}") +# m3.ongrid(g5).output("m3-grid5", "met3 off-grid #{g5}") +# v3.ongrid(g5).output("v3-grid5", "via3 off-grid #{g5}") +# m4.ongrid(g5).output("m4-grid5", "met4 off-grid #{g5}") +# v4.ongrid(g5).output("v4-grid5", "via4 off-grid #{g5}") +# m5.ongrid(g5).output("m5-grid5", "met5 off-grid #{g5}") + +# dnwell = input( 64, 18) +# pwres = input( 64, 13) +# nwell = input( 64, 20) +# diff = input( 65, 20) +# tap = input( 65, 44) +psdm = input( 94, 20) +isEmpty(psdm, "psdm - 94/20") +cpsdm = input( 32, 0) # MASK +isEmpty(cpsdm, "cpsdm - 32/0 [NOT CHECKED]") +nsdm = input( 93, 44) +isEmpty(nsdm, "nsdm - 93/20") +cnsdm = input( 30, 0) # MASK +isEmpty(cnsdm, "cnsdm - 30/0 [NOT CHECKED]") +# lvtn = input( 125, 44) +hvtp = input( 78, 44) +isEmpty(hvtp, "hvtp - 78/44") +chvtp = input( 97, 0) # MASK +isEmpty(chvtp, "chvtp - 97/0 [NOT CHECKED]") +# sonos = input( 80, 20) +# coreid = input( 81, 2) +# stdcel = input( 81, 4) +# npnid = input( 82, 20) +# rpm = input( 86, 20) +# urpm = input( 79, 20) +# ldntm = input( 11, 44) +# hvntm = input( 125, 20) +thkox = input( 75, 20) # hvi +isEmpty(thkox, "thkox(hvi) - 75/20") +# licon = input( 66, 44) +npc = inputVerb( 95, 20, "npc - 95/20") +cnpc = inputVerb( 49, 0, "cnpc.mask - 49/0 [NOT CHECKED]") + +# li = input( 67, 20) +# mcon = input( 67, 44) +# rdl = input( 74, 20) +# glass = input( 76, 20) +# bound = input( 235, 4) +# capm = input( 89, 44) +# capm2 = input( 97, 44) +# lowtapd = input( 81, 14) +# fillobsm1 = input( 62, 24) +# fillobsm2 = input( 105, 52) +# fillobsm3 = input( 107, 24) +# fillobsm4 = input( 112, 4) + +# dnwell.ongrid(g5).output("dnwell-grid5","dnwell off-grid #{g5}") +# pwres.ongrid(g5).output("pwres-grid5","pwres off-grid #{g5}") +# nwell.ongrid(g5).output("nwell-grid5","nwell off-grid #{g5}") +# diff.ongrid(g5).output("diff-grid5","diff off-grid #{g5}") +# tap.ongrid(g5).output("tap-grid5","tap off-grid #{g5}") +# psdm.ongrid(g5).output("psdm-grid5","psdm off-grid #{g5}") +# nsdm.ongrid(g5).output("nsdm-grid5","nsdm off-grid #{g5}") +# lvtn.ongrid(g5).output("lvtn-grid5","lvtn off-grid #{g5}") +# hvtp.ongrid(g5).output("hvtp-grid5","hvtp off-grid #{g5}") +# sonos.ongrid(g5).output("sonos-grid5","sonos off-grid #{g5}") +# coreid.ongrid(g5).output("coreid-grid5","coreid off-grid #{g5}") +# stdcel.ongrid(g5).output("stdcel-grid5","stdcel off-grid #{g5}") +# npnid.ongrid(g5).output("npnid-grid5","npnid off-grid #{g5}") +# rpm.ongrid(g5).output("rpm-grid5","rpm off-grid #{g5}") +# urpm.ongrid(g5).output("urpm-grid5","urpm off-grid #{g5}") +# ldntm.ongrid(g5).output("ldntm-grid5","ldntm off-grid #{g5}") +# hvntm.ongrid(g5).output("hvntm-grid5","hvntm off-grid #{g5}") +# thkox.ongrid(g5).output("thkox-grid5","thkox off-grid #{g5}") +# licon.ongrid(g5).output("licon-grid5","licon off-grid #{g5}") +# npc.ongrid(g5).output("npc-grid5","npc off-grid #{g5}") +# li.ongrid(g5).output("li-grid5","li off-grid #{g5}") +# mcon.ongrid(g5).output("mcon-grid5","mcon off-grid #{g5}") +# rdl.ongrid(g5).output("rdl-grid5","rdl off-grid #{g5}") +# glass.ongrid(g5).output("glass-grid5","glass off-grid #{g5}") +# bound.ongrid(g5).output("bound-grid5","bound off-grid #{g5}") +# capm.ongrid(g5).output("capm-grid5","capm off-grid #{g5}") +# capm2.ongrid(g5).output("capm2-grid5","capm2 off-grid #{g5}") +# lowtapd.ongrid(g5).output("lowtapd-grid5","lowtapd off-grid #{g5}") +# fillobsm1.ongrid(g5).output("fillobsm1-grid5","fillobsm1 off-grid #{g5}") +# fillobsm2.ongrid(g5).output("fillobsm2-grid5","fillobsm2 off-grid #{g5}") +# fillobsm3.ongrid(g5).output("fillobsm3-grid5","fillobsm3 off-grid #{g5}") +# fillobsm4.ongrid(g5).output("fillobsm4-grid5","fillobsm4 off-grid #{g5}") + +# (HVI) THKOX*: should be thkox (hvi) in periphery +# thkox.space(0.7).output("THKOX*(hvi) space < 0.7") +# thkox.notch(0.7).output("THKOX*(hvi) notch < 0.7") +# thkox.width(0.6).output("THKOX*(hvi) width < 0.6") +rule_mr(thkox.space(0.7), "mr:THKOX*(hvi) space < 0.7") +# rule_mr(thkox.notch(0.7), "THKOX*(hvi) notch < 0.7") +rule_mr(thkox.width(0.6), "mr:THKOX*(hvi) width < 0.6") + +# NPC: +rule_mr(npc.space(0.27), "mr:NPC space < 0.27") +# rule_mr(npc.notch(0.27), "NPC notch < 0.27") +rule_mr(npc.width(0.27), "mr:NPC width < 0.27") + +# NSDM: +# nsdm.space(0.38).output("NSDM.2 space < 0.38") +# nsdm.notch(0.38).output("NSDM.2 notch < 0.38") +# nsdm.width(0.38).output("NSDM.1 width < 0.38") +rule(nsdm.space(0.38), "NSDM.2 space < 0.38") +# rule(nsdm.notch(0.38), "NSDM.2 notch < 0.38") +rule(nsdm.width(0.38), "NSDM.1 width < 0.38") + +# PSDM: +# psdm.space(0.38).output("PSDM.2 space < 0.38") +# psdm.notch(0.38).output("PSDM.2 notch < 0.38") +# psdm.width(0.38).output("PSDM.1 width < 0.38") +rule(psdm.space(0.38), "PSDM.2 space < 0.38") +# rule(psdm.notch(0.38), "PSDM.2 notch < 0.38") +rule(psdm.width(0.38), "PSDM.1 width < 0.38") + +# DNWELL*: should be dnwell-not-... (Photo, UHVI) +# dnwell.space(6.3).output("DNWELL* space < 6.3") +# dnwell.notch(6.3).output("DNWELL* notch < 6.3") +# dnwell.width(3.0).output("DNWELL width < 3.0") +# dnwell.separation(nwell, 4.5).output("DNWELL to NWELL space < 4.5") + +# nwell.space(1.27).output("NWELL space < 1.27") +# nwell.notch(1.27).output("NWELL notch < 1.27") +# nwell.width(0.84).output("NWELL width < 0.84") + +# hvtp.space(0.38).output("HVTP.2 space < 0.38") +# hvtp.notch(0.38).output("HVTP.2 notch < 0.38") +# hvtp.width(0.38).output("HVTP.1 width < 0.38") +rule_mr(hvtp.space(0.38), "mr:HVTP.2 space < 0.38") +# rule_mr(hvtp.notch(0.38), "HVTP.2 notch < 0.38") +rule_mr(hvtp.width(0.38), "mr:HVTP.1 width < 0.38") + +# hvntm.space(0.7).output("HVNTM.2 space < 0.7") +# hvntm.notch(0.7).output("HVNTM.2 notch < 0.7") +# hvntm.width(0.7).output("HVNTM.1 width < 0.7") + +# report(myTitle, markerOut) +# m2 = inputVerb(69, 20, "m2 - 69/20") +# rule(m2.width(2.5), "m2 width < 2.5 (fake: provoke errors)") +# How to get error-count (as-if-flat at top-cell) from this statement?: +# m2.width(2.5).output("m2 width < 2.5") + +end +# How to tabulate as-if-flat "error-counts by error-message" from current report()? +# In old versions, we can't seem to determine here if a check flagged errors ($errs == -1). +if $errs >= 0 + puts "%8d total-MR error(s) among %d error type(s), %d checks, cell: %s (subset)" % [$totals_mr, $errs_mr, $rules_mr, c] + puts "%8d total error(s) among %d error type(s), %d checks, cell: %s" % [$totals, $errs, $rules, c] + # puts "#{$errs} of #{$rules} checks have errors" +else + puts "#{$rules} checks" + $errs = 0 # so exit status == 0. +end +puts "Writing report..." + +# if we roll-over to 256, exit-status seen by shell is zero. +# uncaught I/O errors will yield (built-in) exit status of 1. +if $errs > 0 + $errs = $errs + 1 +end +if $errs > 127 + $errs = 127 +end + +# does not work (to set exit-status) in 0.23.11. +# Does work in 0.24.2, 0.27! +exit $errs + +# For 0.23.11 we could set exit-status as below, but: +# if we do: the report() does not get written! +# +# for exit! we'd lose buffered output unless we flush: +# STDOUT.flush +# STDERR.flush +# +# Kernel.exit!($errs) +# emacs syntax-mode: +# Local Variables: +# mode:ruby +# End: diff --git a/images/foss-asic-tools/addons/sak/magic/lef2maglef.sh b/images/foss-asic-tools/addons/sak/magic/lef2maglef.sh new file mode 100755 index 00000000..d9407cdb --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/lef2maglef.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# SPDX-License-Identifier: Apache-2.0 + + +export PDK_ROOT=~/foss/pdks; +export MAGTYPE=mag ; +export PDKPATH=$PDK_ROOT/sky130A ; +export MAGIC=magic + + +$MAGIC -rcfile $PDKPATH/libs.tech/magic/sky130A.magicrc -dnull -noconsole << EOX +drc off +lef read $1.lef +load $1 +save $1.lef.mag +#writeall force $1.lef.mag + + # copy GDS properties from the MAG view into the MAGLEF view + set gds_properties [list] + set fp [open $1.mag r] + set mag_lines [split [read \$fp] "\n"] + foreach line \$mag_lines { + if { [string first "string GDS_" \$line] != -1 } { + lappend gds_properties \$line + } + } + close \$fp + set fp [open $1.lef.mag r] + set mag_lines [split [read \$fp] "\n"] + set new_mag_lines [list] + foreach line \$mag_lines { + if { [string first "<< end >>" \$line] != -1 } { + lappend new_mag_lines [join \$gds_properties "\n"] + } + lappend new_mag_lines \$line + } + close \$fp + set fp [open $1.lef.mag w] + puts \$fp [join \$new_mag_lines "\n"] + close \$fp + + +quit +EOX + +#mv -f $1.lef.mag ../maglef/$1.mag +#rm -f $1.lef diff --git a/images/foss-asic-tools/addons/sak/magic/list_macros.py b/images/foss-asic-tools/addons/sak/magic/list_macros.py new file mode 100755 index 00000000..476373b7 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/list_macros.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +import argparse + +def list_macros(directory, output): + neededfile = [os.path.join(directory, f) for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f)) and str(f).endswith(".magic.typelist") and os.path.basename(f).split(".",1)[0] != "caravel"][0] + + macro_list=[] + printArr=[] + if(os.path.exists(neededfile)): + print(neededfile) + FileOpener = open(neededfile, "r") + if FileOpener.mode == 'r': + Content = FileOpener.read() + FileOpener.close() + for cell in Content.split(" "): + if not cell.startswith("sky130_fd_sc_"): + macro_list.append(cell) + printArr.append("Macros Count: "+ str(len(macro_list))) + printArr.append("Macros: " + " ".join(macro_list)) + for line in printArr: + print(line) + outputFileOpener = open(output,"w") + outputFileOpener.write("\n".join(printArr)) + outputFileOpener.close() + + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description='The script takes a checks output directory from running the fuzzy checks in the Precheck, \ + and lists the number of macros in the user_project_wrapper.') + + parser.add_argument('--directory', '-d',required=True, + help='The checks directory.') + + parser.add_argument('--output', '-o',default=None, + help="outputs the list of macros") + + + args = parser.parse_args() + directory = args.directory + output = args.output + if output is None: + output = str(directory+"/macro_list.txt") + list_macros(directory,output) diff --git a/images/foss-asic-tools/addons/sak/magic/mag2gds.sh b/images/foss-asic-tools/addons/sak/magic/mag2gds.sh new file mode 100755 index 00000000..793a5be7 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/mag2gds.sh @@ -0,0 +1,23 @@ +#!/bin/sh +export MAGIC=/ef/apps/ocd/magic/8.3.179-202106141345/bin/magic +#export MAGIC=/ef/apps/ocd/magic/8.3.165-202105171922/bin/magic + +export MAGTYPE=mag; + +$MAGIC -dnull -noconsole -rcfile $PDK_ROOT/sky130A/libs.tech/magic/sky130A.magicrc < with subckts, ngspice(orig) --> explicit M for transistors, ngspice(si) <<- DO NOT USE si + +## ext2spice lvs ;# = all the steps commented below +#########ext2spice blackbox on ;# detects MAGTYPE=maglef files and netlists them as blackbox +#########ext2spice global off +# ext2spice -o ${1%.mag}.maglef.lay.spice diff --git a/images/foss-asic-tools/addons/sak/magic/magic-drc.sh b/images/foss-asic-tools/addons/sak/magic/magic-drc.sh new file mode 100755 index 00000000..cda5d7fa --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/magic-drc.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# Copyright 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# To call: ./magic-drc.sh + +export TARGET_DIR=$1 +export DESIGN_NAME=$2 +export PDK_ROOT=$3 +export TARGET_TYPE=$4 +export PDK=$5 +export OUT_DIR=$6 +export TCL_CALL_PATH=${7:-$(pwd)} +#export UTILS=~/foss/tools/sak +echo $PDK_ROOT + +echo "Running Magic..." +export MAGIC_MAGICRC=$PDK_ROOT/$PDK/libs.tech/magic/current/$PDK.magicrc +echo $MAGIC_MAGICRC + +$MAGIC \ + -noconsole \ + -dnull \ + -rcfile $MAGIC_MAGICRC \ + $SAK/magic/tcl/magic-drc.tcl \ + + +export TARGET_DIR=$1 +export DESIGN_NAME=$2 +export PDK_ROOT=$3 +export TARGET_TYPE=$4 +export PDK=$5 +export OUT_DIR=$6 + + +echo "Running Magic..." +export MAGIC_MAGICRC=$PDK_ROOT/$PDK/libs.tech/magic/sky130A.magicrc + +magic \ + -noconsole \ + -dnull \ + -rcfile $MAGIC_MAGICRC \ + $SAK/magic/tcl/magic-ext.tcl \ + . Pass rest via env-var, requoted. +# for-bash\ + export _M0= ;\ + for i in "$@" ; do _M0="$_M0${_M0:+ }\"${i//\"/\\\"}\""; done ;\ + case "$1" in -T) tch="$2"; shift; shift; _MARGS="$*" exec magic -dnull -noconsole -T "$tch" <"$0" ;; esac +# hide next line from magic(tclsh):\ +_MARGS="$*" exec magic -dnull -noconsole <"$0" + +# magicDrc: run magic-DRC in batch on a .mag file, tabulate/pareto the error counts. +set Prog "magicDrc" +set argv [eval "list $env(_M0)"] ;# orig. mix of native plus custom args, for logging all args to script + +proc usage {args} { + if {[llength $args] > 0} { + puts "ERROR: ${::Prog}: [join $args]" + } + puts {usage: [ -T ] [-S ] [-n] [-N] [-l FILE_NAME] [-km FILE_NAME] } + puts " : names a .mag file, the toplevel of the hier. to DRC/pareto" + puts "" + puts " -T name specific techfile, passed to magic itself only, overrides tech implied by magFileName" + puts " -S if given, changes from techfile's default drc style (perhaps \"drc(fast)\") to named style, for example: -S \"drc(full)\"" + puts " -l if given, enumerates EVERY individual error bbox to the FILE_NAME (all cells reported in one file)" + puts " -N if given, do not use -dereference option of load for topcell (not available in older magics)" + puts " -n Do NOT write *.drtcl per-cell feedback files. Can be source-ed in magic and step thru: feedback find." + puts "" + puts " Error tabulation: By default (slowest, most detail): Report table of counts-by-errorString for all cells." + puts " Stdout logs a pareto of error-type by count unless disabled for some/all cells by below; topcell last." + puts " -tt Table of counts-by-errorString for ONLY topcell; and just lumped total error count per subcell." + puts " -tc Just lumped error counts per cell including topcell (fastest, least detail)." + puts " Cells NOT tabulating count-by-errorString can't appear in other output error files: feedback(*.drtcl), -l, -km." + puts " For lumped error counts, overlapped error shapes from unique error-types are merged further reducing count." + puts "" + puts " cell-type +-- (default) --+-- option -tt --+-- option -tc" + puts " subcell | count-by-errorString | lumped-error-count | lumped-error-count" + puts " topcell | count-by-errorString | count-by-errorString | lumped-error-count" + puts "" + puts " -km if given, write to FILE_NAME EVERY individual error bbox (MICRONS) in klayout Marker database(XML) format (suggest *.km or *.lyrdb)" + puts " WARNING: .mag cells, shapes & hierarchy change once output to .gds. Mag-based -km cellnames might no longer exist in gds." + puts " Feedback files (*.drtcl) are written PER-CELL. Can be source-ed in magic and step thru: feedback find." + puts "" + puts " Recommend to run in dir with a ./.magicrc (or ./magic_setup) to configure magic's" + puts " cell search path, thru addpath statements, to locate all cells." + puts " Since about 8.3.68, magic may generate error-type \"See error definition in the subcell\". There typically are" + puts " redundancies of errors across the hierarchy anyway (but with tech-file err-strings), this seems another form." + puts "" + puts "example, just list all styles: by causing an error which provokes usage report:" + puts " magicDrc -T /ef/tech/XFAB/EFXH035B/libs.tech/magic/current/EFXH035B.tech" + puts "example, same but run in a ~/design/*/mag/ dir, so techfile set by ./.magicrc (else magic's builtin minimum.tech):" + puts " magicDrc" + puts "example, run drc, explicit: tech, drc-style:" + puts " magicDrc -T /ef/tech/SW/EFS8A/libs.tech/magic/current/EFS8A.tech -S 'drc(full)' mytopcell" + puts "example, run drc, default tech & styles, write klayout marker database, no per-cell *.drtcl feedback files:" + puts " magicDrc -km /tmp/mytop.km -n mytopcell" + puts "example, run drc, no feedback (*.drtcl), only lumped/merged err-count for all cells" + puts " magicDrc -tc mytopcell" + puts "example, run drc, no feedback (*.drtcl), lumped/merged err-count for subcells, detail errors for topcell" + puts " magicDrc -n -tt mytopcell" + puts "" + + reportTechFile + reportAllStyles + puts "" + + if {[llength $args] > 0} { + puts "ERROR: ${::Prog}: [join $args]" + } +} + +# rb@ef 2015-06-30 author +# rb 2020-03-11 embed some library functions, to standalone from efabless-opengalaxy env, test via magic-8.2.194 +# +# -F flatten top cell in-memory only, not saved (experimental) +# -P do crude drc performance measurement. At top-cell, do 'drc find' times and report time per call. +# +# Normal magic init. files are STILL sourced: ~/.magicrc and either $CWD/.magicrc or $CWD/magic_setup. +# (Would NOT happen if -rcfile magic cmd-line option used; this script does not support same). +# +# WARNING: Before 8.1.70, *.mag on cmd-line that was only found in cell search path set by .magicrc inits, +# would FAIL to determine the default tech-file. +# +# magic itself outputs following usage message though -rcfile doesn't appear to work (in some versions): +# Usage: magic [-g gPort] [-d devType] [-m monType] [-i tabletPort] [-D] [-F objFile saveFile] +# [-T technology] [-rcfile startupFile | -norcfile][-noconsole] [-nowindow] [-wrapper] [file] +# +# optionally hardcode library proc-s (part of site-wide extensions - always available - in context of efabless/open-galaxy) +# This is to make the script more standalone from efabless environment; but these capabilities should be native to magic. + +proc reportTechFile {} { + puts "${::Prog}: tech-name: [tech name] -version: [tech version] -filename: [tech filename] -lambda [tech lambda]" +} + +# query currently loaded tech-file for styles the user might need for -I -S options +# Suggest a bad tech-file if none are found or errors thrown. +# Used after finding error in -I -S options, and probably should add it to the usage. +proc reportAllStyles {} { + set errs {} + if {[catch {set allstyle [cif listall istyle]} msg]} { + lappend errs "ERROR: ${::Prog}: bad tech-file? failed to 'cif listall istyle', $msg" + } elseif {$allstyle == {}} { + lappend errs "ERROR: ${::Prog}: bad tech-file? no cifinput styles found by 'cif listall istyle'" + } else { + puts "info: ${::Prog}: cifinput styles available: $allstyle" + } + if {[catch {set allstyle [drc listall style]} msg]} { + lappend errs "ERROR: ${::Prog}: bad tech-file? failed to 'drc listall style', $msg" + } elseif {$allstyle == {}} { + lappend errs "ERROR: ${::Prog}: bad tech-file? no drc styles found by 'drc listall style'" + } else { + puts "info: ${::Prog}: drc styles available: $allstyle" + } + if {$errs != {}} { + + } + return [llength $errs] +} + +if {[info command scratchWritable] == {}} { + puts "${::Prog}: hardcoding library proc-s..." +# Replacement for 'cellname list exists CELLNAME', to fix ambiguity for cell "0". +# For cell "0" test for membership in 'cellname list allcells'. +# +# Instead of returning 0 for (non-existent) and cellname for exists, +# returns regular 0/1 instead for non-existent/exists. +# +# Therefore NOT direct replacement for uses of 'cellname list exists CELL'. +# Requires code changes. +proc cellnameExists {cell} { + expr {$cell ne "0" && [cellname list exists $cell] eq $cell || + $cell eq "0" && [lsearch -exact [cellname list allcells] $cell] > -1} +} + +# +# scratchWritable [-cleanup] [cellname1 ...] -- +# +# Turn readonly cells writable in-memory, via redirect to scratch dir. +# No cellname args: default is to process just all non-writable cells. +# Explicit cellname arguments: ARE scatchified EVEN if ALREADY writable. +# Limitation: Explicit named cell created in-mem, never saved, won't scratchify. +# If just -cleanup: default is to only do cleanup: don't scratchify +# any cells. +# +# -cleanup: Last scratch-dir, if any, and contents are deleted first. +# No restoring old filepath of cells, save after cleanup will fail. +# +# Caller strongly recommended to first do: 'select top cell; expand' +# to force whole hier. of a topcell to be loaded from disk into memory. +# +# This proc does not force expand cells. Before expanded, cells cannot be +# checked whether writable, and cannot have filepath changed. +# +# For batch DRC, for 'drc listall count', every cell in-memory must +# appear writable. This is the work-around (caller to 1st ensure +# hier. is loaded): Reset filepath of readonly cells to a scratch dir, +# make a dummy/empty .mag in scratch dir for each cell. Change cell's +# writeable flag. +# +# Skipped cells: +# In all cases, cells are skipped if +# 'cellname filepath' matches ::scratchWritableDir (already scratchified), +# This proc does NOT try and force expand; it presumes caller forced an expand +# thus cells are skipped if: +# 'cellname filepath' is "default" (can mean not expanded yet, or created never saved), +# 'cellname filepath' is .mag, indicates failed expand (unbound). +# Note: when filepath gives "default" or .mag, the writeable check not meaningful. +# +# How to scratchify all in-memory cells (still subject to internal skipping): +# scratchWritable {*}[cellname list allcells] +# +# TODO: use a combo of filepath & flags likely can detect created in-mem, +# and could redirect those too scratch dir if named explicitly. +# +# Side-effects: +# Runs zero or one subprocess, '/bin/mktemp -d' to make a scratch dir. +# Redirects where newly modified cells would be saved, if they ever are saved. +# Make's a scratch dir that needs to be cleaned-up. +# Leaves empty *.mag files in that scratch dir. +# +# Uses/requires proc cellnameExists. +# +# Same scratch-dir is reused if called multiple times, until next -cleanup. +# +# return value: list of cells not processed (skipped) for reasons cited above. +# Non-existent cells are also skipped but not included in the return list. +# +if {![info exists ::scratchWritableDir]} {set ::scratchWritableDir {}} +if {![info exists ::scratchWritableVerb]} {set ::scratchWritableVerb 0} +proc scratchWritable {args} { + # parse -cleanup option + set clean [expr {[lindex $args 0] eq {-cleanup}}] + if {$clean} { + set args [lrange $args 1 end] + } + + # If explicit cells given: don't limit to processing just readOnly cells. + set onlyReadonly [expr {$args == {}}] + + # only if no -cleanup, does empty cell list imply all cells + set allcell [cellname list allcells] + if {!$clean && $args == {}} { + set args $allcell + } + + # do cleanup + if {$clean} { + if {$::scratchWritableDir != {} && [file isdir $::scratchWritableDir]} { + set files [glob -dir $::scratchWritableDir -- {*.ext} {*.mag}] + lappend files $::scratchWritableDir + if {$::scratchWritableVerb} { + puts "scratchWritable: running, file delete $files" + } + eval {file delete} $files + set ::scratchWritableDir {} + } + } + + # Filter out non-existent or unbound cells. + # Optionally filter already writable cells. + # + # Unbounds result from placements of cells that now don't exist: + # fail to expand. This proc does not try and force expand; it + # presumes a forced expand was already done by caller (if caller + # wished). + # + # Referenced/used cells are initially unexpanded, not yet even located + # located in the search path, 'cellname filepath' returns "default". + # If expand fails (not found in search path), then 'cellname filepath' + # returns .mag, if expand worked, the directory containing + # the cell. + # + # If cell was 'cellname create' made, but never saved also "default". + # Such a cell is writable. So filter "default" and .mag. + set skipped {} + set ercell1 {} + set docells {} + foreach cell $args { + # filter (without recording as skipped) non-existent cells. + if {![cellnameExists $cell]} { continue } + + # filepath = "default": unexpanded (not loaded from disk), + # or created in-mem and never saved (is writable already + # though flags won't say so): skip both. + # TODO: use a combo of filepath & flags likely can detect created in-mem, + # and might be able to redirect them too to scratch dir if named explicitly. + set tmppath [cellname list filepath $cell] + if {$tmppath eq "default"} { + lappend skipped $cell + continue + } + + # flags not meaningful, until expanded or expand attempted. + # After expand attempt (filepath != "default"), and flags + # can now be used to determine cell unbound: not available. + set flags [cellname list flags $cell] + if {[lsearch -exact $flags available] < 0} { + lappend ercell1 $cell + continue + } + + if {$onlyReadonly && + [cellname list writeable $cell] eq "writeable"} { + lappend skipped $cell + continue + } + lappend docells $cell + } + + if {$::scratchWritableVerb} { + puts "scratchWritable: skipped cells: $skipped" + } + + # don't make a scratch dir if no work to do + if {$docells == {}} { + if {$::scratchWritableVerb} { + puts "scratchWritable: scratch-directed 0 cells" + } + # throw if any errors + if {$ercell1 != {}} { + set pre "ERROR: scratchWritable, " + set msg "$pre unbound cell(s): $ercell1" + error $msg + } + return $skipped + } + + # make a scratch dir if needed + if {$::scratchWritableDir == {}} { + if {[catch {set dir [string trimright [exec /bin/mktemp -d]]} msg]} { + error "ERROR: scratchWritable, '/bin/mktemp -d' failed, $msg" + } + if {![file isdir $dir] || ![file writable $dir]} { + error "ERROR: scratchWritable, mktemp gave $dir, not a writable dir" + } + set ::scratchWritableDir $dir + } + + set ercell2 {} + set okcell {} + set madef 0 + foreach cell $docells { + # Relocate if needed: filepath doesn't already point to the scratch dir). + # 'cellname list filepath ' -> appears to omit .mag extension, + # but disk-file needs the .mag in the path. + set trgr [file join $::scratchWritableDir "$cell"] ;# expected "lookup" path + set trgw [file join $::scratchWritableDir "$cell.mag"] ;# true "write" disk path + set src [cellname list filepath $cell] + if {[cellname list filepath $cell] ne $trgr && [cellname list filepath $cell] ne $trgw} { + + # make empty .mag for the cell + if {[catch {set outmag [open $trgw w]} msg]} { + lappend ercell2 $cell + continue + } + incr madef + close $outmag + + # relocate cell to new file + cellname list filepath $cell $::scratchWritableDir + } + + # make cell writable + cellname list writeable $cell true + lappend okcell $cell + } + + if {$::scratchWritableVerb} { + puts "scratchWritable: scratch-directed $madef cells" + } + if {$ercell1 != {} || $ercell2 != {}} { + set pre "ERROR: scratchWritable, " + set msg {} + if {$ercell1 != {}} { + lappend msg "$pre unbound cell(s): $ercell1" + } + if {$ercell2 != {}} { + lappend msg "$pre failed to make .mag for cell(s): $ercell2" + } + error [join $msg "\n"] + } + set skipped +} ;# end proc scratchWritable +} + +# without top-level proc around bulk of script, intermediate error statements don't abort script. +proc main {argv} { + +# (magic renames the TCL clock command) +set clockp clock +if {[info command $clockp] == {} && [info command orig_clock] != {}} { + set clockp orig_clock +} +set nowSec [$clockp seconds] +set timestamp [$clockp format $nowSec -format "%Y-%m-%d.%T.%Z"] + +# process name-value pair options, if any +set nbrErr 0 +set ndx 0 +set max [llength $argv] +set extTechOpt {} ;# -T ... +set enumFilel {} ;# -l ... enum output file +set enumFileKm {} ;# -km ... enum output file +set doFeedback 1 ;# -n: to turn off feedback +set variant {} ;# -S ... non-default drc style +set subcellTab 1 ;# -tt, -tc both turn OFF subcell count-by-error report +set topcellTab 1 ;# -tc turns OFF topcell count-by-error report +set flatten 0 +set perfN 0 ;# -P do crude DRC perf. test +set noderef 0 ;# -N disable dereference option of: 'load ... -dereference' + +while {$ndx < $max && [string match "-*" [lindex $argv $ndx]]} { + set opt [lindex $argv $ndx] + incr ndx + switch -exact -- $opt { + -T { + if {$ndx == $max} { + usage "missing tech-file argument for -T option" + exit 1 + } + set extTechOpt [lindex $argv $ndx] + incr ndx + } + -S { + if {$ndx == $max} { + usage "missing drcStyle argument for -S option" + exit 1 + } + set variant [lindex $argv $ndx] + incr ndx + } + -P { + if {$ndx == $max} { + usage "missing count argument for -P option" + exit 1 + } + set perfN [lindex $argv $ndx] + incr ndx + } + -F { + set flatten 1 + } + -N { + set noderef 1 + } + -n { + set doFeedback 0 + } + -tt { set subcellTab 0 ; set topcellTab 1} + -tc { set subcellTab 0 ; set topcellTab 0 } + -km { + if {$ndx == $max} { + usage "missing outputFile argument for -km option" + exit 1 + } + set enumFileKm [lindex $argv $ndx] + incr ndx + } + -l { + if {$ndx == $max} { + usage "missing outputFile argument for -l option" + exit 1 + } + set enumFilel [lindex $argv $ndx] + incr ndx + if {[catch {set enumOut [open $enumFilel w]} msg]} { + error "ERROR: ${::Prog}: failed to open-for-write '$enumFilel' threw error, $msg" + } + puts "${::Prog}: enumerating each error bbox to: $enumFilel" + } + default { + usage "unknown option: $opt" + exit 1 + } + } +} + +if {$ndx == $max} { + usage "missing magFileName argument, the topcell" + exit 1 +} + +# get cmd-line topcell, minus dir-path; and minus extension IFF ext is .mag +set topcfull [lindex $argv $ndx] ; incr ndx +set topc [file tail $topcfull] +if {[file extension $topc] eq ".mag"} { + set topc [file rootname $topc] +} +set topcStr $topc + +# abort if user supplies extra args. +if {$ndx != $max} { + usage "extra/unspported arg past magFileName, '[lindex $argv $ndx]'" + exit 1 +} + +# load the techfile +if {$extTechOpt != ""} { + if {![file readable $extTechOpt]} { + error "ERROR: ${::Prog}: tech-file \"$extTechOpt\" is not readable." + } + + tech load $extTechOpt + + # Verify the cmd-line -T option (if any) is still the current 'tech filename'. If we didn't + # explicitly 'tech load' ourselves, the .magicrc or magic.setup might 'tech load' something else. + # The 'file join [pwd] ...' makes relative path absolute, but without resolving + # all symlinks (which 'file normalize' would do). + set techf2 [file join [pwd] [tech filename]] + set techf1 [file join [pwd] $extTechOpt] + if {$techf1 != $techf2} { + error "ERROR: ${::Prog}: failed tech-load \"$techf1\" (tech-filename=\"$techf2\" not a match)" + } +} + +# write a line with timestamp and all arguments to stdout (log) +# Show quoted logged argv here so it's machine readable for replay purposes. +puts "${::Prog}: timestamp: $timestamp, arguments: $::env(_M0)" + +puts "${::Prog}: running drc on topcell: $topcStr" +reportTechFile + +# log the cell search path for this run. Emulates format output by plain "path" (but which prints more than one the cell search path). +puts "Search path for cells is \"[path search]\"" + +# BEFORE LOAD cell: turn off background checker. We'll invoke checks explicitly. +drc off + +# warning on combo of -tc & -km. If -km ok, open its output file. +if {$enumFileKm ne {}} { + if {! $topcellTab} { + puts "WARNING: ${::Prog}: with -tc cannot (-km) write klayout-marker-db" + } else { + if {[catch {set enumOutKm [open $enumFileKm w]} msg]} { + error "ERROR: ${::Prog}: failed to open-for-write '$enumFileKm' threw error, $msg" + } + puts "${::Prog}: enumerating each error bbox to: $enumFileKm" + } +} + +# if mag-cell were passed natively on magic cmd-line, this is too late: +if {$noderef} { + load $topcfull +} else { + load $topcfull -dereference +} + +# error checks: ensure (1st) cmd-line cellname now in-memory, and is now the current cell + +set topcells [cellname list top] +# filter (UNNAMED) +set topcells [lsearch -exact -not -all -inline $topcells "(UNNAMED)"] +# puts "cellname-list-top is: $topcells" + +# could use [cellname list flags $topc] and ensure non-null result (list with available), +# but if it fails (cell not found), it generates unwanted stdout. +if {[lsearch -exact [cellname list allcells] $topc] < 0} { + error "ERROR: ${::Prog}: cmd-line topcell \"$topc\" not in magic's list of allcells." +} + +if {[lsearch -exact $topcells $topc] < 0} { + puts "WARNING: ${::Prog}: cmd-line topcell \"$topc\" not in magic's list of topcells: $topcells" +} + +# crude way even in batch to determine the "current" cell; perhaps not yet the "Edit" cell +# WARNING, if topcell locked elsewhere or not writable, it can't become the "Edit" cell. +set topcw [cellname list window] +if {$topcw ne $topc} { + error "ERROR: ${::Prog}: cmd-line topcell, $topc, is not the current cell, 'cellname list window'=$topcw" +} + +# for topcell, filepath==default doesn't change by expand, +# indicates unknown cell created in-memory by magic's startup sequence. +if {[cellnameExists $topc] && + [cellname list filepath $topc] eq "default"} { + puts "Search path for cells is \"[path search]\"" + error "ERROR: ${::Prog}: cmd-line topcell, $topc, auto-created in-memory: not found in cell search path" +} + +if {$flatten} { + # delete (UNNAMED) if any. + set trg "(UNNAMED)" + if {[cellnameExists $trg]} {cellname delete $trg} + + # rename top cell to (UNNAMED) + cellname rename $topc $trg + + # now Edit Cell contents are original top cell, but under name (UNNAMED) + # flatten Edit-Cell into original top cell name + puts "${::Prog}: flattening..." + flatten $topc + + # load and edit new version of top cell. This is from in-memory, just making it current-cell. + # (So with or without -dereference is expected would have discernable effect by now; + # and since it's flattened there are no subcell instances either). + if {$noderef} { + load $topc + } else { + load $topc -dereference + } + + # crude way even in batch to determine the "current" cell; perhaps not yet the "Edit" cell + # WARNING, if topcell locked elsewhere or not writable, it can't become the "Edit" cell. + set topcw [cellname list window] + if {$topcw ne $topc} { + error "ERROR: ${::Prog}: assertion failed, post-flatten, $topc, is not the current cell, 'cellname list window'=$topcw" + } + + # should not be necessary: + select top cell + edit + + # crude way even in batch to determine the "current" cell; perhaps not yet the "Edit" cell + # WARNING, if topcell locked elsewhere or not writable, it can't become the "Edit" cell. + set topcw [cellname list window] + if {$topcw ne $topc} { + error "ERROR: ${::Prog}: assertion-2 failed, post-flatten, $topc, is not the current cell, 'cellname list window'=$topcw" + } +} + +# todo: Need a check for non-existent topcell (though magic reported not-found and auto-created it). +# todo: We should locate fullpath to topcell on disk to record this in the log. +# +# WARNING, magic junkCell, or magic junkDir/junkCell (passing paths to cells that don't exist), +# generate startup error messages (could not open cell), but magic creates the new cell in memory. +# No simple way to detect this after the fact. Can walk the cell search path to verify it's on disk. +# For the non-existent cell, magic also discards the dirpath from the cmd-line arg. +# If it did exist at that path, magic opens it successfully, despite that dir not in search path. +# A proper check for implicit create of non-existent cell should account for this effect too. + +set res {} +if {$variant != {}} { + if {[catch {set res [drc list style $variant]} msg]} { + puts "ERROR: ${::Prog}: but CONTINUING, 'drc style $variant' threw error, $msg" + } +} else { + if {[catch {set res [drc list style]} msg]} { + puts "ERROR: ${::Prog}: but CONTINUING, 'drc list style' threw error, $msg" + } +} +if {$res != {}} { + puts "drc style reports:\n$res" +} + +# just Manhattan is default, turn on euclidean, and log new mode +drc euclidean on +drc euclidean + +# 1st "select top cell": without it drc-list-count is blank, and error count reduced. +# May be unnecessary in some cases. +# WARNING: if topcell locked by another process, default box is NOT set to full top cell without this (as of 8.1.70 or earlier) +select top cell +# expand cell cells: scratchify step requires this up front else can't force all cells writable. +expand + +# The expand triggered load of all subcells. Till then allcells may be incomplete. +set allcells [cellname list allcells] +# filter (UNNAMED) +set allcells [lsearch -exact -not -all -inline $allcells "(UNNAMED)"] +set nbrAllCells [llength $allcells] +# puts "DEBUG: cellname-list-allcells are: $allcells" + +# TODO: do explicit separate unbound check here (don't rely on scratchWritable for this) + +# make allcells writable. Can error out: +# if are unbounds, or couldn't make scratch dir or .mag files. +set scratch [expr {!$flatten}] +if {$scratch && [catch {scratchWritable} msg]} { + puts stderr "ERROR: ${::Prog}: aborting at scratchWritable due error(s):" + error $msg +} + +# Erase all preexisting *.drtcl first. Else when cell transitions from +# dirty in previous run (leaving *.drtcl), to clean, the old *.drtcl +# remains. +# TODO: only delete *.drtcl of cells in 'cellname list allcells'? +# TODO: move this up, before scratchWritable? +if {$doFeedback} { + set files [glob -nocomplain -types {f} -- ./*.drtcl] + if {$files != {}} { + # TODO: detect/report failure details better here? + puts "${::Prog}: deleting preexisting *.drtcl" + set msg {} + set delfail [catch {eval {file delete} $files} msg] + set files [glob -nocomplain -types {f} -- ./*.drtcl] + if {$delfail || $files != {}} { + puts "ERROR: ${::Prog}: failed to clean old ./*.drtcl files. $msg" + incr nbrErr + } + } +} + +edit ;# Fails if topcell not writable, should not be not needed post scratchWritable + +set outScale [cif scale out] + +# "select top cell" and box [view bbox] should be equivalent in +# placing a box around whole cell extent. +# The box cmd ALSO prints lambda and micron user-friendly box data, +# but it prints microns with not enough resolution, +# (and no option to disable that flawed print out). +# +# todo: emulate box output in full, except for higher resolution, +# here we only scale/print the overall bbox in microns. +# select top cell ;# paranoid, reset the box to data extents post-expand +# set bbox [view bbox] +# set bbs {} +# foreach oord $bbox { +# lappend bbs [format "%.3f" [expr {$outScale * $oord}]] +# } +# puts "outScale: $outScale, view-bbox: $bbox" +# puts "Root cell box2: ([lindex $bbs 0] [lindex $bbs 1]), ([lindex $bbs 2] [lindex $bbs 3])" + +# shouldn't need: +# drc on + +# Want to use 'drc list count' to tell us which cells have errors, so we can +# run 'drc listall why' on just those cells to enumerate details (which reruns +# drc again unfortunately). + +# For accurate DRC (as of 8.1.70), specifically 'drc list count', need: +# all-writable cells, then run: 'drc check' & 'drc catchup'. +# Now we have all writable cells. +set timeRepeat 1 +if {$perfN > 0} { + set timeRepeat $perfN +} +set timeres [time { + set drcCheckTime1 [time {drc check}] + set drcCheckTime2 [time {drc catchup}] } $timeRepeat] + +if {$perfN > 0} { + puts "perf: ${perfN}X 'drc check','drc catchup': $timeres" + puts "perf: last 'drc check' time: $drcCheckTime1" + puts "perf: last 'drc catchup' time: $drcCheckTime2" + drc statistics + drc rulestats +} + +# todo: this 2nd select was in GDS version, test if needed in mag version: +# 2nd select top cell needed else error count may be reduced (why? bbox does not change due to DRC) +select top cell +set outScale [cif scale out] +set bbox [view bbox] +set bbs {} +foreach oord $bbox { + lappend bbs [format "%.3f" [expr {$outScale * $oord}]] +} +puts "outScale(ostyle=[cif list ostyle]): $outScale, view-bbox: $bbox" +puts "Root cell box: ([lindex $bbs 0] [lindex $bbs 1]), ([lindex $bbs 2] [lindex $bbs 3])" +# print several native bbox representations: +box + +# listall vs list appear same as of 8.1.70 or earlier. +# warning: celllist order is not stable, not repeatable; run to run on same data. +# puts "DEBUG: (drc listall count total) is $drcListCountTot" +set celllist [drc listall count] +set celllist [lsearch -not -all -inline -index 0 -exact $celllist "(UNNAMED)"] +# puts "DEBUG: (drc listall count) is [drc listall count]" +set drcListCountTot [drc list count total] +set nbrErrCells [llength $celllist] + +# TODO: major problem: 'drc listall why' repeated an every cell, will do subcells +# multiple times, as many times as their depth in the hier. + +# canonicalize order of celllist, move topc to last (if present whatsoever). +# force our own artificial entry for topc (zero errors) if not present (was clean) +# puts "DEBUG: celllist before: $celllist" +set topcPair [lsearch -inline -index 0 -exact $celllist $topc] +set celllist [lsearch -not -all -inline -index 0 -exact $celllist $topc] +set celllist [lsort -index 0 -dictionary $celllist] +if {$topcPair == {}} { + # puts "DEBUG: $topc clean, forcing celllist entry for it" + set topcPair [list $topc 0] +} +lappend celllist $topcPair +# puts "DEBUG: celllist after: $celllist" +# puts "DEBUG: adjusted celllist(drc list count) is $celllist" + +array set cell2why [list $topc {}] ;# default at least empty topcell why list + +# If topc has non-zero errors, get its 'drc listall why' immediately. +# Does this save time? Experience says no, that 'drc why' is ALWAYS an expensive +# rerun of the DRCs. +# At topcell, can you get both the drc-listall-count and drc-listall-why +# in either order, *without* paying the price of running DRC-twice? Don't believe so. +# In case this changes one day, we still try to get topcell why enumeration soonest. +if {[lindex $topcPair 1] != 0} { + set cell2why($topc) [drc listall why] +} + +# Now we are ABSOLUTELY DONE with the topcell magic-layout. +# So free it to reclaim memory. (Reduce peak process size somewhat). +# TODO: we should order all cells top-down (for the 'drc-why' pass) +# so we can free every cell's data after collecting its drc-why. +cellname delete $topc + +array set kmErr2catNm {} +array set kmErr2catDesc {} +array set kmCell2item {} +if {$celllist != {} && [info exists enumOutKm]} { + # Header example of .lyrdb klayout Marker format + # + # + # Diff of 'x.gds, Cell RINGO' vs. 'x.gds[1], Cell INV2' + # + # + # RINGO + # + # + # red + # Red flag + # + # ... + # + + puts $enumOutKm {} + puts $enumOutKm "$topc DRC timestamp: $timestamp, arguments: $::env(_M0)" + puts $enumOutKm {} + puts $enumOutKm "$topc" + puts $enumOutKm {} + puts $enumOutKm {} + + # multiple ... sections do accumulate, but cells and categories need + # to be defined before use in an item (specific error), and we know cell names here, + # so declare all cells to klayout here. + # + # Cell-specific header of klayout marker file + # + # CELLNAME1 + # 1 (don't need) + # + # + foreach pair $celllist { + set acell [lindex $pair 0] + + # for -tt, no subcell error-detail: don't write subcells in ... section. + if {$acell ne $topc && ! $subcellTab} { continue } + + puts $enumOutKm " $acell" + set kmCell2item($acell) {} + } + puts $enumOutKm {} +} + +# drc-why pass: loop over celllist +# collect 'drc listall why' for the cells in 'cell list count' with non-zero errors +# If 'drc listall why' does report zero (shouldn't since we're only processing cells +# with non-zero counts), it unavoidably writes to console a No drc errors found message. +# We don't want such polluting our list of per-cell pareto's, so don't risk running +# drc why in-line, in-between per-cell paretos. +# +foreach pair $celllist { + if {[lindex $pair 1] < 1} {continue} ;# only happens for topcell if topcell clean + set acell [lindex $pair 0] + + # if we already have drc-why data for this cell (i.e. it's the topcell), + # no need to rerun (the expensive) drc-why. + if {[info exists cell2why($acell)]} { + continue + } + + # TODO: magic needs a useful error checkable load command. + # The 'load' writes errors to console/stdout, but never throws an error, + # nor gives a useful return value. i.e. These catch never catch. + if {$noderef} { + if {[catch {set res [load $acell]} msg]} { + puts "ERROR: ${::Prog}: 'load $acell' threw error, $msg" + exit 1 + } + } else { + if {[catch {set res [load $acell -dereference]} msg]} { + puts "ERROR: ${::Prog}: 'load $acell -dereference' threw error, $msg" + exit 1 + } + } + select top cell ;# paranoid, that without it, drc's are reduced + + # optionally do crude DRC perf. analysis here. Only for top-cell, only if -P option given. + set timeRepeat 1 + if {$perfN > 0 && $topc eq $acell} { + set timeRepeat $perfN + } + set timeres [time {set cell2why($acell) [drc listall why]} $timeRepeat] + if {$perfN > 0 && $topc eq $acell} { + puts "perf: ${::Prog}: for '$acell', ${perfN}X 'drc listall why': $timeres" + } +} + +# done with all magic-specifics here. Shouldn't need scratch dir any longer. +# If this prints something (generally does), don't want it after the pareto table. + +# clean/remove the tmp scratch dir and contents +# TODO: all fatal errors need to call a cleanup proc that includes this before abort +if {$scratch && [catch {scratchWritable -cleanup} msg]} { + puts "ERROR: ${::Prog}: 'scratchWritable -cleanup' threw error, $msg" + incr nbrErr +} + +set gtotal 0 +set gcells 0 +set lumpedHeader 0 +foreach pair $celllist { + set acell [lindex $pair 0] + set acount [lindex $pair 1] + + if {$acell ne $topc && ! $subcellTab} { + if {! $lumpedHeader} { + puts "--- #err|cell, lumped total counts" + set lumpedHeader 1 + } + puts "[format {%8d} $acount] $acell" + incr gcells + incr gtotal $acount + continue + } + if {$acell eq $topc && ! $topcellTab} { + if {! $lumpedHeader} { + puts "--- #err|cell, lumped total counts" + set lumpedHeader 1 + } + puts "[format {%8d} $acount] $acell" + incr gcells + incr gtotal $acount + continue + } + puts "" + if {![info exists cell2why($acell)]} { + puts "ERROR: ${::Prog}: cell: $acell, assertion failed, no drc-why list for 'drc list count' pair: $pair" + # exit 1 + continue + } + set whys $cell2why($acell) + + # enumerate errors under box, plain "drc why" only reports unique types, no quantities + # as-yet-undocumented "drc listall why" gives: {errStr1 {errBox1 ...} errStr2 {errBox1 ...} ... } + set pareto {} + set total 0 + set enumTotal 0 + set types 0 + set typeDup 0 + set dups 0 + + set fbOut {} + # file path for feedback, keep in CWD + if {$doFeedback && $fbOut == {}} { + set fbOut "./$acell.drtcl" + if {![file writable $fbOut] && + ([file exists $fbOut] || ![file writable [file dir $fbOut]])} { + puts stderr "ERROR: ${::Prog}: feedback output not writable, $fbOut" + incr nbrErr + set fbOut {} + } elseif {[catch {set outfb [open $fbOut w]} msg]} { + puts stderr "ERROR: ${::Prog}: failed to truncate previous feedback output, $fbOut : $msg" + incr nbrErr + set fbOut {} + } + } + foreach {str boxes} $whys { + # sort errors + set boxes [lsort -dictionary $boxes] + + # for our pareto, gather data + set this [llength $boxes] + incr total $this + incr types + lappend pareto [list $this $str] + + # for enumOut, emulate formatting of $CAD_ROOT/magic/tcl/drc.tcl, which is + # not tk pure: fails with complaint about winfo + # note: we walk these errors also in order to count/report stats on duplicates, even if not outputing enumerations + if {[info exists enumOut]} { + if {$types == 1} { + puts $enumOut "[join $pair]\n----------------------------------------" + } + puts $enumOut "${str}\n----------------------------------------" + } + if {[info exists enumOutKm]} { + # category names must be declared all together up front before use in items + # so we only store their names (error strings) and error detail (items) + # to dump after all cells and errors are processed. + # TODO: Only quote catName in item if embeds dot, instead of full-time + # TODO: test klayout handles literal (non-entity) single-quote in double-quoted name + set strKmNm $str + set strKmDesc $str + regsub -all -- {&} $strKmDesc {\&} strKmDesc ;# perhaps not needed; just in case + regsub -all -- {<} $strKmDesc {\<} strKmDesc ;# description does not have such bug, so use correct entity + regsub -all -- {>} $strKmDesc {\>} strKmDesc ;# perhaps not needed; just in case + regsub -all -- {&} $strKmNm {-and-} strKmNm ;# perhaps not needed; just in case + regsub -all -- {>} $strKmNm {-gt-} strKmNm ;# perhaps not needed; just in case + regsub -all -- {<} $strKmNm {-lt-} strKmNm ;# catName klayout bug: info win truncates at '<' as < entity + regsub -all -- "\"" $strKmNm {'} strKmNm ;# we dqoute each catNm in item, so change embedded double to single + set kmErr2catNm($str) $strKmNm + set kmErr2catDesc($str) $strKmDesc + # + # example klayout Marker format, header of one item (one error instance) + # + # (don't need?) + # (don't need?) + # 'DRC-MSG-STR' (cat1.cat2 path delimit by dot: names with dot need single|double quotes) + # RINGO:1 (don't need :N variant suffix) + # false (optional? start with false?) + # 1 (not boolean, if error "represents" more that are NOT enumerated) + # ... + # + + set itemStr "\"$strKmNm\"$acell" + } + set lastq {} + set thisDup 0 + foreach quad $boxes { + set quadUM {} + set kmBoxUM {} + foreach coord $quad { + set valum [expr {$coord * $outScale}] + set valumf [format "%.3f" $valum] + lappend quadUM "${valumf}um" + lappend kmBoxUM ${valumf} + } + set dup [expr {$quad == $lastq}] + incr thisDup $dup + set line $quadUM + if {[info exists enumOut]} { + if {$dup} { + puts $enumOut "[join $line] #dup" + } else { + puts $enumOut [join $line] + } + } + if {[info exists enumOutKm]} { + # text: 'item: polygon' (text is optional? Repeat the box coordinates here in um?) + # polygon: (1.4,1.8;-1.4,1.8;-1.4,3.8;1.4,3.8) + # box: (1.4,1.8;-1.4,3.8) + # + set kmItem $itemStr + append kmItem " box: ([lindex $kmBoxUM 0],[lindex $kmBoxUM 1];[lindex $kmBoxUM 2],[lindex $kmBoxUM 3])" + if {$dup} { + append kmItem " text: 'dup'" + } + append kmItem " " + lappend kmCell2item($acell) $kmItem + } + if {$fbOut != {}} { + set line [join $quadUM] + regsub -all -- "(\[\[\"\$\\\\])" $str {\\\1} strdq + puts $outfb "[concat box $line]" nonewline + puts $outfb " ; feedback add \"$strdq\" medium" nonewline + if {$dup} { + puts $outfb " ;#dup" + } else { + puts $outfb "" + } + } + + incr enumTotal + set lastq $quad + } + if {$thisDup} { + incr typeDup + incr dups $thisDup + } + if {[info exists enumOut]} { + puts $enumOut "----------------------------------------\n" + } + } + + if {$fbOut != {}} { + close $outfb + set outfb {} + } + + set pareto [lsort -integer -decreasing -index 0 $pareto] + if {$total > 0} { + puts "--- #err|description, table for cell: $acell" + } + foreach pair $pareto { + puts "[format {%8d} [lindex $pair 0]] [lindex $pair 1]" + } + if {$typeDup} { + puts "[format {%8d} $dups] total duplicate error(s) among $typeDup error type(s), cell: $acell" + } + puts "[format {%8d} $total] total error(s) among $types error type(s), cell: $acell" + # add to grand-totals + incr gcells + incr gtotal $total + + # always compare the total from the enum to the pareto as error check + if {$total != $enumTotal} { + puts "ERROR: ${::Prog}: cell: $acell, internal error, pareto vs enum count mismatch: $total != $enumTotal" + incr nbrErr + } +} + +# TODO: in the summary echo also techfile-full-path and drc-style name? +# grand totals +puts "[format {%8d} $nbrErrCells] of $nbrAllCells cell(s) report error(s)" +puts "[format {%8d} $gtotal] grand-total error(s) across $gcells cell(s)" + +# wish to compare the drc-list-count-total to the pareto total. +# Per te 2014-08-27 : it is not an error. +# if {$total != $drcListCountTot} { +# puts "info: ${::Prog}: drc-list-count-total vs drc-listall-why mismatch {drc list count total} gave $drcListCountTot, but {drc listall why} gave $total" +# } + +if {[info exists enumOut]} { + close $enumOut +} +if {[info exists enumOutKm]} { + # declare all category names and descriptions, note '<' in name vs description are represented differently + # + # layerN width -lt- 1.0um + # layerN width < 1.0um + # ... + # + puts $enumOutKm "" + foreach errStr [array names kmErr2catNm] { + set nm $kmErr2catNm($errStr) + set desc $kmErr2catDesc($errStr) + puts $enumOutKm " $nm$desc" + } + puts $enumOutKm "" + + # dump all items (after all cells and all categories have been defined up front) + puts $enumOutKm "" + foreach {acell items} [array get kmCell2item] { + foreach item $items { + puts $enumOutKm $item + } + } + puts $enumOutKm "" + + # footer example .lyrdb klayout Marker file + # + puts $enumOutKm {} + close $enumOutKm +} + +# set celllist4 [drc list count] +# puts "DEBUG: drc list count0: $celllist0" +# puts "DEBUG: drc list count1: $celllist1" +# puts "DEBUG: drc list count2: $celllist2" +# puts "DEBUG: drc list count3: $celllist3" +# puts "DEBUG: native (drc list count) is $celllistn" +# puts "DEBUG: drc list count4: $celllist4" + +# todo: implement super-pareto, ranked table of SUM of all DRC errs/counts from ALL cells. +# (It still would not reflect as-if-flat hierarchical expansion due to repetition of instances). + +set nbrErr +} + +# non-zero exit-status on errors, either if thrown by main, or counted and returned by main +set nbrErr 0 +if {[catch {set nbrErr [main $argv]} msg]} { + puts stderr $msg + set nbrErr 1 +} elseif {$nbrErr > 0} { + puts "ERROR: ${::Prog}: script terminated with errors reported above." +} +exit $nbrErr + +# for emacs syntax-mode: +# Local Variables: +# mode:tcl +# End: diff --git a/images/foss-asic-tools/addons/sak/magic/magicGdrc b/images/foss-asic-tools/addons/sak/magic/magicGdrc new file mode 100755 index 00000000..4344443d --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/magicGdrc @@ -0,0 +1,896 @@ +#!/bin/sh +# Copyright (C) 2014, 2015, 2020 efabless Corporation. All Rights Reserved. +# send a very-first -T FILE to magic's startup, hide all other args from magic-startup +# for-bash\ + export _M0= ;\ + for i in "$@" ; do _M0="$_M0${_M0:+ }\"${i//\"/\\\"}\""; done ;\ + case "$1" in -T) tch="$2"; shift; shift; _MARGS="$*" exec magic -dnull -noconsole -T "$tch" <"$0" ;; esac +# hide next line from magic(tclsh):\ +_MARGS="$*" exec magic -dnull -noconsole <"$0" +# +# magicDRC: run magic-DRC in batch on a GDS file, tabulate/pareto the error counts. +# +# rb@ef 2014-08-28 author +# rb 2020-02-19 embed some library functions, to standalone from efabless-opengalaxy env, test via magic-8.2.188 +# +# todo: support "-" as GDS file arg, to mean GDS from stdin +# + +set ::Prog "magicGdrc" +set argv [eval "list $env(_M0)"] ;# orig. mix of native plus custom args, for logging all args to script +# set argv [split $env(_MARGS)] ;# (currently unused) + +proc usage {args} { + if {[llength $args] > 0} { + puts "ERROR: ${::Prog}: [join $args]" + } + puts {usage: [ -T techfilePath ] [-S ] [-I ] [-km FILE_NAME] [-l FILE_NAME] [-L FILE_NAME] gdsFileName [topCellName]} + puts " -T if given, must be very first" + puts " -S if given, changes from techfile's default/1st drc style (perhaps \"drc(fast)\") to named style, for example: -S \"drc(full)\"" + puts " -I if given, changes from techfile's default/1st cifinput style (perhaps \"vendorimport\" or \"import(exact)\") to named style, for example: -I \"import(magic)\"" + puts " -path-sub do 'gds path subcell yes' (default:no). Make unique subcell for each path: cut #tiles cost of angles." + puts " -poly-sub do 'gds polygon subcell yes' (default:no). Make unique subcell for each polygon: cut #tiles cost of angles." +# gds polygon subcell [yes|no] + puts " -pps Short hand, equivalent to giving both: -path-sub -poly-sub" + puts "" + puts " Error tabulation: By default (slowest, most detail): Report table of counts-by-errorString for all cells." + puts " Stdout logs a pareto of error-type by count unless disabled for some/all cells by below; topcell last." + puts " -tt Table of counts-by-errorString for ONLY topcell; and just lumped total error count per subcell." + puts " -tc Just lumped error counts per cell including topcell (fastest, least detail)." + puts " Cells NOT tabulating count-by-errorString can't appear in other output error files: feedback(*.drtcl), -l, -km." + puts " For lumped error counts, overlapped error shapes from unique error-types are merged further reducing count." + puts "" + puts " cell-type +-- (default) --+-- option -tt --+-- option -tc" + puts " subcell | count-by-errorString | lumped-error-count | lumped-error-count" + puts " topcell | count-by-errorString | count-by-errorString | lumped-error-count" + puts "" + puts " -km if given, write to FILE_NAME EVERY individual error bbox (MICRONS) in klayout Marker database(XML) format (suggest *.lyrdb)" + puts " -l if given, enumerates EVERY individual error bbox (MICRONS) to FILE_NAME, emulates $::CAD_ROOT/magic/tcl/drc.tcl" + puts " -L same as -l above, but outputs bbox-es in LAMBDA coordinates, not microns" + puts " -nf Do NOT write *.drtcl per-cell feedback files. Can be source-ed in magic and step thru: feedback find." + puts "" + puts " NOTES: Without explicit tech-file option: the ./.magicrc or ./magic_setup and ~/.magicrc may load a default tech-file." + puts " Therefore the tech-file used CAN depend on whether your CWD is ~/design//mag when running this script." + puts " Since no *.mag are loaded by this script: the cell search path defined by any init files has no impact." + puts " Since about 8.3.68, magic may generate error-type \"See error definition in the subcell\". There typically are" + puts " redundancies of errors across the hierarchy anyway (but with tech-file err-strings), this seems another form." + puts "" + puts "example, just list all styles: by causing an error which provokes usage report:" + puts " magicGdrc -T /ef/tech/XFAB/EFXH035B/libs.tech/magic/current/EFXH035B.tech" + puts "example, same but run in a ~/design/*/mag/ dir, so techfile set by ./.magicrc (else magic's builtin minimum.tech):" + puts " magicGdrc" + puts "example, run GDS drc, explicit: tech, cif-istyle, drc-style:" + puts " magicGdrc -T /ef/tech/SW/EFS8A/libs.tech/magic/current/EFS8A.tech -I vendorimport -S 'drc(full)' /tmp/mytop.gds mytopcell" + puts "example, run GDS drc, default tech & styles, write klayout marker database, no per-cell *.drtcl feedback files:" + puts " magicGdrc -km /tmp/mytop.lyrdb -nf /tmp/mytop.gds mytopcell" + puts "example, same but make subcells for paths & polygons" + puts " magicGdrc -km /tmp/mytop.lyrdb -nf -pps /tmp/mytop.gds mytopcell" + puts "example, run GDS drc, no feedback (*.drtcl), only lumped/merged err-count for all cells" + puts " magicGdrc -tc /tmp/mytop.gds mytopcell" + puts "example, run GDS drc, no feedback (*.drtcl), lumped/merged err-count for subcells, detail errors for topcell" + puts " magicGdrc -nf -tt /tmp/mytop.gds mytopcell" + puts "" + + reportTechFile + reportAllStyles + puts "" + + if {[llength $args] > 0} { + puts "ERROR: ${::Prog}: [join $args]" + } +} +proc gdsChk {file} { + foreach suffix {"" ".gds" ".gds2" ".strm"} { + if {[file readable "${file}${suffix}"]} {return 1} + } + puts "ERROR: ${::Prog}: Cannot open (as-is or with .gds, .gds2, or .strm) to read GDS-II stream from: $file" + exit 1 +} + +proc reportTechFile {} { + puts "${::Prog}: tech-name: [tech name] -version: [tech version] -filename: [tech filename] -lambda [tech lambda]" +} + +# query currently loaded tech-file for styles the user might need for -I -S options +# Suggest a bad tech-file if none are found or errors thrown. +# Used after finding error in -I -S options, and probably should add it to the usage. +proc reportAllStyles {} { + set errs {} + if {[catch {set allstyle [cif listall istyle]} msg]} { + lappend errs "ERROR: ${::Prog}: bad tech-file? failed to 'cif listall istyle', $msg" + } elseif {$allstyle == {}} { + lappend errs "ERROR: ${::Prog}: bad tech-file? no cifinput styles found by 'cif listall istyle'" + } else { + puts "info: ${::Prog}: cifinput styles available: $allstyle" + } + if {[catch {set allstyle [drc listall style]} msg]} { + lappend errs "ERROR: ${::Prog}: bad tech-file? failed to 'drc listall style', $msg" + } elseif {$allstyle == {}} { + lappend errs "ERROR: ${::Prog}: bad tech-file? no drc styles found by 'drc listall style'" + } else { + puts "info: ${::Prog}: drc styles available: $allstyle" + } + if {$errs != {}} { + + } + return [llength $errs] +} + +# optionally hardcode library proc-s (part of site-wide extensions - always available - in context of efabless/open-galaxy) +# This is to make the script more standalone from efabless environment; but these capabilities should be native to magic. + +if {[info command unbounds] == {}} { + puts "${::Prog}: hardcoding library proc-s..." +# Replacement for 'cellname list exists CELLNAME', to fix ambiguity for cell "0". +# For cell "0" test for membership in 'cellname list allcells'. +# +# Instead of returning 0 for (non-existent) and cellname for exists, +# returns regular 0/1 instead for non-existent/exists. +# +# Therefore NOT direct replacement for uses of 'cellname list exists CELL'. +# Requires code changes. +proc cellnameExists {cell} { + expr {$cell ne "0" && [cellname list exists $cell] eq $cell || + $cell eq "0" && [lsearch -exact [cellname list allcells] $cell] > -1} +} + +# Walk allcells to get/return list of cellNames that are unbound. +# Only use this after: 'select top cell; expand' to expand whole hierarchy. +# +# foreach CELL in 'cellname list allcells': +# if flags says available : it's Bound, goto next cell. +# if filepath is "default", try to expand the cell. +# if still "default"**: cell made by "cellname create", never saved, goto next. +# if filepath is CELL.mag, check for "available" flags, if none: Unbound. +# else cell is bound. +# **: should never get there +proc unbounds {} { + set allcells [cellname list allcells] + # filter (UNNAMED) + set allcells [lsearch -exact -not -all -inline $allcells "(UNNAMED)"] + # set nbrAllCells [llength $allcells] + set ercell {} + foreach cell $allcells { + # filter (without recording as skipped) non-existent cells. + if {![cellnameExists $cell]} { continue } + + # filepath = "default": unexpanded (not loaded from disk), + # or created in-mem and never saved (is writable already + # though flags won't say so): skip both. + # TODO: use a combo of filepath & flags likely can detect created in-mem + set tmppath [cellname list filepath $cell] + if {$tmppath eq "default"} { + lappend skipped $cell + continue + } + + # flags not meaningful, until expanded or expand attempted. + # After expand attempt (filepath != "default"), and flags + # can now be used to determine cell unbound: not available. + set flags [cellname list flags $cell] + if {[lsearch -exact $flags available] < 0} { + lappend ercell $cell + continue + } + } + set ercell ;# return list of unbound cells, if any +} +} + +# without top-level proc around bulk of script, intermediate error statements don't abort script. +proc main {argv} { + +set mlen [llength $argv] + +# process name-value pair options, if any +set nbrErr 0 +set ndx 0 +set max [llength $argv] +set extTechOpt {} ;# -T ... but not used here +set enumFilel {} ;# -l ... enum output file +set enumFileL {} ;# -L ... enum output file +set enumFileKm {} ;# -km ... enum output file +set variant {} ;# -S ... non-default drc style +set istyle {} ;# -I ... non-default cifinput style +set doFeedback 1 ;# -nf sets to 0: Do not write *.drtcl per-cell feedback files. +set pathSub 0 ;# -path-sub ... do 'gds path subcell yes' +set polySub 0 ;# -poly-sub ... do 'gds polygon subcell yes' +set subcellTab 1 ;# -tt, -tc both turn OFF subcell count-by-error report +set topcellTab 1 ;# -tc turns OFF topcell count-by-error report +set flatten 0 +while {$ndx < $max && [string match "-*" [lindex $argv $ndx]]} { + set opt [lindex $argv $ndx] + incr ndx + switch -exact -- $opt { + -T { + if {$ndx != 1} { + usage "-T option must very 1st (here was #$ndx)" + exit 1 + } + if {$ndx == $max} { + usage "missing tech-file argument for -T option" + exit 1 + } + set extTechOpt [lindex $argv $ndx] ;# unused + incr ndx + } + -S { + if {$ndx == $max} { + usage "missing drcStyle argument for -S option" + exit 1 + } + set variant [lindex $argv $ndx] + incr ndx + } + -I { + if {$ndx == $max} { + usage "missing cifinput-style argument for -I option" + exit 1 + } + set istyle [lindex $argv $ndx] + incr ndx + } + -F { set flatten 1} + -nf { set doFeedback 0 } + -path-sub { set pathSub 1} + -poly-sub { set polySub 1} + -pps { set pathSub 1; set polySub 1} + -tt { set subcellTab 0 ; set topcellTab 1} + -tc { set subcellTab 0 ; set topcellTab 0 } + -km { + if {$ndx == $max} { + usage "missing outputFile argument for -km option" + exit 1 + } + set enumFileKm [lindex $argv $ndx] + incr ndx + } + -l { + if {$ndx == $max} { + usage "missing outputFile argument for -l option" + exit 1 + } + set enumFilel [lindex $argv $ndx] + incr ndx + if {[catch {set enumOut [open $enumFilel w]} msg]} { + error "ERROR: ${::Prog}: failed to open-for-write '$enumFilel' threw error, $msg" + } + puts "${::Prog}: enumerating each error bbox to: $enumFilel" + } + -L { + if {$ndx == $max} { + usage "missing outputFile argument for -L option" + exit 1 + } + set enumFileL [lindex $argv $ndx] + incr ndx + if {[catch {set enumOutL [open $enumFileL w]} msg]} { + error "ERROR: ${::Prog}: failed to open-for-write '$enumFileL' threw error, $msg" + } + puts "${::Prog}: enumerating each error bbox to: $enumFileL" + } + default { + usage "unknown option: $opt" + exit 1 + } + } +} + +if {$ndx == $max} { + usage {Insufficient number of arguments, need gdsFileName [topCellName]} + exit 1 +} + +set gdsf [lindex $argv $ndx] ; incr ndx +set topc {} +set topcStr "(AUTO)" +if {$ndx < $max} { + set topc [lindex $argv $ndx] ; incr ndx + set topcStr $topc +} +# error if extra options (not understood, something is wrong): +if {$ndx < $max} { + error "ERROR: ${::Prog}: after gdsFile=\"$gdsf\", topcell=\"$topc\" found unsupported extra arguments: [lrange $argv $ndx end]" +} +# ndx no longer used for argv position from here + +gdsChk $gdsf + +# warning on combo of -tc & -km. If -km ok, open its output file. +if {$enumFileKm ne {}} { + if {! $topcellTab} { + puts "WARNING: ${::Prog}: with -tc cannot (-km) write klayout-marker-db" + } else { + if {[catch {set enumOutKm [open $enumFileKm w]} msg]} { + error "ERROR: ${::Prog}: failed to open-for-write '$enumFileKm' threw error, $msg" + } + puts "${::Prog}: enumerating each error bbox to: $enumFileKm" + } +} + +# write a line with timestamp and all arguments to stdout (log) +# (magic renames the TCL clock command) +set clockp clock +if {[info command $clockp] == {} && [info command orig_clock] != {}} { + set clockp orig_clock +} +set nowSec [$clockp seconds] +set timestamp [$clockp format $nowSec -format "%Y-%m-%d.%T.%Z"] +# TODO: quote logged argv here as needed so it's machine readable for replay purposes. +puts "${::Prog}: timestamp: $timestamp, arguments: $::env(_M0)" + +# just Manhattan is default, turn on euclidean, and log new mode +drc euclidean on +drc euclidean + +# 8.1.83 this worked: +# drc off; gds drccheck no; gds read ... ; load topcell; select top cell; expand; drc check; drc update; drc listall count +# By 8.2.64, that fails, the 'drc listall count' reports errors only in the top-cell, no subcells. +# 8.1.83 & 8.2.193 this works (gds drccheck defaults to on anyway): +# drc off; gds drccheck yes; gds read ... ; load topcell; select top cell; expand; drc check; drc update; drc listall count +# +# But are we properly avoiding redundant drc runs? +# +# turn off background checker. We'll invoke checks explicitly. +drc off +gds drccheck yes +puts "drc status (whether background checking enabled) is: [drc status]" +puts "gds drccheck (whether gds-read marks new cells as need-drc) is: [gds drccheck]" + +# set user's drc style; set user's cifinput istyle +# These are back-to-back without intervening status messages. +# If both wrong their errors are back-to-back. +set res {} +set res [drc list style] +if {$variant != {}} { + set allstyle [drc listall style] + set ndx [lsearch -exact $allstyle $variant] + if {$ndx < 0} { + puts "ERROR: ${::Prog}: drc style '$variant' not one of those available: $allstyle" + incr nbrErr + } else { + set res [drc list style $variant] + } +} +set res2 [cif list istyle] +if {$istyle != {}} { + set allstyle [cif listall istyle] + set ndx [lsearch -exact $allstyle $istyle] + if {$ndx < 0} { + puts "ERROR: ${::Prog}: istyle '$istyle' not one of those available: $allstyle" + incr nbrErr + } else { + set res2 [cif istyle $istyle] + } +} +if {$res != {}} { + puts "drc style reports:\n$res" +} +if {$res2 != {}} { + puts "cif istyle reports:\n$res2" +} + +# gds {path,polygon} subcell yes +if {$pathSub != 0} { gds path subcells yes } +puts "gds path subcells: [gds path subcells]" +if {$polySub != 0} { gds polygon subcells yes } +puts "gds polygon subcells: [gds polygon subcells]" + +# todo: this catch never happens. Need nicer error check of 'gds read' somehow. Can check for zero-sized file? +# if use /dev/null for example, it prints its own error message, but no throw, no useful return value. +puts "doing: gds read $gdsf ..." +if {[catch {set res [gds read $gdsf]} msg]} { + puts "ERROR: ${::Prog}: 'gds read $gdsf' threw error, $msg" + incr nbrErr +} +# nothing useful: +# puts "gds-read res: $res" + +set topcells [cellname list top] +set allcells [cellname list allcells] +# puts "cellname-list-top from GDS is: $topcells" +# puts "cellname-list-allcells from GDS are: $allcells" +# filter (UNNAMED) +set topcells [lsearch -exact -not -all -inline $topcells "(UNNAMED)"] +set allcells [lsearch -exact -not -all -inline $allcells "(UNNAMED)"] +set nbrAllCells [llength $allcells] + +if {$topcells == {}} { + puts "ERROR: ${::Prog}: GDS-read did not report any useful cell name(s) found." + incr nbrErr +} + +if {$nbrErr > 0} { + return $nbrErr ;# outside of main, we print termination with errors message +} + +if {$topc == {}} { + # try and infer topcell from cellname-list-top. + # presume its list of cells not placed anywhere else. + # todo: test with "library" GDS having more than one topcell + # here we just take the last entry + set topc [lindex $topcells end] + set topcStr $topc + puts "WARNING: auto-picked top-cell \"$topc\"; the topcells inferred from GDS are: $topcells" +} else { + # verify input topc argument exists in GDS read result + set ndx [lsearch -exact $allcells $topc] + if {$ndx < 0} { + puts "ERROR: ${::Prog}: top-cell name: $topc, not found in GDS" + puts "info: top cells inferred from GDS are: $topcells" + puts "info: all cells inferred from GDS are: $allcells" + return [incr nbrErr] ;# outside of main, we print termination with errors message + } +} + +puts "${::Prog}: running drc on -gds: $gdsf -topcell: $topcStr" +reportTechFile + +# todo: need to error check load command somehow (no useful return value). +# it can fail with error message (in log) like: +# File dne.mag couldn't be found +# Creating new cell +if {[catch {set res [load $topc]} msg]} { + puts "ERROR: ${::Prog}: 'load $topc' threw error (maybe cellName not found in GDS?), $msg" + return [incr nbrErr] ;# outside of main, we print termination with errors message +} +# nothing useful: +# puts "load $topc res: $res" + +if {$flatten} { + # delete (UNNAMED) if any. + set trg "(UNNAMED)" + if {[cellnameExists $trg]} {cellname delete $trg} + + # rename top cell to (UNNAMED) + cellname rename $topc $trg + + # now Edit Cell contents are original top cell, but under name (UNNAMED) + # flatten Edit-Cell into original top cell name + puts "${::Prog}: flattening..." + flatten $topc + + # load and edit new version of top cell + load $topc + + # crude way even in batch to determine the "current" cell; perhaps not yet the "Edit" cell + # WARNING, if topcell locked elsewhere or not writable, it can't become the "Edit" cell. + set topcw [cellname list window] + if {$topcw ne $topc} { + puts "ERROR: ${::Prog}: assertion failed, post-flatten, $topc, is not the current cell, 'cellname list window'=$topcw" + return [incr nbrErr] ;# outside of main, we print termination with errors message + } + + # should not be necessary: + select top cell + edit + + # crude way even in batch to determine the "current" cell; perhaps not yet the "Edit" cell + # WARNING, if topcell locked elsewhere or not writable, it can't become the "Edit" cell. + set topcw [cellname list window] + if {$topcw ne $topc} { + puts "ERROR: ${::Prog}: assertion-2 failed, post-flatten, $topc, is not the current cell, 'cellname list window'=$topcw" + return [incr nbrErr] ;# outside of main, we print termination with errors message + } +} + +# Erase all preexisting *.drtcl first. Else when cell transitions from +# dirty in previous run (leaving *.drtcl), to clean, the old *.drtcl +# remains. +# TODO: only delete *.drtcl of cells in 'cellname list allcells'? +if {$doFeedback} { + set files [glob -nocomplain -types {f} -- ./*.drtcl] + if {$flatten} { + # only delete topcell's .drtcl in flatten mode, if there is one + set files [lsearch -all -inline -exact $files ./$topc.drtcl] + } + if {$files != {}} { + # TODO: detect/report failure details better here? + puts "${::Prog}: deleting preexisting *.drtcl" + set msg {} + set delfail [catch {eval {file delete} $files} msg] + set files [glob -nocomplain -types {f} -- ./*.drtcl] + if {$delfail || $files != {}} { + puts "ERROR: ${::Prog}: failed to clean old ./*.drtcl files. $msg" + incr nbrErr + } + } +} + +# 1st "select top cell": without it drc-list-count is blank, and error count reduced. +select top cell + +set bbox0 [view bbox] +set outScale [cif scale out] + +# set bbox1 [view bbox] + +# "select top cell" and box [view bbox] should be equivalent in +# placing a box around whole cell extent. +# The box cmd ALSO prints lambda and micron user-friendly box data, +# but it prints microns with not enough resolution, +# (and no option to disable that flawed print out). +# +# todo: emulate box output in full, except for higher resolution, +# here we only scale/print the overall bbox in microns. +set bbs {} +foreach oord $bbox0 { + lappend bbs [format "%.3f" [expr {$outScale * $oord}]] +} +puts "info: outScale: [format "%.6f" $outScale], view-bbox: $bbox0" +puts "info: Root cell box: ([lindex $bbs 0] [lindex $bbs 1]), ([lindex $bbs 2] [lindex $bbs 3])" + +drc check +drc catchup +drc statistics +drc rulestats +# puts "doing plain: drc count" +drc count + +# 2nd select top cell needed else error count may be reduced (why? bbox does not change due to DRC) +select top cell + +set celllist [drc listall count] +set drcListCountTot [drc list count total] +# puts stdout "(drc listall count) is << " nonewline; puts stdout [list $celllist] nonewline; puts " >>" +# puts stdout "(drc list count) is << " nonewline; puts stdout [list [drc list count]] nonewline; puts " >>" +# puts stdout "(drc list count total) is << " nonewline; puts stdout [list $drcListCountTot] nonewline; puts " >>" +# puts stdout "(drc listall count total) is << " nonewline; puts stdout [list [drc listall count total]] nonewline; puts " >>" +# puts stdout "(drc list why) is << " nonewline; puts stdout [list [drc list why]] nonewline; puts " >>" +# puts stdout "(drc listall why) is << " nonewline; puts stdout [list [drc listall why]] nonewline; puts " >>" + +set bbox2 [view bbox] +if {$bbox2 != $bbox0} { + set bbs {} + foreach oord $bbox2 { + lappend bbs [format "%.3f" [expr {$outScale * $oord}]] + } + puts "info: outScale: [format "%.6f" $outScale], view-bbox: $bbox2" + puts "info: Root cell box2: ([lindex $bbs 0] [lindex $bbs 1]), ([lindex $bbs 2] [lindex $bbs 3])" +} + + +# canonicalize order of celllist, move topc to last (if present whatsoever). +# force our own artificial entry for topc (zero errors) if not present (was clean) +# puts "celllist before: $celllist" +set nbrErrCells [llength $celllist] +set topcPair [lsearch -inline -index 0 -exact $celllist $topc] +set celllist [lsearch -not -all -inline -index 0 -exact $celllist $topc] +set celllist [lsort -index 0 -dictionary $celllist] +if {$topcPair == {}} { + # puts "info: ${::Prog}: $topc clean, forcing celllist entry for it" + set topcPair [list $topc 0] +} +lappend celllist $topcPair +# puts stdout "adjusted celllist(drc list count) is << " nonewline; puts stdout $celllist nonewline; puts " >>" + +array set kmErr2catNm {} +array set kmErr2catDesc {} +array set kmCell2item {} +if {$celllist != {} && [info exists enumOutKm]} { + # Header example of .lyrdb klayout Marker format + # + # + # Diff of 'x.gds, Cell RINGO' vs. 'x.gds[1], Cell INV2' + # + # + # RINGO + # + # + # red + # Red flag + # + # ... + # + + puts $enumOutKm {} + puts $enumOutKm "$topc DRC timestamp: $timestamp, arguments: $::env(_M0)" + puts $enumOutKm {} + puts $enumOutKm "$topc" + puts $enumOutKm {} + puts $enumOutKm {} + + # multiple ... sections do accumulate, but cells and categories need + # to be defined before use in an item (specific error), and we know cell names here, + # so declare all cells to klayout here. + # + # Cell-specific header of klayout marker file + # + # CELLNAME1 + # 1 (don't need) + # + # + foreach pair $celllist { + set acell [lindex $pair 0] + + # for -tt, no subcell error-detail: don't write subcells in ... section. + if {$acell ne $topc && ! $subcellTab} { continue } + + puts $enumOutKm " $acell" + set kmCell2item($acell) {} + } + puts $enumOutKm {} +} + +# loop over celllist +set gtotal 0 +set gcells 0 +set lumpedHeader 0 +foreach pair $celllist { + set acell [lindex $pair 0] + set acount [lindex $pair 1] + + if {$acell ne $topc && ! $subcellTab} { + if {! $lumpedHeader} { + puts "--- #err|cell, lumped total counts" + set lumpedHeader 1 + } + puts "[format {%8d} $acount] $acell" + incr gcells + incr gtotal $acount + continue + } + if {$acell eq $topc && ! $topcellTab} { + if {! $lumpedHeader} { + puts "--- #err|cell, lumped total counts" + set lumpedHeader 1 + } + puts "[format {%8d} $acount] $acell" + incr gcells + incr gtotal $acount + continue + } + puts "" + + # todo: need useful error check of load command + if {[catch {set res [load $acell]} msg]} { + puts "ERROR: ${::Prog}: 'load $acell' threw error, $msg" + return [incr nbrErr] ;# outside of main, we print termination with errors message + } + + # instead use quiet version for per-cell selects + select top cell + + set drcListCountTot [drc listall count total] + + # enumerate errors under box, plain "drc why" only reports unique types, no quantities + # as-yet-undocumented "drc listall why" will give: {errStr1 {errBox1 ...} errStr2 {errBox1 ...} ... } + set pareto {} + set total 0 + set enumTotal 0 + set types 0 + set typeDup 0 + set dups 0 + + set fbOut {} + if {$acount != 0} { + # file path for feedback, keep in CWD + if {$doFeedback && $fbOut == {}} { + set fbOut "./$acell.drtcl" + if {![file writable $fbOut] && + ([file exists $fbOut] || ![file writable [file dir $fbOut]])} { + puts stderr "ERROR: ${::Prog}: feedback output not writable, $fbOut" + incr nbrErr + set fbOut {} + } elseif {[catch {set outfb [open $fbOut w]} msg]} { + puts stderr "ERROR: ${::Prog}: failed to truncate previous feedback output, $fbOut : $msg" + incr nbrErr + set fbOut {} + } + } + + foreach {str boxes} [drc listall why] { + # sort errors + set boxes [lsort -dictionary $boxes] + # for our pareto, gather data + set this [llength $boxes] + incr total $this + incr types + lappend pareto [list $this $str] + + # for enumOut, emulate formatting of $CAD_ROOT/magic/tcl/drc.tcl, which is + # not tk pure: fails with complaint about winfo + # note: we walk these errors also in order to count/report stats on duplicates, even if not outputing enumerations + if {[info exists enumOut]} { + if {$types == 1} { + puts $enumOut "[join $pair]\n----------------------------------------" + } + puts $enumOut "${str}\n----------------------------------------" + } + if {[info exists enumOutL]} { + if {$types == 1} { + puts $enumOutL "[join $pair]\n----------------------------------------" + } + puts $enumOutL "${str}\n----------------------------------------" + } + if {[info exists enumOutKm]} { + # category names must be declared all together up front before use in items + # so we only store their names (error strings) and error detail (items) + # to dump after all cells and errors are processed. + # TODO: Only quote catName in item if embeds dot, instead of full-time + # TODO: test klayout handles literal (non-entity) single-quote in double-quoted name + set strKmNm $str + set strKmDesc $str + regsub -all -- {&} $strKmDesc {\&} strKmDesc ;# perhaps not needed; just in case + regsub -all -- {<} $strKmDesc {\<} strKmDesc ;# description does not have such bug, so use correct entity + regsub -all -- {>} $strKmDesc {\>} strKmDesc ;# perhaps not needed; just in case + regsub -all -- {&} $strKmNm {-and-} strKmNm ;# perhaps not needed; just in case + regsub -all -- {>} $strKmNm {-gt-} strKmNm ;# perhaps not needed; just in case + regsub -all -- {<} $strKmNm {-lt-} strKmNm ;# catName klayout bug: info win truncates at '<' as < entity + regsub -all -- "\"" $strKmNm {'} strKmNm ;# we dqoute each catNm in item, so change embedded double to single + set kmErr2catNm($str) $strKmNm + set kmErr2catDesc($str) $strKmDesc + # + # example klayout Marker format, header of one item (one error instance) + # + # (don't need?) + # (don't need?) + # 'DRC-MSG-STR' (cat1.cat2 path delimit by dot: names with dot need single|double quotes) + # RINGO:1 (don't need :N variant suffix) + # false (optional? start with false?) + # 1 (not boolean, if error "represents" more that are NOT enumerated) + # ... + # + + set itemStr "\"$strKmNm\"$acell" + } + set lastq {} + set thisDup 0 + foreach quad $boxes { + set quadUM {} + set kmBoxUM {} + foreach coord $quad { + set valum [expr {$coord * $outScale}] + set valumf [format "%.3f" $valum] + lappend quadUM "${valumf}um" + lappend kmBoxUM ${valumf} + } + set dup [expr {$quad == $lastq}] + incr thisDup $dup + set line $quadUM + if {[info exists enumOut]} { + if {$dup} { + puts $enumOut "[join $line] #dup" + } else { + puts $enumOut [join $line] + } + } + if {[info exists enumOutL]} { + if {$dup} { + puts $enumOutL "$quad #dup" + } else { + puts $enumOutL $quad + } + } + if {[info exists enumOutKm]} { + # text: 'item: polygon' (text is optional? Repeat the box coordinates here in um?) + # polygon: (1.4,1.8;-1.4,1.8;-1.4,3.8;1.4,3.8) + # box: (1.4,1.8;-1.4,3.8) + # + set kmItem $itemStr + append kmItem " box: ([lindex $kmBoxUM 0],[lindex $kmBoxUM 1];[lindex $kmBoxUM 2],[lindex $kmBoxUM 3])" + if {$dup} { + append kmItem " text: 'dup'" + } + append kmItem " " + lappend kmCell2item($acell) $kmItem + } + if {$fbOut != {}} { + set line [join $quadUM] + regsub -all -- "(\[\[\"\$\\\\])" $str {\\\1} strdq + puts $outfb "[concat box $line]" nonewline + puts $outfb " ; feedback add \"$strdq\" medium" nonewline + if {$dup} { + puts $outfb " ;#dup" + } else { + puts $outfb "" + } + } + + incr enumTotal + set lastq $quad + } + if {$thisDup} { + incr typeDup + incr dups $thisDup + } + if {[info exists enumOut]} { + puts $enumOut "----------------------------------------\n" + } + if {[info exists enumOutL]} { + puts $enumOutL "----------------------------------------\n" + } + } + } + + if {$fbOut != {}} { + close $outfb + set outfb {} + } + + set pareto [lsort -integer -decreasing -index 0 $pareto] + if {$total > 0} { + puts "--- #err|description, table for cell: $acell" + } + foreach pair $pareto { + puts "[format {%8d} [lindex $pair 0]] [lindex $pair 1]" + } + if {$typeDup} { + puts "[format {%8d} $dups] total duplicate error(s) among $typeDup error type(s), cell: $acell" + } + puts "[format {%8d} $total] total error(s) among $types error type(s), cell: $acell" + # add to grand-totals + incr gcells + incr gtotal $total + + # always compare the total from the enum to the pareto as error check + if {$total != $enumTotal} { + puts "ERROR: ${::Prog}: cell: $acell, internal error, pareto vs enum count mismatch: $total != $enumTotal" + incr nbrErr + } + # wish to compare the drc-list-count-total to the pareto total. + # Per te 2014-08-27 : it is not an error. + if {$total != $drcListCountTot} { + # puts "info: ${::Prog}: cell: $acell, drc-list-count-total vs drc-listall-why mismatch {drc list count total} gave $drcListCountTot, but {drc listall why} gave $total" + } +} + +# grand totals +puts "[format {%8d} $nbrErrCells] of $nbrAllCells cell(s) report error(s)" +puts "[format {%8d} $gtotal] grand-total error(s) across $gcells cell(s)" + +if {[info exists enumOut]} { + close $enumOut +} +if {[info exists enumOutL]} { + close $enumOutL +} +if {[info exists enumOutKm]} { + # declare all category names and descriptions, note '<' in name vs description are represented differently + # + # layerN width -lt- 1.0um + # layerN width < 1.0um + # ... + # + puts $enumOutKm "" + foreach errStr [array names kmErr2catNm] { + set nm $kmErr2catNm($errStr) + set desc $kmErr2catDesc($errStr) + puts $enumOutKm " $nm$desc" + } + puts $enumOutKm "" + + # dump all items (after all cells and all categories have been defined up front) + puts $enumOutKm "" + foreach {acell items} [array get kmCell2item] { + foreach item $items { + puts $enumOutKm $item + } + } + puts $enumOutKm "" + + # footer example .lyrdb klayout Marker file + # + puts $enumOutKm {} + close $enumOutKm +} +# todo: implement super-pareto, ranked table of SUM of all DRC errs/counts from ALL cells. +# (It still would not reflect as-if-flat hierarchical expansion due to repetition of instances). + +set nbrErr ;# return value +} ;# end main + +# non-zero exit-status on errors, either if thrown by main, or counted and returned by main +set nbrErr 0 +if {[catch {set nbrErr [main $argv]} msg]} { + puts stderr $msg + set nbrErr 1 +} elseif {$nbrErr > 0} { + puts "ERROR: ${::Prog}: script terminated with errors reported above." +} +exit $nbrErr + +# for emacs syntax-mode: +# Local Variables: +# mode:tcl +# End: diff --git a/images/foss-asic-tools/addons/sak/magic/maglef2gds.sh b/images/foss-asic-tools/addons/sak/magic/maglef2gds.sh new file mode 100755 index 00000000..f98f0076 --- /dev/null +++ b/images/foss-asic-tools/addons/sak/magic/maglef2gds.sh @@ -0,0 +1,20 @@ +#!/bin/sh +#export MAGIC=/ef/apps/ocd/magic/8.3.179-202106141345/bin/magic +export MAGIC=/ef/apps/ocd/magic/8.3.165-202105171922/bin/magic + +export MAGTYPE=maglef; + +$MAGIC -dnull -noconsole -rcfile $PDK_ROOT/sky130A/libs.tech/magic/sky130A.magicrc < + +: ${1?"Usage: $0 "} + +export TARGET_DIR=$1 +if ![[-z "$PDK_ROOT"]] +then + echo "PDK_ROOT is not defined. Please define it before running" + exit 1 +fi +export DESIGN_NAME=${2:-"user_project_wrapper"} +export OUT_DIR=${3:-$TARGET_DIR/signoff/macro_listing_check} +export SCRIPTS_ROOT=${4:-$(dirname $0)} + +if ! [[ -d "$OUT_DIR" ]] +then + mkdir $OUT_DIR +fi +echo "Running Magic..." +export MAGIC_MAGICRC=$PDK_ROOT/sky130A/libs.tech/magic/sky130A.magicrc + +ulimit -c unlimited +magic \ + -noconsole \ + -dnull \ + -rcfile $MAGIC_MAGICRC \ + $SCRIPTS_ROOT/magic_list_instances.tcl \ + /ThunarLauncher/sendto-desktop" "") +; (gtk_accel_path "/ThunarStandardView/create-folder" "n") +; (gtk_accel_path "/ThunarShortcutsPane/sendto-shortcuts" "") +; (gtk_accel_path "/ThunarWindow/view-side-pane-menu" "") +; (gtk_accel_path "/ThunarStandardView/paste-into-folder" "v") +; (gtk_accel_path "/ThunarWindow/open-home" "Home") +; (gtk_accel_path "/ThunarWindow/view-menu" "") +; (gtk_accel_path "/ThunarLauncher/open" "o") +; (gtk_accel_path "/ThunarWindow/go-menu" "") +; (gtk_accel_path "/ThunarWindow/open-file-system" "") +; (gtk_accel_path "/ThunarWindow/zoom-out" "minus") +; (gtk_accel_path "/ThunarStandardView/paste" "v") +; (gtk_accel_path "/ThunarLauncher/open-with-menu" "") +; (gtk_accel_path "/ThunarWindow/help-menu" "") +; (gtk_accel_path "/ThunarWindow/file-menu" "") +; (gtk_accel_path "/ThunarLauncher/open-with-other-in-menu" "") +; (gtk_accel_path "/ThunarWindow/detach-tab" "") +; (gtk_accel_path "/ThunarLauncher/open-in-new-tab" "p") +; (gtk_accel_path "/ThunarStandardView/sort-by-name" "") +; (gtk_accel_path "/ThunarWindow/view-menubar" "m") +; (gtk_accel_path "/ThunarStandardView/back" "Left") +; (gtk_accel_path "/ThunarActions/uca-action-1631667358111140-1" "") +; (gtk_accel_path "/ThunarWindow/close-tab" "w") +; (gtk_accel_path "/ThunarWindow/view-as-compact-list" "3") +; (gtk_accel_path "/ThunarWindow/view-side-pane-tree" "e") +; (gtk_accel_path "/ThunarStandardView/restore" "") +; (gtk_accel_path "/ThunarWindow/open-network" "") +; (gtk_accel_path "/ThunarActions/Tap::create-archive" "") +; (gtk_accel_path "/ThunarWindow/new-tab" "t") +; (gtk_accel_path "/ThunarWindow/preferences" "") +; (gtk_accel_path "/ThunarStandardView/rename" "F2") +; (gtk_accel_path "/ThunarStandardView/sort-by-size" "") +; (gtk_accel_path "/ThunarWindow/sendto-menu" "") +; (gtk_accel_path "/ThunarWindow/edit-menu" "") +; (gtk_accel_path "/ThunarLauncher/open-with-other" "") +; (gtk_accel_path "/ThunarBookmarks/b1c087b4bc214afe40ca5ce7dfc737d1" "") +; (gtk_accel_path "/ThunarWindow/view-location-selector-toolbar" "") +; (gtk_accel_path "/ThunarStandardView/invert-selection" "") +; (gtk_accel_path "/ThunarStandardView/make-link" "") +; (gtk_accel_path "/ThunarWindow/view-as-icons" "1") +; (gtk_accel_path "/ThunarWindow/new-window" "n") +; (gtk_accel_path "/ThunarStandardView/forward" "Right") +; (gtk_accel_path "/ThunarStandardView/move-to-trash" "") +; (gtk_accel_path "/ThunarStandardView/select-by-pattern" "s") +; (gtk_accel_path "/ThunarWindow/about" "") +; (gtk_accel_path "/ThunarWindow/contents" "F1") +; (gtk_accel_path "/ThunarWindow/open-desktop" "") +; (gtk_accel_path "/ThunarWindow/close-all-windows" "w") +; (gtk_accel_path "/ThunarWindow/zoom-in" "plus") +; (gtk_accel_path "/ThunarStandardView/duplicate" "") +; (gtk_accel_path "/ThunarWindow/open-parent" "Up") +; (gtk_accel_path "/ThunarWindow/view-side-pane-shortcuts" "b") +; (gtk_accel_path "/ThunarWindow/reload" "r") +; (gtk_accel_path "/ThunarWindow/open-templates" "") +; (gtk_accel_path "/ThunarStandardView/copy" "c") +; (gtk_accel_path "/ThunarWindow/view-location-selector-pathbar" "") +; (gtk_accel_path "/ThunarStandardView/sort-descending" "") +; (gtk_accel_path "/ThunarStandardView/properties" "Return") +; (gtk_accel_path "/ThunarStandardView/sort-by-type" "") +; (gtk_accel_path "/ThunarStandardView/delete" "") +; (gtk_accel_path "/ThunarStandardView/sort-ascending" "") +; (gtk_accel_path "/ThunarWindow/empty-trash" "") +; (gtk_accel_path "/ThunarWindow/view-location-selector-menu" "") +; (gtk_accel_path "/ThunarLauncher/open-in-new-window" "o") +; (gtk_accel_path "/ThunarStandardView/arrange-items-menu" "") +; (gtk_accel_path "/ThunarStandardView/cut" "x") +; (gtk_accel_path "/ThunarWindow/close-window" "q") +; (gtk_accel_path "/ThunarStandardView/select-all-files" "") +; (gtk_accel_path "/ThunarWindow/open-location" "l") +; (gtk_accel_path "/ThunarStandardView/sort-by-mtime" "") +; (gtk_accel_path "/ThunarWindow/zoom-reset" "0") +; (gtk_accel_path "/ThunarWindow/view-statusbar" "") +; (gtk_accel_path "/ThunarWindow/show-hidden" "h") +; (gtk_accel_path "/ThunarWindow/view-as-detailed-list" "2") diff --git a/images/foss-asic-tools/addons/xfce/.config/Thunar/uca.xml b/images/foss-asic-tools/addons/xfce/.config/Thunar/uca.xml new file mode 100755 index 00000000..e306d062 --- /dev/null +++ b/images/foss-asic-tools/addons/xfce/.config/Thunar/uca.xml @@ -0,0 +1,13 @@ + + + + utilities-terminal + Open Terminal Here + 1631667358111140-1 + exo-open --working-directory %f --launch TerminalEmulator + Example for a custom action + * + + + + diff --git a/images/foss-asic-tools/addons/xfce/.config/Trolltech.conf b/images/foss-asic-tools/addons/xfce/.config/Trolltech.conf new file mode 100755 index 00000000..94e31b17 --- /dev/null +++ b/images/foss-asic-tools/addons/xfce/.config/Trolltech.conf @@ -0,0 +1,22 @@ +[Qt%20Plugin%20Cache%204.8.false] +usr\lib64\qt4\plugins\inputmethods\libqimsw-multi.so=40807, 0, x86_64 linux g++-4 full-config, 2020-11-16T16:49:06 +usr\lib64\qt4\plugins\iconengines\libqsvgicon.so=40807, 0, x86_64 linux g++-4 full-config, 2020-11-16T16:49:06 +usr\lib64\qt4\plugins\imageformats\libqgif.so=40807, 0, x86_64 linux g++-4 full-config, 2020-11-16T16:49:06 +usr\lib64\qt4\plugins\imageformats\libqico.so=40807, 0, x86_64 linux g++-4 full-config, 2020-11-16T16:49:06 +usr\lib64\qt4\plugins\imageformats\libqjpeg.so=40807, 0, x86_64 linux g++-4 full-config, 2020-11-16T16:49:06 +usr\lib64\qt4\plugins\imageformats\libqmng.so=40807, 0, x86_64 linux g++-4 full-config, 2020-11-16T16:49:06 +usr\lib64\qt4\plugins\imageformats\libqsvg.so=40807, 0, x86_64 linux g++-4 full-config, 2020-11-16T16:49:06 +usr\lib64\qt4\plugins\imageformats\libqtga.so=40807, 0, x86_64 linux g++-4 full-config, 2020-11-16T16:49:06 +usr\lib64\qt4\plugins\imageformats\libqtiff.so=40807, 0, x86_64 linux g++-4 full-config, 2020-11-16T16:49:06 + +[Qt%20Factory%20Cache%204.8] +com.trolltech.Qt.QInputContextFactoryInterface%3A\usr\lib64\qt4\plugins\inputmethods\libqimsw-multi.so=2020-11-16T16:49:06, imsw-multi +com.trolltech.Qt.QIconEngineFactoryInterfaceV2%3A\usr\lib64\qt4\plugins\iconengines\libqsvgicon.so=2020-11-16T16:49:06, svg, svgz, svg.gz +com.trolltech.Qt.QIconEngineFactoryInterface%3A\usr\lib64\qt4\plugins\iconengines\libqsvgicon.so=2020-11-16T16:49:06 +com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib64\qt4\plugins\imageformats\libqgif.so=2020-11-16T16:49:06, gif +com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib64\qt4\plugins\imageformats\libqico.so=2020-11-16T16:49:06, ico +com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib64\qt4\plugins\imageformats\libqjpeg.so=2020-11-16T16:49:06, jpeg, jpg +com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib64\qt4\plugins\imageformats\libqmng.so=2020-11-16T16:49:06, mng +com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib64\qt4\plugins\imageformats\libqsvg.so=2020-11-16T16:49:06, svg, svgz +com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib64\qt4\plugins\imageformats\libqtga.so=2020-11-16T16:49:06, tga +com.trolltech.Qt.QImageIOHandlerFactoryInterface%3A\usr\lib64\qt4\plugins\imageformats\libqtiff.so=2020-11-16T16:49:06, tiff, tif diff --git a/images/foss-asic-tools/addons/xfce/.config/bg_sakuli.png b/images/foss-asic-tools/addons/xfce/.config/bg_sakuli.png new file mode 100755 index 00000000..1158ccd6 Binary files /dev/null and b/images/foss-asic-tools/addons/xfce/.config/bg_sakuli.png differ diff --git a/images/foss-asic-tools/addons/xfce/.config/efabless.com.transparent-8.png b/images/foss-asic-tools/addons/xfce/.config/efabless.com.transparent-8.png new file mode 100755 index 00000000..c457a201 Binary files /dev/null and b/images/foss-asic-tools/addons/xfce/.config/efabless.com.transparent-8.png differ diff --git a/images/foss-asic-tools/addons/xfce/.config/efabless_logo.png b/images/foss-asic-tools/addons/xfce/.config/efabless_logo.png new file mode 100755 index 00000000..30ef53d3 Binary files /dev/null and b/images/foss-asic-tools/addons/xfce/.config/efabless_logo.png differ diff --git a/images/foss-asic-tools/addons/xfce/.config/gtk-2.0/gtkfilechooser.ini b/images/foss-asic-tools/addons/xfce/.config/gtk-2.0/gtkfilechooser.ini new file mode 100755 index 00000000..6fc7981d --- /dev/null +++ b/images/foss-asic-tools/addons/xfce/.config/gtk-2.0/gtkfilechooser.ini @@ -0,0 +1,11 @@ +[Filechooser Settings] +LocationMode=path-bar +ShowHidden=true +ShowSizeColumn=true +GeometryX=570 +GeometryY=247 +GeometryWidth=780 +GeometryHeight=585 +SortColumn=name +SortOrder=ascending +StartupMode=recent diff --git a/images/foss-asic-tools/addons/xfce/.config/gtk-3.0/bookmarks b/images/foss-asic-tools/addons/xfce/.config/gtk-3.0/bookmarks new file mode 100755 index 00000000..c9a604ed --- /dev/null +++ b/images/foss-asic-tools/addons/xfce/.config/gtk-3.0/bookmarks @@ -0,0 +1 @@ +file:///google-mpw diff --git a/images/foss-asic-tools/addons/xfce/.config/xfce4/desktop/icons.screen0-1664x898.rc b/images/foss-asic-tools/addons/xfce/.config/xfce4/desktop/icons.screen0-1664x898.rc new file mode 100755 index 00000000..d6683a91 --- /dev/null +++ b/images/foss-asic-tools/addons/xfce/.config/xfce4/desktop/icons.screen0-1664x898.rc @@ -0,0 +1,3 @@ +[xfdesktop-version-4.10.3+-rcfile_format] +4.10.3+=true + diff --git a/images/foss-asic-tools/addons/xfce/.config/xfce4/desktop/icons.screen0-1904x1033.rc b/images/foss-asic-tools/addons/xfce/.config/xfce4/desktop/icons.screen0-1904x1033.rc new file mode 100755 index 00000000..d6683a91 --- /dev/null +++ b/images/foss-asic-tools/addons/xfce/.config/xfce4/desktop/icons.screen0-1904x1033.rc @@ -0,0 +1,3 @@ +[xfdesktop-version-4.10.3+-rcfile_format] +4.10.3+=true + diff --git a/images/foss-asic-tools/addons/xfce/.config/xfce4/panel/launcher-6/16316678561.desktop b/images/foss-asic-tools/addons/xfce/.config/xfce4/panel/launcher-6/16316678561.desktop new file mode 100755 index 00000000..25d9e41f --- /dev/null +++ b/images/foss-asic-tools/addons/xfce/.config/xfce4/panel/launcher-6/16316678561.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Version=1.0 +Type=Application +Exec=exo-open --launch TerminalEmulator +Icon=utilities-terminal +StartupNotify=true +Terminal=false +Categories=Utility;X-XFCE;X-Xfce-Toplevel; +OnlyShowIn=XFCE; +Name=Terminal Emulator +Comment=Use the command line +X-XFCE-Source=file:///usr/share/applications/exo-terminal-emulator.desktop diff --git a/images/foss-asic-tools/addons/xfce/.config/xfce4/panel/launcher-7/16316678652.desktop b/images/foss-asic-tools/addons/xfce/.config/xfce4/panel/launcher-7/16316678652.desktop new file mode 100755 index 00000000..c6ffb77c --- /dev/null +++ b/images/foss-asic-tools/addons/xfce/.config/xfce4/panel/launcher-7/16316678652.desktop @@ -0,0 +1,13 @@ +[Desktop Entry] +Version=1.0 +Type=Application +Exec=exo-open --launch FileManager %u +Icon=system-file-manager +StartupNotify=true +Terminal=false +Categories=Utility;X-XFCE;X-Xfce-Toplevel; +OnlyShowIn=XFCE; +X-XFCE-MimeType=inode/directory;x-scheme-handler/trash; +Name=File Manager +Comment=Browse the file system +X-XFCE-Source=file:///usr/share/applications/exo-file-manager.desktop diff --git a/images/foss-asic-tools/addons/xfce/.config/xfce4/terminal/accels.scm b/images/foss-asic-tools/addons/xfce/.config/xfce4/terminal/accels.scm new file mode 100755 index 00000000..ee6b171e --- /dev/null +++ b/images/foss-asic-tools/addons/xfce/.config/xfce4/terminal/accels.scm @@ -0,0 +1,55 @@ +; xfce4-terminal GtkAccelMap rc-file -*- scheme -*- +; this file is an automated accelerator map dump +; +(gtk_accel_path "/terminal-window/goto-tab-1" "1") +(gtk_accel_path "/terminal-window/goto-tab-3" "3") +; (gtk_accel_path "/terminal-window/file-menu" "") +; (gtk_accel_path "/terminal-window/close-other-tabs" "") +; (gtk_accel_path "/terminal-window/search" "f") +; (gtk_accel_path "/terminal-window/next-tab" "Page_Down") +; (gtk_accel_path "/terminal-window/terminal-menu" "") +; (gtk_accel_path "/terminal-window/show-menubar" "") +; (gtk_accel_path "/terminal-window/zoom-reset" "0") +; (gtk_accel_path "/terminal-window/close-window" "q") +; (gtk_accel_path "/terminal-window/save-contents" "") +; (gtk_accel_path "/terminal-window/close-tab" "w") +; (gtk_accel_path "/terminal-window/view-menu" "") +; (gtk_accel_path "/terminal-window/new-tab" "t") +; (gtk_accel_path "/terminal-window/show-toolbar" "") +; (gtk_accel_path "/terminal-window/copy-input" "") +; (gtk_accel_path "/terminal-window/paste" "v") +; (gtk_accel_path "/terminal-window/copy" "c") +; (gtk_accel_path "/terminal-window/edit-menu" "") +; (gtk_accel_path "/terminal-window/fullscreen" "F11") +(gtk_accel_path "/terminal-window/goto-tab-6" "6") +; (gtk_accel_path "/terminal-window/read-only" "") +; (gtk_accel_path "/terminal-window/detach-tab" "d") +(gtk_accel_path "/terminal-window/goto-tab-8" "8") +(gtk_accel_path "/terminal-window/goto-tab-2" "2") +; (gtk_accel_path "/terminal-window/scroll-on-output" "") +; (gtk_accel_path "/terminal-window/prev-tab" "Page_Up") +; (gtk_accel_path "/terminal-window/move-tab-left" "Page_Up") +; (gtk_accel_path "/terminal-window/zoom-in" "plus") +; (gtk_accel_path "/terminal-window/search-prev" "") +; (gtk_accel_path "/terminal-window/reset-and-clear" "") +; (gtk_accel_path "/terminal-window/about" "") +; (gtk_accel_path "/terminal-window/search-next" "") +(gtk_accel_path "/terminal-window/toggle-menubar" "F10") +(gtk_accel_path "/terminal-window/goto-tab-7" "7") +; (gtk_accel_path "/terminal-window/select-all" "a") +; (gtk_accel_path "/terminal-window/help-menu" "") +(gtk_accel_path "/terminal-window/goto-tab-9" "9") +; (gtk_accel_path "/terminal-window/show-borders" "") +; (gtk_accel_path "/terminal-window/preferences" "") +(gtk_accel_path "/terminal-window/goto-tab-4" "4") +; (gtk_accel_path "/terminal-window/contents" "F1") +; (gtk_accel_path "/terminal-window/new-window" "n") +; (gtk_accel_path "/terminal-window/move-tab-right" "Page_Down") +; (gtk_accel_path "/terminal-window/zoom-out" "minus") +; (gtk_accel_path "/terminal-window/set-title" "s") +; (gtk_accel_path "/terminal-window/paste-selection" "") +; (gtk_accel_path "/terminal-window/undo-close-tab" "") +(gtk_accel_path "/terminal-window/goto-tab-5" "5") +; (gtk_accel_path "/terminal-window/zoom-menu" "") +; (gtk_accel_path "/terminal-window/reset" "") +; (gtk_accel_path "/terminal-window/tabs-menu" "") diff --git a/images/foss-asic-tools/addons/xfce/.config/xfce4/xfconf/xfce-perchannel-xml/thunar.xml b/images/foss-asic-tools/addons/xfce/.config/xfce4/xfconf/xfce-perchannel-xml/thunar.xml new file mode 100755 index 00000000..2640492b --- /dev/null +++ b/images/foss-asic-tools/addons/xfce/.config/xfce4/xfconf/xfce-perchannel-xml/thunar.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/images/foss-asic-tools/addons/xfce/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-desktop.xml b/images/foss-asic-tools/addons/xfce/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-desktop.xml new file mode 100755 index 00000000..12b0ea7b --- /dev/null +++ b/images/foss-asic-tools/addons/xfce/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-desktop.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/foss-asic-tools/addons/xfce/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-keyboard-shortcuts.xml b/images/foss-asic-tools/addons/xfce/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-keyboard-shortcuts.xml new file mode 100755 index 00000000..4e2cea26 --- /dev/null +++ b/images/foss-asic-tools/addons/xfce/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-keyboard-shortcuts.xml @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/foss-asic-tools/addons/xfce/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml b/images/foss-asic-tools/addons/xfce/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml new file mode 100755 index 00000000..b572577c --- /dev/null +++ b/images/foss-asic-tools/addons/xfce/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/foss-asic-tools/addons/xfce/.config/xfce4/xfconf/xfce-perchannel-xml/xfwm4.xml b/images/foss-asic-tools/addons/xfce/.config/xfce4/xfconf/xfce-perchannel-xml/xfwm4.xml new file mode 100755 index 00000000..f61963c3 --- /dev/null +++ b/images/foss-asic-tools/addons/xfce/.config/xfce4/xfconf/xfce-perchannel-xml/xfwm4.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/foss-asic-tools/addons/xfce/.config/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml b/images/foss-asic-tools/addons/xfce/.config/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml new file mode 100755 index 00000000..3324472b --- /dev/null +++ b/images/foss-asic-tools/addons/xfce/.config/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/foss-asic-tools/addons/xfce/Desktop/firefox.desktop b/images/foss-asic-tools/addons/xfce/Desktop/firefox.desktop new file mode 100755 index 00000000..5a7ad82e --- /dev/null +++ b/images/foss-asic-tools/addons/xfce/Desktop/firefox.desktop @@ -0,0 +1,221 @@ +[Desktop Entry] +Version=1.0 +Name=Firefox Web Browser +Name[ar]=متصفح الويب فَيَرفُكْس +Name[ast]=Restolador web Firefox +Name[bn]=ফায়ারফক্স ওয়েব ব্রাউজার +Name[ca]=Navegador web Firefox +Name[cs]=Firefox Webový prohlížeč +Name[da]=Firefox - internetbrowser +Name[el]=Περιηγητής Firefox +Name[es]=Navegador web Firefox +Name[et]=Firefoxi veebibrauser +Name[fa]=مرورگر اینترنتی Firefox +Name[fi]=Firefox-selain +Name[fr]=Navigateur Web Firefox +Name[gl]=Navegador web Firefox +Name[he]=דפדפן האינטרנט Firefox +Name[hr]=Firefox web preglednik +Name[hu]=Firefox webböngésző +Name[it]=Firefox Browser Web +Name[ja]=Firefox ウェブ・ブラウザ +Name[ko]=Firefox 웹 브라우저 +Name[ku]=Geroka torê Firefox +Name[lt]=Firefox interneto naršyklė +Name[nb]=Firefox Nettleser +Name[nl]=Firefox webbrowser +Name[nn]=Firefox Nettlesar +Name[no]=Firefox Nettleser +Name[pl]=Przeglądarka WWW Firefox +Name[pt]=Firefox Navegador Web +Name[pt_BR]=Navegador Web Firefox +Name[ro]=Firefox – Navigator Internet +Name[ru]=Веб-браузер Firefox +Name[sk]=Firefox - internetový prehliadač +Name[sl]=Firefox spletni brskalnik +Name[sv]=Firefox webbläsare +Name[tr]=Firefox Web Tarayıcısı +Name[ug]=Firefox توركۆرگۈ +Name[uk]=Веб-браузер Firefox +Name[vi]=Trình duyệt web Firefox +Name[zh_CN]=Firefox 网络浏览器 +Name[zh_TW]=Firefox 網路瀏覽器 +Comment=Browse the World Wide Web +Comment[ar]=تصفح الشبكة العنكبوتية العالمية +Comment[ast]=Restola pela Rede +Comment[bn]=ইন্টারনেট ব্রাউজ করুন +Comment[ca]=Navegueu per la web +Comment[cs]=Prohlížení stránek World Wide Webu +Comment[da]=Surf på internettet +Comment[de]=Im Internet surfen +Comment[el]=Μπορείτε να περιηγηθείτε στο διαδίκτυο (Web) +Comment[es]=Navegue por la web +Comment[et]=Lehitse veebi +Comment[fa]=صفحات شبکه جهانی اینترنت را مرور نمایید +Comment[fi]=Selaa Internetin WWW-sivuja +Comment[fr]=Naviguer sur le Web +Comment[gl]=Navegar pola rede +Comment[he]=גלישה ברחבי האינטרנט +Comment[hr]=Pretražite web +Comment[hu]=A világháló böngészése +Comment[it]=Esplora il web +Comment[ja]=ウェブを閲覧します +Comment[ko]=웹을 돌아 다닙니다 +Comment[ku]=Li torê bigere +Comment[lt]=Naršykite internete +Comment[nb]=Surf på nettet +Comment[nl]=Verken het internet +Comment[nn]=Surf på nettet +Comment[no]=Surf på nettet +Comment[pl]=Przeglądanie stron WWW +Comment[pt]=Navegue na Internet +Comment[pt_BR]=Navegue na Internet +Comment[ro]=Navigați pe Internet +Comment[ru]=Доступ в Интернет +Comment[sk]=Prehliadanie internetu +Comment[sl]=Brskajte po spletu +Comment[sv]=Surfa på webben +Comment[tr]=İnternet'te Gezinin +Comment[ug]=دۇنيادىكى توربەتلەرنى كۆرگىلى بولىدۇ +Comment[uk]=Перегляд сторінок Інтернету +Comment[vi]=Để duyệt các trang web +Comment[zh_CN]=浏览互联网 +Comment[zh_TW]=瀏覽網際網路 +GenericName=Web Browser +GenericName[ar]=متصفح ويب +GenericName[ast]=Restolador Web +GenericName[bn]=ওয়েব ব্রাউজার +GenericName[ca]=Navegador web +GenericName[cs]=Webový prohlížeč +GenericName[da]=Webbrowser +GenericName[el]=Περιηγητής διαδικτύου +GenericName[es]=Navegador web +GenericName[et]=Veebibrauser +GenericName[fa]=مرورگر اینترنتی +GenericName[fi]=WWW-selain +GenericName[fr]=Navigateur Web +GenericName[gl]=Navegador Web +GenericName[he]=דפדפן אינטרנט +GenericName[hr]=Web preglednik +GenericName[hu]=Webböngésző +GenericName[it]=Browser web +GenericName[ja]=ウェブ・ブラウザ +GenericName[ko]=웹 브라우저 +GenericName[ku]=Geroka torê +GenericName[lt]=Interneto naršyklė +GenericName[nb]=Nettleser +GenericName[nl]=Webbrowser +GenericName[nn]=Nettlesar +GenericName[no]=Nettleser +GenericName[pl]=Przeglądarka WWW +GenericName[pt]=Navegador Web +GenericName[pt_BR]=Navegador Web +GenericName[ro]=Navigator Internet +GenericName[ru]=Веб-браузер +GenericName[sk]=Internetový prehliadač +GenericName[sl]=Spletni brskalnik +GenericName[sv]=Webbläsare +GenericName[tr]=Web Tarayıcı +GenericName[ug]=توركۆرگۈ +GenericName[uk]=Веб-браузер +GenericName[vi]=Trình duyệt Web +GenericName[zh_CN]=网络浏览器 +GenericName[zh_TW]=網路瀏覽器 +Keywords=Internet;WWW;Browser;Web;Explorer +Keywords[ar]=انترنت;إنترنت;متصفح;ويب;وب +Keywords[ast]=Internet;WWW;Restolador;Web;Esplorador +Keywords[ca]=Internet;WWW;Navegador;Web;Explorador;Explorer +Keywords[cs]=Internet;WWW;Prohlížeč;Web;Explorer +Keywords[da]=Internet;Internettet;WWW;Browser;Browse;Web;Surf;Nettet +Keywords[de]=Internet;WWW;Browser;Web;Explorer;Webseite;Site;surfen;online;browsen +Keywords[el]=Internet;WWW;Browser;Web;Explorer;Διαδίκτυο;Περιηγητής;Firefox;Φιρεφοχ;Ιντερνετ +Keywords[es]=Explorador;Internet;WWW +Keywords[fi]=Internet;WWW;Browser;Web;Explorer;selain;Internet-selain;internetselain;verkkoselain;netti;surffaa +Keywords[fr]=Internet;WWW;Browser;Web;Explorer;Fureteur;Surfer;Navigateur +Keywords[he]=דפדפן;אינטרנט;רשת;אתרים;אתר;פיירפוקס;מוזילה; +Keywords[hr]=Internet;WWW;preglednik;Web +Keywords[hu]=Internet;WWW;Böngésző;Web;Háló;Net;Explorer +Keywords[it]=Internet;WWW;Browser;Web;Navigatore +Keywords[is]=Internet;WWW;Vafri;Vefur;Netvafri;Flakk +Keywords[ja]=Internet;WWW;Web;インターネット;ブラウザ;ウェブ;エクスプローラ +Keywords[nb]=Internett;WWW;Nettleser;Explorer;Web;Browser;Nettside +Keywords[nl]=Internet;WWW;Browser;Web;Explorer;Verkenner;Website;Surfen;Online +Keywords[pt]=Internet;WWW;Browser;Web;Explorador;Navegador +Keywords[pt_BR]=Internet;WWW;Browser;Web;Explorador;Navegador +Keywords[ru]=Internet;WWW;Browser;Web;Explorer;интернет;браузер;веб;файрфокс;огнелис +Keywords[sk]=Internet;WWW;Prehliadač;Web;Explorer +Keywords[sl]=Internet;WWW;Browser;Web;Explorer;Brskalnik;Splet +Keywords[tr]=İnternet;WWW;Tarayıcı;Web;Gezgin;Web sitesi;Site;sörf;çevrimiçi;tara +Keywords[uk]=Internet;WWW;Browser;Web;Explorer;Інтернет;мережа;переглядач;оглядач;браузер;веб;файрфокс;вогнелис;перегляд +Keywords[vi]=Internet;WWW;Browser;Web;Explorer;Trình duyệt;Trang web +Keywords[zh_CN]=Internet;WWW;Browser;Web;Explorer;网页;浏览;上网;火狐;Firefox;ff;互联网;网站; +Keywords[zh_TW]=Internet;WWW;Browser;Web;Explorer;網際網路;網路;瀏覽器;上網;網頁;火狐 +Exec=firefox %u +Terminal=false +X-MultipleArgs=false +Type=Application +Icon=/usr/lib/firefox/browser/icons/mozicon128.png +Categories=GNOME;GTK;Network;WebBrowser; +MimeType=text/html;text/xml;application/xhtml+xml;application/xml;application/rss+xml;application/rdf+xml;image/gif;image/jpeg;image/png;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/ftp;x-scheme-handler/chrome;video/webm;application/x-xpinstall; +StartupNotify=true +Actions=NewWindow;NewPrivateWindow; + +[Desktop Action NewWindow] +Name=Open a New Window +Name[ar]=افتح نافذة جديدة +Name[ast]=Abrir una ventana nueva +Name[bn]=Abrir una ventana nueva +Name[ca]=Obre una finestra nova +Name[cs]=Otevřít nové okno +Name[da]=Åbn et nyt vindue +Name[de]=Ein neues Fenster öffnen +Name[el]=Άνοιγμα νέου παραθύρου +Name[es]=Abrir una ventana nueva +Name[fi]=Avaa uusi ikkuna +Name[fr]=Ouvrir une nouvelle fenêtre +Name[gl]=Abrir unha nova xanela +Name[he]=פתיחת חלון חדש +Name[hr]=Otvori novi prozor +Name[hu]=Új ablak nyitása +Name[it]=Apri una nuova finestra +Name[ja]=新しいウィンドウを開く +Name[ko]=새 창 열기 +Name[ku]=Paceyeke nû veke +Name[lt]=Atverti naują langą +Name[nb]=Åpne et nytt vindu +Name[nl]=Nieuw venster openen +Name[pt]=Abrir nova janela +Name[pt_BR]=Abrir nova janela +Name[ro]=Deschide o fereastră nouă +Name[ru]=Новое окно +Name[sk]=Otvoriť nové okno +Name[sl]=Odpri novo okno +Name[sv]=Öppna ett nytt fönster +Name[tr]=Yeni pencere aç +Name[ug]=يېڭى كۆزنەك ئېچىش +Name[uk]=Відкрити нове вікно +Name[vi]=Mở cửa sổ mới +Name[zh_CN]=新建窗口 +Name[zh_TW]=開啟新視窗 +Exec=firefox -new-window +OnlyShowIn=Unity; + +[Desktop Action NewPrivateWindow] +Name=Open a New Private Window +Name[ar]=افتح نافذة جديدة للتصفح الخاص +Name[ca]=Obre una finestra nova en mode d'incògnit +Name[de]=Ein neues privates Fenster öffnen +Name[es]=Abrir una ventana privada nueva +Name[fi]=Avaa uusi yksityinen ikkuna +Name[fr]=Ouvrir une nouvelle fenêtre de navigation privée +Name[he]=פתיחת חלון גלישה פרטית חדש +Name[hu]=Új privát ablak nyitása +Name[it]=Apri una nuova finestra anonima +Name[nb]=Åpne et nytt privat vindu +Name[ru]=Новое приватное окно +Name[sl]=Odpri novo okno zasebnega brskanja +Name[tr]=Yeni bir pencere aç +Name[uk]=Відкрити нове вікно у потайливому режимі +Name[zh_TW]=開啟新隱私瀏覽視窗 +Exec=firefox -private-window +OnlyShowIn=Unity; diff --git a/images/foss-asic-tools/addons/xfce/wm_startup.sh b/images/foss-asic-tools/addons/xfce/wm_startup.sh new file mode 100755 index 00000000..d0fd552d --- /dev/null +++ b/images/foss-asic-tools/addons/xfce/wm_startup.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +### every exit != 0 fails the script +set -e + +echo -e "\n------------------ startup of Xfce4 window manager ------------------" + +### disable screensaver and power management +xset -dpms & +xset s noblank & +xset s off & + +/usr/bin/startxfce4 --replace > $HOME/wm.log & +sleep 1 +cat $HOME/wm.log \ No newline at end of file diff --git a/images/foss-asic-tools/info.json b/images/foss-asic-tools/info.json new file mode 100755 index 00000000..ce7c5e92 --- /dev/null +++ b/images/foss-asic-tools/info.json @@ -0,0 +1,8 @@ +{ + "args": { + "BASE_IMAGE": "base", + "NAME": "foss-asic-tools", + "REPO_URL": "https://github.com/efabless/foss-asic-tools", + "REPO_COMMIT": "alpha" + } +} diff --git a/images/foss-asic-tools/scripts/chrome-init.sh b/images/foss-asic-tools/scripts/chrome-init.sh new file mode 100644 index 00000000..4bdf1a85 --- /dev/null +++ b/images/foss-asic-tools/scripts/chrome-init.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +### every exit != 0 fails the script +set -e + +VNC_RES_W=${VNC_RESOLUTION%x*} +VNC_RES_H=${VNC_RESOLUTION#*x} + +echo -e "\n------------------ update chromium-browser.init ------------------" +echo -e "\n... set window size $VNC_RES_W x $VNC_RES_H as chrome window size!\n" + +echo "CHROMIUM_FLAGS='--no-sandbox --disable-gpu --user-data-dir --window-size=$VNC_RES_W,$VNC_RES_H --window-position=0,0'" > $HOME/.chromium-browser.init diff --git a/images/foss-asic-tools/scripts/chrome.sh b/images/foss-asic-tools/scripts/chrome.sh new file mode 100644 index 00000000..ce2e4f3f --- /dev/null +++ b/images/foss-asic-tools/scripts/chrome.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +### every exit != 0 fails the script +set -e + +echo "Install Chromium Browser" +yum -y install chromium chromium-libs chromium-libs-media +yum clean all + +ln -s /usr/bin/chromium-browser /usr/bin/google-chrome + +### fix to start chromium in a Docker container, see https://github.com/ConSol/docker-headless-vnc-container/issues/2 + +echo "CHROMIUM_FLAGS='--no-sandbox --start-maximized --user-data-dir'" > $HOME/.chromium-browser.init + +# add `source $INST_SCRIPTS/install/chromium-wrapper`string before last line + +#sed -i '$isource $STARTUPDIR/scripts/chromium-wrapper' #/usr/lib64/chromium-browser/chromium-browser.sh diff --git a/images/foss-asic-tools/scripts/chromium-wrapper b/images/foss-asic-tools/scripts/chromium-wrapper new file mode 100644 index 00000000..0c17d1a1 --- /dev/null +++ b/images/foss-asic-tools/scripts/chromium-wrapper @@ -0,0 +1,8 @@ +## custom wrapper to support the $HOME/.chromium-browser.init file +## will be "sourced" from /usr/lib64/chromium-browser/chromium-browser.sh + +source $HOME/.chromium-browser.init +echo "CHROMIUM_FLAGS: $CHROMIUM_FLAGS" + +CHROMIUM_DISTRO_FLAGS="$CHROMIUM_DISTRO_FLAGS $CHROMIUM_FLAGS " +echo "CHROMIUM_DISTRO_FLAGS: $CHROMIUM_DISTRO_FLAGS" diff --git a/images/foss-asic-tools/scripts/env.sh b/images/foss-asic-tools/scripts/env.sh new file mode 100755 index 00000000..ced81158 --- /dev/null +++ b/images/foss-asic-tools/scripts/env.sh @@ -0,0 +1,94 @@ + +base_path=/foss/tools/ +function get_path() { + tool_name=$1 + bin_path=$(realpath $base_path/$tool_name/*/bin) + echo $bin_path +} + +magic_path=$(get_path "magic") +gtkwave_path=$(get_path "gtkwave") +iverilog_path=$(get_path "iverilog") +klayout_path=$(realpath $base_path/klayout/* ) +netgen_path=$(get_path "netgen") +openlane_tools_path=$(get_path "openlane_tools" ) +riscv32i_path=$(get_path "riscv-gnu-toolchain-rv32i" ) +gaw3_path=$(get_path "gaw3") +ngscope_path=$(realpath $base_path/ngscope/*/usr/local/bin ) +ngspice_path=$(get_path "ngspice") +xschem_path=$(get_path "xschem") +xyce_path=$(get_path "xyce/Parallel") +covered_path=$(get_path "covered") + +export PATH=$PATH:${magic_path}:${gtkwave_path}:${iverilog_path}:${klayout_path}:${netgen_path}:${openlane_tools_path}:${riscv32i_path}:${gaw3_path}:${ngscope_path}:${ngspice_path}:${xschem_path}:${xyce_path}:${covered_path} + +export LD_LIBRARY_PATH=$(realpath $base_path/klayout/*/ ) + +export PDK_ROOT=/foss/pdks +export TOOLS=/foss/tools +export DESIGNS=/foss/designs + +alias magic='magic -d XR' +alias mmagic-sky130A='MAGTYPE=mag magic -rcfile ${PDK_ROOT}/sky130A/libs.tech/magic/sky130A.magicrc' +alias lmagic-sky130A='MAGTYPE=maglef magic -rcfile ${PDK_ROOT}/sky130A/libs.tech/magic/sky130A.magicrc' + +alias k='klayout -c $SAK/klayout/tech/sky130A/sky130A.krc -nn $SAK/klayout/tech/sky130A/sky130A.lyt -l $SAK/klayout/tech/sky130A/sky130A-eft.lyp' +alias ke='klayout -e -c $SAK/klayout/tech/sky130A/sky130A.krc -nn $SAK/klayout/tech/sky130A/sky130A.lyt -l $SAK/klayout/tech/sky130A/sky130A-eft.lyp' +alias kf='klayout -c $SAK/klayout/tech/sky130A/sky130A.krc -nn $SAK/klayout/tech/sky130A/sky130A.lyt -l $SAK/klayout/tech/sky130A/sky130A-fom.lyp' + +alias t='cd /foss/tools' +alias d='cd /foss/designs' +alias p='cd /foss/pdks' + +export SAK=$TOOLS/sak/ +export EDITOR='gedit' +export PATH=$TOOLS/bin:$SAK:/usr/local/sbin:$PATH + +#---------------------------------------- +# Miscellaneous +#---------------------------------------- + +alias sh1='sha1sum' +alias destroy='sudo \rm -rf' +alias cp='cp -i' +alias egrep='egrep ' +alias fgrep='fgrep ' +alias grep='grep ' +alias l.='ls -d .* ' +alias ll='ls -l' +alias la='ls -al ' +alias llt='ls -lt' +alias llta='ls -alt' +alias du='du -skh' +alias mv='mv -i' +alias perlll='eval `perl -Mlocal::lib`' +alias rm='rm -i' +alias vrc='vi ~/.bashrc' +alias dux='du -sh* | sort -h' +alias shs='md5sum' +alias h='history' +alias hh='history | grep' +alias rc='source ~/.bashrc' +alias m='less' +alias c='vi ~/.commands' + +#---------------------------------------- +# Git +#---------------------------------------- + +alias gcl='git clone' +alias gcll='git clone --single-branch --depth=1' +alias ga='git add' +alias gc='git commit -a' +alias gps='git push' +alias gpl='git pull' +alias gco='git checkout' +alias gss='git status' +alias gr='git remote -v' +alias gl='git log' +alias gln='git log --name-status' +alias gsss='git submodule status' + + + + diff --git a/images/foss-asic-tools/scripts/firefox.sh b/images/foss-asic-tools/scripts/firefox.sh new file mode 100644 index 00000000..b3185773 --- /dev/null +++ b/images/foss-asic-tools/scripts/firefox.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -e + +echo "Install Firefox" + +function disableUpdate(){ + ff_def="$1/browser/defaults/profile" + mkdir -p $ff_def + echo < $ff_def/user.js +} + +#copy from org/sakuli/common/bin/installer_scripts/linux/install_firefox_portable.sh +function instFF() { + if [ ! "${1:0:1}" == "" ]; then + FF_VERS=$1 + if [ ! "${2:0:1}" == "" ]; then + FF_INST=$2 + echo "download Firefox $FF_VERS and install it to '$FF_INST'." + mkdir -p "$FF_INST" + FF_URL=http://releases.mozilla.org/pub/firefox/releases/$FF_VERS/linux-x86_64/zh-CN/firefox-$FF_VERS.tar.bz2 + echo "FF_URL: $FF_URL" + wget -qO- $FF_URL | tar xvj --strip 1 -C $FF_INST/ + ln -s "$FF_INST/firefox" /usr/bin/firefox + disableUpdate $FF_INST + exit $? + fi + fi + echo "function parameter are not set correctly please call it like 'instFF [version] [install path]'" + exit -1 +} + +instFF '45.9.0esr' '/usr/lib/firefox' + +#yum -y install firefox-45.7.0-2.el7.centos +#yum -y install firefox +#yum clean all +#apt-get update +#apt-get install -y firefox +#apt-get install -y firefox=45* +#apt-mark hold firefox +#apt-get clean -y diff --git a/images/foss-asic-tools/scripts/generate_container_user b/images/foss-asic-tools/scripts/generate_container_user new file mode 100644 index 00000000..dbdd4797 --- /dev/null +++ b/images/foss-asic-tools/scripts/generate_container_user @@ -0,0 +1,28 @@ +# Set current user in nss_wrapper +USER_ID=$(id -u) +GROUP_ID=$(id -g) +echo "USER_ID: $USER_ID, GROUP_ID: $GROUP_ID" + +if [ x"$USER_ID" != x"0" ]; then + + NSS_WRAPPER_PASSWD=/tmp/passwd + NSS_WRAPPER_GROUP=/etc/group + + cat /etc/passwd > $NSS_WRAPPER_PASSWD + + echo "default:x:${USER_ID}:${GROUP_ID}:Default Application User:${HOME}:/bin/bash" >> $NSS_WRAPPER_PASSWD + + export NSS_WRAPPER_PASSWD + export NSS_WRAPPER_GROUP + + if [ -r /usr/lib/libnss_wrapper.so ]; then + LD_PRELOAD=/usr/lib/libnss_wrapper.so + elif [ -r /usr/lib64/libnss_wrapper.so ]; then + LD_PRELOAD=/usr/lib64/libnss_wrapper.so + else + echo "no libnss_wrapper.so installed!" + exit 1 + fi + echo "nss_wrapper location: $LD_PRELOAD" + export LD_PRELOAD +fi diff --git a/images/foss-asic-tools/scripts/icewm_ui.sh b/images/foss-asic-tools/scripts/icewm_ui.sh new file mode 100644 index 00000000..843d9ce5 --- /dev/null +++ b/images/foss-asic-tools/scripts/icewm_ui.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +### every exit != 0 fails the script +set -e + +echo "Install Xfce4 UI components and disable xfce-polkit" + +yum -y install xorg-x11-fonts* xulrunner icewm +yum -y groups install "Fonts" +yum erase -y *power* *screensaver* +yum clean all +/bin/dbus-uuidgen > /etc/machine-id \ No newline at end of file diff --git a/images/foss-asic-tools/scripts/libnss_wrapper.sh b/images/foss-asic-tools/scripts/libnss_wrapper.sh new file mode 100644 index 00000000..903c67f5 --- /dev/null +++ b/images/foss-asic-tools/scripts/libnss_wrapper.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +### every exit != 0 fails the script +set -e + +echo "Install nss-wrapper to be able to execute image as non-root user" +yum -y install nss_wrapper gettext +yum clean all + +echo "add 'source generate_container_user' to .bashrc" + +# have to be added to hold all env vars correctly +echo 'source $STARTUPDIR/scripts/generate_container_user' >> $HOME/.bashrc diff --git a/images/foss-asic-tools/scripts/miscellaneous.sh b/images/foss-asic-tools/scripts/miscellaneous.sh new file mode 100755 index 00000000..636edd91 --- /dev/null +++ b/images/foss-asic-tools/scripts/miscellaneous.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +############### + +mkdir -p $DESIGNS +mkdir -p /foss/pdks +mkdir -p /foss/tools/bin +cd /foss/tools/bin +ln -s ../*/*/bin/* . + + +mkdir $STARTUPDIR/logs + + +############### + +cd /foss/pdks +ln -s ../tools/xschem/*/share xschem-share +ln -s ../tools/xschem/*/share/xschem/xschem_library . + +############### + diff --git a/images/foss-asic-tools/scripts/no_vnc.sh b/images/foss-asic-tools/scripts/no_vnc.sh new file mode 100644 index 00000000..f05be845 --- /dev/null +++ b/images/foss-asic-tools/scripts/no_vnc.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +### every exit != 0 fails the script +set -e +set -u + +echo "Install noVNC - HTML5 based VNC viewer" + +mkdir -p $NO_VNC_HOME/utils/websockify +wget -qO- https://github.com/novnc/noVNC/archive/v1.0.0.tar.gz | tar xz --strip 1 -C $NO_VNC_HOME + +# use older version of websockify to prevent hanging connections on offline containers, see https://github.com/ConSol/docker-headless-vnc-container/issues/50 + +wget -qO- https://github.com/novnc/websockify/archive/v0.6.1.tar.gz | tar xz --strip 1 -C $NO_VNC_HOME/utils/websockify + +chmod +x -v $NO_VNC_HOME/utils/*.sh +## create index.html to forward automatically to `vnc_lite.html` +ln -s $NO_VNC_HOME/vnc_lite.html $NO_VNC_HOME/index.html diff --git a/images/foss-asic-tools/scripts/set_user_permission.sh b/images/foss-asic-tools/scripts/set_user_permission.sh new file mode 100644 index 00000000..13f9e1e1 --- /dev/null +++ b/images/foss-asic-tools/scripts/set_user_permission.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +### every exit != 0 fails the script +set -e +if [[ -n $DEBUG ]]; then + verbose="-v" +fi + +for var in "$@" +do + echo "fix permissions for: $var" + find "$var"/ -name '*.sh' -exec chmod $verbose a+x {} + + find "$var"/ -name '*.desktop' -exec chmod $verbose a+x {} + + chgrp -R 0 "$var" && chmod -R $verbose a+rw "$var" && find "$var" -type d -exec chmod $verbose a+x {} + +done \ No newline at end of file diff --git a/images/foss-asic-tools/scripts/source_env.sh b/images/foss-asic-tools/scripts/source_env.sh new file mode 100755 index 00000000..0e93df1b --- /dev/null +++ b/images/foss-asic-tools/scripts/source_env.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +cat /env/env.sh >> $HOME/.bashrc diff --git a/images/foss-asic-tools/scripts/tigervnc.sh b/images/foss-asic-tools/scripts/tigervnc.sh new file mode 100644 index 00000000..532c13db --- /dev/null +++ b/images/foss-asic-tools/scripts/tigervnc.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -e + +echo "Install TigerVNC server" +yum -y install tigervnc-server +yum clean all diff --git a/images/foss-asic-tools/scripts/tools.sh b/images/foss-asic-tools/scripts/tools.sh new file mode 100644 index 00000000..573ad234 --- /dev/null +++ b/images/foss-asic-tools/scripts/tools.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +### every exit != 0 fails the script +set -e + +echo "Install some common tools for further installation" +yum -y install epel-release + +yum -y update + +yum clean all + +yum install -y \ + git \ + qt-devel \ + octave \ + openmpi-devel \ + ruby-devel \ + tcl \ + tk \ + tcllib \ + wxGTK-devel \ + xorg-x11-server-Xvfb \ + sudo + +yum install -y \ + wget \ + net-tools \ + nmap \ + bzip2 \ + mailcap \ + numpy \ + gedit + diff --git a/images/foss-asic-tools/scripts/vnc_startup.sh b/images/foss-asic-tools/scripts/vnc_startup.sh new file mode 100755 index 00000000..39edd27b --- /dev/null +++ b/images/foss-asic-tools/scripts/vnc_startup.sh @@ -0,0 +1,49 @@ +#!/bin/bash +### every exit != 0 fails the script +set -e + +## resolve_vnc_connection +VNC_IP=$(hostname -i) + +## change vnc password +echo -e "\n------------------ change VNC password ------------------" +# first entry is control, second is view (if only one is valid for both) +mkdir -p "$HOME/.vnc" +PASSWD_PATH="$HOME/.vnc/passwd" +echo "$VNC_PW" | vncpasswd -f > $PASSWD_PATH +chmod 600 $PASSWD_PATH + + +## start vncserver and noVNC webclient +echo -e "\n------------------ start noVNC ----------------------------" + +$NO_VNC_HOME/utils/launch.sh --vnc localhost:$VNC_PORT --listen $NO_VNC_PORT &> $STARTUPDIR/logs/no_vnc_startup.log & +PID_SUB=$! + +echo -e "start vncserver with param: VNC_COL_DEPTH=$VNC_COL_DEPTH, VNC_RESOLUTION=$VNC_RESOLUTION\n..." + +vncserver $DISPLAY -depth $VNC_COL_DEPTH -geometry $VNC_RESOLUTION &> $STARTUPDIR/logs/vnc_startup.log + +echo -e "start window manager\n..." +$STARTUPDIR/scripts/wm_startup.sh &> $STARTUPDIR/logs/wm_startup.log + +## log connect options +echo -e "\n\n------------------ VNC environment started ------------------" +echo -e "\nVNCSERVER started on DISPLAY= $DISPLAY \n\t=> connect via VNC viewer with $VNC_IP:$VNC_PORT" +echo -e "\nnoVNC HTML client started:\n\t=> connect via http://localhost/?password=$VNC_PW\n" + + +if [[ $DEBUG == true ]] || [[ $1 =~ -t|--tail-log ]]; then + echo -e "\n------------------ $HOME/.vnc/*$DISPLAY.log ------------------" + # if option `-t` or `--tail-log` block the execution and tail the VNC log + tail -f $STARTUPDIR/logs/*.log $HOME/.vnc/*$DISPLAY.log +fi + +if [ -z "$1" ] || [[ $1 =~ -w|--wait ]]; then + wait $PID_SUB +else + # unknown option ==> call command + echo -e "\n\n------------------ EXECUTE COMMAND ------------------" + echo "Executing command: '$@'" + exec "$@" +fi diff --git a/images/foss-asic-tools/scripts/wm_startup.sh b/images/foss-asic-tools/scripts/wm_startup.sh new file mode 100755 index 00000000..1bee25b8 --- /dev/null +++ b/images/foss-asic-tools/scripts/wm_startup.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +### every exit != 0 fails the script +set -e + +echo -e "\n------------------ startup of Xfce4 window manager ------------------" + +### disable screensaver and power management +xset -dpms & +xset s noblank & +xset s off & + +/usr/bin/startxfce4 --replace > $STARTUPDIR/logs/wm.log & +sleep 1 +cat $STARTUPDIR/logs/wm.log diff --git a/images/foss-asic-tools/scripts/xfce_ui.sh b/images/foss-asic-tools/scripts/xfce_ui.sh new file mode 100644 index 00000000..c6b3c935 --- /dev/null +++ b/images/foss-asic-tools/scripts/xfce_ui.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +### every exit != 0 fails the script +set -e + +echo "Install Xfce4 UI components and disable xfce-polkit" + +yum --enablerepo=epel -y -x gnome-keyring --skip-broken groupinstall "Xfce" + +yum -y groups install "Fonts" + +yum erase -y *power* + +yum clean all + +rm /etc/xdg/autostart/xfce-polkit* + +/bin/dbus-uuidgen > /etc/machine-id diff --git a/images/gaw3-xschem/Dockerfile b/images/gaw3-xschem/Dockerfile new file mode 100755 index 00000000..d42a6e28 --- /dev/null +++ b/images/gaw3-xschem/Dockerfile @@ -0,0 +1,12 @@ +ARG BASE_IMAGE +FROM ${BASE_IMAGE} as builder + +ARG REPO_URL +ARG REPO_COMMIT +ARG NAME + +ADD scripts/dependencies.sh dependencies.sh +RUN bash dependencies.sh + +ADD scripts/install.sh install.sh +RUN bash install.sh diff --git a/images/gaw3-xschem/info.json b/images/gaw3-xschem/info.json new file mode 100755 index 00000000..7e7082b7 --- /dev/null +++ b/images/gaw3-xschem/info.json @@ -0,0 +1,8 @@ +{ + "args": { + "BASE_IMAGE": "base", + "NAME": "gaw3", + "REPO_URL": "https://github.com/StefanSchippers/xschem-gaw.git", + "REPO_COMMIT": "2a1fc97bcc3081af72fc37a8bc52bc4632e176b2" + } +} diff --git a/images/gaw3-xschem/scripts/dependencies.sh b/images/gaw3-xschem/scripts/dependencies.sh new file mode 100755 index 00000000..92642137 --- /dev/null +++ b/images/gaw3-xschem/scripts/dependencies.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +yum install -y \ + autoconf automake make \ + alsa-lib-devel \ + gtk3-devel \ + diff --git a/images/gaw3-xschem/scripts/install.sh b/images/gaw3-xschem/scripts/install.sh new file mode 100755 index 00000000..4b40f89b --- /dev/null +++ b/images/gaw3-xschem/scripts/install.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +source scl_source enable devtoolset-8 + +git clone ${REPO_URL} ${NAME} +cd ${NAME} + +git checkout ${REPO_COMMIT} + +chmod +x configure + +autoreconf -f -i + +./configure --prefix=/foss/tools/${NAME}/${REPO_COMMIT} +make -j$(nproc) +make install diff --git a/images/gtkwave/Dockerfile b/images/gtkwave/Dockerfile new file mode 100755 index 00000000..d42a6e28 --- /dev/null +++ b/images/gtkwave/Dockerfile @@ -0,0 +1,12 @@ +ARG BASE_IMAGE +FROM ${BASE_IMAGE} as builder + +ARG REPO_URL +ARG REPO_COMMIT +ARG NAME + +ADD scripts/dependencies.sh dependencies.sh +RUN bash dependencies.sh + +ADD scripts/install.sh install.sh +RUN bash install.sh diff --git a/images/gtkwave/info.json b/images/gtkwave/info.json new file mode 100755 index 00000000..b76c35a1 --- /dev/null +++ b/images/gtkwave/info.json @@ -0,0 +1,8 @@ +{ + "args" : { + "BASE_IMAGE" : "base", + "NAME": "gtkwave", + "REPO_URL": "https://github.com/gtkwave/gtkwave", + "REPO_COMMIT": "bc06f0fabd174d44f50647b09d6f7c702b3b6c40" + } +} diff --git a/images/gtkwave/scripts/dependencies.sh b/images/gtkwave/scripts/dependencies.sh new file mode 100755 index 00000000..31ac3d1b --- /dev/null +++ b/images/gtkwave/scripts/dependencies.sh @@ -0,0 +1,17 @@ +#!/bin/bash +install_gpref() { + wget http://ftp.gnu.org/pub/gnu/gperf/gperf-3.1.tar.gz + tar -xvzf gperf-3.1.tar.gz && \ + cd gperf-3.1 && \ + autoconf && \ + ./configure && \ + make -j$(nproc) && \ + make install +} + +yum install -y \ + gtk3-devel \ + bzip2-devel + +source scl_source enable devtoolset-8 +install_gpref diff --git a/images/gtkwave/scripts/install.sh b/images/gtkwave/scripts/install.sh new file mode 100755 index 00000000..cfde05d8 --- /dev/null +++ b/images/gtkwave/scripts/install.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +source scl_source enable devtoolset-8 + +git clone ${REPO_URL} ${NAME} +cd ${NAME}/gtkwave3-gtk3/ + +git checkout ${REPO_COMMIT} + +./autogen.sh +./configure --prefix=/foss/tools/${NAME}/${REPO_COMMIT} --enable-gtk3 +make -j$(nproc) +make install diff --git a/images/irsim/.log.txt b/images/irsim/.log.txt new file mode 100755 index 00000000..0a92461c --- /dev/null +++ b/images/irsim/.log.txt @@ -0,0 +1,2 @@ +make[1]: Entering directory '/home/karim/work/ef/chipignite/tools/magic' +make[1]: Leaving directory '/home/karim/work/ef/chipignite/tools/magic' diff --git a/images/irsim/Dockerfile b/images/irsim/Dockerfile new file mode 100755 index 00000000..dfc28092 --- /dev/null +++ b/images/irsim/Dockerfile @@ -0,0 +1,10 @@ +ARG BASE_IMAGE +FROM ${BASE_IMAGE} as builder + +ARG REPO_URL +ARG REPO_COMMIT +ARG NAME + +ADD scripts/install.sh install.sh +RUN bash install.sh + diff --git a/images/irsim/info.json b/images/irsim/info.json new file mode 100755 index 00000000..7c680312 --- /dev/null +++ b/images/irsim/info.json @@ -0,0 +1,8 @@ +{ + "args": { + "BASE_IMAGE": "base", + "NAME": "irsim", + "REPO_URL": "https://github.com/rtimothyedwards/irsim", + "REPO_COMMIT": " 5f33a7328787f726c1a22e787c8cc810f46971d3" + } +} \ No newline at end of file diff --git a/images/irsim/scripts/install.sh b/images/irsim/scripts/install.sh new file mode 100755 index 00000000..997af74c --- /dev/null +++ b/images/irsim/scripts/install.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +source scl_source enable devtoolset-8 + +git clone ${REPO_URL} ${NAME} +cd ${NAME} +git checkout ${REPO_COMMIT} +./configure --prefix=/foss/tools/${NAME}/${REPO_COMMIT} +make -j$(nproc) +make install + diff --git a/images/iverilog/Dockerfile b/images/iverilog/Dockerfile new file mode 100755 index 00000000..554da9c6 --- /dev/null +++ b/images/iverilog/Dockerfile @@ -0,0 +1,14 @@ +ARG NAME +ARG BASE_IMAGE +FROM ${BASE_IMAGE} as builder + +ARG REPO_URL +ARG REPO_COMMIT +ARG NAME +# +ADD scripts/dependencies.sh dependencies.sh +RUN bash dependencies.sh +# + +ADD scripts/install.sh install.sh +RUN bash install.sh diff --git a/images/iverilog/info.json b/images/iverilog/info.json new file mode 100755 index 00000000..27a8a971 --- /dev/null +++ b/images/iverilog/info.json @@ -0,0 +1,8 @@ +{ + "args" : { + "BASE_IMAGE" : "base", + "NAME": "iverilog", + "REPO_URL": "https://github.com/steveicarus/iverilog.git", + "REPO_COMMIT": "v11_0" + } +} diff --git a/images/iverilog/scripts/dependencies.sh b/images/iverilog/scripts/dependencies.sh new file mode 100755 index 00000000..210aa1e4 --- /dev/null +++ b/images/iverilog/scripts/dependencies.sh @@ -0,0 +1,11 @@ +#!/bin/bash +yum group install "Development Tools" -y +yum -y install gcc-c++ + +wget http://ftp.gnu.org/pub/gnu/gperf/gperf-3.1.tar.gz +tar -xvzf gperf-3.1.tar.gz && \ + cd gperf-3.1 && \ + autoconf && \ + ./configure --prefix=/opt/gperf/ && \ + make -j$(nproc) && \ + make install diff --git a/images/iverilog/scripts/install.sh b/images/iverilog/scripts/install.sh new file mode 100755 index 00000000..8cc233f1 --- /dev/null +++ b/images/iverilog/scripts/install.sh @@ -0,0 +1,13 @@ +#!/bin/bash + + +git clone ${REPO_URL} ${NAME} +cd ${NAME} +git checkout ${REPO_COMMIT} + +chmod +x autoconf.sh +PATH=/opt/gperf/bin:$PATH ./autoconf.sh +./configure --prefix=/foss/tools/${NAME}/${REPO_COMMIT} +make -j$(nproc) +make install + diff --git a/images/klayout/Dockerfile b/images/klayout/Dockerfile new file mode 100755 index 00000000..f9aa6d4a --- /dev/null +++ b/images/klayout/Dockerfile @@ -0,0 +1,13 @@ +ARG BASE_IMAGE +FROM ${BASE_IMAGE} as builder + +ARG REPO_URL +ARG REPO_COMMIT +ARG NAME +# +ADD scripts/dependencies.sh dependencies.sh +RUN bash dependencies.sh + +ADD scripts/install.sh install.sh +RUN bash install.sh + diff --git a/images/klayout/info.json b/images/klayout/info.json new file mode 100755 index 00000000..f6fb2120 --- /dev/null +++ b/images/klayout/info.json @@ -0,0 +1,8 @@ +{ + "args": { + "BASE_IMAGE": "base", + "NAME": "klayout", + "REPO_URL": "https://github.com/KLayout/klayout", + "REPO_COMMIT": "8b1278808485cc06aeb29cb9425b089df4c58546" + } +} \ No newline at end of file diff --git a/images/klayout/scripts/dependencies.sh b/images/klayout/scripts/dependencies.sh new file mode 100755 index 00000000..3d19bb75 --- /dev/null +++ b/images/klayout/scripts/dependencies.sh @@ -0,0 +1,23 @@ +#!/bin/bash +yum install -y \ + alsa-lib \ + libmng \ + libyaml \ + pciutils \ + pciutils-libs \ + qt \ + qt-devel \ + qt-settings \ + qt-x11 \ + ruby \ + ruby-devel \ + ruby-irb \ + ruby-libs \ + rubygem-bigdecimal \ + rubygem-io-console \ + rubygem-json \ + rubygem-psych \ + rubygem-rdoc \ + rubygems + + diff --git a/images/klayout/scripts/install.sh b/images/klayout/scripts/install.sh new file mode 100755 index 00000000..ed90e16b --- /dev/null +++ b/images/klayout/scripts/install.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +source scl_source enable devtoolset-8 + +git clone ${REPO_URL} ${NAME} +cd ${NAME} +git checkout ${REPO_COMMIT} + +prefix=/foss/tools/${NAME}/${REPO_COMMIT} +mkdir -p $prefix +./build.sh -j$(nproc) -prefix "$prefix" +./build.sh -j$(nproc) -prefix "$prefix" + diff --git a/images/magic/Dockerfile b/images/magic/Dockerfile new file mode 100755 index 00000000..dfc28092 --- /dev/null +++ b/images/magic/Dockerfile @@ -0,0 +1,10 @@ +ARG BASE_IMAGE +FROM ${BASE_IMAGE} as builder + +ARG REPO_URL +ARG REPO_COMMIT +ARG NAME + +ADD scripts/install.sh install.sh +RUN bash install.sh + diff --git a/images/magic/info.json b/images/magic/info.json new file mode 100755 index 00000000..1bdb87b5 --- /dev/null +++ b/images/magic/info.json @@ -0,0 +1,8 @@ +{ + "args": { + "BASE_IMAGE": "base", + "NAME": "magic", + "REPO_URL": "https://github.com/rtimothyedwards/magic", + "REPO_COMMIT": "73929a0bccd3083c3fe5c74b7ebf5a20d74bb4ee" + } +} \ No newline at end of file diff --git a/images/magic/scripts/install.sh b/images/magic/scripts/install.sh new file mode 100755 index 00000000..997af74c --- /dev/null +++ b/images/magic/scripts/install.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +source scl_source enable devtoolset-8 + +git clone ${REPO_URL} ${NAME} +cd ${NAME} +git checkout ${REPO_COMMIT} +./configure --prefix=/foss/tools/${NAME}/${REPO_COMMIT} +make -j$(nproc) +make install + diff --git a/images/netgen/Dockerfile b/images/netgen/Dockerfile new file mode 100755 index 00000000..d42a6e28 --- /dev/null +++ b/images/netgen/Dockerfile @@ -0,0 +1,12 @@ +ARG BASE_IMAGE +FROM ${BASE_IMAGE} as builder + +ARG REPO_URL +ARG REPO_COMMIT +ARG NAME + +ADD scripts/dependencies.sh dependencies.sh +RUN bash dependencies.sh + +ADD scripts/install.sh install.sh +RUN bash install.sh diff --git a/images/netgen/info.json b/images/netgen/info.json new file mode 100755 index 00000000..e60f5dbc --- /dev/null +++ b/images/netgen/info.json @@ -0,0 +1,8 @@ +{ + "args": { + "BASE_IMAGE": "base", + "NAME": "netgen", + "REPO_URL": "https://github.com/rtimothyedwards/netgen", + "REPO_COMMIT": "18dcac73bcb10455475826facbfdb4c25ce1a951" + } +} \ No newline at end of file diff --git a/images/netgen/scripts/dependencies.sh b/images/netgen/scripts/dependencies.sh new file mode 100755 index 00000000..05a7907c --- /dev/null +++ b/images/netgen/scripts/dependencies.sh @@ -0,0 +1,2 @@ +#!/bin/bash + diff --git a/images/netgen/scripts/install.sh b/images/netgen/scripts/install.sh new file mode 100755 index 00000000..29e68b5c --- /dev/null +++ b/images/netgen/scripts/install.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +source scl_source enable devtoolset-8 + +git clone ${REPO_URL} ${NAME} + +cd ${NAME} +git checkout ${REPO_COMMIT} + +./configure CFLAGS="-O2 -g" --prefix=/foss/tools/${NAME}/${REPO_COMMIT} +make clean +make -j$(nproc) +make install + + diff --git a/images/ngscope/Dockerfile b/images/ngscope/Dockerfile new file mode 100755 index 00000000..d42a6e28 --- /dev/null +++ b/images/ngscope/Dockerfile @@ -0,0 +1,12 @@ +ARG BASE_IMAGE +FROM ${BASE_IMAGE} as builder + +ARG REPO_URL +ARG REPO_COMMIT +ARG NAME + +ADD scripts/dependencies.sh dependencies.sh +RUN bash dependencies.sh + +ADD scripts/install.sh install.sh +RUN bash install.sh diff --git a/images/ngscope/info.json b/images/ngscope/info.json new file mode 100755 index 00000000..0e62be67 --- /dev/null +++ b/images/ngscope/info.json @@ -0,0 +1,8 @@ +{ + "args": { + "BASE_IMAGE": "base", + "NAME": "ngscope", + "REPO_URL": "none", + "REPO_COMMIT": "0.9.5" + } +} \ No newline at end of file diff --git a/images/ngscope/scripts/dependencies.sh b/images/ngscope/scripts/dependencies.sh new file mode 100755 index 00000000..edb22062 --- /dev/null +++ b/images/ngscope/scripts/dependencies.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +yum -y install bison flex gawk zlib-devel libtool wget git curl zip unzip +yum -y install autoconf automake make gcc-c++ libstdc++-static.x86_64 +yum -y install curl libffi-devel readline-devel tcl tcl-devel graphviz xdot tk tk-devel bzip2-devel xz-devel gtk2* +yum -y install wxGTK-devel + +cmakeVersionBig=3.14 +cmakeVersionSmall=${cmakeVersionBig}.0 + +install_cmake() { + wget https://cmake.org/files/v${cmakeVersionBig}/cmake-${cmakeVersionSmall}-Linux-x86_64.sh + md5sum -c <(echo "73041a43d27a30cdcbfdfdb61310d081 cmake-${cmakeVersionSmall}-Linux-x86_64.sh") || exit 1 + chmod +x cmake-${cmakeVersionSmall}-Linux-x86_64.sh + ./cmake-${cmakeVersionSmall}-Linux-x86_64.sh --skip-license --prefix=/usr/local +} + + +install_cmake diff --git a/images/ngscope/scripts/install.sh b/images/ngscope/scripts/install.sh new file mode 100755 index 00000000..3a67429f --- /dev/null +++ b/images/ngscope/scripts/install.sh @@ -0,0 +1,14 @@ +#!/bin/bash + + +wget https://sourceforge.net/projects/ngscope/files/rel_0_9/ngscope_0_9_5.tar.bz2 + +tar -xvf ngscope_0_9_5.tar.bz2 +cd ngscope +mkdir build +cd build + +prefix=/foss/tools/${NAME}/${REPO_COMMIT} +cmake -DCMAKE_INSTALL_PREFIX=$prefix .. +make -j$(nproc) +make DESTDIR=$prefix install diff --git a/images/ngspice/Dockerfile b/images/ngspice/Dockerfile new file mode 100755 index 00000000..d42a6e28 --- /dev/null +++ b/images/ngspice/Dockerfile @@ -0,0 +1,12 @@ +ARG BASE_IMAGE +FROM ${BASE_IMAGE} as builder + +ARG REPO_URL +ARG REPO_COMMIT +ARG NAME + +ADD scripts/dependencies.sh dependencies.sh +RUN bash dependencies.sh + +ADD scripts/install.sh install.sh +RUN bash install.sh diff --git a/images/ngspice/info.json b/images/ngspice/info.json new file mode 100755 index 00000000..74bdd0dc --- /dev/null +++ b/images/ngspice/info.json @@ -0,0 +1,8 @@ +{ + "args" : { + "BASE_IMAGE" : "base", + "NAME": "ngspice", + "REPO_URL": "https://git.code.sf.net/p/ngspice/ngspice", + "REPO_COMMIT": "51cc21de1637d1abca1b361b756784e69a28cf76" + } +} diff --git a/images/ngspice/scripts/dependencies.sh b/images/ngspice/scripts/dependencies.sh new file mode 100755 index 00000000..0cfcb117 --- /dev/null +++ b/images/ngspice/scripts/dependencies.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +yum -y install bison flex gawk zlib-devel libtool wget git curl zip unzip +yum -y install autoconf automake make gcc-c++ libstdc++-static.x86_64 +yum -y install curl libffi-devel readline-devel tcl tcl-devel graphviz xdot tk tk-devel bzip2-devel xz-devel gtk2* +yum -y install wxGTK-devel libXaw-devel + +cmakeVersionBig=3.14 +cmakeVersionSmall=${cmakeVersionBig}.0 + +install_cmake() { + wget https://cmake.org/files/v${cmakeVersionBig}/cmake-${cmakeVersionSmall}-Linux-x86_64.sh + md5sum -c <(echo "73041a43d27a30cdcbfdfdb61310d081 cmake-${cmakeVersionSmall}-Linux-x86_64.sh") || exit 1 + chmod +x cmake-${cmakeVersionSmall}-Linux-x86_64.sh + ./cmake-${cmakeVersionSmall}-Linux-x86_64.sh --skip-license --prefix=/usr/local +} + + +install_cmake diff --git a/images/ngspice/scripts/install.sh b/images/ngspice/scripts/install.sh new file mode 100755 index 00000000..25853832 --- /dev/null +++ b/images/ngspice/scripts/install.sh @@ -0,0 +1,17 @@ +#!/bin/bash +source scl_source enable devtoolset-8 + +git clone ${REPO_URL} ${NAME} +cd ${NAME} + +git checkout ${REPO_COMMIT} + +./autogen.sh +./autogen.sh + +./configure --disable-debug --enable-openmp --with-x --with-readline=yes --enable-xspice --with-fftw3=yes --prefix=/foss/tools/${NAME}/${REPO_COMMIT} +make +make install + + + diff --git a/images/open_pdks/Dockerfile b/images/open_pdks/Dockerfile new file mode 100755 index 00000000..1097bf79 --- /dev/null +++ b/images/open_pdks/Dockerfile @@ -0,0 +1,20 @@ +ARG BASE_IMAGE +ARG MAGIC_IMAGE +ARG SKYWATER_IMAGE + + +FROM ${MAGIC_IMAGE} as magic +FROM ${SKYWATER_IMAGE} as sw +FROM ${BASE_IMAGE} as builder +COPY --from=magic /foss/tools/ /foss/tools/ +COPY --from=sw /foss/pdks/ /foss/pdks/ + +ARG REPO_URL +ARG REPO_COMMIT +ARG NAME + +ADD scripts/dependencies.sh dependencies.sh +RUN bash dependencies.sh + +ADD scripts/install.sh install.sh +RUN bash install.sh diff --git a/images/open_pdks/info.json b/images/open_pdks/info.json new file mode 100755 index 00000000..633abf6d --- /dev/null +++ b/images/open_pdks/info.json @@ -0,0 +1,10 @@ +{ + "args": { + "BASE_IMAGE": "base", + "MAGIC_IMAGE": "magic", + "NAME": "open_pdks", + "REPO_URL": "https://github.com/RTimothyEdwards/open_pdks", + "REPO_COMMIT": "527bfa4c2a069542981a0217946868068b0d33fe", + "SKYWATER_IMAGE": "skywater-pdk" + } +} \ No newline at end of file diff --git a/images/open_pdks/scripts/dependencies.sh b/images/open_pdks/scripts/dependencies.sh new file mode 100755 index 00000000..05a7907c --- /dev/null +++ b/images/open_pdks/scripts/dependencies.sh @@ -0,0 +1,2 @@ +#!/bin/bash + diff --git a/images/open_pdks/scripts/install.sh b/images/open_pdks/scripts/install.sh new file mode 100755 index 00000000..ed56acf6 --- /dev/null +++ b/images/open_pdks/scripts/install.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +source scl_source enable devtoolset-8 + +magic_version=$(ls /foss/tools/magic/ ) +export PATH=$PATH:/foss/tools/magic/$magic_version/bin/ + +pdk_path=/foss/pdks/ +cd $pdk_path +git clone ${REPO_URL} ${NAME} +cd ${NAME} +git checkout master +git pull +git checkout -qf ${REPO_COMMIT} + +##./configure --enable-sky130-pdk=$pdk_path/skywater-pdk/libraries --enable-sram-sky130="disabled" + +./configure --enable-sky130-pdk=$pdk_path/skywater-pdk/libraries --enable-alpha-sky130 --enable-xschem-sky130 --enable-sram-sky130 + +cd sky130 +make veryclean +make prerequisites +make -j$(nproc) +make SHARED_PDKS_PATH=$pdk_path install +make clean + +cd $pdk_path +\rm -rf skywater-pdk open_pdks share + diff --git a/images/openlane/Dockerfile b/images/openlane/Dockerfile new file mode 100755 index 00000000..25b3dd14 --- /dev/null +++ b/images/openlane/Dockerfile @@ -0,0 +1,13 @@ +ARG BASE_IMAGE +FROM ${BASE_IMAGE} as builder + +ARG REPO_URL +ARG REPO_COMMIT +ARG NAME + +ADD scripts/dependencies.sh dependencies.sh +RUN bash dependencies.sh + +ADD scripts/install.sh install.sh +RUN bash install.sh +# diff --git a/images/openlane/info.json b/images/openlane/info.json new file mode 100755 index 00000000..b97ffcaf --- /dev/null +++ b/images/openlane/info.json @@ -0,0 +1,8 @@ +{ + "args": { + "BASE_IMAGE": "base", + "NAME": "openlane", + "REPO_URL": "https://github.com/The-OpenROAD-Project/OpenLane", + "REPO_COMMIT": "2021.09.23_03.17.13" + } +} \ No newline at end of file diff --git a/images/openlane/scripts/dependencies.sh b/images/openlane/scripts/dependencies.sh new file mode 100755 index 00000000..7a693aac --- /dev/null +++ b/images/openlane/scripts/dependencies.sh @@ -0,0 +1,3 @@ +#!/bin/bash + + diff --git a/images/openlane/scripts/install.sh b/images/openlane/scripts/install.sh new file mode 100755 index 00000000..c9935d61 --- /dev/null +++ b/images/openlane/scripts/install.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +source scl_source enable devtoolset-8 + + +install_openlane_tools() { + cd docker_build + make export-all + mkdir -p /foss/tools/${NAME}_tools/${REPO_COMMIT} + cp -r build/* /foss/tools/${NAME}_tools/${REPO_COMMIT} +} + +mkdir -p /foss/tools/ +git clone ${REPO_URL} /foss/tools/${NAME}/${REPO_COMMIT} +cd /foss/tools/${NAME}/${REPO_COMMIT} + +git checkout ${REPO_COMMIT} + +install_openlane_tools + diff --git a/images/riscv-gnu-toolchain-rv32i/Dockerfile b/images/riscv-gnu-toolchain-rv32i/Dockerfile new file mode 100755 index 00000000..09f77bb1 --- /dev/null +++ b/images/riscv-gnu-toolchain-rv32i/Dockerfile @@ -0,0 +1,10 @@ +ARG NAME +ARG BASE_IMAGE +FROM ${BASE_IMAGE} as builder + +ARG REPO_URL +ARG REPO_COMMIT +ARG NAME + +ADD scripts/install.sh install.sh +RUN bash install.sh diff --git a/images/riscv-gnu-toolchain-rv32i/info.json b/images/riscv-gnu-toolchain-rv32i/info.json new file mode 100755 index 00000000..1ba5966b --- /dev/null +++ b/images/riscv-gnu-toolchain-rv32i/info.json @@ -0,0 +1,8 @@ +{ + "args" : { + "BASE_IMAGE" : "base", + "NAME": "riscv-gnu-toolchain-rv32i", + "REPO_URL": "https://github.com/riscv/riscv-gnu-toolchain", + "REPO_COMMIT": "411d134" + } +} diff --git a/images/riscv-gnu-toolchain-rv32i/scripts/dependencies.sh b/images/riscv-gnu-toolchain-rv32i/scripts/dependencies.sh new file mode 100755 index 00000000..210aa1e4 --- /dev/null +++ b/images/riscv-gnu-toolchain-rv32i/scripts/dependencies.sh @@ -0,0 +1,11 @@ +#!/bin/bash +yum group install "Development Tools" -y +yum -y install gcc-c++ + +wget http://ftp.gnu.org/pub/gnu/gperf/gperf-3.1.tar.gz +tar -xvzf gperf-3.1.tar.gz && \ + cd gperf-3.1 && \ + autoconf && \ + ./configure --prefix=/opt/gperf/ && \ + make -j$(nproc) && \ + make install diff --git a/images/riscv-gnu-toolchain-rv32i/scripts/install.sh b/images/riscv-gnu-toolchain-rv32i/scripts/install.sh new file mode 100755 index 00000000..1a7c300b --- /dev/null +++ b/images/riscv-gnu-toolchain-rv32i/scripts/install.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +source scl_source enable devtoolset-8 + +git clone ${REPO_URL} ${NAME} +cd ${NAME} +git checkout ${REPO_COMMIT} + +git submodule update --init --recursive +mkdir build +cd build +../configure --with-arch=rv32i --prefix=/foss/tools/${NAME}/${REPO_COMMIT} +make -j$(nproc) diff --git a/images/skywater-pdk/Dockerfile b/images/skywater-pdk/Dockerfile new file mode 100755 index 00000000..8bb76a35 --- /dev/null +++ b/images/skywater-pdk/Dockerfile @@ -0,0 +1,11 @@ +ARG BASE_IMAGE +FROM ${BASE_IMAGE} as base +ARG REPO_URL +ARG REPO_COMMIT +ARG NAME + +ADD scripts/dependencies.sh dependencies.sh +RUN bash dependencies.sh + +ADD scripts/install.sh install.sh +RUN bash install.sh diff --git a/images/skywater-pdk/info.json b/images/skywater-pdk/info.json new file mode 100755 index 00000000..740b800e --- /dev/null +++ b/images/skywater-pdk/info.json @@ -0,0 +1,8 @@ +{ + "args" : { + "BASE_IMAGE" : "base", + "NAME": "skywater-pdk", + "REPO_URL": "https://github.com/google/skywater-pdk.git", + "REPO_COMMIT" : "c094b6e83a4f9298e47f696ec5a7fd53535ec5eb" + } +} diff --git a/images/skywater-pdk/scripts/dependencies.sh b/images/skywater-pdk/scripts/dependencies.sh new file mode 100755 index 00000000..7a693aac --- /dev/null +++ b/images/skywater-pdk/scripts/dependencies.sh @@ -0,0 +1,3 @@ +#!/bin/bash + + diff --git a/images/skywater-pdk/scripts/install.sh b/images/skywater-pdk/scripts/install.sh new file mode 100755 index 00000000..41059f20 --- /dev/null +++ b/images/skywater-pdk/scripts/install.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +source scl_source enable devtoolset-8 + +mkdir -p /foss/pdks +git clone ${REPO_URL} /foss/pdks/${NAME}/ +cd /foss/pdks/${NAME}/ && \ +git checkout main && git submodule init && git pull --no-recurse-submodules && \ +git checkout -qf ${REPO_COMMIT} && \ +git submodule update --init libraries/sky130_fd_sc_hd/latest && \ +git submodule update --init libraries/sky130_fd_io/latest && \ +git submodule update --init libraries/sky130_fd_sc_hvl/latest && \ +git submodule update --init libraries/sky130_fd_pr/latest && \ +make timing + diff --git a/images/xschem/Dockerfile b/images/xschem/Dockerfile new file mode 100755 index 00000000..d42a6e28 --- /dev/null +++ b/images/xschem/Dockerfile @@ -0,0 +1,12 @@ +ARG BASE_IMAGE +FROM ${BASE_IMAGE} as builder + +ARG REPO_URL +ARG REPO_COMMIT +ARG NAME + +ADD scripts/dependencies.sh dependencies.sh +RUN bash dependencies.sh + +ADD scripts/install.sh install.sh +RUN bash install.sh diff --git a/images/xschem/info.json b/images/xschem/info.json new file mode 100755 index 00000000..712a0fa5 --- /dev/null +++ b/images/xschem/info.json @@ -0,0 +1,8 @@ +{ + "args": { + "BASE_IMAGE": "base", + "NAME": "xschem", + "REPO_URL": "https://github.com/StefanSchippers/xschem.git", + "REPO_COMMIT": "945368db9cf21c6a402260f6ee03350893a233ef" + } +} \ No newline at end of file diff --git a/images/xschem/scripts/dependencies.sh b/images/xschem/scripts/dependencies.sh new file mode 100755 index 00000000..d9fb0092 --- /dev/null +++ b/images/xschem/scripts/dependencies.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +yum install -y \ + alsa-lib-devel \ + gtk3-devel \ + libXpm-devel + +yum install -y libX11 libX11-devel libXrender libXrender-devel \ + libxcb libxcb-devel libcairo2 \ + libcairo2-devel tcl tcl-devel tk tk-devel \ + flex bison libXpm libXpm-devel gawk + + + diff --git a/images/xschem/scripts/install.sh b/images/xschem/scripts/install.sh new file mode 100755 index 00000000..b285852f --- /dev/null +++ b/images/xschem/scripts/install.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +source scl_source enable devtoolset-8 + +git clone ${REPO_URL} ${NAME} +cd ${NAME} + +autoreconf -f -i + +git checkout ${REPO_COMMIT} + +./configure --prefix=/foss/tools/${NAME}/${REPO_COMMIT} +make -j$(nproc) +make install diff --git a/images/xyce/Dockerfile b/images/xyce/Dockerfile new file mode 100755 index 00000000..b2de1df1 --- /dev/null +++ b/images/xyce/Dockerfile @@ -0,0 +1,15 @@ +ARG BASE_IMAGE +FROM ${BASE_IMAGE} as builder + +ARG REPO_URL +ARG REPO_COMMIT +ARG NAME + + +ADD scripts/dependencies.sh dependencies.sh +RUN bash dependencies.sh + +COPY scripts/trilinos.reconfigure.sh /trilinos.reconfigure.sh +COPY scripts/xyce.reconfigure.sh /xyce.reconfigure.sh +ADD scripts/install.sh install.sh +RUN bash install.sh diff --git a/images/xyce/info.json b/images/xyce/info.json new file mode 100755 index 00000000..2fe6c71f --- /dev/null +++ b/images/xyce/info.json @@ -0,0 +1,8 @@ +{ + "args": { + "BASE_IMAGE": "base", + "NAME": "xyce", + "REPO_URL": "https://github.com/Xyce/Xyce.git", + "REPO_COMMIT": "a157dbaa9516d5c218725f174b35f670b9e34131" + } +} diff --git a/images/xyce/scripts/dependencies.sh b/images/xyce/scripts/dependencies.sh new file mode 100755 index 00000000..a3f44e53 --- /dev/null +++ b/images/xyce/scripts/dependencies.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +yum -y install devtoolset-8-gcc-gfortran +yum -y install make bison libtool +yum -y install suitesparse-devel flex-devel fftw-devel blas-devel lapack-devel openmpi-devel + +cmakeVersionBig=3.17 +cmakeVersionSmall=${cmakeVersionBig}.0 + +install_cmake() { + wget https://cmake.org/files/v${cmakeVersionBig}/cmake-${cmakeVersionSmall}-Linux-x86_64.sh + chmod +x cmake-${cmakeVersionSmall}-Linux-x86_64.sh + ./cmake-${cmakeVersionSmall}-Linux-x86_64.sh --skip-license --prefix=/usr/local +} + + +install_cmake diff --git a/images/xyce/scripts/install.sh b/images/xyce/scripts/install.sh new file mode 100755 index 00000000..9c7a87b3 --- /dev/null +++ b/images/xyce/scripts/install.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +source scl_source enable devtoolset-8 + +git clone ${REPO_URL} ${NAME} +cd ${NAME} +git checkout ${REPO_COMMIT} +./bootstrap + +git clone https://github.com/trilinos/Trilinos trilinos +cd trilinos +git checkout trilinos-release-12-12-1 +mkdir -p parallel_build && cd parallel_build +cp /trilinos.reconfigure.sh ./reconfigure +chmod +x reconfigure +./reconfigure +make -j$(nproc) +make install + +cd /${NAME} +mkdir -p parallel_build && cd parallel_build +cp /xyce.reconfigure.sh ./reconfigure +chmod +x reconfigure +./reconfigure +make -j$(nproc) +make install + diff --git a/images/xyce/scripts/trilinos.reconfigure.sh b/images/xyce/scripts/trilinos.reconfigure.sh new file mode 100755 index 00000000..83ecc849 --- /dev/null +++ b/images/xyce/scripts/trilinos.reconfigure.sh @@ -0,0 +1,43 @@ +#!/bin/sh +SRCDIR=/xyce/trilinos +ARCHDIR=/xyce/XyceLibs/Parallel +FLAGS="-O3 -fPIC" +PATH=$PATH:/usr/lib64/openmpi/bin +cmake \ +-G "Unix Makefiles" \ +-DCMAKE_C_COMPILER=mpicc \ +-DCMAKE_CXX_COMPILER=mpic++ \ +-DCMAKE_Fortran_COMPILER=mpif77 \ +-DCMAKE_CXX_FLAGS="$FLAGS" \ +-DCMAKE_C_FLAGS="$FLAGS" \ +-DCMAKE_Fortran_FLAGS="$FLAGS" \ +-DCMAKE_INSTALL_PREFIX=$ARCHDIR \ +-DCMAKE_MAKE_PROGRAM="make" \ +-DTrilinos_ENABLE_NOX=ON \ +-DNOX_ENABLE_LOCA=ON \ +-DTrilinos_ENABLE_EpetraExt=ON \ +-DEpetraExt_BUILD_BTF=ON \ +-DEpetraExt_BUILD_EXPERIMENTAL=ON \ +-DEpetraExt_BUILD_GRAPH_REORDERINGS=ON \ +-DTrilinos_ENABLE_TrilinosCouplings=ON \ +-DTrilinos_ENABLE_Ifpack=ON \ +-DTrilinos_ENABLE_ShyLU=ON \ +-DTrilinos_ENABLE_Isorropia=ON \ +-DTrilinos_ENABLE_AztecOO=ON \ +-DTrilinos_ENABLE_Belos=ON \ +-DTrilinos_ENABLE_Teuchos=ON \ +-DTeuchos_ENABLE_COMPLEX=ON \ +-DTrilinos_ENABLE_Amesos=ON \ +-DAmesos_ENABLE_KLU=ON \ +-DTrilinos_ENABLE_Sacado=ON \ +-DTrilinos_ENABLE_Kokkos=OFF \ +-DTrilinos_ENABLE_Zoltan=ON \ +-DTrilinos_ENABLE_ALL_OPTIONAL_PACKAGES=OFF \ +-DTrilinos_ENABLE_CXX11=ON \ +-DTPL_ENABLE_AMD=ON \ +-DAMD_LIBRARY_DIRS="/usr/lib" \ +-DTPL_AMD_INCLUDE_DIRS="/usr/include/suitesparse" \ +-DTPL_ENABLE_BLAS=ON \ +-DTPL_ENABLE_LAPACK=ON \ +-DTPL_ENABLE_MPI=ON \ +$SRCDIR diff --git a/images/xyce/scripts/xyce.reconfigure.sh b/images/xyce/scripts/xyce.reconfigure.sh new file mode 100755 index 00000000..16dee50f --- /dev/null +++ b/images/xyce/scripts/xyce.reconfigure.sh @@ -0,0 +1,13 @@ +export PATH=$PATH:/usr/lib64/openmpi/bin +../configure \ +CXXFLAGS="-O3 -std=c++11" \ +ARCHDIR="/xyce/XyceLibs/Parallel" \ +CPPFLAGS="-I/usr/include/suitesparse" \ +--enable-shared \ +--enable-Xyce-shareable \ +--enable-mpi \ +CXX=/usr/lib64/openmpi/bin/mpicxx \ +CC=/usr/lib64/openmpi/bin/mpicc \ +F77=/usr/lib64/openmpi/bin/mpif77 \ +--prefix=/foss/tools/${NAME}/Parallel/${REPO_COMMIT} \ +--enable-fft --enable-intel_fft --enable-fftw --enable-athena --enable-adms_sensitivities --enable-hdf5 diff --git a/paths/__pycache__/paths.cpython-37.pyc b/paths/__pycache__/paths.cpython-37.pyc new file mode 100755 index 00000000..17b52819 Binary files /dev/null and b/paths/__pycache__/paths.cpython-37.pyc differ diff --git a/paths/__pycache__/paths.cpython-39.pyc b/paths/__pycache__/paths.cpython-39.pyc new file mode 100755 index 00000000..618ea610 Binary files /dev/null and b/paths/__pycache__/paths.cpython-39.pyc differ diff --git a/paths/paths.py b/paths/paths.py new file mode 100755 index 00000000..669b3dff --- /dev/null +++ b/paths/paths.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 + +import os + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +IMAGES_PATH = "../images/" + + +def getAllImagesPath(): + packages_dir = os.path.join(SCRIPT_DIR, IMAGES_PATH) + dirs = os.listdir(packages_dir) + dirs_not_hidden = [f for f in dirs if not f.startswith('.')] + full_dirs_path = [os.path.join(packages_dir, f) for f in dirs_not_hidden] + dirs_not_hidden_folders = [f for f in full_dirs_path if os.path.isdir(f)] + return dirs_not_hidden_folders + + +def getImagePath(package_name): + path = os.path.join(SCRIPT_DIR, IMAGES_PATH, package_name) + return path + diff --git a/recipe-pdk-only.csv b/recipe-pdk-only.csv new file mode 100755 index 00000000..bee254ff --- /dev/null +++ b/recipe-pdk-only.csv @@ -0,0 +1,5 @@ +Name,Version +base,alpha +magic,f7820ed960a0d8a891ba4040d3b37086cd0879f8 +skywater-pdk,c094b6e83a4f9298e47f696ec5a7fd53535ec5eb +open_pdks,81d28fd0423ca6bbf3f3bf00b7d407958cf8f0f3 diff --git a/recipe.csv b/recipe.csv new file mode 100755 index 00000000..6e2787c0 --- /dev/null +++ b/recipe.csv @@ -0,0 +1,19 @@ +Name,Version +base,alpha +magic,73929a0bccd3083c3fe5c74b7ebf5a20d74bb4ee +klayout,8b1278808485cc06aeb29cb9425b089df4c58546 +skywater-pdk,c094b6e83a4f9298e47f696ec5a7fd53535ec5eb +open_pdks,527bfa4c2a069542981a0217946868068b0d33fe +gtkwave,bc06f0fabd174d44f50647b09d6f7c702b3b6c40 +iverilog,v11_0 +netgen,18dcac73bcb10455475826facbfdb4c25ce1a951 +openlane,2021.09.23_03.17.13 +riscv-gnu-toolchain-rv32i,411d134 +gaw3-xschem,2a1fc97bcc3081af72fc37a8bc52bc4632e176b2 +ngscope,0.9.5 +ngspice,51cc21de1637d1abca1b361b756784e69a28cf76 +xschem,945368db9cf21c6a402260f6ee03350893a233ef +xyce,a157dbaa9516d5c218725f174b35f670b9e34131 +covered,93bee2e0d89c1beb5943a329109dcf24d59498e6 +irsim, 5f33a7328787f726c1a22e787c8cc810f46971d3 +foss-asic-tools,alpha diff --git a/recipe.json b/recipe.json new file mode 100755 index 00000000..a825f742 --- /dev/null +++ b/recipe.json @@ -0,0 +1,53 @@ +{ + "base": { + "version": "alpha" + }, + "magic": { + "version": "f7820ed960a0d8a891ba4040d3b37086cd0879f8" + }, + "klayout": { + "version": "7031c6faf40744ff4309858293bd9aa17ed355ab" + }, + "open_pdks": { + "version": "28fd0423ca6bbf3f3bf00b7d407958cf8f0f3" + }, + "skywater-pdk": { + "version": "c094b6e83a4f9298e47f696ec5a7fd53535ec5e" + }, + "gtkwave": { + "version": "bc06f0fabd174d44f50647b09d6f7c702b3b6c40" + }, + "iverilog": { + "version": "v11_0" + }, + "netgen": { + "version": "738c1f7b3705bca2f1cc66fbc1cfb20f12d49a06" + }, + "openlane": { + "version": "2021.09.12_03.17.39" + }, + "riscv-gnu-toolchain-rv32i": { + "version": "411d134" + }, + "gaw3": { + "version": "2f1fbe08a8ccd139e2b410a31ad0d24c0f6d73" + }, + "ngscope": { + "version": "0.9.5" + }, + "ngspice": { + "version": "51cc21de1637d1abca1b361b756784e69a28cf76" + }, + "xschem": { + "version": "2a1fc97bcc3081af72fc37a8bc52bc4632e176b2" + }, + "xyce": { + "version": "ff6c96ceda5c4918d4d7ce1f72b58d7cc87dadf9" + }, + "covered": { + "version": "93bee2e0d89c1beb5943a329109dcf24d59498e6" + }, + "foss-asic-tools": { + "version": "alpha" + } +} diff --git a/recipe/__pycache__/recipe.cpython-37.pyc b/recipe/__pycache__/recipe.cpython-37.pyc new file mode 100755 index 00000000..db4453f0 Binary files /dev/null and b/recipe/__pycache__/recipe.cpython-37.pyc differ diff --git a/recipe/__pycache__/recipe.cpython-39.pyc b/recipe/__pycache__/recipe.cpython-39.pyc new file mode 100755 index 00000000..fe955069 Binary files /dev/null and b/recipe/__pycache__/recipe.cpython-39.pyc differ diff --git a/recipe/recipe.py b/recipe/recipe.py new file mode 100755 index 00000000..08c48136 --- /dev/null +++ b/recipe/recipe.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 + +from paths.paths import getImagePath +import json +import csv +from image.image import Image + + +def parseRecipeDict(recipe_dict): + images = [] + for item in recipe_dict: + name = item + version = recipe_dict[name]["version"] + pkg_path = getImagePath(name) + image = Image.createFromPath(pkg_path) + image.setVersion(version) + images.append(image) + + return images + + +def readJsonFile(recipe_file): + f = open(recipe_file) + json_dict = json.load(f) + f.close() + + return json_dict + + +def tableToDict(table): + dict = {} + for row in table: + name = row[0] + version = row[1] + + entry_dict = {} + entry_dict["version"] = version + dict[name] = entry_dict + + return dict + +def parseCsvFile(recipe_file): + rows = [] + with open(recipe_file, 'r') as csvfile: + csvreader = csv.reader(csvfile) + next(csvreader) + for row in csvreader: + rows.append(row) + + dict = tableToDict(rows) + return dict diff --git a/requirements.txt b/requirements.txt new file mode 100755 index 00000000..57de6b90 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +docker +six +gitpython diff --git a/run.py b/run.py new file mode 100755 index 00000000..ec7e005b --- /dev/null +++ b/run.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 + +import argparse +from image.image import Image +from docker_builder.docker_builder import DockerBuilder +from paths import paths as p +from recipe import recipe + +def buildImages(paths): + builder = DockerBuilder() + images = [] + for image_path in paths: + image = Image.createFromPath(image_path) + image.build_status = builder.build(image) + images.append(image) + + return images + +def build(args): + all_flag = args.all + paths = [] + + if (all_flag == True): + paths = p.getAllImagesPath() + else: + images_name = args.images + for image_name in images_name: + paths.append(p.getImagePath(image_name)) + + images = buildImages(paths) + for image in images: + print("Image: " + image.name + " " + str(image.build_status)) + + +def update(args): + updateFlag = args.yes + all_flag = args.all + paths = [] + + if (all_flag == True): + paths = p.getAllImagesPath() + else: + images = args.images + for image in images: + paths.append(p.getImagePath(image)) + + for path in paths: + image = Image.createFromPath(path) + image.update(updateFlag) + + +def handleRecipe(args): + json_file = args.json + csv_file = args.csv + dict = None + + if json_file != None: + dict = recipe.readJsonFile(json_file) + elif csv_file != None: + dict = recipe.parseCsvFile(csv_file) + + images = recipe.parseRecipeDict(dict) + builder = DockerBuilder() + for image in images: + image.build_status = builder.build(image) + + for image in images: + status = "Fail" + if image.build_status == True: + status = "Success" + print("Image | {:^30} | {:10} ".format(image.name, status)) + + +parser = argparse.ArgumentParser( + description="I don't know how to describe this yet" +) +subparsers = parser.add_subparsers() +build_subparser = subparsers.add_parser("build", + help="build ") +build_subparser.add_argument("--all", action="store_true") +build_subparser.add_argument("images", nargs='*', type=str) +build_subparser.set_defaults(func=build) + +update_subparser = subparsers.add_parser("update", + help="update") +update_subparser.add_argument("--all", action="store_true") +update_subparser.add_argument("-y", "--yes", action="store_true") +update_subparser.add_argument("images", nargs='*', type=str) +update_subparser.set_defaults(func=update) + +recipe_subparser = subparsers.add_parser("recipe", + help="recipe ") +recipe_subparser.add_argument("--json", type=str) +recipe_subparser.add_argument("--csv", type=str) +recipe_subparser.set_defaults(func=handleRecipe) + +args = parser.parse_args() +args.func(args) diff --git a/setup-venv.sh b/setup-venv.sh new file mode 100755 index 00000000..7604460a --- /dev/null +++ b/setup-venv.sh @@ -0,0 +1,3 @@ +virtualenv -p python3 venv +source venv/bin/activate +pip3 install -r requirements.txt