From e6a009312e7965b87c9b0af9e36c3ffffd7b9179 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 13 Oct 2021 09:46:02 -0700 Subject: [PATCH 001/229] Move mem reg before usage for compatibility --- compiler/base/verilog.py | 8 ++++---- compiler/tests/golden/sram_2_16_1_freepdk45.v | 5 +++-- compiler/tests/golden/sram_2_16_1_scn4m_subm.v | 5 +++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/compiler/base/verilog.py b/compiler/base/verilog.py index 9cfd7d7c..414b4491 100644 --- a/compiler/base/verilog.py +++ b/compiler/base/verilog.py @@ -94,12 +94,12 @@ class verilog: self.vf.write("\n") + # This is the memory array itself + self.vf.write(" reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];\n\n") + for port in self.all_ports: self.register_inputs(port) - # This is the memory array itself - self.vf.write("reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];\n") - for port in self.all_ports: if port in self.write_ports: self.add_write_block(port) @@ -162,7 +162,7 @@ class verilog: if port in self.read_ports: self.vf.write(" #(T_HOLD) dout{0} = {1}'bx;\n".format(port, self.word_size)) if port in self.readwrite_ports: - self.vf.write(" if ( !csb{0}_reg && web{0}_reg && VERBOSE ) \n".format(port)) + self.vf.write(" if ( !csb{0}_reg && web{0}_reg && VERBOSE )\n".format(port)) self.vf.write(" $display($time,\" Reading %m addr{0}=%b dout{0}=%b\",addr{0}_reg,mem[addr{0}_reg]);\n".format(port)) elif port in self.read_ports: self.vf.write(" if ( !csb{0}_reg && VERBOSE ) \n".format(port)) diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45.v b/compiler/tests/golden/sram_2_16_1_freepdk45.v index 859d1cc6..da4625a9 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45.v +++ b/compiler/tests/golden/sram_2_16_1_freepdk45.v @@ -30,6 +30,8 @@ module sram_2_16_1_freepdk45( input [DATA_WIDTH-1:0] din0; output [DATA_WIDTH-1:0] dout0; + reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1]; + reg csb0_reg; reg web0_reg; reg [ADDR_WIDTH-1:0] addr0_reg; @@ -44,13 +46,12 @@ module sram_2_16_1_freepdk45( addr0_reg = addr0; din0_reg = din0; #(T_HOLD) dout0 = 2'bx; - if ( !csb0_reg && web0_reg && VERBOSE ) + if ( !csb0_reg && web0_reg && VERBOSE ) $display($time," Reading %m addr0=%b dout0=%b",addr0_reg,mem[addr0_reg]); if ( !csb0_reg && !web0_reg && VERBOSE ) $display($time," Writing %m addr0=%b din0=%b",addr0_reg,din0_reg); end -reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1]; // Memory Write Block Port 0 // Write Operation : When web0 = 0, csb0 = 0 diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm.v b/compiler/tests/golden/sram_2_16_1_scn4m_subm.v index ce3714b2..0d25d63b 100644 --- a/compiler/tests/golden/sram_2_16_1_scn4m_subm.v +++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm.v @@ -30,6 +30,8 @@ module sram_2_16_1_scn4m_subm( input [DATA_WIDTH-1:0] din0; output [DATA_WIDTH-1:0] dout0; + reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1]; + reg csb0_reg; reg web0_reg; reg [ADDR_WIDTH-1:0] addr0_reg; @@ -44,13 +46,12 @@ module sram_2_16_1_scn4m_subm( addr0_reg = addr0; din0_reg = din0; #(T_HOLD) dout0 = 2'bx; - if ( !csb0_reg && web0_reg && VERBOSE ) + if ( !csb0_reg && web0_reg && VERBOSE ) $display($time," Reading %m addr0=%b dout0=%b",addr0_reg,mem[addr0_reg]); if ( !csb0_reg && !web0_reg && VERBOSE ) $display($time," Writing %m addr0=%b din0=%b",addr0_reg,din0_reg); end -reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1]; // Memory Write Block Port 0 // Write Operation : When web0 = 0, csb0 = 0 From c8139cf1452c13f98e200e24a45f1c79d91c9c27 Mon Sep 17 00:00:00 2001 From: Bugra Onal Date: Thu, 28 Oct 2021 18:43:28 +0300 Subject: [PATCH 002/229] Added OpenPDKS repo to makefile --- Makefile | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 84a9335d..d585d52a 100644 --- a/Makefile +++ b/Makefile @@ -23,10 +23,13 @@ TOP_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))) # Skywater PDK SRAM library #SRAM_LIBRARY ?= $(PDK_ROOT)/skywater-pdk/libraries/sky130_fd_bd_sram -SRAM_GIT_REPO ?= git@github.com:google/skywater-pdk-libs-sky130_fd_bd_sram.git +SRAM_GIT_REPO ?= https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git SRAM_LIBRARY ?= $(TOP_DIR)/sky130_fd_bd_sram + # Open PDKs -OPEN_PDKS ?= $(PDK_ROOT)/sky130A +PDK_ROOT ?= $(TOP_DIR)/open_pdks +OPEN_PDKS_REPO ?= https://github.com/RTimothyEdwards/open_pdks.git +OPEN_PDKS ?= $(PDK_ROOT)/sky130/sky130A # Create lists of all the files to copy/link @@ -57,9 +60,15 @@ install: $(INSTALL_DIRS) $(SRAM_LIBRARY): git clone $(SRAM_GIT_REPO) $(SRAM_LIBRARY) -.PHONY: $(SRAM_LIBRARY) $(INSTALL_DIRS) install +$(OPEN_PDKS): + git clone $(OPEN_PDKS_REPO) $(PDK_ROOT) + cd $(PDK_ROOT) &&\ + $(PDK_ROOT)/configure --enable-sky130-pdk + make -C $(PDK_ROOT) -all: $(SRAM_LIBRARY) +.PHONY: $(SRAM_LIBRARY) $(OPEN_PDKS) $(INSTALL_DIRS) install + +all: $(SRAM_LIBRARY) $(OPEN_PDKS) @echo "Installing sky130 SRAM PDK..." @echo "PDK_ROOT='$(PDK_ROOT)'" @echo "SRAM_LIBRARY='$(SRAM_LIBRARY)'" @@ -141,7 +150,8 @@ $(INSTALL_BASE)/sp_lib: $(filter-out %.$(SPICE_LVS_SUFFIX) %.$(SPICE_CALIBRE_SUF @echo clean: - rm -f $(SRAM_LIBRARY) + rm -rf $(SRAM_LIBRARY) + rm -rf $(PDK_ROOT) rm -f $(INSTALL_BASE)/tech/.magicrc rm -f $(INSTALL_BASE)/mag_lib/.magicrc rm -f $(INSTALL_BASE)/lef_lib/.magicrc From 9d49a369eac4fb0b351c6d60d9b54e7975e8b54b Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 2 Nov 2021 11:10:59 -0700 Subject: [PATCH 003/229] Initial docker setup --- Makefile | 62 ++++++------ docker/Dockerfile | 94 +++++++++++++++++++ docker/Makefile | 17 ++++ docker/set-paths.sh | 20 ++++ macros/Makefile | 72 ++++++++++++++ .../configs}/big_config_scn4m_subm.py | 0 .../example_config_1rw_1r_scn4m_subm.py | 0 .../example_config_1rw_1w_scn4m_subm.py | 0 .../example_config_1rw_2mux_scn4m_subm.py | 0 .../example_config_1w_1r_scn4m_subm.py | 0 .../configs}/example_config_2rw_scn4m_subm.py | 0 .../configs}/example_config_freepdk45.py | 0 .../configs}/example_config_scn4m_subm.py | 0 .../configs}/giant_config_scn4m_subm.py | 0 .../configs}/medium_config_scn4m_subm.py | 0 .../configs}/riscv_freepdk45_8kbyte.py | 0 .../riscv_scn4m_subm_16kbyte_1rw1r.py | 0 .../configs}/riscv_scn4m_subm_1kbyte_1rw1r.py | 0 .../configs}/riscv_scn4m_subm_2kbyte_1rw1r.py | 0 .../riscv_scn4m_subm_32kbyte_1rw1r.py | 0 .../configs}/riscv_scn4m_subm_4kbyte_1rw1r.py | 0 .../configs}/riscv_scn4m_subm_8kbyte_1rw1r.py | 0 .../configs}/riscv_sky130_1kbyte_1rw.py | 0 .../configs}/riscv_sky130_1kbyte_1rw1r.py | 0 .../configs}/riscv_sky130_2kbyte_1rw.py | 0 .../configs}/riscv_sky130_2kbyte_1rw1r.py | 0 .../configs}/riscv_sky130_4kbyte_1rw.py | 0 .../configs}/riscv_sky130_4kbyte_1rw1r.py | 0 .../sky130_sram_1kbyte_1r1w_8x1024_8.py | 0 .../sky130_sram_1kbyte_1rw1r_32x256_8.py | 0 .../sky130_sram_1kbyte_1rw1r_8x1024_8.py | 0 .../sky130_sram_1kbyte_1rw_32x256_8.py | 0 .../sky130_sram_2kbyte_1rw1r_32x512_8.py | 0 .../sky130_sram_2kbyte_1rw_32x512_8.py | 0 .../sky130_sram_4kbyte_1rw1r_32x1024_8.py | 0 .../sky130_sram_4kbyte_1rw_32x1024_8.py | 0 .../configs}/sky130_sram_common.py | 0 setpaths.sh | 4 +- 38 files changed, 239 insertions(+), 30 deletions(-) create mode 100644 docker/Dockerfile create mode 100644 docker/Makefile create mode 100644 docker/set-paths.sh create mode 100644 macros/Makefile rename {compiler/example_configs => macros/configs}/big_config_scn4m_subm.py (100%) rename {compiler/example_configs => macros/configs}/example_config_1rw_1r_scn4m_subm.py (100%) rename {compiler/example_configs => macros/configs}/example_config_1rw_1w_scn4m_subm.py (100%) rename {compiler/example_configs => macros/configs}/example_config_1rw_2mux_scn4m_subm.py (100%) rename {compiler/example_configs => macros/configs}/example_config_1w_1r_scn4m_subm.py (100%) rename {compiler/example_configs => macros/configs}/example_config_2rw_scn4m_subm.py (100%) rename {compiler/example_configs => macros/configs}/example_config_freepdk45.py (100%) rename {compiler/example_configs => macros/configs}/example_config_scn4m_subm.py (100%) rename {compiler/example_configs => macros/configs}/giant_config_scn4m_subm.py (100%) rename {compiler/example_configs => macros/configs}/medium_config_scn4m_subm.py (100%) rename {compiler/example_configs => macros/configs}/riscv_freepdk45_8kbyte.py (100%) rename {compiler/example_configs => macros/configs}/riscv_scn4m_subm_16kbyte_1rw1r.py (100%) rename {compiler/example_configs => macros/configs}/riscv_scn4m_subm_1kbyte_1rw1r.py (100%) rename {compiler/example_configs => macros/configs}/riscv_scn4m_subm_2kbyte_1rw1r.py (100%) rename {compiler/example_configs => macros/configs}/riscv_scn4m_subm_32kbyte_1rw1r.py (100%) rename {compiler/example_configs => macros/configs}/riscv_scn4m_subm_4kbyte_1rw1r.py (100%) rename {compiler/example_configs => macros/configs}/riscv_scn4m_subm_8kbyte_1rw1r.py (100%) rename {compiler/example_configs => macros/configs}/riscv_sky130_1kbyte_1rw.py (100%) rename {compiler/example_configs => macros/configs}/riscv_sky130_1kbyte_1rw1r.py (100%) rename {compiler/example_configs => macros/configs}/riscv_sky130_2kbyte_1rw.py (100%) rename {compiler/example_configs => macros/configs}/riscv_sky130_2kbyte_1rw1r.py (100%) rename {compiler/example_configs => macros/configs}/riscv_sky130_4kbyte_1rw.py (100%) rename {compiler/example_configs => macros/configs}/riscv_sky130_4kbyte_1rw1r.py (100%) rename {compiler/example_configs => macros/configs}/sky130_sram_1kbyte_1r1w_8x1024_8.py (100%) rename {compiler/example_configs => macros/configs}/sky130_sram_1kbyte_1rw1r_32x256_8.py (100%) rename {compiler/example_configs => macros/configs}/sky130_sram_1kbyte_1rw1r_8x1024_8.py (100%) rename {compiler/example_configs => macros/configs}/sky130_sram_1kbyte_1rw_32x256_8.py (100%) rename {compiler/example_configs => macros/configs}/sky130_sram_2kbyte_1rw1r_32x512_8.py (100%) rename {compiler/example_configs => macros/configs}/sky130_sram_2kbyte_1rw_32x512_8.py (100%) rename {compiler/example_configs => macros/configs}/sky130_sram_4kbyte_1rw1r_32x1024_8.py (100%) rename {compiler/example_configs => macros/configs}/sky130_sram_4kbyte_1rw_32x1024_8.py (100%) rename {compiler/example_configs => macros/configs}/sky130_sram_common.py (100%) diff --git a/Makefile b/Makefile index d585d52a..cd09060a 100644 --- a/Makefile +++ b/Makefile @@ -1,29 +1,11 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2020 Regents of the University of California -# -# 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 - -# The top directory where environment will be created. TOP_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))) +include $(TOP_DIR)/openram.mk -.DEFAULT_GOAL := all +.DEFAULT_GOAL := install # Skywater PDK SRAM library -#SRAM_LIBRARY ?= $(PDK_ROOT)/skywater-pdk/libraries/sky130_fd_bd_sram SRAM_GIT_REPO ?= https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git +SRAM_GIT_COMMIT ?= 9fa642baaf01110b59ac2783beba9a4fda03aeaf SRAM_LIBRARY ?= $(TOP_DIR)/sky130_fd_bd_sram # Open PDKs @@ -55,11 +37,6 @@ INSTALL_BASE := $(OPENRAM_HOME)/../technology/sky130 INSTALL_DIRS := $(addprefix $(INSTALL_BASE)/,$(INSTALL_BASE_DIRS)) -install: $(INSTALL_DIRS) - -$(SRAM_LIBRARY): - git clone $(SRAM_GIT_REPO) $(SRAM_LIBRARY) - $(OPEN_PDKS): git clone $(OPEN_PDKS_REPO) $(PDK_ROOT) cd $(PDK_ROOT) &&\ @@ -68,7 +45,7 @@ $(OPEN_PDKS): .PHONY: $(SRAM_LIBRARY) $(OPEN_PDKS) $(INSTALL_DIRS) install -all: $(SRAM_LIBRARY) $(OPEN_PDKS) +install: $(SRAM_LIBRARY) $(INSTALL_DIRS) $(OPEN_PDKS) @echo "Installing sky130 SRAM PDK..." @echo "PDK_ROOT='$(PDK_ROOT)'" @echo "SRAM_LIBRARY='$(SRAM_LIBRARY)'" @@ -76,6 +53,12 @@ all: $(SRAM_LIBRARY) $(OPEN_PDKS) make install @true +$(SRAM_LIBRARY): + git clone $(SRAM_GIT_REPO) $(SRAM_LIBRARY) + +.PHONY: $(SRAM_LIBRARY) $(INSTALL_DIRS) install + + $(INSTALL_BASE)/gds_lib: $(GDS_FILES) @echo @echo "Setting up GDS cell library for OpenRAM." @@ -149,7 +132,29 @@ $(INSTALL_BASE)/sp_lib: $(filter-out %.$(SPICE_LVS_SUFFIX) %.$(SPICE_CALIBRE_SUF @echo "==================================================================" @echo -clean: +macros: + cd macros && make + +.PHONY: macros + +tests: + docker run -v $(TOP_DIR):/openram \ + -e OPENRAM_HOME=/openram/compiler \ + -e OPENRAM_TECH=/openram/technology \ + vlsida/openram-ubuntu:latest \ + sh -c "cd /openram/compiler/tests && ./regress.py -v -k" +.PHONY: tests + + +mount: + docker run -it -v $(TOP_DIR):/openram \ + -e OPENRAM_HOME=/openram/compiler \ + -e OPENRAM_TECH=/openram/technology \ + vlsida/openram-ubuntu:latest +.PHONY: macros + + +uninstall: rm -rf $(SRAM_LIBRARY) rm -rf $(PDK_ROOT) rm -f $(INSTALL_BASE)/tech/.magicrc @@ -157,3 +162,4 @@ clean: rm -f $(INSTALL_BASE)/lef_lib/.magicrc rm -f $(INSTALL_BASE)/maglef_lib/.magicrc rm -rf $(INSTALL_DIRS) +.PHONY: uninstall diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 00000000..939b911b --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,94 @@ +FROM ubuntu:20.04 + +ENV DEBIAN_FRONTEND noninteractive +RUN ln -s /usr/share/zoneinfo/America/Los_Angeles /etc/localtime +RUN echo "America/Los_Angeles" > /etc/timezone + +RUN apt-get update +RUN apt-get --no-install-recommends -y upgrade + +### Dependencies ### +# General tools for building etc. +RUN apt-get install --no-install-recommends -y build-essential git ssh vim gosu autoconf automake libtool bison flex +# Use bash instead of dash +RUN rm /bin/sh && ln -s /bin/bash /bin/sh +# Needed by OpenRAM +RUN apt-get install --no-install-recommends -y python3 python3-numpy python3-scipy python3-pip python3-matplotlib python3-venv python3-sklearn python3-subunit python3-coverage +# Needed by Netgen +RUN apt-get install --no-install-recommends -y m4 csh tk tk-dev tcl-dev +# Needed by ngspice +RUN apt-get install --no-install-recommends -y libxaw7-dev libreadline8 libreadline-dev +# X11 +RUN apt-get install --no-install-recommends -y libx11-dev libcairo2-dev +# Klayout +RUN apt-get install --no-install-recommends -y qt5-default qtcreator ruby-full ruby-dev python3-dev qtmultimedia5-dev libqt5multimediawidgets5 libqt5multimedia5-plugins libqt5multimedia5 libqt5svg5-dev libqt5designer5 libqt5designercomponents5 libqt5xmlpatterns5-dev qttools5-dev + +### Klayout ### +ARG KLAYOUT_COMMIT=ea1bf40a1ee1c1c934e47a0020417503ab3d7e7e +WORKDIR /root +RUN git clone https://github.com/KLayout/klayout +WORKDIR /root/klayout +RUN git checkout ${KLAYOUT_COMMIT} +RUN ./build.sh -qt5 \ + && cp -r bin-release /usr/local/klayout +RUN rm -rf /root/klayout + +### Magic ### +ARG MAGIC_COMMIT=8.3.221 +WORKDIR /root +RUN git clone git://opencircuitdesign.com/magic-8.3 magic +WORKDIR /root/magic +RUN git checkout ${MAGIC_COMMIT} +RUN ./configure \ + && make \ + && make install +RUN rm -rf /root/magic + +### Ngspice ### +ARG NGSPICE_COMIT=032b1c32c4dbad45ff132bcfac1dbecadbd8abb0 +WORKDIR /root +RUN git clone git://git.code.sf.net/p/ngspice/ngspice +WORKDIR /root/ngspice +RUN git checkout ${NGSPICE_COMMIT} +RUN ./autogen.sh \ + && ./configure --enable-openmp --with-readline \ + && make \ + && make install +RUN rm -rf /root/ngspice + +### Netgen ### +ARG NETGEN_COMMIT=1.5.194 +WORKDIR /root +RUN git clone git://opencircuitdesign.com/netgen-1.5 netgen +WORKDIR /root/netgen +RUN git checkout ${NETGEN_COMMIT} +RUN ./configure \ + && make -j$(nproc) \ + && make install +RUN rm -rf /root/netgen + +#ARG XYCE_COMMIT=b7bb12d81f11d8b50141262537299b09d64b5565 +#ARG TRILINOS_COMIT= + +# ### SET UP A GENERIC USER ### +# WORKDIR / +# RUN echo "cd ~" >> /etc/skel/.bashrc +# RUN echo "source /set-paths.sh" >> /etc/skel/.bashrc +# ADD set-paths.sh /set-paths.sh +# RUN chmod 755 /set-paths.sh + +### CLEAN UP ### + +# Remove development tools to save space +RUN apt-get remove -y build-essential autoconf automake libtool bison flex tcl-dev tk-dev +# Cleanup to save some space +RUN apt-get clean +RUN rm -rf /var/lib/apt/lists/* + +WORKDIR / + +### ADD ENTRY POINT ### +# COPY entrypoint.sh /usr/local/bin/entrypoint.sh +# RUN chmod 755 /usr/local/bin/entrypoint.sh +# ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] +# CMD ["/bin/bash"] diff --git a/docker/Makefile b/docker/Makefile new file mode 100644 index 00000000..067cf49c --- /dev/null +++ b/docker/Makefile @@ -0,0 +1,17 @@ + +TAG_DATE := $(shell date +%F) +all: build push + +.PHONY: build +build: + docker build -t vlsida/openram-ubuntu:${TAG_DATE} -f Dockerfile . | tee -i openram-ubuntu.log + docker tag vlsida/openram-ubuntu:${TAG_DATE} vlsida/openram-ubuntu:latest + +.PHONY: push +push: + docker login + docker push vlsida/openram-ubuntu:latest + +.PHONY: pull +pull: + docker pull vlsida/openram-ubuntu:latest diff --git a/docker/set-paths.sh b/docker/set-paths.sh new file mode 100644 index 00000000..96582dbd --- /dev/null +++ b/docker/set-paths.sh @@ -0,0 +1,20 @@ + +export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin + +export SWROOT=/software + +# Klayout +export PATH=$PATH:/usr/local/klayout/bin + +# Xyce +export XYCE_HOME=$SWROOT/Xyce/Parallel +export XYCE_PATH=$XYCE_HOME/bin +export PATH=$PATH:$XYCE_PATH +export XYCE_LIB=$XYCE_HOME/lib +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$XYCE_LIB +export XYCE_NO_TRACKING="anything at all" + +# PDKs +export FREEPDK45=/home/PDKs/FreePDK45 +# Set to the PDK you want to use +export PDK_DIR=$FREEPDK45 diff --git a/macros/Makefile b/macros/Makefile new file mode 100644 index 00000000..2e0ecc0f --- /dev/null +++ b/macros/Makefile @@ -0,0 +1,72 @@ +MACRO_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))) +TOP_DIR := $(realpath $(MACRO_DIR)/..) +include $(TOP_DIR)/openram.mk + +.DEFAULT_GOAL := all + +OPENRAM_OPTS := $(OPENRAM_OPTS) +# Define `OPENRAM_FULL` in your environment to run a full characterize +ifeq ($(OPENRAM_FULL),) +# Do not characterize (default) +else +# Characterize +OPTS += -c +endif +# Verbosity +OPENRAM_OPTS += -v --keeptemp + +CONFIG_DIR = configs +SRCS=$(filter-out disabled-% %_common.py,$(sort $(notdir $(wildcard $(CONFIG_DIR)/*.py)))) +DIRS=$(basename $(SRCS)) +STAMPS=$(addsuffix .ok,$(DIRS)) + +configs: + @echo + @echo "Using OpenRAM at $(OPENRAM_HOME)" + @echo " (which is version $$(cd $(OPENRAM_HOME); git describe --tags))" + @echo + @echo "Configurations:" + @for D in $(DIRS); do echo " - $$D"; done + @echo + +.PHONY: configs + +BROKEN := \ + sky130_sram_1kbyte_1r1w_8x1024_8 \ + sky130_sram_1kbyte_1rw_32x256_8 \ + sky130_sram_2kbyte_1rw_32x512_8 \ + sky130_sram_4kbyte_1rw_32x1024_8 \ + +WORKING_STAMPS=$(filter-out $(addsuffix .ok, (BROKEN)), $(STAMPS)) + +all: | configs + @echo + @echo "Building following working configs" + @for S in $(WORKING_STAMPS); do echo " - $$S"; done + @sleep 5 + $(MAKE) $(WORKING_STAMPS) + @echo "Built all macros." + +%.ok: configs/%.py + @echo "Building $*" + @mkdir -p $* + docker run -v $(TOP_DIR):/openram \ + -v $(PDK_ROOT)/share/sky130A:/sky130A \ + -e PDK_ROOT=/ \ + -e OPENRAM_HOME=/openram/compiler \ + -e OPENRAM_TECH=/openram/technology \ + -e OPENRAM_TMP=/openram/macros/$*/tmp \ + vlsida/openram-ubuntu:latest \ + python3 -u /openram/compiler/openram.py $(OPENRAM_OPTS) -o $* -p /openram/macros/$* /openram/macros/$< && touch $@ + +.DELETE_ON_ERROR: $(STAMPS) + +$(DIRS): + @$(MAKE) --no-print-directory $@.ok + +.PHONY: $(DIRS) + +clean: + rm -rf $(STAMPS) + rm -rf $(DIRS) +.PHONY: clean diff --git a/compiler/example_configs/big_config_scn4m_subm.py b/macros/configs/big_config_scn4m_subm.py similarity index 100% rename from compiler/example_configs/big_config_scn4m_subm.py rename to macros/configs/big_config_scn4m_subm.py diff --git a/compiler/example_configs/example_config_1rw_1r_scn4m_subm.py b/macros/configs/example_config_1rw_1r_scn4m_subm.py similarity index 100% rename from compiler/example_configs/example_config_1rw_1r_scn4m_subm.py rename to macros/configs/example_config_1rw_1r_scn4m_subm.py diff --git a/compiler/example_configs/example_config_1rw_1w_scn4m_subm.py b/macros/configs/example_config_1rw_1w_scn4m_subm.py similarity index 100% rename from compiler/example_configs/example_config_1rw_1w_scn4m_subm.py rename to macros/configs/example_config_1rw_1w_scn4m_subm.py diff --git a/compiler/example_configs/example_config_1rw_2mux_scn4m_subm.py b/macros/configs/example_config_1rw_2mux_scn4m_subm.py similarity index 100% rename from compiler/example_configs/example_config_1rw_2mux_scn4m_subm.py rename to macros/configs/example_config_1rw_2mux_scn4m_subm.py diff --git a/compiler/example_configs/example_config_1w_1r_scn4m_subm.py b/macros/configs/example_config_1w_1r_scn4m_subm.py similarity index 100% rename from compiler/example_configs/example_config_1w_1r_scn4m_subm.py rename to macros/configs/example_config_1w_1r_scn4m_subm.py diff --git a/compiler/example_configs/example_config_2rw_scn4m_subm.py b/macros/configs/example_config_2rw_scn4m_subm.py similarity index 100% rename from compiler/example_configs/example_config_2rw_scn4m_subm.py rename to macros/configs/example_config_2rw_scn4m_subm.py diff --git a/compiler/example_configs/example_config_freepdk45.py b/macros/configs/example_config_freepdk45.py similarity index 100% rename from compiler/example_configs/example_config_freepdk45.py rename to macros/configs/example_config_freepdk45.py diff --git a/compiler/example_configs/example_config_scn4m_subm.py b/macros/configs/example_config_scn4m_subm.py similarity index 100% rename from compiler/example_configs/example_config_scn4m_subm.py rename to macros/configs/example_config_scn4m_subm.py diff --git a/compiler/example_configs/giant_config_scn4m_subm.py b/macros/configs/giant_config_scn4m_subm.py similarity index 100% rename from compiler/example_configs/giant_config_scn4m_subm.py rename to macros/configs/giant_config_scn4m_subm.py diff --git a/compiler/example_configs/medium_config_scn4m_subm.py b/macros/configs/medium_config_scn4m_subm.py similarity index 100% rename from compiler/example_configs/medium_config_scn4m_subm.py rename to macros/configs/medium_config_scn4m_subm.py diff --git a/compiler/example_configs/riscv_freepdk45_8kbyte.py b/macros/configs/riscv_freepdk45_8kbyte.py similarity index 100% rename from compiler/example_configs/riscv_freepdk45_8kbyte.py rename to macros/configs/riscv_freepdk45_8kbyte.py diff --git a/compiler/example_configs/riscv_scn4m_subm_16kbyte_1rw1r.py b/macros/configs/riscv_scn4m_subm_16kbyte_1rw1r.py similarity index 100% rename from compiler/example_configs/riscv_scn4m_subm_16kbyte_1rw1r.py rename to macros/configs/riscv_scn4m_subm_16kbyte_1rw1r.py diff --git a/compiler/example_configs/riscv_scn4m_subm_1kbyte_1rw1r.py b/macros/configs/riscv_scn4m_subm_1kbyte_1rw1r.py similarity index 100% rename from compiler/example_configs/riscv_scn4m_subm_1kbyte_1rw1r.py rename to macros/configs/riscv_scn4m_subm_1kbyte_1rw1r.py diff --git a/compiler/example_configs/riscv_scn4m_subm_2kbyte_1rw1r.py b/macros/configs/riscv_scn4m_subm_2kbyte_1rw1r.py similarity index 100% rename from compiler/example_configs/riscv_scn4m_subm_2kbyte_1rw1r.py rename to macros/configs/riscv_scn4m_subm_2kbyte_1rw1r.py diff --git a/compiler/example_configs/riscv_scn4m_subm_32kbyte_1rw1r.py b/macros/configs/riscv_scn4m_subm_32kbyte_1rw1r.py similarity index 100% rename from compiler/example_configs/riscv_scn4m_subm_32kbyte_1rw1r.py rename to macros/configs/riscv_scn4m_subm_32kbyte_1rw1r.py diff --git a/compiler/example_configs/riscv_scn4m_subm_4kbyte_1rw1r.py b/macros/configs/riscv_scn4m_subm_4kbyte_1rw1r.py similarity index 100% rename from compiler/example_configs/riscv_scn4m_subm_4kbyte_1rw1r.py rename to macros/configs/riscv_scn4m_subm_4kbyte_1rw1r.py diff --git a/compiler/example_configs/riscv_scn4m_subm_8kbyte_1rw1r.py b/macros/configs/riscv_scn4m_subm_8kbyte_1rw1r.py similarity index 100% rename from compiler/example_configs/riscv_scn4m_subm_8kbyte_1rw1r.py rename to macros/configs/riscv_scn4m_subm_8kbyte_1rw1r.py diff --git a/compiler/example_configs/riscv_sky130_1kbyte_1rw.py b/macros/configs/riscv_sky130_1kbyte_1rw.py similarity index 100% rename from compiler/example_configs/riscv_sky130_1kbyte_1rw.py rename to macros/configs/riscv_sky130_1kbyte_1rw.py diff --git a/compiler/example_configs/riscv_sky130_1kbyte_1rw1r.py b/macros/configs/riscv_sky130_1kbyte_1rw1r.py similarity index 100% rename from compiler/example_configs/riscv_sky130_1kbyte_1rw1r.py rename to macros/configs/riscv_sky130_1kbyte_1rw1r.py diff --git a/compiler/example_configs/riscv_sky130_2kbyte_1rw.py b/macros/configs/riscv_sky130_2kbyte_1rw.py similarity index 100% rename from compiler/example_configs/riscv_sky130_2kbyte_1rw.py rename to macros/configs/riscv_sky130_2kbyte_1rw.py diff --git a/compiler/example_configs/riscv_sky130_2kbyte_1rw1r.py b/macros/configs/riscv_sky130_2kbyte_1rw1r.py similarity index 100% rename from compiler/example_configs/riscv_sky130_2kbyte_1rw1r.py rename to macros/configs/riscv_sky130_2kbyte_1rw1r.py diff --git a/compiler/example_configs/riscv_sky130_4kbyte_1rw.py b/macros/configs/riscv_sky130_4kbyte_1rw.py similarity index 100% rename from compiler/example_configs/riscv_sky130_4kbyte_1rw.py rename to macros/configs/riscv_sky130_4kbyte_1rw.py diff --git a/compiler/example_configs/riscv_sky130_4kbyte_1rw1r.py b/macros/configs/riscv_sky130_4kbyte_1rw1r.py similarity index 100% rename from compiler/example_configs/riscv_sky130_4kbyte_1rw1r.py rename to macros/configs/riscv_sky130_4kbyte_1rw1r.py diff --git a/compiler/example_configs/sky130_sram_1kbyte_1r1w_8x1024_8.py b/macros/configs/sky130_sram_1kbyte_1r1w_8x1024_8.py similarity index 100% rename from compiler/example_configs/sky130_sram_1kbyte_1r1w_8x1024_8.py rename to macros/configs/sky130_sram_1kbyte_1r1w_8x1024_8.py diff --git a/compiler/example_configs/sky130_sram_1kbyte_1rw1r_32x256_8.py b/macros/configs/sky130_sram_1kbyte_1rw1r_32x256_8.py similarity index 100% rename from compiler/example_configs/sky130_sram_1kbyte_1rw1r_32x256_8.py rename to macros/configs/sky130_sram_1kbyte_1rw1r_32x256_8.py diff --git a/compiler/example_configs/sky130_sram_1kbyte_1rw1r_8x1024_8.py b/macros/configs/sky130_sram_1kbyte_1rw1r_8x1024_8.py similarity index 100% rename from compiler/example_configs/sky130_sram_1kbyte_1rw1r_8x1024_8.py rename to macros/configs/sky130_sram_1kbyte_1rw1r_8x1024_8.py diff --git a/compiler/example_configs/sky130_sram_1kbyte_1rw_32x256_8.py b/macros/configs/sky130_sram_1kbyte_1rw_32x256_8.py similarity index 100% rename from compiler/example_configs/sky130_sram_1kbyte_1rw_32x256_8.py rename to macros/configs/sky130_sram_1kbyte_1rw_32x256_8.py diff --git a/compiler/example_configs/sky130_sram_2kbyte_1rw1r_32x512_8.py b/macros/configs/sky130_sram_2kbyte_1rw1r_32x512_8.py similarity index 100% rename from compiler/example_configs/sky130_sram_2kbyte_1rw1r_32x512_8.py rename to macros/configs/sky130_sram_2kbyte_1rw1r_32x512_8.py diff --git a/compiler/example_configs/sky130_sram_2kbyte_1rw_32x512_8.py b/macros/configs/sky130_sram_2kbyte_1rw_32x512_8.py similarity index 100% rename from compiler/example_configs/sky130_sram_2kbyte_1rw_32x512_8.py rename to macros/configs/sky130_sram_2kbyte_1rw_32x512_8.py diff --git a/compiler/example_configs/sky130_sram_4kbyte_1rw1r_32x1024_8.py b/macros/configs/sky130_sram_4kbyte_1rw1r_32x1024_8.py similarity index 100% rename from compiler/example_configs/sky130_sram_4kbyte_1rw1r_32x1024_8.py rename to macros/configs/sky130_sram_4kbyte_1rw1r_32x1024_8.py diff --git a/compiler/example_configs/sky130_sram_4kbyte_1rw_32x1024_8.py b/macros/configs/sky130_sram_4kbyte_1rw_32x1024_8.py similarity index 100% rename from compiler/example_configs/sky130_sram_4kbyte_1rw_32x1024_8.py rename to macros/configs/sky130_sram_4kbyte_1rw_32x1024_8.py diff --git a/compiler/example_configs/sky130_sram_common.py b/macros/configs/sky130_sram_common.py similarity index 100% rename from compiler/example_configs/sky130_sram_common.py rename to macros/configs/sky130_sram_common.py diff --git a/setpaths.sh b/setpaths.sh index 44485f14..e4d0ff90 100755 --- a/setpaths.sh +++ b/setpaths.sh @@ -4,5 +4,5 @@ # like this: # source setpaths.sh -export OPENRAM_HOME="`pwd`/compiler" -export OPENRAM_TECH="`pwd`/technology" +export OPENRAM_HOME="/openram/compiler" +export OPENRAM_TECH="/openram/technology" From d7a20bc69bfe6b554ad6b7b7d862464ff2ed10f1 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 2 Nov 2021 15:07:18 -0700 Subject: [PATCH 004/229] Debug initial docker run scripts --- Makefile | 84 ++++++++++++++++-------------- macros/Makefile | 21 +++++++- macros/configs/sky130_sram_tiny.py | 21 ++++++++ openram.mk | 8 +++ technology/sky130/__init__.py | 2 +- 5 files changed, 93 insertions(+), 43 deletions(-) create mode 100644 macros/configs/sky130_sram_tiny.py create mode 100644 openram.mk diff --git a/Makefile b/Makefile index cd09060a..cdd7efe6 100644 --- a/Makefile +++ b/Makefile @@ -3,68 +3,76 @@ include $(TOP_DIR)/openram.mk .DEFAULT_GOAL := install +# Keep it locally if they didn't specify +PDK_ROOT ?= $(TOP_DIR) + # Skywater PDK SRAM library -SRAM_GIT_REPO ?= https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git -SRAM_GIT_COMMIT ?= 9fa642baaf01110b59ac2783beba9a4fda03aeaf -SRAM_LIBRARY ?= $(TOP_DIR)/sky130_fd_bd_sram +SRAM_LIB_DIR ?= $(PDK_ROOT)/sky130_fd_bd_sram +SRAM_LIB_GIT_REPO ?= https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git +SRAM_LIB_GIT_COMMIT ?= main # Open PDKs -PDK_ROOT ?= $(TOP_DIR)/open_pdks -OPEN_PDKS_REPO ?= https://github.com/RTimothyEdwards/open_pdks.git -OPEN_PDKS ?= $(PDK_ROOT)/sky130/sky130A - +OPEN_PDKS_DIR ?= $(PDK_ROOT)/open_pdks +OPEN_PDKS_GIT_REPO ?= https://github.com/RTimothyEdwards/open_pdks.git +OPEN_PDKS_GIT_COMMIT ?= 1.0.156 +SKY130_PDK ?= $(PDK_ROOT)/share/pdk/sky130A # Create lists of all the files to copy/link -GDS_FILES := $(sort $(wildcard $(SRAM_LIBRARY)/cells/*/*.gds)) -MAG_FILES := $(sort $(wildcard $(SRAM_LIBRARY)/cells/*/*.mag)) +GDS_FILES := $(sort $(wildcard $(SRAM_LIB_DIR)/cells/*/*.gds)) +MAG_FILES := $(sort $(wildcard $(SRAM_LIB_DIR)/cells/*/*.mag)) SPICE_SUFFIX := spice SPICE_LVS_SUFFIX := lvs.$(SPICE_SUFFIX) SPICE_CALIBRE_SUFFIX := lvs.calibre.$(SPICE_SUFFIX) SPICE_BASE_SUFFIX := base.$(SPICE_SUFFIX) -ALL_SPICE_FILES := $(sort $(wildcard $(SRAM_LIBRARY)/cells/*/*.$(SPICE_SUFFIX))) +ALL_SPICE_FILES := $(sort $(wildcard $(SRAM_LIB_DIR)/cells/*/*.$(SPICE_SUFFIX))) MAGLEF_SUFFIX := maglef -MAGLEF_FILES := $(sort $(wildcard $(SRAM_LIBRARY)/cells/*/*.$(MAGLEF_SUFFIX))) +MAGLEF_FILES := $(sort $(wildcard $(SRAM_LIB_DIR)/cells/*/*.$(MAGLEF_SUFFIX))) -MAGICRC_FILE := $(OPEN_PDKS)/libs.tech/magic/sky130A.magicrc +MAGICRC_FILE := $(SKY130_PDK)/libs.tech/magic/sky130A.magicrc ALL_FILES := $(ALL_SPICE_FILES) $(GDS_FILES) $(MAG_FILES) $(MAGLEF_FILES) -INSTALL_BASE_DIRS := gds_lib mag_lib sp_lib lvs_lib calibre_lvs_lib lef_lib maglef_lib +INSTALL_BASE_DIRS := gds_lib mag_lib sp_lib lvs_lib calibre_lvs_lib maglef_lib INSTALL_BASE := $(OPENRAM_HOME)/../technology/sky130 INSTALL_DIRS := $(addprefix $(INSTALL_BASE)/,$(INSTALL_BASE_DIRS)) +$(OPEN_PDKS_DIR): + @echo "Cloning open_pdks..." + git clone $(OPEN_PDKS_GIT_REPO) $(OPEN_PDKS_DIR) + cd $(OPEN_PDKS_DIR) && git checkout $(OPEN_PDKS_GIT_COMMIT) -$(OPEN_PDKS): - git clone $(OPEN_PDKS_REPO) $(PDK_ROOT) - cd $(PDK_ROOT) &&\ - $(PDK_ROOT)/configure --enable-sky130-pdk - make -C $(PDK_ROOT) +$(SKY130_PDK): $(OPEN_PDKS_DIR) + @echo "Installing open_pdks..." + cd $(OPEN_PDKS_DIR) &&\ + ./configure --prefix=$(PDK_ROOT) --enable-sky130-pdk \ + --disable-openlane --disable-irsim --disable-xschem --disable-qflow + @sleep 5 + make -C $(OPEN_PDKS_DIR) install -.PHONY: $(SRAM_LIBRARY) $(OPEN_PDKS) $(INSTALL_DIRS) install - -install: $(SRAM_LIBRARY) $(INSTALL_DIRS) $(OPEN_PDKS) +install: $(SRAM_LIB_DIR) $(SKY130_PDK) $(INSTALL_DIRS) @echo "Installing sky130 SRAM PDK..." @echo "PDK_ROOT='$(PDK_ROOT)'" - @echo "SRAM_LIBRARY='$(SRAM_LIBRARY)'" - @echo "OPEN_PDKS='$(OPEN_PDKS)'" - make install + @echo "SRAM_LIB_DIR='$(SRAM_LIB_DIR)'" + @echo "SKY130_PDK='$(SKY130_PDK)'" @true +.PHONY: install -$(SRAM_LIBRARY): - git clone $(SRAM_GIT_REPO) $(SRAM_LIBRARY) - -.PHONY: $(SRAM_LIBRARY) $(INSTALL_DIRS) install +$(SRAM_LIB_DIR): + @echo "Cloning SRAM library..." + git clone $(SRAM_LIB_GIT_REPO) $(SRAM_LIB_DIR) + cd $(SRAM_LIB_DIR) && git checkout $(SRAM_LIB_GIT_COMMIT) +.PHONY: $(INSTALL_DIRS) $(INSTALL_BASE)/gds_lib: $(GDS_FILES) @echo @echo "Setting up GDS cell library for OpenRAM." @echo "==================================================================" mkdir -p $@ - @cp -va $? $@ + cp -va $? $@ @echo "==================================================================" @echo @@ -146,20 +154,16 @@ tests: .PHONY: tests -mount: - docker run -it -v $(TOP_DIR):/openram \ - -e OPENRAM_HOME=/openram/compiler \ - -e OPENRAM_TECH=/openram/technology \ - vlsida/openram-ubuntu:latest -.PHONY: macros - - -uninstall: - rm -rf $(SRAM_LIBRARY) - rm -rf $(PDK_ROOT) +clean: + rm -rf $(SKY130_PDK) rm -f $(INSTALL_BASE)/tech/.magicrc rm -f $(INSTALL_BASE)/mag_lib/.magicrc rm -f $(INSTALL_BASE)/lef_lib/.magicrc rm -f $(INSTALL_BASE)/maglef_lib/.magicrc rm -rf $(INSTALL_DIRS) +.PHONY: clean + +uninstall: clean + rm -rf $(SRAM_LIB_DIR) + rm -rf $(OPEN_PDKS_DIR) .PHONY: uninstall diff --git a/macros/Makefile b/macros/Makefile index 2e0ecc0f..f10ab19e 100644 --- a/macros/Makefile +++ b/macros/Makefile @@ -2,8 +2,13 @@ MACRO_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))) TOP_DIR := $(realpath $(MACRO_DIR)/..) include $(TOP_DIR)/openram.mk +UID = $(shell id -u) +GID = $(shell id -g) + .DEFAULT_GOAL := all +SKY130_PDK ?= $(PDK_ROOT)/share/pdk/sky130A + OPENRAM_OPTS := $(OPENRAM_OPTS) # Define `OPENRAM_FULL` in your environment to run a full characterize ifeq ($(OPENRAM_FULL),) @@ -51,14 +56,26 @@ all: | configs @echo "Building $*" @mkdir -p $* docker run -v $(TOP_DIR):/openram \ - -v $(PDK_ROOT)/share/sky130A:/sky130A \ - -e PDK_ROOT=/ \ + -v $(SKY130_PDK):$(SKY130_PDK) \ + -e PDK_ROOT=$(PDK_ROOT) \ -e OPENRAM_HOME=/openram/compiler \ -e OPENRAM_TECH=/openram/technology \ -e OPENRAM_TMP=/openram/macros/$*/tmp \ + --user $(UID):$(GID) \ vlsida/openram-ubuntu:latest \ python3 -u /openram/compiler/openram.py $(OPENRAM_OPTS) -o $* -p /openram/macros/$* /openram/macros/$< && touch $@ +mount: + docker run -it -v $(TOP_DIR):/openram \ + -v $(SKY130_PDK):$(SKY130_PDK) \ + -e PDK_ROOT=$(PDK_ROOT) \ + -e OPENRAM_HOME=/openram/compiler \ + -e OPENRAM_TECH=/openram/technology \ + --user $(UID):$(GID) \ + vlsida/openram-ubuntu:latest +.PHONY: macros + + .DELETE_ON_ERROR: $(STAMPS) $(DIRS): diff --git a/macros/configs/sky130_sram_tiny.py b/macros/configs/sky130_sram_tiny.py new file mode 100644 index 00000000..95bfd61f --- /dev/null +++ b/macros/configs/sky130_sram_tiny.py @@ -0,0 +1,21 @@ +""" +Dual port (1 read/write + 1 read only) 1 kbytes SRAM with byte write. + +FIXME: What is this useful for? +FIXME: Why would you want byte write on this? +""" +word_size = 8 # Bits +num_words = 16 +human_byte_size = "{:.0f}kbytes".format((word_size * num_words)/1024/8) + +# Allow byte writes +write_size = 2 # Bits + +# Dual port +num_rw_ports = 1 +num_r_ports = 1 +num_w_ports = 0 +ports_human = '1rw1r' + +import os +exec(open(os.path.join(os.path.dirname(__file__), 'sky130_sram_common.py')).read()) diff --git a/openram.mk b/openram.mk new file mode 100644 index 00000000..1bd95897 --- /dev/null +++ b/openram.mk @@ -0,0 +1,8 @@ +OPENRAM_HOME := $(abspath $(TOP_DIR)/compiler) +OPENRAM_TECH := $(abspath $(TOP_DIR)/technology) +OPENRAM_COMPILER := $(OPENRAM_HOME)/openram.py +ifeq (,$(wildcard $(OPENRAM_COMPILER))) +$(error Did not find '$(OPENRAM_COMPILER)' in '$(OPENRAM_HOME)' (from $$OPENRAM_HOME)) +endif +export OPENRAM_HOME +export OPENRAM_TECH diff --git a/technology/sky130/__init__.py b/technology/sky130/__init__.py index 3df3f555..c17c62d8 100644 --- a/technology/sky130/__init__.py +++ b/technology/sky130/__init__.py @@ -21,7 +21,7 @@ os.environ["MGC_TMPDIR"] = "/tmp" # OpenPDK needed for magicrc, tech file and spice models of transistors if 'PDK_ROOT' in os.environ: - open_pdks = os.path.join(os.environ['PDK_ROOT'], 'sky130A', 'libs.tech') + open_pdks = os.path.join(os.environ['PDK_ROOT'], 'share', 'pdk', 'sky130A', 'libs.tech') else: raise SystemError("Unable to find open_pdks tech file. Set PDK_ROOT.") From 8d78bcc4dc6dc50db41ae7d088609e84500053a2 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 2 Nov 2021 15:12:26 -0700 Subject: [PATCH 005/229] Revert setpaths.sh --- setpaths.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setpaths.sh b/setpaths.sh index e4d0ff90..44485f14 100755 --- a/setpaths.sh +++ b/setpaths.sh @@ -4,5 +4,5 @@ # like this: # source setpaths.sh -export OPENRAM_HOME="/openram/compiler" -export OPENRAM_TECH="/openram/technology" +export OPENRAM_HOME="`pwd`/compiler" +export OPENRAM_TECH="`pwd`/technology" From eb310dbb6e834a68f6bf95af90ae2e988b1f860d Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 3 Nov 2021 08:31:50 -0700 Subject: [PATCH 006/229] Run docker as user. Revert to working magic commit 8.3.197. --- docker/Dockerfile | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 939b911b..9bcf031f 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -34,7 +34,7 @@ RUN ./build.sh -qt5 \ RUN rm -rf /root/klayout ### Magic ### -ARG MAGIC_COMMIT=8.3.221 +ARG MAGIC_COMMIT=8.3.197 WORKDIR /root RUN git clone git://opencircuitdesign.com/magic-8.3 magic WORKDIR /root/magic @@ -57,7 +57,7 @@ RUN ./autogen.sh \ RUN rm -rf /root/ngspice ### Netgen ### -ARG NETGEN_COMMIT=1.5.194 +ARG NETGEN_COMMIT=e4a15f12fbdd3480b6adc0eeba09df269ed7b387 WORKDIR /root RUN git clone git://opencircuitdesign.com/netgen-1.5 netgen WORKDIR /root/netgen @@ -70,25 +70,30 @@ RUN rm -rf /root/netgen #ARG XYCE_COMMIT=b7bb12d81f11d8b50141262537299b09d64b5565 #ARG TRILINOS_COMIT= -# ### SET UP A GENERIC USER ### -# WORKDIR / -# RUN echo "cd ~" >> /etc/skel/.bashrc -# RUN echo "source /set-paths.sh" >> /etc/skel/.bashrc -# ADD set-paths.sh /set-paths.sh -# RUN chmod 755 /set-paths.sh - ### CLEAN UP ### - # Remove development tools to save space RUN apt-get remove -y build-essential autoconf automake libtool bison flex tcl-dev tk-dev # Cleanup to save some space RUN apt-get clean RUN rm -rf /var/lib/apt/lists/* -WORKDIR / + +# ### SET UP A GENERIC USER ### +# WORKDIR /p +# RUN echo "cd ~" >> /etc/skel/.bashrc +# RUN echo "source /set-paths.sh" >> /etc/skel/.bashrc +# ADD set-paths.sh /set-paths.sh +# RUN chmod 755 /set-paths.sh ### ADD ENTRY POINT ### # COPY entrypoint.sh /usr/local/bin/entrypoint.sh # RUN chmod 755 /usr/local/bin/entrypoint.sh # ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] # CMD ["/bin/bash"] + +RUN mkdir /home/cad-user +RUN useradd cad-user +RUN chown -R cad-user /home/cad-user +RUN chgrp -R cad-user /home/cad-user +USER cad-user +WORKDIR /home/cad-user From f68ee76bc747b8cf1b1d1553066704d634632e5f Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 3 Nov 2021 08:32:08 -0700 Subject: [PATCH 007/229] Add UID/GID to makefile config --- openram.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openram.mk b/openram.mk index 1bd95897..02a9ee12 100644 --- a/openram.mk +++ b/openram.mk @@ -6,3 +6,6 @@ $(error Did not find '$(OPENRAM_COMPILER)' in '$(OPENRAM_HOME)' (from $$OPENRAM_ endif export OPENRAM_HOME export OPENRAM_TECH + +UID = $(shell id -u) +GID = $(shell id -g) From af67b738af6b52b13ffa1d795901e63690313b1b Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 3 Nov 2021 08:32:29 -0700 Subject: [PATCH 008/229] Add ability to run a single unit test in docker --- Makefile | 61 +++++++++++++++++++++++++++-- macros/Makefile | 7 +--- technology/scn4m_subm/tech/.magicrc | 1 + 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index cdd7efe6..bd9aee94 100644 --- a/Makefile +++ b/Makefile @@ -145,14 +145,69 @@ macros: .PHONY: macros +TEST_DIR = $(TOP_DIR)/compiler/tests +TEST_SRCS=$(sort $(notdir $(wildcard $(TEST_DIR)/*_test.py))) +TEST_DIRS=$(basename $(TEST_SRCS)) +TEST_STAMPS=$(addsuffix .ok,$(TEST_DIRS)) + +TEST_BROKEN := \ + sky130_sram_1kbyte_1r1w_8x1024_8 \ + sky130_sram_1kbyte_1rw_32x256_8 \ + sky130_sram_2kbyte_1rw_32x512_8 \ + sky130_sram_4kbyte_1rw_32x1024_8 \ + +WORKING_TEST_STAMPS=$(filter-out $(addsuffix .ok, (TEST_BROKEN)), $(TEST_STAMPS)) + +$(TEST_DIRS): + @$(MAKE) --no-print-directory $@.ok + tests: + @echo "Running the following tests" + @for S in $(WORKING_TEST_STAMPS); do echo " - $$S"; done + @sleep 5 + $(MAKE) $(WORKING_TEST_STAMPS) +.PHONY: tests + +%.ok: compiler/tests/%.py + @echo "Testing $*" + @mkdir -p $* + docker run -v $(TOP_DIR):/openram \ + -v $(SKY130_PDK):$(SKY130_PDK) \ + -e PDK_ROOT=$(PDK_ROOT) \ + -e OPENRAM_HOME=/openram/compiler \ + -e OPENRAM_TECH=/openram/technology \ + -e OPENRAM_TMP=/openram/$* \ + --user $(UID):$(GID) \ + vlsida/openram-ubuntu:latest \ + python3 -u /openram/compiler/tests/$*.py -v -k && touch $@ + +.DELETE_ON_ERROR: $(TEST_STAMPS) + +regress: docker run -v $(TOP_DIR):/openram \ -e OPENRAM_HOME=/openram/compiler \ -e OPENRAM_TECH=/openram/technology \ - vlsida/openram-ubuntu:latest \ - sh -c "cd /openram/compiler/tests && ./regress.py -v -k" -.PHONY: tests + --user $(UID):$(GID) \ + vlsida/openram-ubuntu:latest \ + sh -c "python3 -u /openram/compiler/tests/regress.py" +.PHONY: regress +mount: + docker run -it -v $(TOP_DIR):/openram \ + -v $(SKY130_PDK):$(SKY130_PDK) \ + -e PDK_ROOT=$(PDK_ROOT) \ + -e OPENRAM_HOME=/openram/compiler \ + -e OPENRAM_TECH=/openram/technology \ + --user $(UID):$(GID) \ + vlsida/openram-ubuntu:latest +.PHONY: mount + + +testclean: + rm -rf $(TEST_STAMPS) + rm -rf $(TEST_DIRS) + rm *.zip +.PHONE: testclean clean: rm -rf $(SKY130_PDK) diff --git a/macros/Makefile b/macros/Makefile index f10ab19e..2014cb96 100644 --- a/macros/Makefile +++ b/macros/Makefile @@ -2,9 +2,6 @@ MACRO_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))) TOP_DIR := $(realpath $(MACRO_DIR)/..) include $(TOP_DIR)/openram.mk -UID = $(shell id -u) -GID = $(shell id -g) - .DEFAULT_GOAL := all SKY130_PDK ?= $(PDK_ROOT)/share/pdk/sky130A @@ -42,7 +39,7 @@ BROKEN := \ sky130_sram_2kbyte_1rw_32x512_8 \ sky130_sram_4kbyte_1rw_32x1024_8 \ -WORKING_STAMPS=$(filter-out $(addsuffix .ok, (BROKEN)), $(STAMPS)) +WORKING_STAMPS=$(filter-out $(addsuffix .ok, $(BROKEN)), $(STAMPS)) all: | configs @echo @@ -73,7 +70,7 @@ mount: -e OPENRAM_TECH=/openram/technology \ --user $(UID):$(GID) \ vlsida/openram-ubuntu:latest -.PHONY: macros +.PHONY: mount .DELETE_ON_ERROR: $(STAMPS) diff --git a/technology/scn4m_subm/tech/.magicrc b/technology/scn4m_subm/tech/.magicrc index c85bb879..8fdad1b7 100644 --- a/technology/scn4m_subm/tech/.magicrc +++ b/technology/scn4m_subm/tech/.magicrc @@ -6,3 +6,4 @@ tech load SCN4M_SUBM.20 -noprompt scalegrid 1 4 set GND gnd set VDD vdd +set SUB gnd From 066e558b20df8131837abe743e68ab7d07c988bb Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 3 Nov 2021 08:34:49 -0700 Subject: [PATCH 009/229] Add Makefile targets for clean, uninstall, and wipe --- Makefile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index bd9aee94..3f2cf7a5 100644 --- a/Makefile +++ b/Makefile @@ -202,23 +202,23 @@ mount: vlsida/openram-ubuntu:latest .PHONY: mount - -testclean: +clean: rm -rf $(TEST_STAMPS) rm -rf $(TEST_DIRS) - rm *.zip -.PHONE: testclean + rm -f *.zip +.PHONE: clean -clean: - rm -rf $(SKY130_PDK) +uninstall: clean rm -f $(INSTALL_BASE)/tech/.magicrc rm -f $(INSTALL_BASE)/mag_lib/.magicrc rm -f $(INSTALL_BASE)/lef_lib/.magicrc rm -f $(INSTALL_BASE)/maglef_lib/.magicrc rm -rf $(INSTALL_DIRS) -.PHONY: clean +.PHONY: uninstall -uninstall: clean +# wipe the entire repos +wipe: uninstall + rm -rf $(SKY130_PDK) rm -rf $(SRAM_LIB_DIR) rm -rf $(OPEN_PDKS_DIR) -.PHONY: uninstall +.PHONY: wipe From e31bab26aecaf6d2f3005f2a7b6e954945bcb31e Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 3 Nov 2021 08:36:10 -0700 Subject: [PATCH 010/229] Warn for wiping repos --- Makefile | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 3f2cf7a5..ecd2a82b 100644 --- a/Makefile +++ b/Makefile @@ -203,22 +203,24 @@ mount: .PHONY: mount clean: - rm -rf $(TEST_STAMPS) - rm -rf $(TEST_DIRS) - rm -f *.zip + @rm -rf $(TEST_STAMPS) + @rm -rf $(TEST_DIRS) + @rm -f *.zip .PHONE: clean uninstall: clean - rm -f $(INSTALL_BASE)/tech/.magicrc - rm -f $(INSTALL_BASE)/mag_lib/.magicrc - rm -f $(INSTALL_BASE)/lef_lib/.magicrc - rm -f $(INSTALL_BASE)/maglef_lib/.magicrc - rm -rf $(INSTALL_DIRS) + @rm -f $(INSTALL_BASE)/tech/.magicrc + @rm -f $(INSTALL_BASE)/mag_lib/.magicrc + @rm -f $(INSTALL_BASE)/lef_lib/.magicrc + @rm -f $(INSTALL_BASE)/maglef_lib/.magicrc + @rm -rf $(INSTALL_DIRS) .PHONY: uninstall # wipe the entire repos wipe: uninstall - rm -rf $(SKY130_PDK) - rm -rf $(SRAM_LIB_DIR) - rm -rf $(OPEN_PDKS_DIR) + @echo "Wiping PDK repos in 5 sec... (ctrl-c to quit)" + @sleep 5 + @rm -rf $(SKY130_PDK) + @rm -rf $(SRAM_LIB_DIR) + @rm -rf $(OPEN_PDKS_DIR) .PHONY: wipe From 540711bcf275e4a5476545216aeafbc41b9186e8 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 3 Nov 2021 08:42:00 -0700 Subject: [PATCH 011/229] Silence some makefile commands --- Makefile | 8 +++----- docker/Makefile | 13 +++++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index ecd2a82b..5c175302 100644 --- a/Makefile +++ b/Makefile @@ -164,14 +164,12 @@ $(TEST_DIRS): tests: @echo "Running the following tests" @for S in $(WORKING_TEST_STAMPS); do echo " - $$S"; done - @sleep 5 $(MAKE) $(WORKING_TEST_STAMPS) .PHONY: tests %.ok: compiler/tests/%.py - @echo "Testing $*" @mkdir -p $* - docker run -v $(TOP_DIR):/openram \ + @docker run -v $(TOP_DIR):/openram \ -v $(SKY130_PDK):$(SKY130_PDK) \ -e PDK_ROOT=$(PDK_ROOT) \ -e OPENRAM_HOME=/openram/compiler \ @@ -184,7 +182,7 @@ tests: .DELETE_ON_ERROR: $(TEST_STAMPS) regress: - docker run -v $(TOP_DIR):/openram \ + @docker run -v $(TOP_DIR):/openram \ -e OPENRAM_HOME=/openram/compiler \ -e OPENRAM_TECH=/openram/technology \ --user $(UID):$(GID) \ @@ -193,7 +191,7 @@ regress: .PHONY: regress mount: - docker run -it -v $(TOP_DIR):/openram \ + @docker run -it -v $(TOP_DIR):/openram \ -v $(SKY130_PDK):$(SKY130_PDK) \ -e PDK_ROOT=$(PDK_ROOT) \ -e OPENRAM_HOME=/openram/compiler \ diff --git a/docker/Makefile b/docker/Makefile index 067cf49c..5ef0d273 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -1,3 +1,6 @@ +DOCKER_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))) +TOP_DIR := $(realpath $(DOCKER_DIR)/..) +include $(TOP_DIR)/openram.mk TAG_DATE := $(shell date +%F) all: build push @@ -15,3 +18,13 @@ push: .PHONY: pull pull: docker pull vlsida/openram-ubuntu:latest + +mount: + docker run -it -v $(TOP_DIR):/openram \ + -v $(SKY130_PDK):$(SKY130_PDK) \ + -e PDK_ROOT=$(PDK_ROOT) \ + -e OPENRAM_HOME=/openram/compiler \ + -e OPENRAM_TECH=/openram/technology \ + --user $(UID):$(GID) \ + vlsida/openram-ubuntu:latest +.PHONY: mount From 6f33e8102fd2507a0ef9d10dbd33a42989a87b0d Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 3 Nov 2021 10:08:21 -0700 Subject: [PATCH 012/229] Revert to version of netgen without proxy pin bug --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 9bcf031f..d117456d 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -57,7 +57,7 @@ RUN ./autogen.sh \ RUN rm -rf /root/ngspice ### Netgen ### -ARG NETGEN_COMMIT=e4a15f12fbdd3480b6adc0eeba09df269ed7b387 +ARG NETGEN_COMMIT=88d53fab15eb611cffc024eebf8743fae5cf8cb7 WORKDIR /root RUN git clone git://opencircuitdesign.com/netgen-1.5 netgen WORKDIR /root/netgen From c102ed728c7f1d539e9bed0f1e3b82ed1ddcbba2 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 3 Nov 2021 11:36:19 -0700 Subject: [PATCH 013/229] Move tests to test Makefile --- Makefile | 47 ----------------------- compiler/Makefile | 13 +++---- compiler/tests/testutils.py | 22 +++++------ technology/freepdk45/tech/freepdk45.lylvs | 14 ++----- technology/freepdk45/tech/tech.py | 13 ++++--- 5 files changed, 29 insertions(+), 80 deletions(-) diff --git a/Makefile b/Makefile index 5c175302..b85f5336 100644 --- a/Makefile +++ b/Makefile @@ -145,51 +145,6 @@ macros: .PHONY: macros -TEST_DIR = $(TOP_DIR)/compiler/tests -TEST_SRCS=$(sort $(notdir $(wildcard $(TEST_DIR)/*_test.py))) -TEST_DIRS=$(basename $(TEST_SRCS)) -TEST_STAMPS=$(addsuffix .ok,$(TEST_DIRS)) - -TEST_BROKEN := \ - sky130_sram_1kbyte_1r1w_8x1024_8 \ - sky130_sram_1kbyte_1rw_32x256_8 \ - sky130_sram_2kbyte_1rw_32x512_8 \ - sky130_sram_4kbyte_1rw_32x1024_8 \ - -WORKING_TEST_STAMPS=$(filter-out $(addsuffix .ok, (TEST_BROKEN)), $(TEST_STAMPS)) - -$(TEST_DIRS): - @$(MAKE) --no-print-directory $@.ok - -tests: - @echo "Running the following tests" - @for S in $(WORKING_TEST_STAMPS); do echo " - $$S"; done - $(MAKE) $(WORKING_TEST_STAMPS) -.PHONY: tests - -%.ok: compiler/tests/%.py - @mkdir -p $* - @docker run -v $(TOP_DIR):/openram \ - -v $(SKY130_PDK):$(SKY130_PDK) \ - -e PDK_ROOT=$(PDK_ROOT) \ - -e OPENRAM_HOME=/openram/compiler \ - -e OPENRAM_TECH=/openram/technology \ - -e OPENRAM_TMP=/openram/$* \ - --user $(UID):$(GID) \ - vlsida/openram-ubuntu:latest \ - python3 -u /openram/compiler/tests/$*.py -v -k && touch $@ - -.DELETE_ON_ERROR: $(TEST_STAMPS) - -regress: - @docker run -v $(TOP_DIR):/openram \ - -e OPENRAM_HOME=/openram/compiler \ - -e OPENRAM_TECH=/openram/technology \ - --user $(UID):$(GID) \ - vlsida/openram-ubuntu:latest \ - sh -c "python3 -u /openram/compiler/tests/regress.py" -.PHONY: regress - mount: @docker run -it -v $(TOP_DIR):/openram \ -v $(SKY130_PDK):$(SKY130_PDK) \ @@ -201,8 +156,6 @@ mount: .PHONY: mount clean: - @rm -rf $(TEST_STAMPS) - @rm -rf $(TEST_DIRS) @rm -f *.zip .PHONE: clean diff --git a/compiler/Makefile b/compiler/Makefile index 171c1a10..117e4bd2 100644 --- a/compiler/Makefile +++ b/compiler/Makefile @@ -35,7 +35,7 @@ ${CELL_TESTS} \ ${MODULE_TESTS} \ ${TOP_TESTS} \ ${CHAR_TESTS} \ -${USAGE_TESTS} +${USAGE_TESTS} .PHONY: ${ALL_TESTS} @@ -64,8 +64,8 @@ usage: ${USAGE_TESTS} $(ALL_TESTS): python3 $@ -t ${TECH} - - + + OPENRAM_TECHS = $(subst :, ,$(OPENRAM_TECH)) TECH_DIR := $(word 1, $(foreach dir,$(OPENRAM_TECHS),$(wildcard $(dir)/$(TECH)))) CONFIG_DIR = $(OPENRAM_HOME)/model_configs @@ -75,9 +75,9 @@ CSV_DIR = $(TECH_DIR)/sim_data # Creates names of technology specific okay files for the configs STAMPS=$(addprefix $(SIM_DIR)/, $(addsuffix .ok, $(notdir $(basename $(MODEL_CONFIGS))))) -OPTS = +OPTS = # Characterize and perform DRC/LVS -OPTS += -c +OPTS += -c # Do not characterize or perform DRC/LVS OPTS += -n # Verbosity @@ -100,8 +100,7 @@ model: $(STAMPS) clean_model: rm -f -r $(SIM_DIR)/*.ok - + clean: find . -name \*.pyc -exec rm {} \; find . -name \*~ -exec rm {} \; - diff --git a/compiler/tests/testutils.py b/compiler/tests/testutils.py index 928536a7..67c08d2e 100644 --- a/compiler/tests/testutils.py +++ b/compiler/tests/testutils.py @@ -24,24 +24,24 @@ class openram_test(unittest.TestCase): def tearDown(self): duration = time.time() - self.start_time print('%s: %.3fs' % (self.id(), duration)) - + def fail(self, msg): import inspect s = inspect.stack() base_filename = os.path.splitext(os.path.basename(s[2].filename))[0] - + try: OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME")) except: debug.error("$OPENRAM_HOME is not properly defined.", 1) - - import shutil - zip_file = "{0}/../{1}_{2}".format(OPENRAM_HOME, base_filename, os.getpid()) - debug.info(0, "Archiving failed temp files {0} to {1}".format(OPTS.openram_temp, zip_file)) - shutil.make_archive(zip_file, 'zip', OPTS.openram_temp) - + + # import shutil + # zip_file = "{0}/../{1}_{2}".format(OPENRAM_HOME, base_filename, os.getpid()) + # debug.info(0, "Archiving failed temp files {0} to {1}".format(OPTS.openram_temp, zip_file)) + # shutil.make_archive(zip_file, 'zip', OPTS.openram_temp) + super().fail(msg) - + def local_drc_check(self, w): self.reset() @@ -55,7 +55,7 @@ class openram_test(unittest.TestCase): self.fail("DRC failed: {}".format(w.name)) elif not OPTS.keep_temp: self.cleanup() - + def local_check(self, a, final_verification=False): self.reset() @@ -128,7 +128,7 @@ class openram_test(unittest.TestCase): def cleanup(self): """ Reset the duplicate checker and cleanup files. """ - + files = glob.glob(OPTS.openram_temp + '*') for f in files: # Only remove the files diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index 5d8e50b3..640454d6 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -209,16 +209,10 @@ connect_global(pwell, "PWELL") connect_global(nwell, "NWELL") connect_global(bulk, "BULK") -#for pat in %w(pnand*_0 and2_dec_0 port_address* replica_bitcell_array) -# connect_explicit(pat, [ "NWELL", "vdd" ]) -# connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) -#end - -#for pat in %w(XOR* XNOR* TLAT* TINV* TBUF* SDFF* OR* OAI* NOR* NAND* MUX* LOGIC* INV* HA* FILLCELL* -# FA* DLL* DLH* DFF* DFFS* DFFR* DFFRS* CLKGATE* CLKBUF* BUF* AOI* ANTENNA* AND*) -# connect_explicit(pat, [ "NWELL", "VDD" ]) -# connect_explicit(pat, [ "BULK", "VSS" ]) -#end +for pat in %w(pnand* and2_dec* port_address* replica_bitcell_array) + connect_explicit(pat, [ "NWELL", "vdd" ]) + connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) +end # Actually performs the extraction netlist # ... not really required diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index fd477077..3988a411 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -457,10 +457,10 @@ parameter["sa_inv_nmos_size"] = 0.27 # micro-meters parameter["bitcell_drain_cap"] = 0.1 # In Femto-Farad, approximation of drain capacitance # Spice Values uses to calculate analytical delay based on CACTI equations -spice["i_on_n"] = 0.0004463 # A/um +spice["i_on_n"] = 0.0004463 # A/um spice["i_on_p"] = 0.0000771 # A/um spice["tox"] = 0.00114 # microns -spice["eps_ox"] = 0.00245e-14 # F/um, calculated from CACTI 45nm data +spice["eps_ox"] = 0.00245e-14 # F/um, calculated from CACTI 45nm data spice["cox"] = spice["eps_ox"]/spice["tox"] # F/um^2 spice["c_g_ideal"] = spice["cox"]*drc["minlength_channel"] # F/um spice["c_overlap"] = 0.2*spice["c_g_ideal"] # F/um @@ -477,8 +477,11 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa # Technology Tool Preferences ################################################### -drc_name = "calibre" -lvs_name = "calibre" -pex_name = "calibre" +#drc_name = "calibre" +#lvs_name = "calibre" +#pex_name = "calibre" +drc_name = "klayout" +lvs_name = "klayout" +pex_name = "klayout" blackbox_bitcell = False From 968a233b82c35e0f158844fb036e3830881c3d43 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 8 Nov 2021 09:31:56 -0800 Subject: [PATCH 014/229] Don't install in share/pdk --- Makefile | 18 ++++++++++-------- technology/sky130/__init__.py | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index b85f5336..f13aadca 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ SRAM_LIB_GIT_COMMIT ?= main OPEN_PDKS_DIR ?= $(PDK_ROOT)/open_pdks OPEN_PDKS_GIT_REPO ?= https://github.com/RTimothyEdwards/open_pdks.git OPEN_PDKS_GIT_COMMIT ?= 1.0.156 -SKY130_PDK ?= $(PDK_ROOT)/share/pdk/sky130A +SKY130_PDK ?= $(PDK_ROOT)/sky130A # Create lists of all the files to copy/link GDS_FILES := $(sort $(wildcard $(SRAM_LIB_DIR)/cells/*/*.gds)) @@ -47,10 +47,12 @@ $(OPEN_PDKS_DIR): $(SKY130_PDK): $(OPEN_PDKS_DIR) @echo "Installing open_pdks..." cd $(OPEN_PDKS_DIR) &&\ - ./configure --prefix=$(PDK_ROOT) --enable-sky130-pdk \ - --disable-openlane --disable-irsim --disable-xschem --disable-qflow - @sleep 5 - make -C $(OPEN_PDKS_DIR) install + ./configure --enable-sky130-pdk=$(PDK_ROOT)/skywater-pdk/libraries \ + --disable-openlane --disable-irsim --disable-xschem --disable-qflow &&\ + cd sky130 && \ + make veryclean && \ + make && \ + make SHARED_PDKS_PATH=$(PDK_ROOT) install install: $(SRAM_LIB_DIR) $(SKY130_PDK) $(INSTALL_DIRS) @echo "Installing sky130 SRAM PDK..." @@ -171,7 +173,7 @@ uninstall: clean wipe: uninstall @echo "Wiping PDK repos in 5 sec... (ctrl-c to quit)" @sleep 5 - @rm -rf $(SKY130_PDK) - @rm -rf $(SRAM_LIB_DIR) - @rm -rf $(OPEN_PDKS_DIR) + rm -rf $(SKY130_PDK) + rm -rf $(SRAM_LIB_DIR) + rm -rf $(OPEN_PDKS_DIR) .PHONY: wipe diff --git a/technology/sky130/__init__.py b/technology/sky130/__init__.py index c17c62d8..3df3f555 100644 --- a/technology/sky130/__init__.py +++ b/technology/sky130/__init__.py @@ -21,7 +21,7 @@ os.environ["MGC_TMPDIR"] = "/tmp" # OpenPDK needed for magicrc, tech file and spice models of transistors if 'PDK_ROOT' in os.environ: - open_pdks = os.path.join(os.environ['PDK_ROOT'], 'share', 'pdk', 'sky130A', 'libs.tech') + open_pdks = os.path.join(os.environ['PDK_ROOT'], 'sky130A', 'libs.tech') else: raise SystemError("Unable to find open_pdks tech file. Set PDK_ROOT.") From 3902cee003d44d2bdeb4950378993a9e9eebc0e4 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 16 Nov 2021 11:17:00 -0800 Subject: [PATCH 015/229] Update READMEs --- README.md | 61 ++++++++++++++++++++++-------------------------- docker/README.md | 47 +++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 33 deletions(-) create mode 100644 docker/README.md diff --git a/README.md b/README.md index 820c52a0..7dafe0d1 100644 --- a/README.md +++ b/README.md @@ -26,21 +26,25 @@ things that need to be fixed. # Basic Setup +## Docker + +We have a [docker setup](./docker) to run OpenRAM. + ## Dependencies The OpenRAM compiler has very few dependencies: -+ [Ngspice] 26 (or later) or HSpice I-2013.12-1 (or later) or CustomSim 2017 (or later) or [Xyce] 7.2 (or later) -+ Python 3.5 or higher ++ [Ngspice] 34 (or later) or HSpice I-2013.12-1 (or later) or CustomSim 2017 (or later) or [Xyce] 7.4 (or later) ++ Python 3.6 or higher + Various Python packages (pip install -r requirements.txt) + [Git] If you want to perform DRC and LVS, you will need either: + Calibre (for [FreePDK45]) -+ [Magic] 8.3.130 or newer -+ [Netgen] 1.5.164 or newer ++ [Magic] 8.3.197 or newer ++ [Netgen] 1.5.195 or newer -You must set two environment variables: -+ OPENRAM\_HOME should point to the compiler source directory. +You must set two environment variables: ++ OPENRAM\_HOME should point to the compiler source directory. + OPENERAM\_TECH should point to one or more root technology directories (colon separated). ## Environment @@ -58,24 +62,15 @@ You may also wish to add OPENRAM\_HOME to your PYTHONPATH: export PYTHONPATH="$PYTHONPATH:$OPENRAM_HOME" ``` -We include the tech files necessary for [SCMOS] SCN4M_SUBM. The -[SCMOS] spice models, however, are generic and should be replaced with -foundry models. If you are using [FreePDK45], you should also have -that set up and have the environment variable point to the PDK. For -example add this to your .bashrc: - -``` - export FREEPDK45="/bsoe/software/design-kits/FreePDK45" -``` - -You may get the entire [FreePDK45 PDK here][FreePDK45]. -If you are using [SCMOS], you should install [Magic] and [Netgen]. -We have included the most recent SCN4M_SUBM design rules from [Qflow]. +We include the tech files necessary for [SCMOS] SCN4M_SUBM, +[FreePDK45], and [Sky130]. The [SCMOS] spice models, however, are +generic and should be replaced with foundry models. You may get the +entire [FreePDK45 PDK here][FreePDK45]. # Basic Usage -Once you have defined the environment, you can run OpenRAM from the command line -using a single configuration file written in Python. +Once you have defined the environment, you can run OpenRAM from the command line +using a single configuration file written in Python. For example, create a file called *myconfig.py* specifying the following parameters for your memory: @@ -119,7 +114,7 @@ $OPENRAM\_HOME/options.py # Unit Tests Regression testing performs a number of tests for all modules in OpenRAM. -From the unit test directory ($OPENRAM\_HOME/tests), +From the unit test directory ($OPENRAM\_HOME/tests), use the following command to run all regression tests: ``` @@ -127,16 +122,16 @@ use the following command to run all regression tests: ``` To run a specific test: ``` - python3 {unit test}.py + python3 {unit test}.py ``` -The unit tests take the same arguments as openram.py itself. +The unit tests take the same arguments as openram.py itself. To increase the verbosity of the test, add one (or more) -v options: ``` python3 tests/00_code_format_check_test.py -v -t freepdk45 ``` To specify a particular technology use "-t " such as -"-t freepdk45". The default for a unit test is scn4m_subm. +"-t freepdk45". The default for a unit test is scn4m_subm. The default for openram.py is specified in the configuration file. @@ -144,7 +139,7 @@ The default for openram.py is specified in the configuration file. If you want to support a new technology, you will need to create: + a setup script for each technology you want to use -+ a technology directory for each technology with the base cells ++ a technology directory for each technology with the base cells We provide two technology examples for [SCMOS] and [FreePDK45]. Each specific technology (e.g., [FreePDK45]) should be a subdirectory @@ -154,10 +149,10 @@ specific technology (e.g., [FreePDK45]) should be a subdirectory * sense_amp.gds * write_driver.gds * cell_1rw.gds - * replica\_cell\_1rw.gds - * dummy\_cell\_1rw.gds + * replica\_cell\_1rw.gds + * dummy\_cell\_1rw.gds * sp_lib folder with all the .sp (premade) library netlists for the above cells. -* layers.map +* layers.map * A valid tech Python module (tech directory with \_\_init\_\_.py and tech.py) with: * References in tech.py to spice models * DRC/LVS rules needed for dynamic cells and routing @@ -169,7 +164,7 @@ specific technology (e.g., [FreePDK45]) should be a subdirectory + Report bugs by submitting [Github issues]. + Develop new features (see [how to contribute](./CONTRIBUTING.md)) -+ Submit code/fixes using a [Github pull request] ++ Submit code/fixes using a [Github pull request] + Follow our [project][Github project]. + Read and cite our [ICCAD paper][OpenRAMpaper] @@ -181,7 +176,7 @@ specific technology (e.g., [FreePDK45]) should be a subdirectory + [OpenRAM Users Group][user-group] ([subscribe here][user-group-subscribe]) + [OpenRAM Developers Group][dev-group] ([subscribe here][dev-group-subscribe]) -# License +# License OpenRAM is licensed under the [BSD 3-clause License](./LICENSE). @@ -203,7 +198,7 @@ If I forgot to add you, please let me know! [Github issues]: https://github.com/VLSIDA/OpenRAM/issues [Github pull request]: https://github.com/VLSIDA/OpenRAM/pulls -[Github project]: https://github.com/VLSIDA/OpenRAM +[Github project]: https://github.com/VLSIDA/OpenRAM [documentation]: https://docs.google.com/presentation/d/10InGB33N51I6oBHnqpU7_w9DXlx-qe9zdrlco2Yc5co/edit?usp=sharing [dev-group]: mailto:openram-dev-group@ucsc.edu @@ -218,8 +213,8 @@ If I forgot to add you, please let me know! [Xyce]: http://xyce.sandia.gov/ [Git]: https://git-scm.com/ -[OSUPDK]: https://vlsiarch.ecen.okstate.edu/flow/ [FreePDK45]: https://www.eda.ncsu.edu/wiki/FreePDK45:Contents [SCMOS]: https://www.mosis.com/files/scmos/scmos.pdf +[Sky130]: https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git [Slack]: https://join.slack.com/t/openram/shared_invite/enQtNDgxMjc3NzU5NTI1LWZiYWMwNjNkZThmYTdkODc3NDE1NDhjNzUxNDhmMDQ4ZTM3NDgwNWFlNjM5NWFiZDkyMzBlNzc1NTg3ZjllNTY diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 00000000..34b25ff9 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,47 @@ +# Docker images for OpenRAM # + +## Installing Docker ## + +There are a number of ways to install Docker. Pick your favorite. + +* On Mac from docker.com with .app: + https://docs.docker.com/docker-for-mac/install/ + +* On Windows from docker.com: + https://docs.docker.com/docker-for-windows/install/ + +* On Ubuntu: + https://docs.docker.com/install/linux/docker-ce/ubuntu/ + +NOTE: If you plan to use a VPN, do *NOT* use the Docker Toolbox for +Mac or the docker from [Macports](https://www.macports.org/ +"Macports") as these require a network socket that breaks when you +install some VPN software. To understand the difference, check out [this +page](https://docs.docker.com/docker-for-mac/docker-toolbox/). + +## Running Docker ## + +### Terminal only ### + +* To run as a generic user: +``` +make mount +``` + +## Updating the image ## + +If there are updates to the image, you can pull a new one from the hub with: +``` +make pull +``` +This is not automatically done, so if you have a problem, make sure you are up-to-date. + +## Building your own image ## + +You can run the build script to build a local image: + +``` +make build +``` + +If you want to change things, modify the openram-ubuntu/Dockerfile and let me know what should be fixed. From edf3a701e414d7fd706c5eddd10891588869550b Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 16 Nov 2021 14:33:35 -0800 Subject: [PATCH 016/229] Update options for arguments and readme. --- PORTING.md | 24 +++++++++++++ README.md | 51 +++++++++++---------------- compiler/tests/Makefile | 76 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 31 deletions(-) create mode 100644 PORTING.md create mode 100644 compiler/tests/Makefile diff --git a/PORTING.md b/PORTING.md new file mode 100644 index 00000000..e98871e9 --- /dev/null +++ b/PORTING.md @@ -0,0 +1,24 @@ +# Porting to a New Technology + +If you want to support a new technology, you will need to create: ++ a setup script for each technology you want to use ++ a technology directory for each technology with the base cells + +We provide two technology examples for [SCMOS] and [FreePDK45]. Each +specific technology (e.g., [FreePDK45]) should be a subdirectory +(e.g., $OPENRAM_TECH/freepdk45) and include certain folders and files: +* gds_lib folder with all the .gds (premade) library cells: + * dff.gds + * sense_amp.gds + * write_driver.gds + * cell_1rw.gds + * replica\_cell\_1rw.gds + * dummy\_cell\_1rw.gds +* sp_lib folder with all the .sp (premade) library netlists for the above cells. +* layers.map +* A valid tech Python module (tech directory with \_\_init\_\_.py and tech.py) with: + * References in tech.py to spice models + * DRC/LVS rules needed for dynamic cells and routing + * Layer information + * Spice and supply information + * etc. diff --git a/README.md b/README.md index 7dafe0d1..28c62a58 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,11 @@ We include the tech files necessary for [SCMOS] SCN4M_SUBM, generic and should be replaced with foundry models. You may get the entire [FreePDK45 PDK here][FreePDK45]. +To install [Sky130], simply run: +``` +make install +``` + # Basic Usage Once you have defined the environment, you can run OpenRAM from the command line @@ -111,6 +116,12 @@ python3 $OPENRAM_HOME/openram.py myconfig You can see all of the options for the configuration file in $OPENRAM\_HOME/options.py +To run designs in Docker, it is suggested to use, for example: +``` +cd openram/macros +make example_config_scn4m_subm +``` + # Unit Tests Regression testing performs a number of tests for all modules in OpenRAM. @@ -118,50 +129,28 @@ From the unit test directory ($OPENRAM\_HOME/tests), use the following command to run all regression tests: ``` - python3 regress.py +cd openram/compiler/tests +make regress ``` + To run a specific test: ``` - python3 {unit test}.py +ce openram/compiler/tests +make 05_bitcell_array_test ``` -The unit tests take the same arguments as openram.py itself. -To increase the verbosity of the test, add one (or more) -v options: +To increase the verbosity of the test, add one (or more) -v options and +pass it as an argument to OpenRAM: ``` - python3 tests/00_code_format_check_test.py -v -t freepdk45 +make 05_bitcell_array_test ARGS="-v -t scn4m_subm" ``` To specify a particular technology use "-t " such as "-t freepdk45". The default for a unit test is scn4m_subm. The default for openram.py is specified in the configuration file. - -# Porting to a New Technology - -If you want to support a new technology, you will need to create: -+ a setup script for each technology you want to use -+ a technology directory for each technology with the base cells - -We provide two technology examples for [SCMOS] and [FreePDK45]. Each -specific technology (e.g., [FreePDK45]) should be a subdirectory -(e.g., $OPENRAM_TECH/freepdk45) and include certain folders and files: -* gds_lib folder with all the .gds (premade) library cells: - * dff.gds - * sense_amp.gds - * write_driver.gds - * cell_1rw.gds - * replica\_cell\_1rw.gds - * dummy\_cell\_1rw.gds -* sp_lib folder with all the .sp (premade) library netlists for the above cells. -* layers.map -* A valid tech Python module (tech directory with \_\_init\_\_.py and tech.py) with: - * References in tech.py to spice models - * DRC/LVS rules needed for dynamic cells and routing - * Layer information - * Spice and supply information - * etc. - # Get Involved ++ [Port it](./PORTING.md) to a new technology. + Report bugs by submitting [Github issues]. + Develop new features (see [how to contribute](./CONTRIBUTING.md)) + Submit code/fixes using a [Github pull request] diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile new file mode 100644 index 00000000..460b7fcc --- /dev/null +++ b/compiler/tests/Makefile @@ -0,0 +1,76 @@ +TOP_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))../..) +include $(TOP_DIR)/openram.mk + +.DEFAULT_GOAL := regress + +ARGS ?= "" + +TEST_DIR = $(TOP_DIR)/compiler/tests +TEST_SRCS=$(sort $(notdir $(wildcard $(TEST_DIR)/*_test.py))) +TEST_DIRS=$(basename $(TEST_SRCS)) +TEST_STAMPS=$(addsuffix .ok,$(TEST_DIRS)) + +TEST_BROKEN := \ + 50_riscv_1k_1rw1r_func_test.py \ + 50_riscv_1k_1rw_func_test.py \ + 50_riscv_1rw1r_func_test.py \ + 50_riscv_1rw1r_phys_test.py \ + 50_riscv_1rw_func_test.py \ + 50_riscv_1rw_phys_test.py \ + 50_riscv_2k_1rw1r_func_test.py \ + 50_riscv_2k_1rw_func_test.py \ + 50_riscv_4k_1rw1r_func_test.py \ + 50_riscv_4k_1rw_func_test.py \ + 50_riscv_512b_1rw1r_func_test.py \ + 50_riscv_512b_1rw_func_test.py \ + 50_riscv_8k_1rw1r_func_test.py \ + 50_riscv_8k_1rw_func_test.py + + +WORKING_TEST_STAMPS=$(filter-out $(addsuffix .ok, (TEST_BROKEN)), $(TEST_STAMPS)) + +$(TEST_DIRS): + @$(MAKE) --no-print-directory $@.ok + +tests: + @echo "Running the following tests" + @for S in $(WORKING_TEST_STAMPS); do echo " - $$S"; done + @sleep 5 + @$(MAKE) $(WORKING_TEST_STAMPS) +.PHONY: + +%.ok: %.py + @echo "Running $*" + @mkdir -p $(TOP_DIR)/compiler/tests/results/$* + @docker run -v $(TOP_DIR):/openram \ + -v $(SKY130_PDK):$(SKY130_PDK) \ + -e PDK_ROOT=$(PDK_ROOT) \ + -e OPENRAM_HOME=/openram/compiler \ + -e OPENRAM_TECH=/openram/technology \ + -e OPENRAM_TMP=/openram/compiler/tests/results/$* \ + --user $(UID):$(GID) \ + vlsida/openram-ubuntu:latest \ + python3 -u /openram/compiler/tests/$*.py $(ARGS) && touch $@ + +.DELETE_ON_ERROR: $(TEST_STAMPS) + +TECHS := scn4m_subm freepdk45 +#sky130 + +$(TECHS): + @docker run -v $(TOP_DIR):/openram \ + -e OPENRAM_HOME=/openram/compiler \ + -e OPENRAM_TECH=/openram/technology \ + --user $(UID):$(GID) \ + -e OPENRAM_TMP=/openram/compiler/tests/tmp_$@/$* \ + vlsida/openram-ubuntu:latest \ + sh -c "python3 -u /openram/compiler/tests/regress.py $(ARGS) -t $@" +.PHONY: $(TECHS) + +regress: $(TECHS) +.PHONY: regress + +clean: + @rm -rf $(TEST_STAMPS) + @rm -rf $(TEST_DIRS) +.PHONE: clean From f764ac446c509679c63a205bfbbb1eacae59dffc Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 17 Nov 2021 13:19:23 -0800 Subject: [PATCH 017/229] Use Caravel-like sky130 install path with ngspice models. --- macros/Makefile | 2 +- technology/sky130/__init__.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/macros/Makefile b/macros/Makefile index 2014cb96..5da8d7ef 100644 --- a/macros/Makefile +++ b/macros/Makefile @@ -4,7 +4,7 @@ include $(TOP_DIR)/openram.mk .DEFAULT_GOAL := all -SKY130_PDK ?= $(PDK_ROOT)/share/pdk/sky130A +SKY130_PDK ?= $(PDK_ROOT)/sky130A OPENRAM_OPTS := $(OPENRAM_OPTS) # Define `OPENRAM_FULL` in your environment to run a full characterize diff --git a/technology/sky130/__init__.py b/technology/sky130/__init__.py index 3df3f555..409f0032 100644 --- a/technology/sky130/__init__.py +++ b/technology/sky130/__init__.py @@ -25,9 +25,9 @@ if 'PDK_ROOT' in os.environ: else: raise SystemError("Unable to find open_pdks tech file. Set PDK_ROOT.") -spice_model_dir = os.path.join(open_pdks, "SIMULATOR",) +# The ngspice models work with Xyce too now +spice_model_dir = os.path.join(open_pdks, "ngspice") sky130_lib_ngspice = os.path.join(open_pdks, "ngspice", "sky130.lib.spice") -# We may end up using Xyce but check if at least ngspice exists if not os.path.exists(sky130_lib_ngspice): raise SystemError("Did not find {} under {}".format(sky130_lib_ngspice, open_pdks)) os.environ["SPICE_MODEL_DIR"] = spice_model_dir From 2fb08af6846c59e989f295f0c7c55fbed82da029 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Wed, 17 Nov 2021 17:22:03 -0800 Subject: [PATCH 018/229] change col mux array poly routing from straight to 'L' --- compiler/modules/column_mux_array.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/modules/column_mux_array.py b/compiler/modules/column_mux_array.py index 544b37e1..34c75390 100644 --- a/compiler/modules/column_mux_array.py +++ b/compiler/modules/column_mux_array.py @@ -177,13 +177,16 @@ class column_mux_array(design.design): # height to connect the gate to the correct horizontal row # sel_height = self.get_pin("sel_{}".format(sel_index)).by() # use the y offset from the sel pin and the x offset from the gate + offset = vector(gate_offset.x, self.get_pin("sel_{}".format(sel_index)).cy()) + + bl_offset = offset + vector((self.mux_inst[col].get_pin("br_out").bc().x - self.mux_inst[col].get_pin("bl_out").bc().x)/2, 0) self.add_via_stack_center(from_layer="poly", to_layer=self.sel_layer, - offset=offset, + offset=bl_offset, directions=self.via_directions) - self.add_path("poly", [offset, gate_offset]) + self.add_path("poly", [offset, gate_offset, bl_offset]) def route_bitlines(self): """ Connect the output bit-lines to form the appropriate width mux """ From ce40f2ae2806bd2ca9f282779d1d27b049a224f5 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 19 Nov 2021 09:42:06 -0800 Subject: [PATCH 019/229] Allow non-unique matching for replica bitcell test. --- compiler/verify/magic.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 8c07df8b..8f9ece29 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -337,16 +337,25 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False, output_path= # Netlists match uniquely. test = re.compile("match uniquely.") - correct = list(filter(test.search, final_results)) + uniquely = list(filter(test.search, final_results)) + + # Netlists match uniquely. + test = re.compile("match correctly.") + correctly = list(filter(test.search, final_results)) + # Fail if they don't match. Something went wrong! - if len(correct) == 0: + if len(uniquely) == 0 and len(correctly) == 0: total_errors += 1 + if len(uniquely) == 0 and len(correctly) > 0: + debug.warning("{0}\tLVS matches but not uniquely".format(cell_name)) + if total_errors>0: # Just print out the whole file, it is short. for e in results: debug.info(1,e.strip("\n")) - debug.error("{0}\tLVS mismatch (results in {1})".format(cell_name,resultsfile)) + debug.error("{0}\tLVS mismatch (results in {1})".format(cell_name, + resultsfile)) else: debug.info(1, "{0}\tLVS matches".format(cell_name)) From 7d7ffe76e0301fd288ed5273baf7092ad355ea84 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 22 Sep 2021 16:54:52 -0700 Subject: [PATCH 020/229] Debugging klayout for SCMOS and FreePDK45. --- compiler/verify/klayout.py | 35 +++- technology/freepdk45/tech/freepdk45.lylvs | 11 +- technology/freepdk45/tech/tech.py | 3 + technology/scn4m_subm/tech/scn4m_subm.lylvs | 214 ++++++++++++++++++++ technology/scn4m_subm/tech/tech.py | 3 + 5 files changed, 258 insertions(+), 8 deletions(-) create mode 100644 technology/scn4m_subm/tech/scn4m_subm.lylvs diff --git a/compiler/verify/klayout.py b/compiler/verify/klayout.py index b5e1fb82..ca19e79b 100644 --- a/compiler/verify/klayout.py +++ b/compiler/verify/klayout.py @@ -41,6 +41,16 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa else: debug.warning("Could not locate file: {}".format(full_drc_file)) + # Copy .gds file into the output directory + if os.path.isabs(gds_name): + shutil.copy(gds_name, output_path) + gds_name = os.path.basename(gds_name) + + # Copy .sp file into the output directory + if sp_name and os.path.isabs(sp_name): + shutil.copy(sp_name, output_path) + sp_name = os.path.basename(sp_name) + # Create an auxiliary script to run calibre with the runset run_file = output_path + "run_drc.sh" f = open(run_file, "w") @@ -111,14 +121,29 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, out else: debug.warning("Could not locate file: {}".format(full_lvs_file)) + # Copy .gds file into the output directory + if os.path.isabs(gds_name): + shutil.copy(gds_name, output_path) + gds_name = os.path.basename(gds_name) + + # Copy .sp file into the output directory + if os.path.isabs(sp_name): + shutil.copy(sp_name, output_path) + sp_name = os.path.basename(sp_name) + run_file = output_path + "/run_lvs.sh" f = open(run_file, "w") f.write("#!/bin/sh\n") - cmd = "{0} -b -r {1} -rd input={2} -rd report={4}.lvs.report -rd schematic={3} -rd target_netlist={4}.spice".format(OPTS.lvs_exe[1], - lvs_file, - gds_name, - sp_name, - cell_name) + if final_verification: + connect_supplies = "" + else: + connect_supplies = "-rd connect_supplies=1" + cmd = "{0} -b -r {1} -rd input={2} -rd report={4}.lvs.report -rd schematic={3} -rd target_netlist={4}.spice {5}".format(OPTS.lvs_exe[1], + lvs_file, + gds_name, + sp_name, + cell_name, + connect_supplies) f.write(cmd) f.write("\n") f.close() diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index 5d8e50b3..64fde014 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -205,9 +205,14 @@ connect(metal10, metal10_pin) # Global schematic.simplify -connect_global(pwell, "PWELL") -connect_global(nwell, "NWELL") -connect_global(bulk, "BULK") +if $connect_supplies + connect_implicit("vdd") + connect_implicit("gnd") +end + +#connect_global(pwell, "PWELL") +#connect_global(nwell, "NWELL") +#connect_global(bulk, "BULK") #for pat in %w(pnand*_0 and2_dec_0 port_address* replica_bitcell_array) # connect_explicit(pat, [ "NWELL", "vdd" ]) diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index fd477077..2ae9c06c 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -480,5 +480,8 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa drc_name = "calibre" lvs_name = "calibre" pex_name = "calibre" +drc_name = "klayout" +lvs_name = "klayout" +pex_name = "klayout" blackbox_bitcell = False diff --git a/technology/scn4m_subm/tech/scn4m_subm.lylvs b/technology/scn4m_subm/tech/scn4m_subm.lylvs new file mode 100644 index 00000000..16dd5c6e --- /dev/null +++ b/technology/scn4m_subm/tech/scn4m_subm.lylvs @@ -0,0 +1,214 @@ + + + + + lvs + + + + false + false + + true + lvs_scripts + tools_menu.lvs.end + dsl + lvs-dsl-xml + # +# Extraction for freePDK45 +# +############################ +tstart = Time.now + +# 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 lvs_freepdk45.lvs +if $input + source($input) +end + +if $report + report_lvs($report) +else + report_lvs("lvs_report.lvsdb") +end + +if $schematic +#reference netlist + schematic($schematic) +else + schematic(RBA::CellView::active.filename.sub(/\.(oas|gds|oas.gz|gds.gz)$/, ".sp")) +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 + +if $target_netlist + target_netlist($target_netlist) +else + # target_netlist("netlist.cir", write_spice(spice_with_net_names, spice_with_comments), "The netlist comment goes here.") + target_netlist(File.join(File.dirname(RBA::CellView::active.filename), source.cell_name+"_extracted.cir"), 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 +######################## +info("Layers definitions") + + DNW = input(38,0) + nwell = input(42,0) + pwell = input(41,0) + CW = input(59,0) + active = input(43,0) + TA = input(60,0) + PBase = input(58,0) + poly = input(46,0) + SB = input(29,0) + nplus = input(45,0) + pplus = input(44,0) + PO2 = input(56,0) + HR = input(34,0) + Contact = input(25,0) + ContactPoly = input(47,0) + ContactActive = input(48,0) + ContactPoly2 = input(55, 0) + CT = Contact + ContactPoly + ContactActive + ContactPoly2 + M1 = input(49,0) + V1 = input(50,0) + M2 = input(51,0) + V2 = input(61,0) + M3 = input(62,0) + V3 = input(30,0) + M4 = input(31,0) + CTM = input(35,0) + V4 = input(32,0) + M5 = input(33,0) + V5 = input(36,0) + M6 = input(37,0) + Glass = input(52,0) + Pads = input(26,0) + +# layers processing +######################## +info("Layers processing") + +# Bulk layer for terminal provisioning +bulk = polygon_layer + +active_in_nwell = active & nwell +pactive = active_in_nwell & pplus +ntie = active_in_nwell & nplus +pgate = pactive & poly +psd = pactive - pgate + +active_in_pwell = active & pwell +nactive = active_in_pwell & nplus +ptie = active_in_pwell & pplus +ngate = nactive & poly +nsd = nactive - ngate + + +cheat("cell_6t", "dummy_cell_6t", "cell_1rw", "dummy_cell_1rw", "cell_2rw", "dummy_cell_2rw", "dff","wordline_driver_0") { + +# PMOS transistor device extraction +extract_devices(mos4("p"), { "SD" => psd, "G" => pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell }) + +# NMOS transistor device extraction +extract_devices(mos4("n"), { "SD" => nsd, "G" => ngate, "tS" => nsd, "tD" => nsd, "tG" => poly, "W" => pwell }) + +} + +# Define connectivity for netlist extraction + +# Inter-layer +connect(nwell, ntie) +connect(pwell, ptie) +connect(CT, ntie) +connect(CT, ptie) +connect(psd, CT) +connect(nsd, CT) +connect(poly, CT) +connect(CT, M1) +connect(CT, M1) +connect(M1, V1) +connect(V1, M2) +connect(M2, V2) +connect(V2, M3) +connect(M3, V3) +connect(V3, M4) +connect(M4, V4) +connect(V4, M5) +connect(M5, V5) +connect(V5, M6) + + +# Global +schematic.simplify + +if $connect_supplies + connect_implicit("vdd") + connect_implicit("gnd") +end + +connect_global(pwell, "PWELL") +connect_global(nwell, "NWELL") +#connect_global(bulk, "BULK") + +#for pat in %w(pnand*_0 and2_dec_0 port_address* replica_bitcell_array) +# connect_explicit(pat, [ "NWELL", "vdd" ]) +# connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) +#end + +#for pat in %w(XOR* XNOR* TLAT* TINV* TBUF* SDFF* OR* OAI* NOR* NAND* MUX* LOGIC* INV* HA* FILLCELL* +# FA* DLL* DLH* DFF* DFFS* DFFR* DFFRS* CLKGATE* CLKBUF* BUF* AOI* ANTENNA* AND*) +# connect_explicit(pat, [ "NWELL", "VDD" ]) +# connect_explicit(pat, [ "BULK", "VSS" ]) +#end + +# 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 + +# Tolerances for the devices extracted parameters +# tolerance(device_class_name, parameter_name [, :absolute => absolute_tolerance] [, :relative => relative_tolerance]) +tolerance("P", "W", :absolute => 1.nm, :relative => 0.001) +tolerance("N", "W", :absolute => 1.nm, :relative => 0.001) + +#max_res(1000000) +#min_caps(1e-15) + +max_branch_complexity(65536) +max_depth(16) + +if ! compare + #raise "ERROR : Netlists don't match" + puts "ERROR : Netlists don't match" +else + puts "CONGRATULATIONS! Netlists match." +end + +# time spent for the LVS +time = Time.now +hours = ((time - tstart)/3600).to_i +minutes = ((time - tstart)/60 - hours * 60).to_i +seconds = ((time - tstart) - (minutes * 60 + hours * 3600)).to_i +$stdout.write "LVS finished at : #{time.hour}:#{time.min}:#{time.sec} - LVS duration = #{hours} hrs. #{minutes} min. #{seconds} sec.\n" + diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index a8c44996..374ba4c8 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -428,5 +428,8 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa drc_name = "magic" lvs_name = "netgen" pex_name = "magic" +drc_name = "klayout" +lvs_name = "klayout" +pex_name = "klayout" blackbox_bitcell = False From 141b42dc0eb9a256c3e49012a8f0396a14003806 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 22 Sep 2021 17:06:37 -0700 Subject: [PATCH 021/229] Add DRC rules and display files --- technology/freepdk45/tech/scn4m_subm.lyp | 2518 +++++++++++++++++++ technology/freepdk45/tech/scn4m_subm.lyt | 205 ++ technology/scn4m_subm/tech/scn4m_subm.lydrc | 804 ++++++ 3 files changed, 3527 insertions(+) create mode 100644 technology/freepdk45/tech/scn4m_subm.lyp create mode 100644 technology/freepdk45/tech/scn4m_subm.lyt create mode 100644 technology/scn4m_subm/tech/scn4m_subm.lydrc diff --git a/technology/freepdk45/tech/scn4m_subm.lyp b/technology/freepdk45/tech/scn4m_subm.lyp new file mode 100644 index 00000000..2aa688d3 --- /dev/null +++ b/technology/freepdk45/tech/scn4m_subm.lyp @@ -0,0 +1,2518 @@ + + + + #ff80ff + #ff80ff + 0 + 0 + C56 + + true + true + false + 2 + false + false + 0 + DeepNwell.drawing - 38/0 + 38/0@1 + + + #ff8000 + #ff8000 + 0 + 0 + C56 + + true + true + false + 2 + false + false + 0 + Nwell.drawing - 42/0 + 42/0@1 + + + #ff8000 + #ff8000 + 0 + 0 + C61 + + true + true + false + 1 + false + false + 0 + Pwell.drawing - 41/0 + 41/0@1 + + + #ff8000 + #ff8000 + 0 + 0 + C68 + + true + true + false + 1 + false + false + 0 + CapWell.drawing - 59/0 + 59/0@1 + + + #00ff00 + #00ff00 + 0 + 0 + C58 + + true + true + false + 1 + false + false + 0 + Active.drawing - 43/0 + 43/0@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C58 + + true + true + false + 1 + false + false + 0 + ThickActive.drawing - 60/0 + 60/0@1 + + + #ffff00 + #ffff00 + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + pBase.drawing - 60/0 + 60/0@1 + + + #ff0000 + #ff0000 + 0 + 0 + I11 + + true + true + false + 1 + false + false + 0 + Poly.drawing - 46/0 + 46/0@1 + + + #ff0000 + #ff0000 + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Poly.text - 46/1 + 46/1@1 + + + #008050 + #008050 + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + SiBlock.drawing - 29/0 + 29/0@1 + + + #ff80a8 + #ff80a8 + 0 + 0 + C57 + + true + true + false + 1 + false + false + 0 + Nselect.drawing - 45/0 + 45/0@1 + + + #bf4026 + #bf4026 + 0 + 0 + C76 + + true + true + false + 1 + false + false + 0 + Pselect.drawing - 44/0 + 44/0@1 + + + #ff8000 + #ff8000 + 0 + 0 + C76 + + true + true + false + 1 + false + false + 0 + Poly2.drawing - 56/0 + 56/0@1 + + + #802626 + #802626 + 0 + 0 + C66 + + true + true + false + 1 + false + false + 0 + HiRes.drawing - 34/0 + 34/0@1 + + + #00cc66 + #00cc66 + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Contact.drawing - 25/0 + 25/0@1 + + + #00cc66 + #00cc66 + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + ContactPoly.drawing - 47/0 + 47/0@1 + + + #00cc66 + #00cc66 + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + ContactActive.drawing - 48/0 + 48/0@1 + + + #0000ff + #0000ff + 0 + 0 + C39 + + true + true + false + 1 + false + false + 0 + Metal1.drawing - 49/0 + 49/0@1 + + + #0000ff + #0000ff + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Metal1.text - 49/1 + 49/1@1 + + + #ffff00 + #ffff00 + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + Via.drawing - 50/0 + 50/0@1 + + + #00ffff + #00ffff + 0 + 0 + C40 + + true + true + false + 1 + false + false + 0 + Metal2.drawing - 51/0 + 51/0@1 + + + #00ffff + #00ffff + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Metal2.text - 51/1 + 51/1@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + Via2.drawing - 61/0 + 61/0@1 + + + #ffff00 + #ffff00 + 0 + 0 + I8 + + true + true + false + 1 + false + false + 0 + Metal3.drawing - 62/0 + 62/0@1 + + + #ffff00 + #ffff00 + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Metal3.text - 62/1 + 62/1@1 + + + #91ff00 + #91ff00 + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + Via3.drawing - 30/0 + 30/0@1 + + + #7a732d + #7a732d + 0 + 0 + C39 + + true + true + false + 1 + false + false + 0 + Metal4.drawing - 31/0 + 31/0@1 + + + #7a732d + #7a732d + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Metal4.text - 31/1 + 31/1@1 + + + #8000ff + #8000ff + 0 + 0 + I6 + + true + true + false + 1 + false + false + 0 + CapTopMetal.drawing - 35/0 + 35/0@1 + + + #008000 + #008000 + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + Via4.drawing - 32/0 + 32/0@1 + + + #7777ff + #7777ff + 0 + 0 + I11 + + true + true + false + 1 + false + false + 0 + Metal5.drawing - 33/0 + 33/0@1 + + + #7777ff + #7777ff + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Metal5.text - 33/1 + 33/1@1 + + + #004080 + #004080 + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + Via5.drawing - 36/0 + 36/0@1 + + + #ff9933 + #ff9933 + 0 + 0 + I7 + + true + true + false + 1 + false + false + 0 + Metal6.drawing - 37/0 + 37/0@1 + + + #ff9933 + #ff9933 + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Metal6.text - 37/1 + 37/1@1 + + + #808000 + #808000 + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + Via6.drawing - 127/0 + 127/0@1 + + + #ff7777 + #ff7777 + 0 + 0 + I11 + + true + true + false + 1 + false + false + 0 + Metal7.drawing - 126/0 + 126/0@1 + + + #ff7777 + #ff7777 + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Metal7.text - 126/1 + 126/1@1 + + + #804080 + #804080 + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + Via7.drawing - 129/0 + 129/0@1 + + + #3399ff + #3399ff + 0 + 0 + I7 + + true + true + false + 1 + false + false + 0 + Metal8.drawing - 53/0 + 53/0@1 + + + #3399ff + #3399ff + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Metal8.text - 53/1 + 53/1@1 + + + #008080 + #008080 + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + Via8.drawing - 26/0 + 26/0@1 + + + #77ff77 + #77ff77 + 0 + 0 + I11 + + true + true + false + 1 + false + false + 0 + Metal9.drawing - 54/0 + 54/0@1 + + + #77ff77 + #77ff77 + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Metal9.text - 54/1 + 54/1@1 + + + #33aaff + #33aaff + 0 + 0 + I1 + I2 + true + true + false + 3 + false + false + 0 + Glass.drawing - 52/0 + 52/0@1 + + + #ffffff + #ffffff + 0 + 0 + I15 + + true + true + false + 3 + false + false + 0 + Pads.drawing - 26/0 + 26/0@1 + + + #ffffff + #ffffff + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Text.drawing - 63/0 + 63/0@1 + + + #ffffff + #ffffff + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Text.drawing - 83/0 + 83/0@1 + + + + + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + + 1 + SCst4 + + + + ................ + ....*.*.....*.*. + .....*.......*.. + ....*.*.....*.*. + ................ + .*.*.....*.*.... + .*.......*...... + .*.*.....*.*.... + ................ + ....*.*.....*.*. + .....*.......*.. + ....*.*.....*.*. + ................ + .*.*.....*.*.... + .*.......*...... + .*.*.....*.*.... + + 2 + SCst3 + + + + ................ + ....*.*.....*.*. + .....*.......*.. + ....*.*.....*.*. + ................ + *.*.....*.*..... + .*.......*...... + *.*.....*.*..... + ................ + ....*.*.....*.*. + .....*.......*.. + ....*.*.....*.*. + ................ + *.*.....*.*..... + .*.......*...... + *.*.....*.*..... + + 3 + SCst2 + + + + *.*.*.*. + .*.*.*.* + *.*.*.*. + .*.*.*.* + *.*.*.*. + .*.*.*.* + *.*.*.*. + .*.*.*.* + + 4 + SCst1 + + + + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + + 5 + verLine + + + + ................ + **************** + ................ + ................ + ................ + ................ + **************** + ................ + ................ + ................ + ................ + **************** + ................ + ................ + ................ + ................ + + 6 + horLine + + + + ................ + ................ + ................ + ................ + ................ + ..........*..... + .........*...... + ........*....... + .......*........ + ......*......... + .....*.......... + ................ + ................ + ................ + ................ + ................ + + 7 + stipple35 + + + + ................ + ................ + ................ + ................ + ................ + .....*.......... + ......*......... + .......*........ + ........*....... + .........*...... + ..........*..... + ................ + ................ + ................ + ................ + ................ + + 8 + stipple34 + + + + ....*.......*... + ................ + ................ + ................ + *.......*....... + ................ + ................ + ................ + ....*.......*... + ................ + ................ + ................ + *.......*....... + ................ + ................ + ................ + + 9 + stipple33 + + + + *.......*....... + ................ + ................ + ................ + ....*.......*... + ................ + ................ + ................ + *.......*....... + ................ + ................ + ................ + ....*.......*... + ................ + ................ + ................ + + 10 + stipple32 + + + + ...............* + ..............*. + .............*.. + ............*... + ...........*.... + ..........*..... + .........*...... + ........*....... + .......*........ + ......*......... + .....*.......... + ....*........... + ...*............ + ..*............. + .*.............. + *............... + + 11 + stipple31 + + + + .....*.......*.. + ....*.......*... + ...*.......*.... + ..*.......*..... + .*.......*...... + *.......*....... + .......*.......* + ......*.......*. + .....*.......*.. + ....*.......*... + ...*.......*.... + ..*.......*..... + .*.......*...... + *.......*....... + .......*.......* + ......*.......*. + + 12 + stipple30 + + + + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + + 13 + stipple29 + + + + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + + 14 + stipple28 + + + + ..*....*..*....* + .**...*..**...*. + *....*..*....*.. + *...*..**...*..* + ...*..*....*..*. + ..*..**...*..**. + .*..*....*..*... + *..**...*..**... + ..*....*..*....* + .**...*..**...*. + *....*..*....*.. + *...*..**...*..* + ...*..*....*..*. + ..*..**...*..**. + .*..*....*..*... + *..**...*..**... + + 15 + stipple27 + + + + ...*..*....*..*. + ....***.....***. + .*..*....*..*... + ..***.....***... + ..*....*..*....* + ***.....***..... + *....*..*....*.. + *.....***.....** + ...*..*....*..*. + ....***.....***. + .*..*....*..*... + ..***.....***... + ..*....*..*....* + ***.....***..... + *....*..*....*.. + *.....***.....** + + 16 + stipple26 + + + + ..**...*..**...* + .**...*..**...*. + **...*..**...*.. + *...*..**...*..* + ...*..**...*..** + ..*..**...*..**. + .*..**...*..**.. + *..**...*..**... + ..**...*..**...* + .**...*..**...*. + **...*..**...*.. + *...*..**...*..* + ...*..**...*..** + ..*..**...*..**. + .*..**...*..**.. + *..**...*..**... + + 17 + stipple25 + + + + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + + 18 + stipple24 + + + + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + .*...*...*...*.. + .*...*...*...*.. + .*...*...*...*.. + .*...*...*...*.. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + .*...*...*...*.. + .*...*...*...*.. + .*...*...*...*.. + .*...*...*...*.. + + 19 + stipple23 + + + + ....****....**** + ....****....**** + ....****....**** + ....****....**** + ****....****.... + ****....****.... + ****....****.... + ****....****.... + ....****....**** + ....****....**** + ....****....**** + ....****....**** + ****....****.... + ****....****.... + ****....****.... + ****....****.... + + 20 + stipple22 + + + + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + + 21 + stipple21 + + + + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + + 22 + stipple20 + + + + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + + 23 + stipple19 + + + + ................ + .*.*.*.*.*.*.*.* + ................ + *.*.*.*.*.*.*.*. + ................ + .*.*.*.*.*.*.*.* + ................ + *.*.*.*.*.*.*.*. + ................ + .*.*.*.*.*.*.*.* + ................ + *.*.*.*.*.*.*.*. + ................ + .*.*.*.*.*.*.*.* + ................ + *.*.*.*.*.*.*.*. + + 24 + stipple18 + + + + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + + 25 + stipple17 + + + + ................ + **************** + ................ + **************** + ................ + **************** + ................ + **************** + ................ + **************** + ................ + **************** + ................ + **************** + ................ + **************** + + 26 + stipple16 + + + + *.......*....... + *.......*....... + .*.......*...... + .*.......*...... + ..*.......*..... + ..*.......*..... + ...*.......*.... + ...*.......*.... + ....*.......*... + ....*.......*... + .....*.......*.. + .....*.......*.. + ......*.......*. + ......*.......*. + .......*.......* + .......*.......* + + 27 + stipple15 + + + + .......*.......* + .......*.......* + ......*.......*. + ......*.......*. + .....*.......*.. + .....*.......*.. + ....*.......*... + ....*.......*... + ...*.......*.... + ...*.......*.... + ..*.......*..... + ..*.......*..... + .*.......*...... + .*.......*...... + *.......*....... + *.......*....... + + 28 + stipple14 + + + + *............... + .*.............. + ..*............. + ...*............ + ....*........... + .....*.......... + ......*......... + .......*........ + ........*....... + .........*...... + ..........*..... + ...........*.... + ............*... + .............*.. + ..............*. + ...............* + + 29 + stipple13 + + + + *..**..**..**..* + **..**..**..**.. + .**..**..**..**. + ..**..**..**..** + *..**..**..**..* + **..**..**..**.. + .**..**..**..**. + ..**..**..**..** + *..**..**..**..* + **..**..**..**.. + .**..**..**..**. + ..**..**..**..** + *..**..**..**..* + **..**..**..**.. + .**..**..**..**. + ..**..**..**..** + + 30 + stipple12 + + + + .**..**..**..**. + ...*...*...*...* + *...*...*...*... + .**..**..**..**. + .**..**..**..**. + *...*...*...*... + ...*...*...*...* + .**..**..**..**. + .**..**..**..**. + ...*...*...*...* + *...*...*...*... + .**..**..**..**. + .**..**..**..**. + *...*...*...*... + ...*...*...*...* + .**..**..**..**. + + 31 + stipple11 + + + + ..*.*.....*.*... + .*...*...*...*.. + *.....*.*.....*. + .......*.......* + *.....*.*.....*. + .*...*...*...*.. + ..*.*.....*.*... + ...*.......*.... + ..*.*.....*.*... + .*...*...*...*.. + *.....*.*.....*. + .......*.......* + *.....*.*.....*. + .*...*...*...*.. + ..*.*.....*.*... + ...*.......*.... + + 32 + stipple10 + + + + *...........*... + .*...........*.. + ..*...........*. + ...*...........* + ....*........... + .....*.......... + ......*......... + .......*........ + ........*....... + .........*...... + ..........*..... + ...........*.... + *...........*... + .*...........*.. + ..*...........*. + ...*...........* + + 33 + stipple9 + + + + ................ + .*.*.*.*.*.*.*.* + ................ + .*.*.*.*.*.*.*.* + ................ + .*.*.*.*.*.*.*.* + ................ + .*.*.*.*.*.*.*.* + ................ + .*.*.*.*.*.*.*.* + ................ + .*.*.*.*.*.*.*.* + ................ + .*.*.*.*.*.*.*.* + ................ + .*.*.*.*.*.*.*.* + + 34 + stipple8 + + + + *...*...*...*... + ................ + ................ + ................ + *...*...*...*... + ................ + ................ + ................ + *...*...*...*... + ................ + ................ + ................ + *...*...*...*... + ................ + ................ + ................ + + 35 + stipple7 + + + + .**..**..**..**. + *...*...*...*... + ...*...*...*...* + .**..**..**..**. + .**..**..**..**. + ...*...*...*...* + *...*...*...*... + .**..**..**..**. + .**..**..**..**. + *...*...*...*... + ...*...*...*...* + .**..**..**..**. + .**..**..**..**. + ...*...*...*...* + *...*...*...*... + .**..**..**..**. + + 36 + stipple6 + + + + ...*...*...*...* + ...*...*...*...* + *...*...*...*... + *...*...*...*... + ...*...*...*...* + ...*...*...*...* + *...*...*...*... + *...*...*...*... + ...*...*...*...* + ...*...*...*...* + *...*...*...*... + *...*...*...*... + ...*...*...*...* + ...*...*...*...* + *...*...*...*... + *...*...*...*... + + 37 + stipple5 + + + + ...**......**... + ..*..*....*..*.. + .*....*..*....*. + *......**......* + *......**......* + .*....*..*....*. + ..*..*....*..*.. + ...**......**... + ...**......**... + ..*..*....*..*.. + .*....*..*....*. + *......**......* + *......**......* + .*....*..*....*. + ..*..*....*..*.. + ...**......**... + + 38 + stipple4 + + + + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + + 39 + stipple3 + + + + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + + 40 + stipple2 + + + + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + + 41 + stipple1 + + + + * + + 42 + stipple0 + + + + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + + 43 + x + + + + ................ + ................ + .......********* + ........*.....*. + .........*...*.. + ..........*.*... + ...........*.... + ................ + ................ + ................ + *********....... + .*.....*........ + ..*...*......... + ...*.*.......... + ....*........... + ................ + + 44 + triangle + + + + .....*.......*.. + .....*.......*.. + .....*.......*.. + ...*****...***** + .....*.......*.. + .....*.......*.. + .....*.......*.. + ................ + ..*.......*..... + ..*.......*..... + ..*.......*..... + *****...*****... + ..*.......*..... + ..*.......*..... + ..*.......*..... + ................ + + 45 + dagger + + + + ......*.......*. + ......*.......*. + ......*.......*. + **************** + ..*.......*..... + ..*.......*..... + ..*.......*..... + **************** + ......*.......*. + ......*.......*. + ......*.......*. + **************** + ..*.......*..... + ..*.......*..... + ..*.......*..... + **************** + + 46 + brick + + + + ..****....****.. + ..*.......*..... + ..*.......*..... + ..*.......*..... + ..****....****.. + .....*.......*.. + .....*.......*.. + .....*.......*.. + ..****....****.. + ..*.......*..... + ..*.......*..... + ..*.......*..... + ..****....****.. + .....*.......*.. + .....*.......*.. + .....*.......*.. + + 47 + vCurb + + + + ................ + ................ + ****...*****...* + ...*...*...*...* + ...*...*...*...* + ...*****...***** + ................ + ................ + ................ + ................ + ****...*****...* + ...*...*...*...* + ...*...*...*...* + ...*****...***** + ................ + ................ + + 48 + hCurb + + + + ....*.....*....* + ....*....*....*. + ...*....*.....*. + ..*.....*....*.. + ..*....*....*... + .*....*.....*... + *.....*....*.... + *....*....*..... + ....*.....*....* + ....*....*....*. + ...*....*.....*. + ..*.....*....*.. + ..*....*....*... + .*....*.....*... + *.....*....*.... + *....*....*..... + + 49 + vZigZag + + + + .......*.......* + .....**......**. + ....*.......*... + ..**......**.... + .*.......*...... + *......**......* + ......*.......*. + ....**......**.. + ...*.......*.... + .**......**..... + *.......*....... + ......**......** + .....*.......*.. + ...**......**... + ..*.......*..... + **......**...... + + 50 + hZigZag + + + + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + + 51 + grid + + + + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + + 52 + vLine + + + + **************** + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + ................ + ................ + ................ + + 53 + hLine + + + + ................ + ................ + ................ + ....*.*.*.*..... + ...*.*.*.*.*.... + ....*........... + ...*............ + ....*........... + ...*...*........ + ....*...*....... + ...*.*.*........ + ....*.*.*....... + ................ + ................ + ................ + ................ + + 54 + spiral + + + + ................ + ......*.*.*.*... + .....*.*.*.*.*.. + ......*......... + .....*.......... + ......*......... + .....*...*...... + ......*...*..... + .....*.*.*...... + ......*.*.*..... + ................ + ................ + ................ + ................ + ................ + ................ + + 55 + spiral22 + + + + *...*........... + .*...*.......*.. + ......*.......*. + ...*...*.......* + *...*........... + .*...*...*...... + ..*...*...*..... + ...*...*...*.... + ........*...*... + .....*...*...*.. + ......*.......*. + .......*...*...* + ........*...*... + .*.......*...*.. + ..*.......*...*. + ...*.......*...* + + 56 + slash3Fill + + + + ................ + .*........*..... + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ...*........*... + ................ + ................ + ................ + ................ + + 57 + dats5 + + + + *.....*.....*... + ................ + ................ + ...*.....*.....* + ................ + ................ + *.....*.....*... + ................ + ................ + ...*.....*.....* + ................ + ................ + *.....*.....*... + ................ + ................ + ...*.....*.....* + + 58 + dots4 + + + + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + + 59 + dots2 + + + + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + + 60 + stipple11 + + + + *.......*....... + ................ + ................ + ................ + ................ + ................ + ................ + ................ + *.......*....... + ................ + ................ + ................ + ................ + ................ + ................ + ................ + + 61 + stipple10 + + + + .*...*...*...*.. + .*...*...*...*.. + .*...*...*...*.. + .*...*...*...*.. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + .*...*...*...*.. + .*...*...*...*.. + .*...*...*...*.. + .*...*...*...*.. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + + 62 + stipple9 + + + + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + + 63 + stipple8 + + + + ..****....****.. + .*....*..*....*. + *......**......* + *......**......* + *......**......* + *......**......* + .*....*..*....*. + ..****....****.. + ..****....****.. + .*....*..*....*. + *......**......* + *......**......* + *......**......* + *......**......* + .*....*..*....*. + ..****....****.. + + 64 + stipple7 + + + + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + + 65 + stipple3 + + + + ****....****.... + ****....****.... + ****....****.... + ****....****.... + ....****....**** + ....****....**** + ....****....**** + ....****....**** + ****....****.... + ****....****.... + ****....****.... + ****....****.... + ....****....**** + ....****....**** + ....****....**** + ....****....**** + + 66 + stipple2 + + + + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + + 67 + x + + + + ................ + ....*........... + ...*.*.......... + ..*...*......... + .*.....*........ + *********....... + ................ + ................ + ................ + ...........*.... + ..........*.*... + .........*...*.. + ........*.....*. + .......********* + ................ + ................ + + 68 + triangle + + + + ................ + ..*.......*..... + ..*.......*..... + ..*.......*..... + *****...*****... + ..*.......*..... + ..*.......*..... + ..*.......*..... + ................ + .....*.......*.. + .....*.......*.. + .....*.......*.. + ...*****...***** + .....*.......*.. + .....*.......*.. + .....*.......*.. + + 69 + dagger + + + + **************** + ..*.......*..... + ..*.......*..... + ..*.......*..... + **************** + ......*.......*. + ......*.......*. + ......*.......*. + **************** + ..*.......*..... + ..*.......*..... + ..*.......*..... + **************** + ......*.......*. + ......*.......*. + ......*.......*. + + 70 + brick + + + + .....*.......*.. + .....*.......*.. + .....*.......*.. + ..****....****.. + ..*.......*..... + ..*.......*..... + ..*.......*..... + ..****....****.. + .....*.......*.. + .....*.......*.. + .....*.......*.. + ..****....****.. + ..*.......*..... + ..*.......*..... + ..*.......*..... + ..****....****.. + + 71 + vCurb + + + + ................ + ................ + ...*****...***** + ...*...*...*...* + ...*...*...*...* + ****...*****...* + ................ + ................ + ................ + ................ + ...*****...***** + ...*...*...*...* + ...*...*...*...* + ****...*****...* + ................ + ................ + + 72 + hCurb + + + + *....*....*..... + *.....*....*.... + .*....*.....*... + ..*....*....*... + ..*.....*....*.. + ...*....*.....*. + ....*....*....*. + ....*.....*....* + *....*....*..... + *.....*....*.... + .*....*.....*... + ..*....*....*... + ..*.....*....*.. + ...*....*.....*. + ....*....*....*. + ....*.....*....* + + 73 + vZigZag + + + + **......**...... + ..*.......*..... + ...**......**... + .....*.......*.. + ......**......** + *.......*....... + .**......**..... + ...*.......*.... + ....**......**.. + ......*.......*. + *......**......* + .*.......*...... + ..**......**.... + ....*.......*... + .....**......**. + .......*.......* + + 74 + hZigZag + + + + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + + 75 + grid + + + + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + + 76 + hLine + + + + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + + 77 + dots1 + + + + * + + 0 + + + + + * + + 0 + + + + + * + + 0 + + + + + * + + 0 + + + diff --git a/technology/freepdk45/tech/scn4m_subm.lyt b/technology/freepdk45/tech/scn4m_subm.lyt new file mode 100644 index 00000000..714dcc92 --- /dev/null +++ b/technology/freepdk45/tech/scn4m_subm.lyt @@ -0,0 +1,205 @@ + + + MOSIS_SCMOS + MOSIS SCMOS lambda based process + + 0.001 + $(appdata_path)/tech/MOSIS_SCMOS + MOSIS_SCMOS.lyp + true + + + 1 + true + true + + + true + layer_map() + true + true + + + true + layer_map() + 0.001 + true + #1 + true + #1 + false + #1 + true + OUTLINE + true + PLACEMENT_BLK + true + REGIONS + true + + 0 + true + .PIN + 2 + true + .PIN + 2 + true + .FILL + 5 + true + .OBS + 3 + true + .BLK + 4 + true + .LABEL + 1 + true + + 0 + true + + 0 + VIA_ + true + default + false + + + + false + true + true + 64 + 0 + 1 + 0 + DATA + 0 + 0 + BORDER + layer_map() + true + + + 0.001 + 1 + 100 + 100 + 0 + 0 + 0 + false + false + false + true + layer_map() + + + 0 + 0.001 + layer_map() + true + false + + + 1 + 0.001 + layer_map() + true + false + true + + + + + + + true + false + false + false + false + false + 8000 + 32000 + LIB + + + 2 + false + false + 1 + * + false + + + 0 + + + false + false + + + 0 + + true + + + + # Provide z stack information here +# Each line is one layer. The specification consists of a layer specification, a colon and arguments. +# The arguments are named (like "x=...") or in serial. Parameters are separated by comma or blanks. +# Named arguments are: +# +# zstart The lower z position of the extruded layer in µm +# zstop The upper z position of the extruded layer in µm +# height The height of the extruded layer in µm +# +# 'height', 'zstart' and 'zstop' can be used in any combination. If no value is given for 'zstart', # the upper level of the previous layer will be used. +# +# If a single unnamed parameter is given, it corresponds to 'height'. Two parameters correspond to +# 'zstart' and 'zstop'. +# +# Examples: +# 1: 0.5 1.5 # extrude layer 1/0 from 0.5 to 1.5 vertically +# 1/0: 0.5 1.5 # same with explicit datatype +# 1: zstop=1.5, zstart=0.5 # same with named parameters +# 1: height=1.0, zstop=1.5 # same with z stop minus height +# 1: 1.0 zstop=1.5 # same with height as unnamed parameter +42: zstart=-0.1 , height=0.1 +41: zstart=-0.1 , height=0.1 +13: zstart=0.001 , height=0.25 +46: zstart=0.1 , height=0.15 +49: zstart=0.2 , height=0.05 +50: zstart=0.2 , height=0.15 +51: zstart=0.3 , height=0.05 +61: zstart=0.3 , height=0.15 +62: zstart=0.4 , height=0.05 +30: zstart=0.4 , height=0.15 +31: zstart=0.5 , height=0.05 +32: zstart=0.5 , height=0.15 +33: zstart=0.6 , height=0.05 +36: zstart=0.6 , height=0.15 +37: zstart=0.7 , height=0.05 +127: zstart=0.7 , height=0.15 +126: zstart=0.8 , height=0.05 +129: zstart=0.9 , height=0.15 +53: zstart=0.8 , height=0.05 +26: zstart=0.9 , height=0.15 +54: zstart=0.9 , height=0.2 + + + + poly,25,49 + 56,55,49 + 49,50,51 + 51,61,62 + 62,30,31 + 31,32,33 + 33,36,37 + poly='46-34' + + diff --git a/technology/scn4m_subm/tech/scn4m_subm.lydrc b/technology/scn4m_subm/tech/scn4m_subm.lydrc new file mode 100644 index 00000000..345f4a41 --- /dev/null +++ b/technology/scn4m_subm/tech/scn4m_subm.lydrc @@ -0,0 +1,804 @@ + + + + + drc + + + + false + false + + true + drc_scripts + tools_menu.drc.end + dsl + drc-dsl-xml + # +# MOSIS SCMOS DRC +# +######################## +tstart = Time.now + +# optionnal for a batch launch : klayout -b r drc_SCMOS.lydrc -rd input=my_layout.gds -rd topcell=your_topcell -rd output=SCMOS_DRC.lyrdb +if $input + if $topcell + source($input,$topcell) + else + source($input) + end +end + +if $output + report("SCMOS DRC runset", $output) +else + report("SCMOS DRC runset", "SCMOS_DRC.lyrdb") +end + + +# PROCESS OPTIONS +######################## +LAMBDA = 0.2 +SUBM = true +DEEP = false +NBR_OF_METALS = 6 + +DFM = false + +# design rules limits definitions +######################## +R1_3 = ( 6 *LAMBDA ).round(3) +R2_1 = ( 3 *LAMBDA ).round(3) +R2_2 = ( 3 *LAMBDA ).round(3) +R2_4 = ( 3 *LAMBDA ).round(3) +R2_5 = ( 4 *LAMBDA ).round(3) +R3_1 = ( 2 *LAMBDA ).round(3) +R3_5 = ( 1 *LAMBDA ).round(3) +R4_1 = ( 3 *LAMBDA ).round(3) +R4_2 = ( 2 *LAMBDA ).round(3) +R5_1 = ( 2 *LAMBDA ).round(3) +R5_2 = ( 1.5 *LAMBDA ).round(3) +R5_4 = ( 2 *LAMBDA ).round(3) +R5_2_b = ( 1 *LAMBDA ).round(3) +R5_6_b = ( 2 *LAMBDA ).round(3) +R5_7_b = ( 3 *LAMBDA ).round(3) +R6_1 = ( 2 *LAMBDA ).round(3) +R6_2 = ( 1.5 *LAMBDA ).round(3) +R6_4 = ( 2 *LAMBDA ).round(3) +R6_2_b = ( 1 *LAMBDA ).round(3) +R6_5_b = ( 5 *LAMBDA ).round(3) +R6_6_b = ( 2 *LAMBDA ).round(3) +R6_7_b = ( 3 *LAMBDA ).round(3) +R6_8_b = ( 4 *LAMBDA ).round(3) +R7_1 = ( 3 *LAMBDA ).round(3) +R7_3 = ( 1 *LAMBDA ).round(3) +R8_2 = ( 3 *LAMBDA ).round(3) +R8_3 = ( 1 *LAMBDA ).round(3) +R8_4 = ( 2 *LAMBDA ).round(3) +R9_1 = ( 3 *LAMBDA ).round(3) +R9_3 = ( 1 *LAMBDA ).round(3) +R10_1 = ( 60 *LAMBDA ).round(3) +R10_2 = ( 20 *LAMBDA ).round(3) +R10_3 = ( 6 *LAMBDA ).round(3) +R10_4 = ( 30 *LAMBDA ).round(3) +R10_5 = ( 15 *LAMBDA ).round(3) +R11_2 = ( 3 *LAMBDA ).round(3) +R11_4 = ( 2 *LAMBDA ).round(3) +R11_6 = ( 2 *LAMBDA ).round(3) +R12_1 = ( 2 *LAMBDA ).round(3) +R12_2 = ( 3 *LAMBDA ).round(3) +R12_3 = ( 2 *LAMBDA ).round(3) +R12_4 = ( 1 *LAMBDA ).round(3) +R12_5 = ( 2 *LAMBDA ).round(3) +R12_6 = ( 3 *LAMBDA ).round(3) +R13_1 = ( 2 *LAMBDA ).round(3) +R13_3 = ( 3 *LAMBDA ).round(3) +R13_4 = ( 2 *LAMBDA ).round(3) +R13_5 = ( 3 *LAMBDA ).round(3) +R14_2 = ( 3 *LAMBDA ).round(3) +R14_3 = ( 1 *LAMBDA ).round(3) +R14_4 = ( 2 *LAMBDA ).round(3) +if NBR_OF_METALS > 3 + R15_3 = ( 1 *LAMBDA ).round(3) +else + R15_3 = ( 2 *LAMBDA ).round(3) +end +R16_1 = ( 2 *LAMBDA ).round(3) +R16_2 = ( 3 *LAMBDA ).round(3) +R16_3 = ( 2 *LAMBDA ).round(3) +R16_4 = ( 4 *LAMBDA ).round(3) +R16_5 = ( 2 *LAMBDA ).round(3) +R16_6 = ( 2 *LAMBDA ).round(3) +R16_7 = ( 6 *LAMBDA ).round(3) +R16_8 = ( 4 *LAMBDA ).round(3) +R16_9 = ( 2 *LAMBDA ).round(3) +R16_10 = ( 3 *LAMBDA ).round(3) +R16_11 = ( 2 *LAMBDA ).round(3) +R18_1 = ( 3 *LAMBDA ).round(3) +R18_2 = ( 2 *LAMBDA ).round(3) +R18_3 = ( 3 *LAMBDA ).round(3) +R18_4 = ( 2 *LAMBDA ).round(3) +R18_5 = ( 6 *LAMBDA ).round(3) +R20_1 = ( 4 *LAMBDA ).round(3) +R20_2 = ( 4 *LAMBDA ).round(3) +R20_3 = ( 2 *LAMBDA ).round(3) +R20_4 = ( 2 *LAMBDA ).round(3) +R20_5 = ( 2 *LAMBDA ).round(3) +R20_7 = ( 5 *LAMBDA ).round(3) +R20_8 = ( 7 *LAMBDA ).round(3) +R20_9 = ( 2 *LAMBDA ).round(3) +R20_10 = ( 3 *LAMBDA ).round(3) +R21_2 = ( 3 *LAMBDA ).round(3) +R21_3 = ( 1 *LAMBDA ).round(3) +if NBR_OF_METALS > 4 + R22_3 = ( 1 *LAMBDA ).round(3) +else + R22_3 = ( 2 *LAMBDA ).round(3) +end +R23_1 = ( 8 *LAMBDA ).round(3) +R23_2 = ( 4 *LAMBDA ).round(3) +R23_3 = ( 8 *LAMBDA ).round(3) +R23_4 = ( 3 *LAMBDA ).round(3) +R23_5 = ( 2 *LAMBDA ).round(3) +R23_6 = ( 2 *LAMBDA ).round(3) +R23_7 = ( 2 *LAMBDA ).round(3) +R23_8 = ( 4 *LAMBDA ).round(3) +R23_9 = ( 2 *LAMBDA ).round(3) +R24_1 = ( 4 *LAMBDA ).round(3) +R24_2 = ( 4 *LAMBDA ).round(3) +R24_3 = ( 4 *LAMBDA ).round(3) +R24_4 = ( 4 *LAMBDA ).round(3) +R24_5 = ( 3 *LAMBDA ).round(3) +R27_1 = ( 4 *LAMBDA ).round(3) +R27_2 = ( 4 *LAMBDA ).round(3) +R27_3 = ( 2 *LAMBDA ).round(3) +R27_4 = ( 2 *LAMBDA ).round(3) +R27_5 = ( 2 *LAMBDA ).round(3) +R27_7 = ( 5 *LAMBDA ).round(3) +R27_8 = ( 7 *LAMBDA ).round(3) +R27_9 = ( 2 *LAMBDA ).round(3) + + +if !SUBM && !DEEP + R1_1 = ( 10 *LAMBDA ).round(3) + R1_2 = ( 9 *LAMBDA ).round(3) + R2_3 = ( 5 *LAMBDA ).round(3) + R3_2 = ( 2 *LAMBDA ).round(3) + R3_2_a = ( 2 *LAMBDA ).round(3) + R3_3 = ( 2 *LAMBDA ).round(3) + R3_4 = ( 3 *LAMBDA ).round(3) + R4_3 = ( 1 *LAMBDA ).round(3) + R4_4 = ( 2 *LAMBDA ).round(3) + R5_3 = ( 2 *LAMBDA ).round(3) + R5_5_b = ( 4 *LAMBDA ).round(3) + R6_3 = ( 2 *LAMBDA ).round(3) + R7_2 = ( 2 *LAMBDA ).round(3) + R7_4 = ( 4 *LAMBDA ).round(3) + R8_1 = ( 2 *LAMBDA ).round(3) + R8_5 = ( 2 *LAMBDA ).round(3) + R9_2 = ( 3 *LAMBDA ).round(3) + R9_4 = ( 6 *LAMBDA ).round(3) + R11_1 = ( 3 *LAMBDA ).round(3) + R11_3 = ( 2 *LAMBDA ).round(3) + R11_5 = ( 3 *LAMBDA ).round(3) + R13_2 = ( 2 *LAMBDA ).round(3) + R14_1 = ( 2 *LAMBDA ).round(3) + if NBR_OF_METALS > 3 + R15_1 = ( 3 *LAMBDA ).round(3) + R15_2 = ( 3 *LAMBDA ).round(3) + R15_4 = ( 6 *LAMBDA ).round(3) + else + R15_1 = ( 6 *LAMBDA ).round(3) + R15_2 = ( 4 *LAMBDA ).round(3) + R15_4 = ( 8 *LAMBDA ).round(3) + end + R17_1 = ( 10 *LAMBDA ).round(3) + R17_2 = ( 9 *LAMBDA ).round(3) + R17_3 = ( 5 *LAMBDA ).round(3) + R17_4 = ( 5 *LAMBDA ).round(3) + R20_11 = ( 3 *LAMBDA ).round(3) + R21_1 = ( 2 *LAMBDA ).round(3) + if NBR_OF_METALS > 4 + R22_1 = ( 3 *LAMBDA ).round(3) + R22_2 = ( 3 *LAMBDA ).round(3) + R22_4 = ( 6 *LAMBDA ).round(3) + else + R22_1 = ( 6 *LAMBDA ).round(3) + R22_2 = ( 6 *LAMBDA ).round(3) + R22_4 = ( 12 *LAMBDA ).round(3) + end +end + +if SUBM + R1_1 = ( 12 *LAMBDA ).round(3) + R1_2 = ( 18 *LAMBDA ).round(3) + R2_3 = ( 6 *LAMBDA ).round(3) + R3_2 = ( 3 *LAMBDA ).round(3) + R3_2_a = ( 3 *LAMBDA ).round(3) + R3_3 = ( 2 *LAMBDA ).round(3) + R3_4 = ( 3 *LAMBDA ).round(3) + R4_3 = ( 1 *LAMBDA ).round(3) + R4_4 = ( 2 *LAMBDA ).round(3) + R5_3 = ( 3 *LAMBDA ).round(3) + R5_5_b = ( 5 *LAMBDA ).round(3) + R6_3 = ( 3 *LAMBDA ).round(3) + R7_2 = ( 3 *LAMBDA ).round(3) + R7_4 = ( 6 *LAMBDA ).round(3) + R8_1 = ( 2 *LAMBDA ).round(3) + R8_5 = ( 2 *LAMBDA ).round(3) + R9_2 = ( 3 *LAMBDA ).round(3) + R9_4 = ( 6 *LAMBDA ).round(3) + R11_1 = ( 7 *LAMBDA ).round(3) + R11_3 = ( 5 *LAMBDA ).round(3) + R11_5 = ( 6 *LAMBDA ).round(3) + R13_2 = ( 3 *LAMBDA ).round(3) + R14_1 = ( 2 *LAMBDA ).round(3) + if NBR_OF_METALS > 3 + R15_1 = ( 3 *LAMBDA ).round(3) + R15_2 = ( 3 *LAMBDA ).round(3) + R15_4 = ( 6 *LAMBDA ).round(3) + else + R15_1 = ( 5 *LAMBDA ).round(3) + R15_2 = ( 3 *LAMBDA ).round(3) + R15_4 = ( 6 *LAMBDA ).round(3) + end + R17_1 = ( 12 *LAMBDA ).round(3) + R17_2 = ( 18 *LAMBDA ).round(3) + R17_3 = ( 6 *LAMBDA ).round(3) + R17_4 = ( 6 *LAMBDA ).round(3) + R20_11 = ( 5 *LAMBDA ).round(3) + R21_1 = ( 2 *LAMBDA ).round(3) + if NBR_OF_METALS > 4 + R22_1 = ( 3 *LAMBDA ).round(3) + R22_2 = ( 3 *LAMBDA ).round(3) + R22_4 = ( 6 *LAMBDA ).round(3) + else + R22_1 = ( 6 *LAMBDA ).round(3) + R22_2 = ( 6 *LAMBDA ).round(3) + R22_4 = ( 12 *LAMBDA ).round(3) + end + R25_1 = ( 2 *LAMBDA ).round(3) + R25_2 = ( 3 *LAMBDA ).round(3) + R25_3 = ( 1 *LAMBDA ).round(3) + if NBR_OF_METALS > 5 + R26_1 = ( 3 *LAMBDA ).round(3) + R26_2 = ( 3 *LAMBDA ).round(3) + R26_3 = ( 1 *LAMBDA ).round(3) + R26_4 = ( 6 *LAMBDA ).round(3) + else + R26_1 = ( 4 *LAMBDA ).round(3) + R26_2 = ( 4 *LAMBDA ).round(3) + R26_3 = ( 2 *LAMBDA ).round(3) + R26_4 = ( 8 *LAMBDA ).round(3) + end + R28_1 = ( 40 *LAMBDA ).round(3) + R28_2 = ( 12 *LAMBDA ).round(3) + R28_3 = ( 4 *LAMBDA ).round(3) + R28_4 = ( 3 *LAMBDA ).round(3) + R28_5 = ( 4 *LAMBDA ).round(3) + R28_6 = ( 2 *LAMBDA ).round(3) + R28_7 = ( 25 *LAMBDA ).round(3) + R28_8 = ( 4 *LAMBDA ).round(3) + R28_9 = ( 8 *LAMBDA ).round(3) + R28_10 = ( 20 *LAMBDA ).round(3) + R28_11 = ( 40 *LAMBDA ).round(3) + R29_1 = ( 3 *LAMBDA ).round(3) + R29_2 = ( 4 *LAMBDA ).round(3) + R29_3 = ( 1 *LAMBDA ).round(3) + R30_1 = ( 5 *LAMBDA ).round(3) + R30_2 = ( 5 *LAMBDA ).round(3) + R30_3 = ( 1 *LAMBDA ).round(3) + R30_4 = ( 10 *LAMBDA ).round(3) + R31_1 = ( 30 *LAMBDA ).round(3) + R31_2 = ( 50 *LAMBDA ).round(3) + R31_3 = ( 15 *LAMBDA ).round(3) + R31_4 = ( 20 *LAMBDA ).round(3) + R31_5 = ( 35 *LAMBDA ).round(3) + R31_6 = ( 5 *LAMBDA ).round(3) + R31_7 = ( 30 *LAMBDA ).round(3) + R31_8 = ( 10 *LAMBDA ).round(3) +end + +if DEEP + R1_1 = ( 12 *LAMBDA ).round(3) + R1_2 = ( 18 *LAMBDA ).round(3) + R2_3 = ( 6 *LAMBDA ).round(3) + R3_2 = ( 3 *LAMBDA ).round(3) + R3_2_a = ( 4 *LAMBDA ).round(3) + R3_3 = ( 2.5 *LAMBDA ).round(3) + R3_4 = ( 4 *LAMBDA ).round(3) + R4_3 = ( 1.5 *LAMBDA ).round(3) + R4_4 = ( 4 *LAMBDA ).round(3) + R5_3 = ( 4 *LAMBDA ).round(3) + R5_5_b = ( 5 *LAMBDA ).round(3) + R6_3 = ( 4 *LAMBDA ).round(3) + R7_2 = ( 3 *LAMBDA ).round(3) + R7_4 = ( 6 *LAMBDA ).round(3) + R8_1 = ( 3 *LAMBDA ).round(3) + R9_2 = ( 4 *LAMBDA ).round(3) + R9_4 = ( 8 *LAMBDA ).round(3) + R11_1 = ( 7 *LAMBDA ).round(3) + R11_3 = ( 5 *LAMBDA ).round(3) + R11_5 = ( 6 *LAMBDA ).round(3) + R13_2 = ( 3 *LAMBDA ).round(3) + R14_1 = ( 3 *LAMBDA ).round(3) + if NBR_OF_METALS > 3 + R15_1 = ( 3 *LAMBDA ).round(3) + R15_2 = ( 4 *LAMBDA ).round(3) + R15_4 = ( 8 *LAMBDA ).round(3) + else + R15_1 = ( 5 *LAMBDA ).round(3) + R15_2 = ( 3 *LAMBDA ).round(3) + R15_4 = ( 6 *LAMBDA ).round(3) + end + R17_1 = ( 12 *LAMBDA ).round(3) + R17_2 = ( 18 *LAMBDA ).round(3) + R17_3 = ( 6 *LAMBDA ).round(3) + R17_4 = ( 6 *LAMBDA ).round(3) + R20_11 = ( 5 *LAMBDA ).round(3) + R21_1 = ( 3 *LAMBDA ).round(3) + if NBR_OF_METALS > 4 + R22_1 = ( 3 *LAMBDA ).round(3) + R22_2 = ( 4 *LAMBDA ).round(3) + R22_4 = ( 8 *LAMBDA ).round(3) + else + R22_1 = ( 6 *LAMBDA ).round(3) + R22_2 = ( 6 *LAMBDA ).round(3) + R22_4 = ( 12 *LAMBDA ).round(3) + end + R25_1 = ( 3 *LAMBDA ).round(3) + R25_2 = ( 3 *LAMBDA ).round(3) + R25_3 = ( 1 *LAMBDA ).round(3) + if NBR_OF_METALS > 5 + R26_1 = ( 3 *LAMBDA ).round(3) + R26_2 = ( 4 *LAMBDA ).round(3) + R26_3 = ( 1 *LAMBDA ).round(3) + R26_4 = ( 8 *LAMBDA ).round(3) + else + R26_1 = ( 4 *LAMBDA ).round(3) + R26_2 = ( 4 *LAMBDA ).round(3) + R26_3 = ( 2 *LAMBDA ).round(3) + R26_4 = ( 8 *LAMBDA ).round(3) + end + R28_1 = ( 45 *LAMBDA ).round(3) + R28_2 = ( 14 *LAMBDA ).round(3) + R28_3 = ( 5 *LAMBDA ).round(3) + R28_4 = ( 3 *LAMBDA ).round(3) + R28_5 = ( 5 *LAMBDA ).round(3) + R28_6 = ( 2 *LAMBDA ).round(3) + R28_7 = ( 25 *LAMBDA ).round(3) + R28_8 = ( 5 *LAMBDA ).round(3) + R28_9 = ( 9 *LAMBDA ).round(3) + R28_10 = ( 23 *LAMBDA ).round(3) + R28_11 = ( 45 *LAMBDA ).round(3) + R29_1 = ( 4 *LAMBDA ).round(3) + R29_2 = ( 4 *LAMBDA ).round(3) + R29_3 = ( 1 *LAMBDA ).round(3) + R30_1 = ( 5 *LAMBDA ).round(3) + R30_2 = ( 5 *LAMBDA ).round(3) + R30_3 = ( 2 *LAMBDA ).round(3) + R30_4 = ( 10 *LAMBDA ).round(3) + R31_1 = ( 34 *LAMBDA ).round(3) + R31_2 = ( 56 *LAMBDA ).round(3) + R31_3 = ( 17 *LAMBDA ).round(3) + R31_4 = ( 23 *LAMBDA ).round(3) + R31_5 = ( 39 *LAMBDA ).round(3) + R31_6 = ( 6 *LAMBDA ).round(3) + R31_7 = ( 34 *LAMBDA ).round(3) + R31_8 = ( 13 *LAMBDA ).round(3) +end + + +# KLAYOUT setttings +######################## +# Use a tile size of 1mm +tiles(1000.um) +# Use a tile border of 10 micron: +tile_borders(1.um) +#no_borders + +# Use 4 CPU cores +threads(4) +verbose(true) + +# 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 + +# layers definitions +######################## +info("Layers definitions") + + DNW = input(38,0) + NW = input(42,0) + PW = input(41,0) + CW = input(59,0) + AA = input(43,0) + TA = input(60,0) + PBase = input(58,0) + PL = input(46,0) + SB = input(29,0) + Nselect = input(45,0) + Pselect = input(44,0) + PO2 = input(56,0) + HR = input(34,0) + Contact = input(25,0) + ContactPoly = input(47,0) + ContactActive = input(48,0) + ContactPoly2 = input(55, 0) + CT = Contact + ContactPoly + ContactActive + ContactPoly2 + M1 = input(49,0) + V1 = input(50,0) + M2 = input(51,0) + V2 = input(61,0) + M3 = input(62,0) + V3 = input(30,0) + M4 = input(31,0) + CTM = input(35,0) + V4 = input(32,0) + M5 = input(33,0) + V5 = input(36,0) + M6 = input(37,0) + Glass = input(52,0) + Pads = input(26,0) + +# layers processing +######################## +info("Layers processing") +#CHIP = extent.sized(1.0) +NP = AA & Nselect +PP = AA & Pselect +NSTP = NP.and(NW) +PSTP = PP.not(NW) +GATE = PL & AA + +# DRC section +######################## +info("DRC section") + +### Deep NWell +DNW.ongrid(0.5*LAMBDA).output("DNW_offgrid", "Offgrid vertex on DNW") +DNW.with_angle(0 .. 45).output("DNW_angle", "Non 45 degree angle DNW") +DNW.edges.and(PW).output("DNW_PW","DNW cannot cross PWell") +DNW.width(R31_1, euclidian).output("31.1 DNW_width", "31.1 : Min. DNW width : #{R31_1}um") +DNW.isolated(R31_2, euclidian).output("31.2 DNW_space", "31.2 : Min. DNW spacing : #{R31_2}um") +NW.enclosing(DNW, R31_3, euclidian).output("31.3 NW_enc_DNW", "31.3 : Min. NWell enclosing DNW : #{R31_3}um") +DNW.enclosing(NW, R31_4, euclidian).output("31.4 DNW_enc_NW", "31.4 : Min. DNW enclosing NWell : #{R31_4}um") +DNW.separation(NW, R31_5, euclidian).output("31.5 DNW_sep_NW", "31.5 : Min. DNW separation NWell : #{R31_5}um") +DNW.not(NW).enclosing(NP, R31_6, euclidian).output("31.6 DNW_enc_NP", "31.6 : Min. PW in DNW enclosing N+ : #{R31_6}um") +DNW.separation(NP, R31_7, euclidian).output("31.7 DNW_sep_NP", "31.7 : Min. DNW separation N+ : #{R31_7}um") + +### Nwell / Pwell +NW.ongrid(0.5*LAMBDA).output("NW_offgrid", "Offgrid vertex on NWell") +NW.with_angle(0 .. 45).output("NW_angle", "Non 45 degree angle NWell") +NW.and(PW).output("NW_PW","NW over PW not allowed") +NW.width(R1_1, euclidian).output("1.1 NW_width", "1.1 : Min. NWell width : #{R1_1}um") +NW.isolated(R1_2, euclidian).output("1.2 NW_space", "1.2 : Min. NWell spacing : #{R1_2}um") +NW.and(TA).isolated(18, euclidian).output("1.3 NW_TA_space", "1.3 : Min. NWell-TA spacing : #{R1_3}um") +PW.width(R1_1, euclidian).output("1.1 PW_width", "1.1 : Min. PWell width : #{R1_1}um") +PW.isolated(R1_2, euclidian).output("1.2 PW_space", "1.2 : Min. PWell spacing : #{R1_2}um") +PW.and(TA).isolated(R1_3, euclidian).output("1.3 PW_TA_space", "1.3 : Min. PWell-TA spacing : #{R1_3}um") + +### Active +AA.ongrid(0.5*LAMBDA).output("AA_offgrid", "Offgrid vertex on AA") +AA.with_angle(0 .. 45).output("AA_angle", "Non 45 degree angle AA") +AA.width(R2_1, euclidian).output("2.1 AA_width", "2.1 : Min. active width : #{R2_1}um") +AA.space(R2_2, euclidian).output("2.2 AA_space", "2.2 : Min. active spacing : #{R2_2}3um") +NW.enclosing(PP.interacting(GATE), R2_3, euclidian).output("2.3 NW_enc_PP", "2.3 : Min. NWell enclosing Source/Drain : #{R2_3}um") +PW.enclosing(NP.interacting(GATE), R2_3, euclidian).output("2.3 PW_enc_NP", "2.3 : Min. PWell enclosing Source/Drain : #{R2_3}um") +NW.enclosing(NP, R2_4, euclidian).output("2.4 NW_enc_NP", "2.4 : Min. NWell enclosing Nstrap : #{R2_4}um") +PW.enclosing(PP, R2_4, euclidian).output("2.4 PW_enc_PP", "2.4 : Min. PWell enclosing Pstrap : #{R2_4}um") +NP.separation(PP, R2_5, euclidian).polygons.without_area(0).output("2.5 NP_space_PP", "2.5 : Min. N+ space P+ : #{R2_5}um (if not abutted)") + +### TA Thick Active +TA.ongrid(0.5*LAMBDA).output("TA_offgrid", "Offgrid vertex on TA") +TA.with_angle(0 .. 45).output("TA_angle", "Non 45 degree angle TA") +TA.width(R24_1, euclidian).output("24.1 TA_width", "24.1 : Min. TA width : #{R24_1}um") +TA.space(R24_2, euclidian).output("24.2 TA_space", "24.2 : Min. TA spacing : #{R24_2}um") +TA.enclosing(AA, R24_3, euclidian).output("24.3 TA_enc_AA", "24.3 : Min. TA enclosing Active : #{R24_3}um") +TA.separation(AA, R24_4, euclidian).output("24.4 TA_space_AA", "24.4 : Min. TA spacing Active : #{R24_4}um") +TA.and(GATE).width(R24_5, euclidian).output("24.5 TA_gate_width", "24.5 : Min. TA Gate width : #{R24_5}um") +AA.edges.and(TA).output("24.6 AA_in_TA","24.6 : Active edge cannot cross TA") + +### Poly +PL.ongrid(0.5*LAMBDA).output("POLY_offgrid", "Offgrid vertex on Poly") +PL.with_angle(0 .. 45).output("POLY_angle", "Non 45 degree angle Poly") +PL.width(R3_1, euclidian).output("3.1 POLY_width", "3.1 : Min. Poly width : #{R3_1}um") +PL.space(R3_2, euclidian).output("3.2 Poly_space", "3.2 : Min. Poly spacing : #{R3_2}um") +GATE.space(R3_2_a, euclidian).output("3.2a Gate_space", "3.2a : Min. Gate spacing : #{R3_2_a}um") +PL.enclosing(GATE, R3_3, projection).polygons.without_area(0).output("3.3 PL_enc_GATE", "3.3 : Min. Poly extention Gate : #{R3_3}um") +AA.enclosing(GATE, R3_4, projection).polygons.without_area(0).output("3.4 AA_enc_GATE", "3.4 : Min. Source/Drain length : #{R3_4}um") +PL.not(AA).separation(AA, 1, euclidian).polygons.without_area(0).output("3.5 PL_space_AA", "3.5 : Min. Poly on Field spacing Active : #{R3_5}um") + +### Poly2 +if !DEEP +PO2.ongrid(0.5*LAMBDA).output("POLY2_offgrid", "Offgrid vertex on Poly2") +PO2.with_angle(0 .. 45).output("POLY2_angle", "Non 45 degree angle Poly2") +PO2.width(R12_1, euclidian).output("12.1 POLY2_width", "12.1 : Min. Poly2 width : #{R12_1}um") +PO2.space(R12_2, euclidian).output("12.2 POLY2_space", "12.2 : Min. Poly2 space : #{R12_2}um") +# rule R12.3 not coded +PO2.not(AA).separation(AA, R12_4, euclidian).output("12.4 POLY2_space_AA"," 12.4 : Min. Poly2 on Field spacing Active : #{R12_4}um") +PO2.not(PL).separation(PL, R12_5, euclidian).output("12.5 POLY2_space_PL"," 12.5 : Min. Poly2 spacing Poly : #{R12_5}um") +PO2.enclosing(PL, R12_5, euclidian).output("12.5 POLY2_overlap_PL"," 12.5 : Min. Poly2 overlap of Poly : #{R12_5}um") +PO2.separation(AA.or(PL).and(CT), R12_6, euclidian).output("12.6 POLY2_space_CT"," 12.5 : Min. Poly2 spacing Poly or Active contact: #{R12_6}um") +PO2cap = PL & PO2 +PO2cap.width(R11_1, euclidian).output("11.1 POLY2CAP_width", "11.1 : Min. Poly2 Capacitor width : #{R11_1}um") +PO2cap.space(R11_2, euclidian).output("11.2 POLY2CAP_space", "11.2 : Min. Poly2 Capacitor space : #{R11_2}um") +PL.enclosing(PO2cap, R11_3, euclidian).output("12.3 PL_overlap_POLY2CAP"," 11.3 : Min. Poly overlap of Poly2 Capacitor : #{R11_3}um") +PO2cap.edges.separation(AA.or(NW).edges, R11_4, euclidian).output("11.4 POLY2CAP_space_AA/NW"," 11.4 : Min. Poly2 Capacitor spacing Active or Well: #{R11_4}um") +PO2cap.separation(PL.and(CT), R11_5, euclidian).output("11.5 POLY2CAP_space_PLCT"," 11.5 : Min. Poly2 Capacitor spacing Poly contact: #{R11_5}um") +PO2cap.separation(M1.or(M2).or(M3), R11_6, euclidian).output("11.6 POLY2CAP_space_METAL"," 11.6 : Min. Poly2 Capacitor spacing any Metal: #{R11_6}um") +PO2cap.forget + +### Capacitor Well +CW.ongrid(0.5*LAMBDA).output("CW_offgrid", "Offgrid vertex on CapacitorWell") +CW.with_angle(0 .. 45).output("CW_angle", "Non 45 degree angle CapacitorWell") +CW.width(R17_1, euclidian).output("17.1 CW_width", "17.1 : Min. CapacitorWell width : #{R17_1}um") +CW.space(R17_2, euclidian).output("17.2 CW_space", "17.2 : Min. CapacitorWell space : #{R17_2}um") +AA.not(CW).separation(CW, R17_3, euclidian).output("17.3 CW_space_AA"," 17.3 : Min. CapacitorWell spacing Active : #{R17_3}um") +CW.enclosing(AA, R17_4, euclidian).output("17.4 CW_overlap_AA"," 17.4 : Min. CapacitorWell overlap of Active : #{R17_4}um") +LinCap = PL & CW +LinCap.width(R18_1, euclidian).output("18.1 LC_width", "18.1 : Min. Linear Capacitor width : #{R18_1}um") +LinCap.space(R18_2, euclidian).output("18.2 LC_space", "18.2 : Min. Linear Capacitor space : #{R18_2}um") +LinCap.separation(AA.and(CT), R18_3, euclidian).output("18.3 LC_space_AACT"," 18.3 : Min. Linear Capacitor spacing Active contact : #{R18_3}um") +LinCap.separation(PL.and(CT), R18_4, euclidian).output("18.4 LC_space_PLCT"," 18.4 : Min. Linear Capacitor spacing Poly contact : #{R18_4}um") +LinCap.forget +end + +### N+/P+ Select +Nselect.ongrid(0.5*LAMBDA).output("NSel_offgrid", "Offgrid vertex on Nselect") +Pselect.ongrid(0.5*LAMBDA).output("PSel_offgrid", "Offgrid vertex on Pselect") +Nselect.with_angle(0 .. 45).output("N+_angle", "Non 45 degree angle Nselect") +Pselect.with_angle(0 .. 45).output("N+_angle", "Non 45 degree angle Pselect") +NP.enclosing(GATE, R4_1, projection).polygons.without_area(0).output("4.1 N+_enc_GATE", "4.1 : Min. N+ extention Gate on Source/Drain : #{R4_1}um") +PP.enclosing(GATE, R4_1, projection).polygons.without_area(0).output("4.1 P+_enc_GATE", "4.1 : Min. P+ extention Gate on Source/Drain : #{R4_1}um") +Nselect.enclosing(AA, R4_2, euclidian).output("4.2 N+_enc_AA", "4.2 : Min. N+ enclosing Active : #{R4_2}um") +Pselect.enclosing(AA, R4_2, euclidian).output("4.2 P+_enc_AA", "4.2 : Min. P+ enclosing Active : #{R4_2}um") +Nselect.enclosing(CT, R4_3, euclidian).output("4. N+_enc_CT", "4.3 : Min. N+ enclosing Contact : #{R4_3}um") +Pselect.enclosing(CT, R4_3, euclidian).output("4.3 P+_enc_CT", "4.3 : Min. P+ enclosing Contact : #{R4_3}um") +Nselect.width(R4_4,euclidian).output("4.4 N+_width", "4.4 : Min. N+ width : #{R4_4}um") +Pselect.width(R4_4,euclidian).output("4.4 P+_width", "4.4 : Min. N+ width : #{R4_4}um") +Nselect.space(R4_4,euclidian).output("4.4 N+_space", "4.4 : Min. N+ spacing : #{R4_4}um") +Pselect.space(R4_4,euclidian).output("4.4 P+_space", "4.4 : Min. N+ spacing : #{R4_4}um") +Nselect.and(Pselect).output("4.4 N+_and_P+", "4.4 : N+ over P+ not allowed") + +### HR - High Resistive +HR.ongrid(0.5*LAMBDA).output("HR_offgrid", "Offgrid vertex on HighRes") +HR.with_angle(0 .. 45).output("HR_angle", "Non 45 degree angle HighRes") +HR.width(R27_1, euclidian).output("27.1 HR_width", "27.1 : Min. HiRes width : #{R27_1}um") +HR.space(R27_2, euclidian).output("27.2 HR_space", "27.2 : Min. HiRes spacing : #{R27_2}um") +HR.and(CT).output("27.3 CT_and_HR", "27.3 : Contact on HiRes not allowed") +HR.separation(CT, R27_3, euclidian).output("27.3 HR_space_CT", "27.3 : Min. HiRes space to Contact : #{R27_3}um") +HR.separation(AA, R27_5, euclidian).output("27.4 HR_space_AA", "27.4 : Min. HiRes space to Active : #{R27_4}um") +HR.separation(PO2, R27_5, euclidian).output("27.5 HR_space_PO2", "27.5 : Min. HiRes space to Poly2 : #{R27_5}um") +HR.and(PO2).and(AA).output("27.6 HR_and_active", "27.6 : HiRes Po2 over Active not allowed") +HR.and(PO2).and(NW.or(PW)).output("27.6 HR_and_Well", "27.6 : HiRes Po2 over Well not allowed") +HR.and(PO2).width(R27_7,euclidian).output("27.7 HRPO2_width", "27.7 : Min. HiRes Poly2 width : #{R27_7}um") +HR.and(PO2).space(R27_8,euclidian).output("27.8 HRPO2_space", "27.8 : Min. HiRes Poly2 space : #{R27_8}um") +HR.enclosing(PO2, R27_9, projection).output("27.9 HR_enc_PO2", "27.9 : Min. HiRes enclosing Poly2 : #{R27_9}um") + +### SB - Silicide block +SB.ongrid(0.5*LAMBDA).output("SB_offgrid", "Offgrid vertex on Sil. Block") +SB.with_angle(0 .. 45).output("SB_angle", "Non 45 degree angle Sil. Block") +SB.width(R20_1, euclidian).output("20.1 SB_width", "20.1 : Min. Sil. Block width : #{R20_1}um") +SB.space(R20_2, euclidian).output("20.2 SB_space", "20.2 : Min. Sil. Block spacing : #{R20_2}um") +SB.separation(CT, R20_3, euclidian).output("20.3 SB_space_CT", "20.3 : Min. Sil. Block space to Contact : #{R20_3}um") +SB.and(CT).output("20.3 SB_and_CT", "20.3 : Sil. Block over Contact not allowed") +SB.separation(AA, R20_4, euclidian).output("20.4 SB_space_AA", "20.4 : Min. Sil. Block space to Active : #{R20_4}um") +SB.separation(PL, R20_5, euclidian).output("20.5 SB_space_PL", "20.5 : Min. Sil. Block space to Poly : #{R20_5}um") +SB.and(GATE).output("20.6 SBres_overAA","20.6 : SB resistor over Active not allowed") +SB.and(PL).and(Nselect.or(Pselect)).output("20.6 SBres_over_WELL","20.6 : SB resistor over Well not allowed") +SB.and(PL).width(R20_7,euclidian).output("20.6 SBres_width", "20.7 : Min. SB resistor width : #{R20_7}um") +SB.and(PL).space(R20_7,euclidian).output("20.7 SBres_space", "20.7 : Min. SB resistor space : #{R20_7}um") +SB.enclosing(AA, R20_8, projection).polygons.without_area(0).output("20.8 SB_enc_AA", "20.8 : Min. Sil. Block enclosing Active : #{R20_8}um") +AA.enclosing(SB, R20_9, projection).polygons.without_area(0).output("20.9 AA_enc_SB", "20.9 : Min. Active enclosing Sil. Block : #{R20_9}um") +SB.enclosing(PL, R20_9, projection).output("20.8 SB_enc_PL", "20.8 : Min. Sil. Block enclosing Poly : #{R20_8}um") +PL.enclosing(SB, R20_8, projection).polygons.without_area(0).output("20.9 PL_enc_SB", "20.9 : Min. Poly enclosing Sil. Block : #{R20_9}um") +SB.separation(GATE, R20_11, euclidian).output("20.11 SB_space_GATE", "20.11 : Min. Sil. Block space to Gate : #{R20_11}um") + +### Contact +CT.ongrid(0.5*LAMBDA).output("CT_offgrid", "Offgrid vertex on Contact") +CT.with_angle(0 .. 90).output("CT_angle", "Non 90 degree angle Contact") +CT.and(GATE).output("CT_and_GATE", "Contact on Gate not allowed") +CT.not(M1).output("CT_not_M1", "Contact without Metal1 not recommended") +# CT.drc(length != R5_1).output("5.1 CT_width", "5.1 : Exact Contact width : #{R5_1}um") +CT.width(R5_1).output("5.1 CT_width", "5.1 : Exact Contact width : #{R5_1}um") +CT.without_area(R5_1*R5_1).output("5.1 CT_area", "5.1 : Exact Contact Area : #{R5_1*R5_1}um2") +CT.space(R5_3, euclidian).output("5.3 CT_space", "5.3 : Contact spacing : #{R5_3}um") +PL.enclosing(CT, R5_2_b, euclidian).output("5.2 PL_enc_CT", "5.2 : Min. Poly enclosing Contact : #{R5_2_b}um") +AA.enclosing(CT, R6_2_b, euclidian).output("6.2 AA_enc_CT", "6.2 : Min. Active enclosing Contact : #{R6_2_b}um") +PO2.enclosing(CT, R13_3, euclidian).output("13.3 PO2_enc_CT", "13.3 : Min. Poly2 enclosing Contact : #{R13_3}um") +CT.and(AA).separation(GATE, R5_4, euclidian).output("5.4 CTAA_space_GATE", "5.4 : Min. ActiveContact space to Gate : #{R5_4}um") +CT.and(PL).separation(PL, R5_5_b, euclidian).polygons.without_area(0).output("5.5.b CTPL_space_Poly", "5.5.b : Min. PolyContact space to Poly : #{R5_5_b}um") +CT.and(PL).separation(AA, R5_6_b, euclidian).output("5.6.b CTPL_space_AA", "5.6.b : Min. PolyContact space to AA : #{R5_6_b}um") +# rule 5.7.b not coded +CT.and(AA).separation(AA, R6_5_b, euclidian).polygons.without_area(0).output("6.5.b CTAA_space_AA", "6.5.b : Min. ActiveContact space to AA : #{R6_5_b}um") +CT.and(AA).separation(PL, R6_6_b, euclidian).output("6.6.b CTAA_space_PL", "6.6.b : Min. ActiveContact space to Poly : #{R6_6_b}um") +CT.and(AA).separation(CT.and(PL), R6_7_b, euclidian).output("6.7.b CTAA_space_CTPL", "6.7.b : Min. ActiveContact space to PolyContact : #{R6_7_b}um") +# rule 6.8.b not coded +CT.and(PO2).separation(AA, R13_5, euclidian).output("13.5 CTPO2_space_AA", "13.5 : Min. Poly2Contact space to AA : #{R13_5}um") +CT.and(PO2).separation(PL, R13_5, euclidian).output("13.5 CTPO2_space_PL", "13.5 : Min. Poly2Contact space to Poly : #{R13_5}um") +M1.enclosing(CT, R7_3, euclidian).output("7.3 M1_enc_CT", "7.3 : Min. Metal1 enclosing Contact : #{R7_3}um") + +### Metal 1 +M1.ongrid(0.5*LAMBDA).output("M1_offgrid", "Offgrid vertex on ME1") +M1.with_angle(0 .. 45).output("M1_angle", "Non 45 degree angle ME1") +M1.holes.with_area(0 .. R7_1*R7_1).output("M1_holes", "Min. Metal1 holes area : #{R7_1*R7_1}um2") +M1.width(R7_1, euclidian).output("7.1 M1_width", "7.1 : Min. Metal1 width : #{R7_1}um") +M1.space(R7_2, euclidian).output("7.2 M1_space", "7.2 : Min. Metal1 spacing : #{R7_2}um") +M1.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M1,R7_4,euclidian).polygons.without_area(0).output("7.4 M1_10_space", "7.4 : Space if at least one metal1 line width is > #{10*LAMBDA}um : #{R7_4}um") + +### Via 1 +V1.ongrid(0.5*LAMBDA).output("V1_offgrid", "Offgrid vertex on Via1") +V1.not(M1).output("V1_not_M1", "Via1 without Metal1 not allowed") +V1.not(M2).output("V1_not_M2", "Via1 without Metal2 not allowed") +V1.with_angle(0 .. 90).output("V1_angle", "Non 90 degree angle Via1") +V1.width(R8_1,square).output("8.1 V1_width", "8.1 : Exact Via1 width : #{R8_1}um") +V1.without_area(R8_1*R8_1).output("8.1 V1_width", "8.1 : Exact Via1 width : #{R8_1}um2") +V1.space(R8_2,euclidian).output("8.2 V1_space", "8.2 : Via1 spacing : #{R8_2}um") +M1.enclosing(V1, R8_3, euclidian).output("8.3 M1_enc_V1", "8.3 : Min. Metal1 enclosing Via1 : #{R8_3}um") +M2.enclosing(V1, R8_3, euclidian).output("9.3 M2_enc_V1", "9.3 : Min. Metal2 enclosing Via1 : #{R9_3}um") +if !DEEP && NBR_OF_METALS < 4 + V1.and(CT).or(V1.separation(CT, R8_4, euclidian).polygons).output("8.4 V1_space_CT", "8.4 : Via1 space CT : #{R8_4}um") + V1.separation(PL + AA, R8_5, euclidian).output("8.5 V1_space_PL/AAedges", "8.5 : Via1 space to Poly orActive edges : #{R8_5}um") +end +if DFM + M1.and(M2).not(V1).with_holes(1,1).output("2_V1", "Min. 2 Via1 are needed") +end + +### Metal 2 +M2.ongrid(0.5*LAMBDA).output("M2_offgrid", "Offgrid vertex on ME2") +M2.with_angle(0 .. 45).output("M2_angle", "Non 45 degree angle ME2") +M2.width(R9_1, euclidian).output("9.1 M2_width", "9.1 : Min. Metal2 width : #{R9_1}um") +M2.space(R9_2, euclidian).output("9.2 M2_space", "9.2 : Min. Metal2 spacing : #{R9_2}um") +M2.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M2,R9_4,euclidian).polygons.without_area(0).output("9.4 M2_10_space", "9.4 : Space if at least one metal2 line width is > #{10*LAMBDA}um : #{R9_4}um") + +### Via 2 +V2.ongrid(0.5*LAMBDA).output("V2_offgrid", "Offgrid vertex on Via2") +V2.not(M3).output("V2_not_M3", "Via2 without Metal3 not allowed") +V2.not(M2).output("V2_not_M2", "Via2 without Metal2 not allowed") +V2.with_angle(0 .. 90).output("V2_angle", "Non 90 degree angle Via2") +V2.width(R14_1, square).output("14.1 V2_width", "14.1 : Exact Via2 width : #{R14_1}um") +V2.without_area(R14_1*R14_1).output("14.1 V2_width", "14.1 : Exact Via2 width : #{R14_1}um2") +V2.space(R14_2, euclidian).output("14.2 V2_space", "14.2 : Via2 spacing : #{R14_2}um") +M2.enclosing(V2, R14_3, euclidian).output("14.3 M2_enc_V2", "14.3 : Min. Metal2 enclosing Via2 : #{R14_3}um") +M3.enclosing(V2, R15_3, euclidian).output("15.3 M3_enc_V2", "15.3 : Min. Metal3 enclosing Via2 : #{R15_3}um") +if !DEEP && NBR_OF_METALS < 4 + V2.and(V1).or(V2.separation(V1, R14_4, euclidian).polygons).output("14.4 V2_space_V1", "14.4 : Via2 space Via1 : #{R14_4}um") +end +if DFM + M2.and(M3).not(V2).with_holes(1,1).output("2_V2", "Min. 2 Via2 are needed") +end + +### Metal 3 +M3.ongrid(0.5*LAMBDA).output("M3_offgrid", "Offgrid vertex on ME3") +M3.with_angle(0 .. 45).output("M3_angle", "Non 45 degree angle ME3") +M3.width(R15_1, euclidian).output("15.1 M3_width", "15.1 : Min. Metal3 width : #{R15_1}um") +M3.space(R15_2, euclidian).output("15.2 M3_space", "15.2 : Min. Metal3 spacing : #{R15_2}um") +M3.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M3, R15_4, euclidian).polygons.without_area(0).output("15.4 M3_10_space", "15.4 : Space if at least one metal3 line width is > #{10*LAMBDA}um : #{R15_4}um") + +### Cap Top Metal +if SUBM || DEEP +CTM.ongrid(0.5*LAMBDA).output("CTM_offgrid", "Offgrid vertex on CTM") +CTM.with_angle(0 .. 45).output("CTM_angle", "Non 45 degree angle CTM") +CTM.width(R28_1, euclidian).output("28.1 CTM_width", "28.1 : Min. Cap Top Metal width : #{R28_1}um") +CTM.space(R28_2, euclidian).output("28.2 CTM_space", "28.2 : Min. Cap Top Metal spacing : #{R28_2}um") +if NBR_OF_METALS == 4 + TM = M4 + VT = V3 + TB = V2 +end +if NBR_OF_METALS == 5 + TM = M5 + VT = V4 + VB = V3 +end +if NBR_OF_METALS == 6 + TM = M6 + VT = V5 + VB = V4 +end +TM.enclosing(CTM, R28_3, euclidian).output("28.3 TM_overlap_CTM", "28.3 : Min. Top Metal overlap Cap Top Metal : #{R28_3}um") +CTM.enclosing(VT, R28_4, euclidian).output("28.4 CTM_overlap_VT", "28.4 : Min. Cap Top Metal overlap Top Via : #{R28_4}um") +CTM.separation(VB, R28_5, euclidian).output("28.5 CTM_space_VB", "28.5 : Min. Cap Top Metal space Bottom Via : #{R28_5}um") +CTM.separation(VT, R28_5, euclidian).output("28.5 CTM_space_VT", "28.5 : Min. Cap Top Metal space Top Via : #{R28_5}um") +TM.enclosing(VB, R28_6, euclidian).output("28.6 TM_overlap_VB", "28.6 : Min. Top Metal overlap Bottom Via : #{R28_6}um") +# rule 28.7 not coded +CTM.not_interacting(VT).width(R28_8, euclidian).output("28.8 CTMdummies_width", "28.8 : Min. dummies Cap Top Metal width : #{R28_8}um") +TM.interacting(CTM).space(R28_9, euclidian).output("28.9 VT_space", "28.9 : Min. Top Metal spacing : #{R28_9}um") +VT.interacting(CTM).space(R28_10, euclidian).output("28.10 VT_space", "28.10 : Min. Top Via spacing : #{R28_10}um") +VB.interacting(TM.interacting(CTM)).space(R28_11, euclidian).output("28.11 VB_space", "28.11 : Min. Bottom Via spacing : #{R28_11}um") +CTM.sized(-15.um).sized(15.um).output("28.12 CTM_width", "28.12 : Max. CTM width/length : 30um") +TM.interacting(CTM).sized(-17.5.um).sized(17.5.um).output("28.13 TM_width", "28.13 : Max. Top Metal width/length : 35um") +CTM.and(VB).output("28.14 CTM_VB", "28.14 : no VB under CTM allowed") +CTM.and(AA.or(PL)).output("28.15 CTM_AA", "28.15 : no active or passive circuitry under CTM allowed") +end + +### Via 3 +if NBR_OF_METALS > 3 +V3.ongrid(0.5*LAMBDA).output("V3_offgrid", "Offgrid vertex on Via3") +V3.not(M3).output("V3_not_M3", "Via3 without Metal3 not allowed") +V3.not(M4).output("V3_not_M4", "Via3 without Metal4 not allowed") +V3.with_angle(0 .. 90).output("V3_angle", "Non 90 degree angle Via3") +V3.width(R21_1, square).output("21.1 V3_width", "21.1 : Exact Via3 width : #{R21_1}um") +V3.without_area(R21_1*R21_1).output("21.1 V3_width", "21.1 : Exact Via3 width : #{R21_1}um2") +V3.space(R21_2, euclidian).output("21.2 V3_space", "21.2 : Via3 spacing : #{R21_2}um") +M3.enclosing(V3, R21_3, euclidian).output("21.3 M3_enc_V3", "21.3 : Min. Metal3 enclosing Via3 : #{R21_3}um") +M4.enclosing(V3, R22_3, euclidian).output("22.3 M4_enc_V3", "22.3 : Min. Metal4 enclosing Via3 : #{R22_3}um") +if DFM + M3.and(M4).not(V3).with_holes(1,1).output("2_V3", "Min. 2 Via3 are needed") +end + +### Metal 4 +M4.ongrid(0.5*LAMBDA).output("M4_offgrid", "Offgrid vertex on ME4") +M4.with_angle(0 .. 45).output("M4_angle", "Non 45 degree angle ME4") +M4.width(R22_1, euclidian).output("22.1 M4_width", "22.1 : Min. Metal4 width : #{R22_1}um") +M4.space(R22_2, euclidian).output("22.2 M4_space", "22.2 : Min. Metal4 spacing : #{R22_2}um") +M4.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M4, R22_4, euclidian).polygons.without_area(0).output("22.4 M4_10_space", "22.4 : Space if at least one metal4 line width is > #{10*LAMBDA}um : #{R22_4}um") + +### Via 4 +if NBR_OF_METALS > 4 +V4.ongrid(0.5*LAMBDA).output("V4_offgrid", "Offgrid vertex on Via4") +V4.not(M5).output("V4_not_M5", "Via4 without Metal5 not allowed") +V4.not(M4).output("V4_not_M4", "Via4 without Metal4 not allowed") +V4.with_angle(0 .. 90).output("V4_angle", "Non 90 degree angle Via4") +V4.width(R25_1, square).output("25.1 V4_width", "25.1 : Exact Via4 width : #{R25_1}um") +V4.without_area(R25_1*R25_1).output("25.1 V4_width", "25.1 : Via4 width : #{R25_1}um2") +V4.space(R25_2, euclidian).output("25.2 V4_space", "25.2 : Exact Via4 spacing : #{R25_2}um") +M4.enclosing(V4, R25_3, euclidian).output("25.3 M4_enc_V4", "25.3 : Min. Metal4 enclosing Via4 : #{R25_3}um") +M5.enclosing(V4, R26_3, euclidian).output("26.3 M5_enc_V4", "26.3 : Min. Metal5 enclosing Via4 : #{R26_3}um") +if DFM + M4.and(M5).not(V4).with_holes(1,1).output("2_V4", "Min. 2 Via4 are needed") +end + +### Metal 5 +M5.ongrid(0.5*LAMBDA).output("M5_offgrid", "Offgrid vertex on ME5") +M5.with_angle(0 .. 45).output("M5_angle", "Non 45 degree angle ME5") +M5.width(R26_1, euclidian).output("26.1 M5_width", "26.1 : Min. Metal5 width : #{R26_1}um") +M5.space(R26_2, euclidian).output("26.2 M5_space", "26.2 : Min. Metal5 spacing : #{R26_2}um") +M5.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M5, R26_4, euclidian).polygons.without_area(0).output("26.4 M5_10_space", "26 .4 : Space if at least one metal5 line width is > #{10*LAMBDA}um : #{R26_4}um") + +### Via 5 +if NBR_OF_METALS > 5 +V5.ongrid(0.5*LAMBDA).output("V5_offgrid", "Offgrid vertex on Via5") +V5.not(M5).output("V5_not_M5", "Via5 without Metal5 not allowed") +V5.not(M6).output("V5_not_M6", "Via5 without Metal6 not allowed") +V5.with_angle(0 .. 90).output("V4_angle", "Non 90 degree angle Via5") +V5.width(R29_1, square).output("29.1 V5_width", "29.1 : Exact Via5 width : #{R29_1}um") +V5.without_area(R29_1*R29_1).output("29.1 V5_width", "29.1 : Exact Via5 width : #{R29_1}um2") +V5.space(R29_2, euclidian).output("29.2 V5_space", "29.2 : Via5 spacing : #{R29_2}um") +M5.enclosing(V5, R29_3, euclidian).output("29.3 M5_enc_V5", "29.3 : Min. Metal5 enclosing Via5 : #{R29_3}um") +M6.enclosing(V5, R30_3, euclidian).output("30.3 M3_enc_V5", "30.3 : Min. Metal6 enclosing Via5 : #{R30_3}um") +if DFM + M5.and(M6).not(V5).with_holes(1,1).output("2_V5", "Min. 2 Via5 are needed") +end + +### Metal 6 +M6.ongrid(0.5*LAMBDA).output("M6_offgrid", "Offgrid vertex on ME6") +M6.with_angle(0 .. 45).output("M6_angle", "Non 45 degree angle ME5") +M6.width(R30_1, euclidian).output("30.1 M6_width", "30.1 : Min. Metal6 width : #{R30_1}um") +M6.space(R30_2, euclidian).output("30.2 M6_space", "30.2 : Min. Metal6 spacing : #{R30_2}um") +M6.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M5, 10, euclidian).polygons.without_area(0).output("30.4 M6_10_space", "30.4 : Space if at least one metal6 line width is > #{10*LAMBDA}um : #{R30_4}um") + +end +end +end + +# time spent for the DRC +time = Time.now +hours = ((time - tstart)/3600).to_i +minutes = ((time - tstart)/60 - hours * 60).to_i +seconds = ((time - tstart) - (minutes * 60 + hours * 3600)).to_i +$stdout.write "DRC finished at : #{time.hour}:#{time.min}:#{time.sec} - DRC duration = #{hours} hrs. #{minutes} min. #{seconds} sec.\n" + From acc9b2d223947c8456e1a5fc0e69479337561d81 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 27 Sep 2021 12:30:06 -0700 Subject: [PATCH 022/229] Connect pwell and bulk when no tap --- technology/freepdk45/tech/freepdk45.lylvs | 8 ++++---- technology/scn4m_subm/tech/scn4m_subm.lylvs | 14 ++++---------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index 64fde014..91009968 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -214,10 +214,10 @@ end #connect_global(nwell, "NWELL") #connect_global(bulk, "BULK") -#for pat in %w(pnand*_0 and2_dec_0 port_address* replica_bitcell_array) -# connect_explicit(pat, [ "NWELL", "vdd" ]) -# connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) -#end +for pat in %w(pnand* and?_dec port_address* replica_bitcell_array) + connect_explicit(pat, [ "NWELL", "vdd" ]) + connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) +end #for pat in %w(XOR* XNOR* TLAT* TINV* TBUF* SDFF* OR* OAI* NOR* NAND* MUX* LOGIC* INV* HA* FILLCELL* # FA* DLL* DLH* DFF* DFFS* DFFR* DFFRS* CLKGATE* CLKBUF* BUF* AOI* ANTENNA* AND*) diff --git a/technology/scn4m_subm/tech/scn4m_subm.lylvs b/technology/scn4m_subm/tech/scn4m_subm.lylvs index 16dd5c6e..46a6c12a 100644 --- a/technology/scn4m_subm/tech/scn4m_subm.lylvs +++ b/technology/scn4m_subm/tech/scn4m_subm.lylvs @@ -164,16 +164,10 @@ connect_global(pwell, "PWELL") connect_global(nwell, "NWELL") #connect_global(bulk, "BULK") -#for pat in %w(pnand*_0 and2_dec_0 port_address* replica_bitcell_array) -# connect_explicit(pat, [ "NWELL", "vdd" ]) -# connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) -#end - -#for pat in %w(XOR* XNOR* TLAT* TINV* TBUF* SDFF* OR* OAI* NOR* NAND* MUX* LOGIC* INV* HA* FILLCELL* -# FA* DLL* DLH* DFF* DFFS* DFFR* DFFRS* CLKGATE* CLKBUF* BUF* AOI* ANTENNA* AND*) -# connect_explicit(pat, [ "NWELL", "VDD" ]) -# connect_explicit(pat, [ "BULK", "VSS" ]) -#end +for pat in %w(pnand* and?_dec port_address* replica_bitcell_array) + connect_explicit(pat, [ "NWELL", "vdd" ]) + connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) +end # Actually performs the extraction netlist # ... not really required From 2e846cb22f63319bee4a7c31576ef78f72cdcab0 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 27 Sep 2021 15:21:26 -0700 Subject: [PATCH 023/229] Fix regexes for cells without well taps --- technology/freepdk45/tech/freepdk45.lylvs | 2 +- technology/scn4m_subm/tech/scn4m_subm.lylvs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index 91009968..bf4852d8 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -214,7 +214,7 @@ end #connect_global(nwell, "NWELL") #connect_global(bulk, "BULK") -for pat in %w(pnand* and?_dec port_address* replica_bitcell_array) +for pat in %w(pinv* pnor* pnand* and?_dec* port_address* replica_bitcell_array*) connect_explicit(pat, [ "NWELL", "vdd" ]) connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) end diff --git a/technology/scn4m_subm/tech/scn4m_subm.lylvs b/technology/scn4m_subm/tech/scn4m_subm.lylvs index 46a6c12a..4421d627 100644 --- a/technology/scn4m_subm/tech/scn4m_subm.lylvs +++ b/technology/scn4m_subm/tech/scn4m_subm.lylvs @@ -164,7 +164,7 @@ connect_global(pwell, "PWELL") connect_global(nwell, "NWELL") #connect_global(bulk, "BULK") -for pat in %w(pnand* and?_dec port_address* replica_bitcell_array) +for pat in %w(pinv* pnor* pnand* and?_dec* port_address* replica_bitcell_array*) connect_explicit(pat, [ "NWELL", "vdd" ]) connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) end From 5dc885a67445cf581cd4ea19058b1f91542edc59 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 29 Sep 2021 09:34:01 -0700 Subject: [PATCH 024/229] Update nwell spacing to be same potential --- technology/scn4m_subm/tech/scn4m_subm.lydrc | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/technology/scn4m_subm/tech/scn4m_subm.lydrc b/technology/scn4m_subm/tech/scn4m_subm.lydrc index 345f4a41..afaf01a8 100644 --- a/technology/scn4m_subm/tech/scn4m_subm.lydrc +++ b/technology/scn4m_subm/tech/scn4m_subm.lydrc @@ -161,7 +161,8 @@ R27_9 = ( 2 *LAMBDA ).round(3) if !SUBM && !DEEP R1_1 = ( 10 *LAMBDA ).round(3) - R1_2 = ( 9 *LAMBDA ).round(3) + R1_2 = ( 6 *LAMBDA ).round(3) + #R1_2 = ( 9 *LAMBDA ).round(3) R2_3 = ( 5 *LAMBDA ).round(3) R3_2 = ( 2 *LAMBDA ).round(3) R3_2_a = ( 2 *LAMBDA ).round(3) @@ -211,7 +212,10 @@ end if SUBM R1_1 = ( 12 *LAMBDA ).round(3) - R1_2 = ( 18 *LAMBDA ).round(3) + # We are assuming the wells are at the same potential since + # DRC can't tell otherwise + #R1_2 = ( 18 *LAMBDA ).round(3) + R1_2 = ( 6 *LAMBDA ).round(3) R2_3 = ( 6 *LAMBDA ).round(3) R3_2 = ( 3 *LAMBDA ).round(3) R3_2_a = ( 3 *LAMBDA ).round(3) @@ -301,7 +305,10 @@ end if DEEP R1_1 = ( 12 *LAMBDA ).round(3) - R1_2 = ( 18 *LAMBDA ).round(3) + # We are assuming the wells are at the same potential since + # DRC can't tell otherwise + #R1_2 = ( 18 *LAMBDA ).round(3) + R1_2 = ( 6 *LAMBDA ).round(3) R2_3 = ( 6 *LAMBDA ).round(3) R3_2 = ( 3 *LAMBDA ).round(3) R3_2_a = ( 4 *LAMBDA ).round(3) @@ -414,7 +421,7 @@ class DRC::DRCLayer end DRC::DRCLayer::new(@engine, new_data) end -end +end # layers definitions ######################## @@ -456,7 +463,7 @@ info("Layers definitions") # layers processing ######################## info("Layers processing") -#CHIP = extent.sized(1.0) +#CHIP = extent.sized(1.0) NP = AA & Nselect PP = AA & Pselect NSTP = NP.and(NW) From 5d33db0ee4c520bfb3c38fd083d2718d7882df0f Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 29 Sep 2021 10:00:54 -0700 Subject: [PATCH 025/229] Add write driver to well connect list --- technology/freepdk45/tech/freepdk45.lylvs | 2 +- technology/scn4m_subm/tech/scn4m_subm.lylvs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index bf4852d8..73a5c351 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -214,7 +214,7 @@ end #connect_global(nwell, "NWELL") #connect_global(bulk, "BULK") -for pat in %w(pinv* pnor* pnand* and?_dec* port_address* replica_bitcell_array*) +for pat in %w(pinv* pnor* pnand* and?_dec* write_driver* port_address* replica_bitcell_array*) connect_explicit(pat, [ "NWELL", "vdd" ]) connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) end diff --git a/technology/scn4m_subm/tech/scn4m_subm.lylvs b/technology/scn4m_subm/tech/scn4m_subm.lylvs index 4421d627..be9e8ac2 100644 --- a/technology/scn4m_subm/tech/scn4m_subm.lylvs +++ b/technology/scn4m_subm/tech/scn4m_subm.lylvs @@ -164,7 +164,7 @@ connect_global(pwell, "PWELL") connect_global(nwell, "NWELL") #connect_global(bulk, "BULK") -for pat in %w(pinv* pnor* pnand* and?_dec* port_address* replica_bitcell_array*) +for pat in %w(pinv* pnor* pnand* and?_dec* write_driver* port_address* replica_bitcell_array*) connect_explicit(pat, [ "NWELL", "vdd" ]) connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) end From 6ee4697711c2566fad10e9c72d80e06eb8a1f8c3 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 4 Oct 2021 14:14:07 -0700 Subject: [PATCH 026/229] Change cell names in lvs file --- technology/scn4m_subm/tech/scn4m_subm.lylvs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/technology/scn4m_subm/tech/scn4m_subm.lylvs b/technology/scn4m_subm/tech/scn4m_subm.lylvs index be9e8ac2..ea768eef 100644 --- a/technology/scn4m_subm/tech/scn4m_subm.lylvs +++ b/technology/scn4m_subm/tech/scn4m_subm.lylvs @@ -118,7 +118,7 @@ ngate = nactive & poly nsd = nactive - ngate -cheat("cell_6t", "dummy_cell_6t", "cell_1rw", "dummy_cell_1rw", "cell_2rw", "dummy_cell_2rw", "dff","wordline_driver_0") { +cheat("cell_1rw", "dummy_cell_1rw", "cell_2rw", "dummy_cell_2rw", "pbitcell", "dummy_pbitcell", "dff") { # PMOS transistor device extraction extract_devices(mos4("p"), { "SD" => psd, "G" => pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell }) From 8f296810bee73317b5fe5ccbca314a442f941d86 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 3 Nov 2021 11:53:30 -0700 Subject: [PATCH 027/229] Fix cheat on wordline driver name. --- technology/freepdk45/tech/freepdk45.lylvs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index 73a5c351..e4587656 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -135,7 +135,7 @@ lv_ngate = ngate - vtg - thkox gv_ngate = ngate & vtg - vth - thkox hv_ngate = ngate - vtg - vth & thkox -cheat("cell_6t", "dummy_cell_6t", "cell_1rw", "dummy_cell_1rw", "cell_2rw", "dummy_cell_2rw", "dff","wordline_driver_0") { +cheat("cell_6t", "dummy_cell_6t", "cell_1rw", "dummy_cell_1rw", "replica_cell_1rw", "cell_2rw", "dummy_cell_2rw", "replica_cell_2rw", "dff","wordline_driver*") { # PMOS transistor device extraction extract_devices(mos4("PMOS_VTL"), { "SD" => psd, "G" => lv_pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell }) @@ -206,13 +206,13 @@ connect(metal10, metal10_pin) schematic.simplify if $connect_supplies - connect_implicit("vdd") - connect_implicit("gnd") +connect_implicit("*", "vdd") +connect_implicit("*", "gnd") end -#connect_global(pwell, "PWELL") -#connect_global(nwell, "NWELL") -#connect_global(bulk, "BULK") +connect_global(pwell, "PWELL") +connect_global(nwell, "NWELL") +connect_global(bulk, "BULK") for pat in %w(pinv* pnor* pnand* and?_dec* write_driver* port_address* replica_bitcell_array*) connect_explicit(pat, [ "NWELL", "vdd" ]) From 43bbd2e722d3ca4ebfcf4b5fe08eaacd7d361945 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 3 Nov 2021 12:05:55 -0700 Subject: [PATCH 028/229] Fixed incorrect via2 spacing rule in tech file. --- technology/freepdk45/tech/tech.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index 2ae9c06c..9303ba3d 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -337,7 +337,7 @@ drc.add_enclosure("m2", # VIA2-3.2 Minimum spacing of Via[2-3] drc.add_layer("via2", width=0.065, - spacing=0.075) + spacing=0.085) # METALINT.1 Minimum width of intermediate metal # METALINT.2 Minimum spacing of intermediate metal From b7362ba011b0d0d5bb2c5b02163103a0e071a08b Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 8 Nov 2021 14:27:41 -0800 Subject: [PATCH 029/229] Do not run same well spacing for backwards compatibility. Add pbitcell cheat. --- compiler/bitcells/pbitcell.py | 6 ++---- technology/freepdk45/tech/freepdk45.lydrc | 5 +++-- technology/freepdk45/tech/freepdk45.lylvs | 2 +- technology/scn4m_subm/tech/scn4m_subm.lylvs | 2 +- technology/scn4m_subm/tech/tech.py | 6 +++--- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/compiler/bitcells/pbitcell.py b/compiler/bitcells/pbitcell.py index 71679bd1..d605f492 100644 --- a/compiler/bitcells/pbitcell.py +++ b/compiler/bitcells/pbitcell.py @@ -425,7 +425,6 @@ class pbitcell(bitcell_base.bitcell_base): width=self.width) self.add_power_pin("gnd", vector(0, gnd_ypos), directions=("H", "H")) - vdd_ypos = self.inverter_nmos_ypos \ + self.inverter_nmos.active_height \ + self.inverter_gap \ @@ -1013,7 +1012,7 @@ class pbitcell(bitcell_base.bitcell_base): well_height = max_nmos_well_height + self.port_ypos \ - self.nwell_enclose_active - self.gnd_position.y # FIXME fudge factor xpos - well_width = self.width + 2*self.nwell_enclose_active + well_width = self.width + 2 * self.nwell_enclose_active offset = vector(self.leftmost_xpos - self.nwell_enclose_active, self.botmost_ypos) self.add_rect(layer="pwell", offset=offset, @@ -1163,7 +1162,7 @@ class pbitcell(bitcell_base.bitcell_base): return pin_dict = {pin: port for pin, port in zip(self.pins, port_nets)} - + # Edges added wl->bl, wl->br for every port except write ports rw_pin_names = zip(self.r_wl_names, self.r_bl_names, self.r_br_names) r_pin_names = zip(self.rw_wl_names, self.rw_bl_names, self.rw_br_names) @@ -1172,4 +1171,3 @@ class pbitcell(bitcell_base.bitcell_base): for wl, bl, br in pin_zip: graph.add_edge(pin_dict[wl], pin_dict[bl], self) graph.add_edge(pin_dict[wl], pin_dict[br], self) - diff --git a/technology/freepdk45/tech/freepdk45.lydrc b/technology/freepdk45/tech/freepdk45.lydrc index 91c7c30f..0c380c50 100644 --- a/technology/freepdk45/tech/freepdk45.lydrc +++ b/technology/freepdk45/tech/freepdk45.lydrc @@ -110,8 +110,9 @@ end # Wells nwell.and(pwell).output("WELL.1", "WELL.1 : nwell/pwell must not overlap") # the rule "WELL.2 : Minimum spacing of well at different potential : 225nm" was not coded : see : https://www.klayout.de/forum/discussion/comment/6021 -nwell.space(135.nm, euclidian).output("WELL.3", "WELL.3 : Minimum spacing of nwell at same potential : 135nm") -pwell.space(135.nm, euclidian).output("WELL.3", "WELL.3 : Minimum spacing of pwell at same potential : 135nm") +# the rule WELL.3 was not detected in the original FreePDK45 rule deck +#nwell.space(135.nm, euclidian).output("WELL.3", "WELL.3 : Minimum spacing of nwell at same potential : 135nm") +#pwell.space(135.nm, euclidian).output("WELL.3", "WELL.3 : Minimum spacing of pwell at same potential : 135nm") well.separation(well, 200.nm, euclidian).output("WELL.4", "WELL.4 : Minimum width of nwell/pwell : 200nm") vtg.not(well).output("VT.1","VT.1 : Vtg adjust layers must coincide with well") vth.not(well).output("VT.1","VT.1 : Vth adjust layers must coincide with well") diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index e4587656..9c3b5971 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -135,7 +135,7 @@ lv_ngate = ngate - vtg - thkox gv_ngate = ngate & vtg - vth - thkox hv_ngate = ngate - vtg - vth & thkox -cheat("cell_6t", "dummy_cell_6t", "cell_1rw", "dummy_cell_1rw", "replica_cell_1rw", "cell_2rw", "dummy_cell_2rw", "replica_cell_2rw", "dff","wordline_driver*") { +cheat("cell_1rw", "dummy_cell_1rw", "replica_cell_1rw", "cell_2rw", "dummy_cell_2rw", "replica_cell_2rw", "pbitcell", "dummy_pbitcell", "replica_pbitcell", "dff", "wordline_driver*") { # PMOS transistor device extraction extract_devices(mos4("PMOS_VTL"), { "SD" => psd, "G" => lv_pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell }) diff --git a/technology/scn4m_subm/tech/scn4m_subm.lylvs b/technology/scn4m_subm/tech/scn4m_subm.lylvs index ea768eef..7a7c1371 100644 --- a/technology/scn4m_subm/tech/scn4m_subm.lylvs +++ b/technology/scn4m_subm/tech/scn4m_subm.lylvs @@ -118,7 +118,7 @@ ngate = nactive & poly nsd = nactive - ngate -cheat("cell_1rw", "dummy_cell_1rw", "cell_2rw", "dummy_cell_2rw", "pbitcell", "dummy_pbitcell", "dff") { +cheat("cell_1rw", "dummy_cell_1rw", "replica_cell_1rw", "cell_2rw", "dummy_cell_2rw", "replica_cell_2rw", "pbitcell", "dummy_pbitcell", "replica_pbitcell", "dff", "wordline_driver*") { # PMOS transistor device extraction extract_devices(mos4("p"), { "SD" => psd, "G" => pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell }) diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index 374ba4c8..ee63203c 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -428,8 +428,8 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa drc_name = "magic" lvs_name = "netgen" pex_name = "magic" -drc_name = "klayout" -lvs_name = "klayout" -pex_name = "klayout" +# drc_name = "klayout" +# lvs_name = "klayout" +# pex_name = "klayout" blackbox_bitcell = False From 552811b41bed2900d8d0974383a66981d0cdcf58 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 16 Nov 2021 14:37:24 -0800 Subject: [PATCH 030/229] Use klayout in SCMOS too. --- technology/scn4m_subm/tech/tech.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index ee63203c..374ba4c8 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -428,8 +428,8 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa drc_name = "magic" lvs_name = "netgen" pex_name = "magic" -# drc_name = "klayout" -# lvs_name = "klayout" -# pex_name = "klayout" +drc_name = "klayout" +lvs_name = "klayout" +pex_name = "klayout" blackbox_bitcell = False From 735f9cf450e647df4a9b2ea31eb1a42ddd9fc29a Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 19 Nov 2021 13:43:54 -0800 Subject: [PATCH 031/229] Remove klayout from scmos --- technology/scn4m_subm/tech/tech.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index 374ba4c8..a8c44996 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -428,8 +428,5 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa drc_name = "magic" lvs_name = "netgen" pex_name = "magic" -drc_name = "klayout" -lvs_name = "klayout" -pex_name = "klayout" blackbox_bitcell = False From b94dd79125201cada139697a4f1408dfac0fa839 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 22 Nov 2021 10:37:26 -0800 Subject: [PATCH 032/229] Add labels to noconn in dummy bitcell for klayout lvs --- compiler/bitcells/pbitcell.py | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/compiler/bitcells/pbitcell.py b/compiler/bitcells/pbitcell.py index d605f492..aaa403dd 100644 --- a/compiler/bitcells/pbitcell.py +++ b/compiler/bitcells/pbitcell.py @@ -474,6 +474,7 @@ class pbitcell(bitcell_base.bitcell_base): self.connect_inst([self.Q_bar, self.rw_wl_names[k], br_name, "gnd"]) + def place_readwrite_ports(self): """ Places read/write ports in the bit cell """ # define read/write transistor variables as empty arrays @@ -528,6 +529,21 @@ class pbitcell(bitcell_base.bitcell_base): offset=self.rwbr_positions[k], height=self.height) + if self.dummy_bitcell: + bl_name = self.rw_bl_names[k] + br_name = self.rw_br_names[k] + bl_name += "_noconn" + br_name += "_noconn" + + # This helps with LVS matching in klayout + drain_pin = self.readwrite_nmos_left[k].get_pin("S") + self.add_label(bl_name, drain_pin.layer, drain_pin.center()) + + # This helps with LVS matching in klayout + source_pin = self.readwrite_nmos_right[k].get_pin("D") + self.add_label(br_name, source_pin.layer, source_pin.center()) + + # update furthest left and right transistor edges self.left_building_edge = left_readwrite_transistor_xpos self.right_building_edge = right_readwrite_transistor_xpos \ @@ -625,6 +641,20 @@ class pbitcell(bitcell_base.bitcell_base): offset=self.wbr_positions[k], height=self.height) + if self.dummy_bitcell: + bl_name = self.w_bl_names[k] + br_name = self.w_br_names[k] + bl_name += "_noconn" + br_name += "_noconn" + + # This helps with LVS matching in klayout + drain_pin = self.write_nmos_left[k].get_pin("S") + self.add_label(bl_name, drain_pin.layer, drain_pin.center()) + + # This helps with LVS matching in klayout + source_pin = self.write_nmos_right[k].get_pin("D") + self.add_label(br_name, source_pin.layer, source_pin.center()) + # update furthest left and right transistor edges self.left_building_edge = left_write_transistor_xpos self.right_building_edge = right_write_transistor_xpos \ @@ -752,6 +782,20 @@ class pbitcell(bitcell_base.bitcell_base): offset=self.rbr_positions[k], height=self.height) + if self.dummy_bitcell: + bl_name = self.r_bl_names[k] + br_name = self.r_br_names[k] + bl_name += "_noconn" + br_name += "_noconn" + + # This helps with LVS matching in klayout + drain_pin = self.read_access_nmos_left[k].get_pin("S") + self.add_label(bl_name, drain_pin.layer, drain_pin.center()) + + # This helps with LVS matching in klayout + source_pin = self.read_access_nmos_right[k].get_pin("D") + self.add_label(br_name, source_pin.layer, source_pin.center()) + def route_wordlines(self): """ Routes gate of transistors to their respective wordlines """ port_transistors = [] From 0c3ee643ab5b64ed2cb64a8e7821757e69c8e7d5 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 22 Nov 2021 10:51:40 -0800 Subject: [PATCH 033/229] Remove add_mod and add module whenever calling add_inst. --- compiler/base/hierarchy_layout.py | 4 +--- compiler/base/hierarchy_spice.py | 22 ++++++++----------- compiler/bitcells/dummy_pbitcell.py | 1 - compiler/bitcells/pbitcell.py | 5 ----- compiler/bitcells/replica_pbitcell.py | 2 -- compiler/modules/and2_dec.py | 3 --- compiler/modules/and3_dec.py | 3 --- compiler/modules/and4_dec.py | 4 ---- compiler/modules/bank.py | 5 ----- compiler/modules/bank_select.py | 5 ----- compiler/modules/bitcell_array.py | 5 ++--- compiler/modules/col_cap_array.py | 4 +--- compiler/modules/column_mux_array.py | 1 - compiler/modules/control_logic.py | 17 ++------------- compiler/modules/delay_chain.py | 8 +++---- compiler/modules/dff_array.py | 1 - compiler/modules/dff_buf.py | 5 +---- compiler/modules/dff_buf_array.py | 1 - compiler/modules/dff_inv.py | 7 ++---- compiler/modules/dff_inv_array.py | 1 - compiler/modules/dummy_array.py | 1 - compiler/modules/global_bitcell_array.py | 3 --- compiler/modules/hierarchical_decoder.py | 6 ------ compiler/modules/hierarchical_predecode.py | 17 ++++++--------- compiler/modules/local_bitcell_array.py | 2 -- compiler/modules/multibank.py | 11 ---------- compiler/modules/orig_bitcell_array.py | 1 - compiler/modules/port_address.py | 6 +----- compiler/modules/port_data.py | 11 +++------- compiler/modules/precharge_array.py | 5 +---- compiler/modules/replica_bitcell_array.py | 13 +++-------- compiler/modules/replica_column.py | 12 +++++------ compiler/modules/row_cap_array.py | 4 +--- compiler/modules/sense_amp_array.py | 1 - compiler/modules/tri_gate_array.py | 3 +-- compiler/modules/wordline_buffer_array.py | 1 - compiler/modules/wordline_driver_array.py | 2 -- compiler/modules/write_driver_array.py | 2 -- compiler/modules/write_mask_and_array.py | 4 +--- compiler/pgates/column_mux.py | 1 - compiler/pgates/pand2.py | 9 +++----- compiler/pgates/pand3.py | 3 --- compiler/pgates/pand4.py | 4 ---- compiler/pgates/pbuf.py | 3 --- compiler/pgates/pbuf_dec.py | 2 -- compiler/pgates/pdriver.py | 1 - compiler/pgates/pinv.py | 21 ++++++++---------- compiler/pgates/pinvbuf.py | 3 --- compiler/pgates/pnand2.py | 22 +++++++------------ compiler/pgates/pnand3.py | 25 ++++++++-------------- compiler/pgates/pnand4.py | 6 ------ compiler/pgates/pnor2.py | 4 ---- compiler/pgates/precharge.py | 2 -- compiler/pgates/ptristate_inv.py | 2 -- compiler/pgates/pwrite_driver.py | 3 --- compiler/pgates/wordline_driver.py | 3 --- compiler/sram/sram_base.py | 21 +++++------------- technology/freepdk45/tech/freepdk45.lylvs | 2 +- 58 files changed, 78 insertions(+), 268 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 8bbc72c7..c30408c7 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -232,6 +232,7 @@ class layout(): # Check that the instance name is unique debug.check(name not in self.inst_names, "Duplicate named instance in {0}: {1}".format(self.cell_name, name)) + self.mods.add(mod) self.inst_names.add(name) self.insts.append(geometry.instance(name, mod, offset, mirror, rotate)) debug.info(3, "adding instance {}".format(self.insts[-1])) @@ -638,7 +639,6 @@ class layout(): directions=directions, implant_type=implant_type, well_type=well_type) - self.add_mod(via) inst = self.add_inst(name=via.name, mod=via, offset=offset) @@ -664,7 +664,6 @@ class layout(): corrected_offset = offset + vector(-0.5 * width, -0.5 * height) - self.add_mod(via) inst = self.add_inst(name=via.name, mod=via, offset=corrected_offset) @@ -756,7 +755,6 @@ class layout(): mos = ptx.ptx(width=width, mults=mults, tx_type=tx_type) - self.add_mod(mos) inst = self.add_inst(name=mos.name, mod=mos, offset=offset, diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index 5a10ff97..33ac02b9 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -45,10 +45,10 @@ class spice(): self.lvs_file = lvs_dir + cell_name + ".sp" else: self.lvs_file = self.sp_file - + self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "BIAS", "POWER", "GROUND"] # Holds subckts/mods for this module - self.mods = [] + self.mods = set() # Holds the pins for this module (in order) self.pins = [] # The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND @@ -128,7 +128,7 @@ class spice(): new_list = [input_list[x] for x in self.pin_indices] return new_list - + def add_pin_types(self, type_list): """ Add pin types for all the cell's pins. @@ -140,7 +140,7 @@ class spice(): \n Module names={}\ ".format(self.name, self.pins, type_list), 1) self.pin_type = {pin: type for pin, type in zip(self.pins, type_list)} - + def get_pin_type(self, name): """ Returns the type of the signal pin. """ pin_type = self.pin_type[name] @@ -187,10 +187,6 @@ class spice(): inout_list.append(pin) return inout_list - def add_mod(self, mod): - """Adds a subckt/submodule to the subckt hierarchy""" - self.mods.append(mod) - def connect_inst(self, args, check=True): """ Connects the pins of the last instance added @@ -199,13 +195,13 @@ class spice(): where we dynamically generate groups of connections after a group of modules are generated. """ - + num_pins = len(self.insts[-1].mod.pins) num_args = len(args) # Order the arguments if the hard cell has a custom port order ordered_args = self.get_ordered_inputs(args) - + if (check and num_pins != num_args): if num_pins < num_args: mod_pins = self.insts[-1].mod.pins + [""] * (num_args - num_pins) @@ -372,15 +368,15 @@ class spice(): # these are wires and paths if self.conns[i] == []: continue - + # Instance with no devices in it needs no subckt/instance if self.insts[i].mod.no_instances: continue - + # If this is a trimmed netlist, skip it by adding comment char if trim and self.insts[i].name in self.trim_insts: sp.write("* ") - + if lvs and hasattr(self.insts[i].mod, "lvs_device"): sp.write(self.insts[i].mod.lvs_device.format(self.insts[i].name, " ".join(self.conns[i]))) diff --git a/compiler/bitcells/dummy_pbitcell.py b/compiler/bitcells/dummy_pbitcell.py index c2082033..7cf8f664 100644 --- a/compiler/bitcells/dummy_pbitcell.py +++ b/compiler/bitcells/dummy_pbitcell.py @@ -56,7 +56,6 @@ class dummy_pbitcell(design.design): def add_modules(self): self.prbc = factory.create(module_type="pbitcell", dummy_bitcell=True) - self.add_mod(self.prbc) self.height = self.prbc.height self.width = self.prbc.width diff --git a/compiler/bitcells/pbitcell.py b/compiler/bitcells/pbitcell.py index aaa403dd..fc131d0f 100644 --- a/compiler/bitcells/pbitcell.py +++ b/compiler/bitcells/pbitcell.py @@ -179,26 +179,21 @@ class pbitcell(bitcell_base.bitcell_base): # create ptx for inverter transistors self.inverter_nmos = ptx(width=inverter_nmos_width, tx_type="nmos") - self.add_mod(self.inverter_nmos) self.inverter_pmos = ptx(width=inverter_pmos_width, tx_type="pmos") - self.add_mod(self.inverter_pmos) # create ptx for readwrite transitors self.readwrite_nmos = ptx(width=readwrite_nmos_width, tx_type="nmos") - self.add_mod(self.readwrite_nmos) # create ptx for write transitors self.write_nmos = ptx(width=write_nmos_width, tx_type="nmos") - self.add_mod(self.write_nmos) # create ptx for read transistors self.read_nmos = ptx(width=read_nmos_width, tx_type="nmos") - self.add_mod(self.read_nmos) def calculate_spacing(self): """ Calculate transistor spacings """ diff --git a/compiler/bitcells/replica_pbitcell.py b/compiler/bitcells/replica_pbitcell.py index e3212d6d..bf2fa032 100644 --- a/compiler/bitcells/replica_pbitcell.py +++ b/compiler/bitcells/replica_pbitcell.py @@ -58,7 +58,6 @@ class replica_pbitcell(design.design): def add_modules(self): self.prbc = factory.create(module_type="pbitcell", replica_bitcell=True) - self.add_mod(self.prbc) self.height = self.prbc.height self.width = self.prbc.width @@ -88,4 +87,3 @@ class replica_pbitcell(design.design): self.copy_layout_pin(self.prbc_inst, "wl{}".format(port)) self.copy_layout_pin(self.prbc_inst, "vdd") self.copy_layout_pin(self.prbc_inst, "gnd") - diff --git a/compiler/modules/and2_dec.py b/compiler/modules/and2_dec.py index d448e3ff..92130b7b 100644 --- a/compiler/modules/and2_dec.py +++ b/compiler/modules/and2_dec.py @@ -43,9 +43,6 @@ class and2_dec(design.design): height=self.height, size=self.size) - self.add_mod(self.nand) - self.add_mod(self.inv) - def create_layout(self): if "li" in layer: diff --git a/compiler/modules/and3_dec.py b/compiler/modules/and3_dec.py index 410b2379..6f788824 100644 --- a/compiler/modules/and3_dec.py +++ b/compiler/modules/and3_dec.py @@ -41,9 +41,6 @@ class and3_dec(design.design): height=self.height, size=self.size) - self.add_mod(self.nand) - self.add_mod(self.inv) - def create_layout(self): if "li" in layer: self.route_layer = "li" diff --git a/compiler/modules/and4_dec.py b/compiler/modules/and4_dec.py index 99026bab..879f581b 100644 --- a/compiler/modules/and4_dec.py +++ b/compiler/modules/and4_dec.py @@ -43,9 +43,6 @@ class and4_dec(design.design): height=self.height, size=self.size) - self.add_mod(self.nand) - self.add_mod(self.inv) - def create_layout(self): if "li" in layer: self.route_layer = "li" @@ -129,4 +126,3 @@ class and4_dec(design.design): offset=pin.center(), width=pin.width(), height=pin.height()) - diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 7a36abf6..bd3fc0a4 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -389,7 +389,6 @@ class bank(design.design): self.bitcell_array = factory.create(module_type="replica_bitcell_array", cols=self.num_cols + self.num_spare_cols, rows=self.num_rows) - self.add_mod(self.bitcell_array) self.port_address = [] for port in self.all_ports: @@ -397,7 +396,6 @@ class bank(design.design): cols=self.num_cols + self.num_spare_cols, rows=self.num_rows, port=port)) - self.add_mod(self.port_address[port]) self.port_data = [] self.bit_offsets = self.get_column_offsets() @@ -407,11 +405,9 @@ class bank(design.design): port=port, bit_offsets=self.bit_offsets) self.port_data.append(temp_pre) - self.add_mod(self.port_data[port]) if(self.num_banks > 1): self.bank_select = factory.create(module_type="bank_select") - self.add_mod(self.bank_select) def create_bitcell_array(self): """ Creating Bitcell Array """ @@ -547,7 +543,6 @@ class bank(design.design): else: # No error checking before? debug.error("Invalid column decoder?", -1) - self.add_mod(self.column_decoder) self.column_decoder_inst = [None] * len(self.all_ports) for port in self.all_ports: diff --git a/compiler/modules/bank_select.py b/compiler/modules/bank_select.py index dcaec9d7..9b375c00 100644 --- a/compiler/modules/bank_select.py +++ b/compiler/modules/bank_select.py @@ -78,20 +78,15 @@ class bank_select(design.design): # 1x Inverter self.inv_sel = factory.create(module_type="pinv", height=height) - self.add_mod(self.inv_sel) # 4x Inverter self.inv4x = factory.create(module_type="pinv", height=height, size=4) - self.add_mod(self.inv4x) self.nor2 = factory.create(module_type="pnor2", height=height) - self.add_mod(self.nor2) self.inv4x_nor = factory.create(module_type="pinv", height=height, size=4) - self.add_mod(self.inv4x_nor) self.nand2 = factory.create(module_type="pnand2", height=height) - self.add_mod(self.nand2) def calculate_module_offsets(self): diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index 238d499f..d08e3f48 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -53,7 +53,6 @@ class bitcell_array(bitcell_base_array): def add_modules(self): """ Add the modules used in this design """ self.cell = factory.create(module_type=OPTS.bitcell) - self.add_mod(self.cell) def create_instances(self): """ Create the module instances used in this design """ @@ -64,11 +63,11 @@ class bitcell_array(bitcell_base_array): self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell) self.connect_inst(self.get_bitcell_pins(row, col)) - + # If it is a "core" cell, it could be trimmed for sim time if col>0 and col0 and row 1 else []) - self.add_mod(la) self.local_mods.append(la) return @@ -90,7 +89,6 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): cols=cols, rbl=self.rbl) - self.add_mod(la) self.local_mods.append(la) def add_pins(self): @@ -344,4 +342,3 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): """Exclude dffs from graph as they do not represent critical path""" self.graph_inst_exclude.add(self.ctrl_dff_inst) - diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index 24267719..c0f42ac8 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -69,14 +69,11 @@ class hierarchical_decoder(design.design): def add_modules(self): self.and2 = factory.create(module_type="and2_dec", height=self.cell_height) - self.add_mod(self.and2) self.and3 = factory.create(module_type="and3_dec", height=self.cell_height) - self.add_mod(self.and3) # TBD # self.and4 = factory.create(module_type="and4_dec") - # self.add_mod(self.and4) self.add_decoders() @@ -84,15 +81,12 @@ class hierarchical_decoder(design.design): """ Create the decoders based on the number of pre-decodes """ self.pre2_4 = factory.create(module_type="hierarchical_predecode2x4", height=self.cell_height) - self.add_mod(self.pre2_4) self.pre3_8 = factory.create(module_type="hierarchical_predecode3x8", height=self.cell_height) - self.add_mod(self.pre3_8) self.pre4_16 = factory.create(module_type="hierarchical_predecode4x16", height=self.cell_height) - self.add_mod(self.pre4_16) def determine_predecodes(self, num_inputs): """ diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index 30908c4c..a8da372a 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -31,7 +31,7 @@ class hierarchical_predecode(design.design): self.cell_height = b.height else: self.cell_height = height - + self.column_decoder = column_decoder self.input_and_rail_pos = [] self.number_of_outputs = int(math.pow(2, self.number_of_inputs)) @@ -59,13 +59,11 @@ class hierarchical_predecode(design.design): inv_type = "inv_dec" self.and_mod = factory.create(module_type=and_type, height=self.cell_height) - self.add_mod(self.and_mod) # This uses the pinv_dec parameterized cell self.inv = factory.create(module_type=inv_type, height=self.cell_height, size=1) - self.add_mod(self.inv) def create_layout(self): """ The general organization is from left to right: @@ -189,13 +187,13 @@ class hierarchical_predecode(design.design): self.route_input_inverters() self.route_input_ands() self.route_output_inverters() - self.route_inputs_to_rails() + self.route_inputs_to_rails() self.route_output_ands() self.route_vdd_gnd() def route_inputs_to_rails(self): """ Route the uninverted inputs to the second set of rails """ - + top_and_gate = self.and_inst[-1] for num in range(self.number_of_inputs): if num == 0: @@ -221,7 +219,7 @@ class hierarchical_predecode(design.design): to_layer=self.bus_layer, offset=[self.input_rails[in_pin].cx(), y_offset], directions= ("H", "H")) - + self.add_via_stack_center(from_layer=self.input_layer, to_layer=self.bus_layer, offset=[self.decode_rails[a_pin].cx(), y_offset], @@ -306,7 +304,7 @@ class hierarchical_predecode(design.design): else: # grow the stack down search_id = 2 next_id = 0 - + curr_stack = next(filter(lambda stack: stack[search_id] == cur_layer, layer_stacks), None) via = factory.create(module_type="contact", @@ -343,7 +341,7 @@ class hierarchical_predecode(design.design): """ Route the different permutations of the NAND/AND decocer cells. """ - + # This 2D array defines the connection mapping and_input_line_combination = self.get_and_input_line_combination() for k in range(self.number_of_outputs): @@ -419,6 +417,3 @@ class hierarchical_predecode(design.design): self.and_inst[0].lx() - self.bus_space]: pin_pos = vector(xoffset, and_pin.cy()) self.copy_power_pin(and_pin, loc=pin_pos) - - - diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index 6049f3b1..49e8ed76 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -73,12 +73,10 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): rbl=self.rbl, left_rbl=self.left_rbl, right_rbl=self.right_rbl) - self.add_mod(self.bitcell_array) self.wl_array = factory.create(module_type="wordline_buffer_array", rows=self.rows + 1, cols=self.cols) - self.add_mod(self.wl_array) def add_pins(self): # Outputs from the wordline driver (by port) diff --git a/compiler/modules/multibank.py b/compiler/modules/multibank.py index 408c91c5..45f46496 100644 --- a/compiler/modules/multibank.py +++ b/compiler/modules/multibank.py @@ -172,47 +172,36 @@ class multibank(design.design): self.bitcell_array = self.mod_bitcell_array(cols=self.num_cols, rows=self.num_rows) - self.add_mod(self.bitcell_array) self.precharge_array = self.mod_precharge_array(columns=self.num_cols) - self.add_mod(self.precharge_array) if self.col_addr_size > 0: self.column_mux_array = self.mod_column_mux_array(columns=self.num_cols, word_size=self.word_size) - self.add_mod(self.column_mux_array) self.sense_amp_array = self.mod_sense_amp_array(word_size=self.word_size, words_per_row=self.words_per_row) - self.add_mod(self.sense_amp_array) if self.write_size: self.write_mask_driver_array = self.mod_write_mask_driver_array(columns=self.num_cols, word_size=self.word_size, write_size=self.write_size) - self.add_mod(self.write_mask_driver_array) else: self.write_driver_array = self.mod_write_driver_array(columns=self.num_cols, word_size=self.word_size) - self.add_mod(self.write_driver_array) self.row_decoder = self.mod_decoder(rows=self.num_rows) - self.add_mod(self.row_decoder) self.tri_gate_array = self.mod_tri_gate_array(columns=self.num_cols, word_size=self.word_size) - self.add_mod(self.tri_gate_array) self.wordline_driver = self.mod_wordline_driver(rows=self.num_rows) - self.add_mod(self.wordline_driver) self.inv = pinv() - self.add_mod(self.inv) if(self.num_banks > 1): self.bank_select = self.mod_bank_select() - self.add_mod(self.bank_select) def add_bitcell_array(self): diff --git a/compiler/modules/orig_bitcell_array.py b/compiler/modules/orig_bitcell_array.py index 42ebdc33..ab154bec 100644 --- a/compiler/modules/orig_bitcell_array.py +++ b/compiler/modules/orig_bitcell_array.py @@ -47,7 +47,6 @@ class bitcell_array(bitcell_base_array): def add_modules(self): """ Add the modules used in this design """ self.cell = factory.create(module_type=OPTS.bitcell) - self.add_mod(self.cell) def create_instances(self): """ Create the module instances used in this design """ diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index 0f456a2d..27dd7e6a 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -145,12 +145,10 @@ class port_address(design.design): self.row_decoder = factory.create(module_type="decoder", num_outputs=self.num_rows) - self.add_mod(self.row_decoder) self.wordline_driver_array = factory.create(module_type="wordline_driver_array", rows=self.num_rows, cols=self.num_cols) - self.add_mod(self.wordline_driver_array) local_array_size = OPTS.local_array_size if local_array_size > 0: @@ -174,8 +172,6 @@ class port_address(design.design): size=driver_size, height=b.height) - self.add_mod(self.rbl_driver) - def create_row_decoder(self): """ Create the hierarchical row decoder """ @@ -235,7 +231,7 @@ class port_address(design.design): # The wordline driver also had an extra gap on the right, so use this offset well_gap = 2 * drc("pwell_to_nwell") + drc("nwell_enclose_active") x_offset = self.wordline_driver_array_inst.rx() - well_gap - self.rbl_driver.width - + if self.port == 0: rbl_driver_offset = vector(x_offset, 0) diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index 01ddad8a..aca8cd02 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -29,7 +29,7 @@ class port_data(design.design): self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) else: self.num_wmasks = 0 - + if num_spare_cols is not None: self.num_spare_cols = num_spare_cols + self.num_spare_cols if self.num_spare_cols is None: @@ -215,7 +215,6 @@ class port_data(design.design): bitcell_bl=self.bl_names[self.port], bitcell_br=self.br_names[self.port], column_offset=self.port - 1) - self.add_mod(self.precharge_array) if self.port in self.read_ports: # RBLs don't get a sense amp @@ -224,7 +223,6 @@ class port_data(design.design): offsets=self.bit_offsets, words_per_row=self.words_per_row, num_spare_cols=self.num_spare_cols) - self.add_mod(self.sense_amp_array) else: self.sense_amp_array = None @@ -236,7 +234,6 @@ class port_data(design.design): offsets=self.bit_offsets, bitcell_bl=self.bl_names[self.port], bitcell_br=self.br_names[self.port]) - self.add_mod(self.column_mux_array) else: self.column_mux_array = None @@ -248,7 +245,6 @@ class port_data(design.design): offsets=self.bit_offsets, write_size=self.write_size, num_spare_cols=self.num_spare_cols) - self.add_mod(self.write_driver_array) if self.write_size is not None: # RBLs don't get a write mask self.write_mask_and_array = factory.create(module_type="write_mask_and_array", @@ -256,7 +252,6 @@ class port_data(design.design): offsets=self.bit_offsets, word_size=self.word_size, write_size=self.write_size) - self.add_mod(self.write_mask_and_array) else: self.write_mask_and_array = None @@ -858,10 +853,10 @@ class port_data(design.design): """ if self.column_mux_array: self.column_mux_array.graph_exclude_columns(column_include_num) - + def graph_clear_column_mux(self): """ Clear mux exclusions to allow different bit tests. """ if self.column_mux_array: - self.column_mux_array.init_graph_params() + self.column_mux_array.init_graph_params() diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index ed19b387..4ff6930e 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -76,8 +76,7 @@ class precharge_array(design.design): size=self.size, bitcell_bl=self.bitcell_bl, bitcell_br=self.bitcell_br) - - self.add_mod(self.pc_cell) + self.cell = factory.create(module_type=OPTS.bitcell) def add_layout_pins(self): @@ -130,5 +129,3 @@ class precharge_array(design.design): offset = vector(tempx, 0) self.local_insts[i].place(offset=offset, mirror=mirror) - - diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index baf83964..a459c266 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -110,7 +110,6 @@ class replica_bitcell_array(bitcell_base_array): column_offset=1 + len(self.left_rbl), cols=self.column_size, rows=self.row_size) - self.add_mod(self.bitcell_array) # Replica bitlines self.replica_columns = {} @@ -138,7 +137,6 @@ class replica_bitcell_array(bitcell_base_array): rbl=self.rbl, column_offset=column_offset, replica_bit=replica_bit) - self.add_mod(self.replica_columns[port]) # Dummy row self.dummy_row = factory.create(module_type="dummy_array", @@ -147,7 +145,6 @@ class replica_bitcell_array(bitcell_base_array): # dummy column + left replica column column_offset=1 + len(self.left_rbl), mirror=0) - self.add_mod(self.dummy_row) # Dummy Row or Col Cap, depending on bitcell array properties col_cap_module_type = ("col_cap_array" if self.cell.end_caps else "dummy_array") @@ -158,7 +155,6 @@ class replica_bitcell_array(bitcell_base_array): column_offset=1 + len(self.left_rbl), mirror=0, location="top") - self.add_mod(self.col_cap_top) self.col_cap_bottom = factory.create(module_type=col_cap_module_type, cols=self.column_size, @@ -167,7 +163,6 @@ class replica_bitcell_array(bitcell_base_array): column_offset=1 + len(self.left_rbl), mirror=0, location="bottom") - self.add_mod(self.col_cap_bottom) # Dummy Col or Row Cap, depending on bitcell array properties row_cap_module_type = ("row_cap_array" if self.cell.end_caps else "dummy_array") @@ -177,7 +172,6 @@ class replica_bitcell_array(bitcell_base_array): column_offset=0, rows=self.row_size + self.extra_rows, mirror=(self.rbl[0] + 1) % 2) - self.add_mod(self.row_cap_left) self.row_cap_right = factory.create(module_type=row_cap_module_type, cols=1, @@ -188,7 +182,6 @@ class replica_bitcell_array(bitcell_base_array): column_offset=1 + len(self.left_rbl) + self.column_size + self.rbl[0], rows=self.row_size + self.extra_rows, mirror=(self.rbl[0] + 1) %2) - self.add_mod(self.row_cap_right) def add_pins(self): @@ -401,7 +394,7 @@ class replica_bitcell_array(bitcell_base_array): dummy_row_offset = self.bitcell_offset.scale(0, self.rbl[1] + flip_dummy) + self.bitcell_array_inst.ul() self.dummy_row_insts[1].place(offset=dummy_row_offset, mirror="MX" if flip_dummy else "R0") - + # Far bottom dummy row (first row below array IS flipped) flip_dummy = (self.rbl[0] + 1) % 2 dummy_row_offset = self.bitcell_offset.scale(0, -self.rbl[0] - 1 + flip_dummy) + self.unused_offset @@ -411,7 +404,7 @@ class replica_bitcell_array(bitcell_base_array): # Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array dummy_col_offset = self.bitcell_offset.scale(-len(self.left_rbl) - 1, -self.rbl[0] - 1) + self.unused_offset self.dummy_col_insts[0].place(offset=dummy_col_offset) - + # Far right dummy col # Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array dummy_col_offset = self.bitcell_offset.scale(len(self.right_rbl), -self.rbl[0] - 1) + self.bitcell_array_inst.lr() @@ -430,7 +423,7 @@ class replica_bitcell_array(bitcell_base_array): offset=pin.ll().scale(0, 1), width=self.width, height=pin.height()) - + # Replica wordlines (go by the row instead of replica column because we may have to add a pin # even though the column is in another local bitcell array) for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts): diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index d237bcc8..b50acfa9 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -37,7 +37,7 @@ class replica_column(bitcell_base_array): self.left_rbl = rbl[0] self.right_rbl = rbl[1] self.replica_bit = replica_bit - + # Total size includes the replica rows and column cap rows self.total_size = self.left_rbl + rows + self.right_rbl + 2 @@ -63,7 +63,7 @@ class replica_column(bitcell_base_array): def create_layout(self): self.place_instances() - + self.height = self.cell_inst[-1].uy() self.width = self.cell_inst[0].rx() @@ -85,15 +85,14 @@ class replica_column(bitcell_base_array): def add_modules(self): self.replica_cell = factory.create(module_type=OPTS.replica_bitcell) - self.add_mod(self.replica_cell) + self.dummy_cell = factory.create(module_type=OPTS.dummy_bitcell) - self.add_mod(self.dummy_cell) + try: edge_module_type = ("col_cap" if self.cell.end_caps else "dummy") except AttributeError: edge_module_type = "dummy" self.edge_cell = factory.create(module_type=edge_module_type + "_" + OPTS.bitcell) - self.add_mod(self.edge_cell) def create_instances(self): self.cell_inst = [] @@ -103,7 +102,7 @@ class replica_column(bitcell_base_array): real_row = row if self.cell.end_caps: real_row -= 1 - + # Regular array cells are replica cells # Replic bit specifies which other bit (in the full range (0,total_size) to make a replica cell. if (row == 0 or row == self.total_size - 1): @@ -238,4 +237,3 @@ class replica_column(bitcell_base_array): for row, cell in enumerate(self.cell_inst): if row != self.replica_bit: self.graph_inst_exclude.add(cell) - diff --git a/compiler/modules/row_cap_array.py b/compiler/modules/row_cap_array.py index a4e7d063..e7dc9816 100644 --- a/compiler/modules/row_cap_array.py +++ b/compiler/modules/row_cap_array.py @@ -37,14 +37,13 @@ class row_cap_array(bitcell_base_array): self.width = max([x.rx() for x in self.insts]) self.height = max([x.uy() for x in self.insts]) - + self.add_boundary() self.DRC_LVS() def add_modules(self): """ Add the modules used in this design """ self.dummy_cell = factory.create(module_type="row_cap_{}".format(OPTS.bitcell)) - self.add_mod(self.dummy_cell) self.cell = factory.create(module_type=OPTS.bitcell) @@ -114,4 +113,3 @@ class row_cap_array(bitcell_base_array): for pin_name in ["vdd", "gnd"]: for pin in inst.get_pins(pin_name): self.copy_power_pin(pin) - diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index 713f4daf..fbfd0c5a 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -91,7 +91,6 @@ class sense_amp_array(design.design): def add_modules(self): self.amp = factory.create(module_type="sense_amp") - self.add_mod(self.amp) # This is just used for measurements, # so don't add the module diff --git a/compiler/modules/tri_gate_array.py b/compiler/modules/tri_gate_array.py index 106c9169..b1e9eebe 100644 --- a/compiler/modules/tri_gate_array.py +++ b/compiler/modules/tri_gate_array.py @@ -46,7 +46,6 @@ class tri_gate_array(design.design): def add_modules(self): self.tri = factory.create(module_type="tri_gate") - self.add_mod(self.tri) def add_pins(self): """create the name of pins depend on the word size""" @@ -120,4 +119,4 @@ class tri_gate_array(design.design): layer="m1", offset=enbar_pin.ll().scale(0, 1), width=width, - height=drc("minwidth_m1")) \ No newline at end of file + height=drc("minwidth_m1")) diff --git a/compiler/modules/wordline_buffer_array.py b/compiler/modules/wordline_buffer_array.py index 31730980..b62ea872 100644 --- a/compiler/modules/wordline_buffer_array.py +++ b/compiler/modules/wordline_buffer_array.py @@ -64,7 +64,6 @@ class wordline_buffer_array(design.design): self.wl_driver = factory.create(module_type="inv_dec", size=self.cols, height=b.height) - self.add_mod(self.wl_driver) def route_vdd_gnd(self): """ diff --git a/compiler/modules/wordline_driver_array.py b/compiler/modules/wordline_driver_array.py index 79906a3a..4faf622f 100644 --- a/compiler/modules/wordline_driver_array.py +++ b/compiler/modules/wordline_driver_array.py @@ -65,8 +65,6 @@ class wordline_driver_array(design.design): self.wl_driver = factory.create(module_type="wordline_driver", cols=self.cols) - self.add_mod(self.wl_driver) - def route_vdd_gnd(self): """ Add a pin for each row of vdd/gnd which diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 07c2ce60..7c4ea52a 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -94,7 +94,6 @@ class write_driver_array(design.design): def add_modules(self): self.driver = factory.create(module_type="write_driver") - self.add_mod(self.driver) # This is just used for measurements, # so don't add the module @@ -259,4 +258,3 @@ class write_driver_array(design.design): layer="m1", offset=inst.get_pin(inst.mod.en_name).ll().scale(0, 1), width=self.width) - diff --git a/compiler/modules/write_mask_and_array.py b/compiler/modules/write_mask_and_array.py index 2ccf34a1..f7818e12 100644 --- a/compiler/modules/write_mask_and_array.py +++ b/compiler/modules/write_mask_and_array.py @@ -63,7 +63,6 @@ class write_mask_and_array(design.design): # Assume stage effort of 3 to compute the size self.and2 = factory.create(module_type="pand2", size=max(self.write_size / 4.0, 1)) - self.add_mod(self.and2) def create_and2_array(self): self.and2_insts = {} @@ -146,7 +145,7 @@ class write_mask_and_array(design.design): self.add_via_stack_center(from_layer=supply_pin.layer, to_layer="m1", offset=supply_pin.center()) - + for supply in ["gnd", "vdd"]: supply_pin = self.and2_insts[0].get_pin(supply) supply_pin_yoffset = supply_pin.cy() @@ -158,4 +157,3 @@ class write_mask_and_array(design.design): to_layer="m1", offset=loc) self.copy_power_pin(supply_pin, loc=loc) - diff --git a/compiler/pgates/column_mux.py b/compiler/pgates/column_mux.py index 0dd923ba..a4a83dcc 100644 --- a/compiler/pgates/column_mux.py +++ b/compiler/pgates/column_mux.py @@ -77,7 +77,6 @@ class column_mux(pgate.pgate): self.ptx_width = self.tx_size * drc("minwidth_tx") self.nmos = factory.create(module_type="ptx", width=self.ptx_width) - self.add_mod(self.nmos) # Space it in the center self.nmos_lower = self.add_inst(name="mux_tx1", diff --git a/compiler/pgates/pand2.py b/compiler/pgates/pand2.py index 48b5d3a7..7e8f4043 100644 --- a/compiler/pgates/pand2.py +++ b/compiler/pgates/pand2.py @@ -39,9 +39,6 @@ class pand2(pgate.pgate): height=self.height, add_wells=self.add_wells) - self.add_mod(self.nand) - self.add_mod(self.inv) - def create_layout(self): if self.vertical: self.height = 2 * self.nand.height @@ -146,8 +143,8 @@ class pand2(pgate.pgate): offset=pin.center(), width=pin.width(), height=pin.height()) - + def is_non_inverting(self): """Return input to output polarity for module""" - - return True \ No newline at end of file + + return True diff --git a/compiler/pgates/pand3.py b/compiler/pgates/pand3.py index 713178cc..477872c8 100644 --- a/compiler/pgates/pand3.py +++ b/compiler/pgates/pand3.py @@ -43,9 +43,6 @@ class pand3(pgate.pgate): height=self.height, add_wells=self.add_wells) - self.add_mod(self.nand) - self.add_mod(self.inv) - def create_layout(self): if self.vertical: self.height = 2 * self.nand.height diff --git a/compiler/pgates/pand4.py b/compiler/pgates/pand4.py index 63eb1133..8911364c 100644 --- a/compiler/pgates/pand4.py +++ b/compiler/pgates/pand4.py @@ -43,9 +43,6 @@ class pand4(pgate.pgate): height=self.height, add_wells=self.add_wells) - self.add_mod(self.nand) - self.add_mod(self.inv) - def create_layout(self): if self.vertical: self.height = 2 * self.nand.height @@ -162,4 +159,3 @@ class pand4(pgate.pgate): slew=nand_delay.slew, load=load) return nand_delay + inv_delay - diff --git a/compiler/pgates/pbuf.py b/compiler/pgates/pbuf.py index 22a28bb9..5ed11f39 100644 --- a/compiler/pgates/pbuf.py +++ b/compiler/pgates/pbuf.py @@ -52,13 +52,11 @@ class pbuf(pgate.pgate): self.inv1 = factory.create(module_type="pinv", size=input_size, height=self.height) - self.add_mod(self.inv1) self.inv2 = factory.create(module_type="pinv", size=self.size, height=self.height, add_wells=False) - self.add_mod(self.inv2) def create_insts(self): self.inv1_inst = self.add_inst(name="buf_inv1", @@ -96,4 +94,3 @@ class pbuf(pgate.pgate): offset=a_pin.center(), width=a_pin.width(), height=a_pin.height()) - diff --git a/compiler/pgates/pbuf_dec.py b/compiler/pgates/pbuf_dec.py index 8552e265..a0cbafca 100644 --- a/compiler/pgates/pbuf_dec.py +++ b/compiler/pgates/pbuf_dec.py @@ -52,12 +52,10 @@ class pbuf_dec(pgate.pgate): self.inv1 = factory.create(module_type="pinv_dec", size=input_size, height=self.height) - self.add_mod(self.inv1) self.inv2 = factory.create(module_type="pinv_dec", size=self.size, height=self.height) - self.add_mod(self.inv2) def create_insts(self): self.inv1_inst = self.add_inst(name="buf_inv1", diff --git a/compiler/pgates/pdriver.py b/compiler/pgates/pdriver.py index bbadb9ab..1948b839 100644 --- a/compiler/pgates/pdriver.py +++ b/compiler/pgates/pdriver.py @@ -93,7 +93,6 @@ class pdriver(pgate.pgate): height=self.height, add_wells=self.add_wells) self.inv_list.append(temp_inv) - self.add_mod(temp_inv) def create_insts(self): self.inv_inst_list = [] diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index a3e467b7..c458a3f0 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -207,7 +207,6 @@ class pinv(pgate.pgate): add_drain_contact=self.route_layer, connect_poly=True, connect_drain_active=True) - self.add_mod(self.nmos) self.pmos = factory.create(module_type="ptx", width=self.pmos_width, @@ -217,7 +216,6 @@ class pinv(pgate.pgate): add_drain_contact=self.route_layer, connect_poly=True, connect_drain_active=True) - self.add_mod(self.pmos) def create_ptx(self): """ @@ -337,30 +335,29 @@ class pinv(pgate.pgate): Overrides base class function. """ self.add_graph_edges(graph, port_nets) - + def is_non_inverting(self): """Return input to output polarity for module""" - - return False + return False def get_on_resistance(self): """On resistance of pinv, defined by single nmos""" is_nchannel = True stack = 1 is_cell = False - return self.tr_r_on(self.nmos_width, is_nchannel, stack, is_cell) + return self.tr_r_on(self.nmos_width, is_nchannel, stack, is_cell) def get_input_capacitance(self): """Input cap of input, passes width of gates to gate cap function""" - return self.gate_c(self.nmos_width+self.pmos_width) - + return self.gate_c(self.nmos_width+self.pmos_width) + def get_intrinsic_capacitance(self): """Get the drain capacitances of the TXs in the gate.""" nmos_stack = 1 - nmos_drain_c = self.drain_c_(self.nmos_width*self.tx_mults, + nmos_drain_c = self.drain_c_(self.nmos_width*self.tx_mults, nmos_stack, self.tx_mults) - pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults, + pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults, 1, - self.tx_mults) - return nmos_drain_c + pmos_drain_c \ No newline at end of file + self.tx_mults) + return nmos_drain_c + pmos_drain_c diff --git a/compiler/pgates/pinvbuf.py b/compiler/pgates/pinvbuf.py index d232cabe..a48f1cf9 100644 --- a/compiler/pgates/pinvbuf.py +++ b/compiler/pgates/pinvbuf.py @@ -65,17 +65,14 @@ class pinvbuf(pgate.pgate): self.inv = factory.create(module_type="pinv", size=input_size, height=self.row_height) - self.add_mod(self.inv) self.inv1 = factory.create(module_type="pinv", size=self.predriver_size, height=self.row_height) - self.add_mod(self.inv1) self.inv2 = factory.create(module_type="pinv", size=self.size, height=self.row_height) - self.add_mod(self.inv2) def create_insts(self): # Create INV1 (capacitance shield) diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index 1fafc210..08b01d4c 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -79,7 +79,6 @@ class pnand2(pgate.pgate): tx_type="nmos", add_source_contact=self.route_layer, add_drain_contact="active") - self.add_mod(self.nmos_left) self.nmos_right = factory.create(module_type="ptx", width=self.nmos_width, @@ -87,7 +86,6 @@ class pnand2(pgate.pgate): tx_type="nmos", add_source_contact="active", add_drain_contact=self.route_layer) - self.add_mod(self.nmos_right) self.pmos_left = factory.create(module_type="ptx", width=self.pmos_width, @@ -95,7 +93,6 @@ class pnand2(pgate.pgate): tx_type="pmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.pmos_left) self.pmos_right = factory.create(module_type="ptx", width=self.pmos_width, @@ -103,7 +100,6 @@ class pnand2(pgate.pgate): tx_type="pmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.pmos_right) def setup_layout_constants(self): """ Pre-compute some handy layout parameters. """ @@ -317,28 +313,26 @@ class pnand2(pgate.pgate): def is_non_inverting(self): """Return input to output polarity for module""" - return False - + def get_on_resistance(self): """On resistance of pnand, defined by stacked NMOS""" is_nchannel = True stack = 2 is_cell = False - return self.tr_r_on(self.nmos_width, is_nchannel, stack, is_cell) - + return self.tr_r_on(self.nmos_width, is_nchannel, stack, is_cell) + def get_input_capacitance(self): """Input cap of input, passes width of gates to gate cap function""" - return self.gate_c(self.nmos_width+self.pmos_width) + return self.gate_c(self.nmos_width+self.pmos_width) def get_intrinsic_capacitance(self): """Get the drain capacitances of the TXs in the gate.""" nmos_stack = 2 - nmos_drain_c = self.drain_c_(self.nmos_width*self.tx_mults, + nmos_drain_c = self.drain_c_(self.nmos_width*self.tx_mults, nmos_stack, self.tx_mults) - pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults, + pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults, 1, - self.tx_mults) - return nmos_drain_c + pmos_drain_c - \ No newline at end of file + self.tx_mults) + return nmos_drain_c + pmos_drain_c diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index b59d0064..0186907f 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -82,7 +82,6 @@ class pnand3(pgate.pgate): tx_type="nmos", add_source_contact="active", add_drain_contact="active") - self.add_mod(self.nmos_center) self.nmos_right = factory.create(module_type="ptx", width=self.nmos_width, @@ -90,7 +89,6 @@ class pnand3(pgate.pgate): tx_type="nmos", add_source_contact="active", add_drain_contact=self.route_layer) - self.add_mod(self.nmos_right) self.nmos_left = factory.create(module_type="ptx", width=self.nmos_width, @@ -98,7 +96,6 @@ class pnand3(pgate.pgate): tx_type="nmos", add_source_contact=self.route_layer, add_drain_contact="active") - self.add_mod(self.nmos_left) self.pmos_left = factory.create(module_type="ptx", width=self.pmos_width, @@ -106,7 +103,6 @@ class pnand3(pgate.pgate): tx_type="pmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.pmos_left) self.pmos_center = factory.create(module_type="ptx", width=self.pmos_width, @@ -114,7 +110,6 @@ class pnand3(pgate.pgate): tx_type="pmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.pmos_center) self.pmos_right = factory.create(module_type="ptx", width=self.pmos_width, @@ -122,7 +117,6 @@ class pnand3(pgate.pgate): tx_type="pmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.pmos_right) def setup_layout_constants(self): """ Pre-compute some handy layout parameters. """ @@ -350,27 +344,26 @@ class pnand3(pgate.pgate): def is_non_inverting(self): """Return input to output polarity for module""" - return False - + def get_on_resistance(self): """On resistance of pnand, defined by stacked NMOS""" is_nchannel = True stack = 3 is_cell = False - return self.tr_r_on(self.nmos_width, is_nchannel, stack, is_cell) - + return self.tr_r_on(self.nmos_width, is_nchannel, stack, is_cell) + def get_input_capacitance(self): """Input cap of input, passes width of gates to gate cap function""" - return self.gate_c(self.nmos_width+self.pmos_width) - + return self.gate_c(self.nmos_width+self.pmos_width) + def get_intrinsic_capacitance(self): """Get the drain capacitances of the TXs in the gate.""" nmos_stack = 3 - nmos_drain_c = self.drain_c_(self.nmos_width*self.tx_mults, + nmos_drain_c = self.drain_c_(self.nmos_width*self.tx_mults, nmos_stack, self.tx_mults) - pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults, + pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults, 1, - self.tx_mults) - return nmos_drain_c + pmos_drain_c \ No newline at end of file + self.tx_mults) + return nmos_drain_c + pmos_drain_c diff --git a/compiler/pgates/pnand4.py b/compiler/pgates/pnand4.py index 80607331..eed71eb9 100644 --- a/compiler/pgates/pnand4.py +++ b/compiler/pgates/pnand4.py @@ -82,7 +82,6 @@ class pnand4(pgate.pgate): tx_type="nmos", add_source_contact="active", add_drain_contact="active") - self.add_mod(self.nmos_center) self.nmos_right = factory.create(module_type="ptx", width=self.nmos_width, @@ -90,7 +89,6 @@ class pnand4(pgate.pgate): tx_type="nmos", add_source_contact="active", add_drain_contact=self.route_layer) - self.add_mod(self.nmos_right) self.nmos_left = factory.create(module_type="ptx", width=self.nmos_width, @@ -98,7 +96,6 @@ class pnand4(pgate.pgate): tx_type="nmos", add_source_contact=self.route_layer, add_drain_contact="active") - self.add_mod(self.nmos_left) self.pmos_left = factory.create(module_type="ptx", width=self.pmos_width, @@ -106,7 +103,6 @@ class pnand4(pgate.pgate): tx_type="pmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.pmos_left) self.pmos_center = factory.create(module_type="ptx", width=self.pmos_width, @@ -114,7 +110,6 @@ class pnand4(pgate.pgate): tx_type="pmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.pmos_center) self.pmos_right = factory.create(module_type="ptx", width=self.pmos_width, @@ -122,7 +117,6 @@ class pnand4(pgate.pgate): tx_type="pmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.pmos_right) def setup_layout_constants(self): """ Pre-compute some handy layout parameters. """ diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py index d59f28fe..d6384676 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/pgates/pnor2.py @@ -77,7 +77,6 @@ class pnor2(pgate.pgate): tx_type="nmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.nmos_left) self.nmos_right = factory.create(module_type="ptx", width=self.nmos_width, @@ -85,7 +84,6 @@ class pnor2(pgate.pgate): tx_type="nmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.nmos_right) self.pmos_left = factory.create(module_type="ptx", width=self.pmos_width, @@ -93,7 +91,6 @@ class pnor2(pgate.pgate): tx_type="pmos", add_source_contact=self.route_layer, add_drain_contact="active") - self.add_mod(self.pmos_left) self.pmos_right = factory.create(module_type="ptx", width=self.pmos_width, @@ -101,7 +98,6 @@ class pnor2(pgate.pgate): tx_type="pmos", add_source_contact="active", add_drain_contact=self.route_layer) - self.add_mod(self.pmos_right) def setup_layout_constants(self): """ Pre-compute some handy layout parameters. """ diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index 951fe834..2042dc7c 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -90,7 +90,6 @@ class precharge(design.design): width=self.ptx_width, mults=self.ptx_mults, tx_type="pmos") - self.add_mod(self.pmos) def route_vdd_rail(self): """ @@ -305,4 +304,3 @@ class precharge(design.design): self.add_path(self.bitline_layer, [left_pos, right_pos], width=pmos_pin.height()) - diff --git a/compiler/pgates/ptristate_inv.py b/compiler/pgates/ptristate_inv.py index 8cac43c0..b37c36ae 100644 --- a/compiler/pgates/ptristate_inv.py +++ b/compiler/pgates/ptristate_inv.py @@ -85,13 +85,11 @@ class ptristate_inv(pgate.pgate): width=self.nmos_width, mults=1, tx_type="nmos") - self.add_mod(self.nmos) self.pmos = factory.create(module_type="ptx", width=self.pmos_width, mults=1, tx_type="pmos") - self.add_mod(self.pmos) def route_supply_rails(self): """ Add vdd/gnd rails to the top and bottom. """ diff --git a/compiler/pgates/pwrite_driver.py b/compiler/pgates/pwrite_driver.py index 2b4a3679..103e902b 100644 --- a/compiler/pgates/pwrite_driver.py +++ b/compiler/pgates/pwrite_driver.py @@ -66,19 +66,16 @@ class pwrite_driver(design.design): # Tristate inverter self.tri = factory.create(module_type="ptristate_inv", height="min") - self.add_mod(self.tri) debug.check(self.tri.width2: self.msb_decoder = self.bank.decoder.pre2_4 - self.add_mod(self.msb_decoder) def add_modules(self): self.bitcell = factory.create(module_type=OPTS.bitcell) @@ -480,30 +478,24 @@ class sram_base(design, verilog, lef): # Create the bank module (up to four are instantiated) self.bank = factory.create("bank", sram_config=self.sram_config, module_name="bank") - self.add_mod(self.bank) self.num_spare_cols = self.bank.num_spare_cols # Create the address and control flops (but not the clk) self.row_addr_dff = factory.create("dff_array", module_name="row_addr_dff", rows=self.row_addr_size, columns=1) - self.add_mod(self.row_addr_dff) if self.col_addr_size > 0: self.col_addr_dff = factory.create("dff_array", module_name="col_addr_dff", rows=1, columns=self.col_addr_size) - self.add_mod(self.col_addr_dff) else: self.col_addr_dff = None self.data_dff = factory.create("dff_array", module_name="data_dff", rows=1, columns=self.word_size + self.num_spare_cols) - self.add_mod(self.data_dff) if self.write_size: self.wmask_dff = factory.create("dff_array", module_name="wmask_dff", rows=1, columns=self.num_wmasks) - self.add_mod(self.wmask_dff) if self.num_spare_cols: self.spare_wen_dff = factory.create("dff_array", module_name="spare_wen_dff", rows=1, columns=self.num_spare_cols) - self.add_mod(self.spare_wen_dff) # Create bank decoder if(self.num_banks > 1): @@ -515,30 +507,27 @@ class sram_base(design, verilog, lef): self.mod_control_logic = getattr(c, OPTS.control_logic) # Create the control logic module for each port type - if len(self.readwrite_ports)>0: + if len(self.readwrite_ports) > 0: self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, word_size=self.word_size, spare_columns=self.num_spare_cols, sram=self, port_type="rw") - self.add_mod(self.control_logic_rw) - if len(self.writeonly_ports)>0: + if len(self.writeonly_ports) > 0: self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, word_size=self.word_size, spare_columns=self.num_spare_cols, sram=self, port_type="w") - self.add_mod(self.control_logic_w) - if len(self.readonly_ports)>0: + if len(self.readonly_ports) > 0: self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, word_size=self.word_size, spare_columns=self.num_spare_cols, sram=self, port_type="r") - self.add_mod(self.control_logic_r) def create_bank(self, bank_num): """ Create a bank """ @@ -779,13 +768,13 @@ class sram_base(design, verilog, lef): Clears the bit exclusions """ self.bank.clear_exclude_bits() - + def graph_exclude_column_mux(self, column_include_num, port): """ Excludes all columns muxes unrelated to the target bit being simulated. """ self.bank.graph_exclude_column_mux(column_include_num, port) - + def graph_clear_column_mux(self, port): """ Clear mux exclusions to allow different bit tests. diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index 9c3b5971..934a981c 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -135,7 +135,7 @@ lv_ngate = ngate - vtg - thkox gv_ngate = ngate & vtg - vth - thkox hv_ngate = ngate - vtg - vth & thkox -cheat("cell_1rw", "dummy_cell_1rw", "replica_cell_1rw", "cell_2rw", "dummy_cell_2rw", "replica_cell_2rw", "pbitcell", "dummy_pbitcell", "replica_pbitcell", "dff", "wordline_driver*") { +cheat("cell_1rw", "dummy_cell_1rw", "replica_cell_1rw", "cell_2rw", "dummy_cell_2rw", "replica_cell_2rw", "pbitcell*", "dummy_pbitcell*", "replica_pbitcell*", "dff", "wordline_driver*") { # PMOS transistor device extraction extract_devices(mos4("PMOS_VTL"), { "SD" => psd, "G" => lv_pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell }) From 779d6ad2b2d1502fa46da1db5debab1c55c2a566 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 22 Sep 2021 16:54:52 -0700 Subject: [PATCH 034/229] Debugging klayout for SCMOS and FreePDK45. --- technology/freepdk45/tech/freepdk45.lylvs | 10 +- technology/scn4m_subm/tech/scn4m_subm.lylvs | 416 ++++++++++---------- technology/scn4m_subm/tech/tech.py | 3 + 3 files changed, 216 insertions(+), 213 deletions(-) diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index 934a981c..97fbf85e 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -206,13 +206,13 @@ connect(metal10, metal10_pin) schematic.simplify if $connect_supplies -connect_implicit("*", "vdd") -connect_implicit("*", "gnd") + connect_implicit("vdd") + connect_implicit("gnd") end -connect_global(pwell, "PWELL") -connect_global(nwell, "NWELL") -connect_global(bulk, "BULK") +#connect_global(pwell, "PWELL") +#connect_global(nwell, "NWELL") +#connect_global(bulk, "BULK") for pat in %w(pinv* pnor* pnand* and?_dec* write_driver* port_address* replica_bitcell_array*) connect_explicit(pat, [ "NWELL", "vdd" ]) diff --git a/technology/scn4m_subm/tech/scn4m_subm.lylvs b/technology/scn4m_subm/tech/scn4m_subm.lylvs index 7a7c1371..80185ede 100644 --- a/technology/scn4m_subm/tech/scn4m_subm.lylvs +++ b/technology/scn4m_subm/tech/scn4m_subm.lylvs @@ -1,208 +1,208 @@ - - - - - lvs - - - - false - false - - true - lvs_scripts - tools_menu.lvs.end - dsl - lvs-dsl-xml - # -# Extraction for freePDK45 -# -############################ -tstart = Time.now - -# 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 lvs_freepdk45.lvs -if $input - source($input) -end - -if $report - report_lvs($report) -else - report_lvs("lvs_report.lvsdb") -end - -if $schematic -#reference netlist - schematic($schematic) -else - schematic(RBA::CellView::active.filename.sub(/\.(oas|gds|oas.gz|gds.gz)$/, ".sp")) -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 - -if $target_netlist - target_netlist($target_netlist) -else - # target_netlist("netlist.cir", write_spice(spice_with_net_names, spice_with_comments), "The netlist comment goes here.") - target_netlist(File.join(File.dirname(RBA::CellView::active.filename), source.cell_name+"_extracted.cir"), 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 -######################## -info("Layers definitions") - - DNW = input(38,0) - nwell = input(42,0) - pwell = input(41,0) - CW = input(59,0) - active = input(43,0) - TA = input(60,0) - PBase = input(58,0) - poly = input(46,0) - SB = input(29,0) - nplus = input(45,0) - pplus = input(44,0) - PO2 = input(56,0) - HR = input(34,0) - Contact = input(25,0) - ContactPoly = input(47,0) - ContactActive = input(48,0) - ContactPoly2 = input(55, 0) - CT = Contact + ContactPoly + ContactActive + ContactPoly2 - M1 = input(49,0) - V1 = input(50,0) - M2 = input(51,0) - V2 = input(61,0) - M3 = input(62,0) - V3 = input(30,0) - M4 = input(31,0) - CTM = input(35,0) - V4 = input(32,0) - M5 = input(33,0) - V5 = input(36,0) - M6 = input(37,0) - Glass = input(52,0) - Pads = input(26,0) - -# layers processing -######################## -info("Layers processing") - -# Bulk layer for terminal provisioning -bulk = polygon_layer - -active_in_nwell = active & nwell -pactive = active_in_nwell & pplus -ntie = active_in_nwell & nplus -pgate = pactive & poly -psd = pactive - pgate - -active_in_pwell = active & pwell -nactive = active_in_pwell & nplus -ptie = active_in_pwell & pplus -ngate = nactive & poly -nsd = nactive - ngate - - -cheat("cell_1rw", "dummy_cell_1rw", "replica_cell_1rw", "cell_2rw", "dummy_cell_2rw", "replica_cell_2rw", "pbitcell", "dummy_pbitcell", "replica_pbitcell", "dff", "wordline_driver*") { - -# PMOS transistor device extraction -extract_devices(mos4("p"), { "SD" => psd, "G" => pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell }) - -# NMOS transistor device extraction -extract_devices(mos4("n"), { "SD" => nsd, "G" => ngate, "tS" => nsd, "tD" => nsd, "tG" => poly, "W" => pwell }) - -} - -# Define connectivity for netlist extraction - -# Inter-layer -connect(nwell, ntie) -connect(pwell, ptie) -connect(CT, ntie) -connect(CT, ptie) -connect(psd, CT) -connect(nsd, CT) -connect(poly, CT) -connect(CT, M1) -connect(CT, M1) -connect(M1, V1) -connect(V1, M2) -connect(M2, V2) -connect(V2, M3) -connect(M3, V3) -connect(V3, M4) -connect(M4, V4) -connect(V4, M5) -connect(M5, V5) -connect(V5, M6) - - -# Global -schematic.simplify - -if $connect_supplies - connect_implicit("vdd") - connect_implicit("gnd") -end - -connect_global(pwell, "PWELL") -connect_global(nwell, "NWELL") -#connect_global(bulk, "BULK") - -for pat in %w(pinv* pnor* pnand* and?_dec* write_driver* port_address* replica_bitcell_array*) - connect_explicit(pat, [ "NWELL", "vdd" ]) - connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) -end - -# 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 - -# Tolerances for the devices extracted parameters -# tolerance(device_class_name, parameter_name [, :absolute => absolute_tolerance] [, :relative => relative_tolerance]) -tolerance("P", "W", :absolute => 1.nm, :relative => 0.001) -tolerance("N", "W", :absolute => 1.nm, :relative => 0.001) - -#max_res(1000000) -#min_caps(1e-15) - -max_branch_complexity(65536) -max_depth(16) - -if ! compare - #raise "ERROR : Netlists don't match" - puts "ERROR : Netlists don't match" -else - puts "CONGRATULATIONS! Netlists match." -end - -# time spent for the LVS -time = Time.now -hours = ((time - tstart)/3600).to_i -minutes = ((time - tstart)/60 - hours * 60).to_i -seconds = ((time - tstart) - (minutes * 60 + hours * 3600)).to_i -$stdout.write "LVS finished at : #{time.hour}:#{time.min}:#{time.sec} - LVS duration = #{hours} hrs. #{minutes} min. #{seconds} sec.\n" - + + + + + lvs + + + + false + false + + true + lvs_scripts + tools_menu.lvs.end + dsl + lvs-dsl-xml + # +# Extraction for freePDK45 +# +############################ +tstart = Time.now + +# 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 lvs_freepdk45.lvs +if $input + source($input) +end + +if $report + report_lvs($report) +else + report_lvs("lvs_report.lvsdb") +end + +if $schematic +#reference netlist + schematic($schematic) +else + schematic(RBA::CellView::active.filename.sub(/\.(oas|gds|oas.gz|gds.gz)$/, ".sp")) +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 + +if $target_netlist + target_netlist($target_netlist) +else + # target_netlist("netlist.cir", write_spice(spice_with_net_names, spice_with_comments), "The netlist comment goes here.") + target_netlist(File.join(File.dirname(RBA::CellView::active.filename), source.cell_name+"_extracted.cir"), 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 +######################## +info("Layers definitions") + + DNW = input(38,0) + nwell = input(42,0) + pwell = input(41,0) + CW = input(59,0) + active = input(43,0) + TA = input(60,0) + PBase = input(58,0) + poly = input(46,0) + SB = input(29,0) + nplus = input(45,0) + pplus = input(44,0) + PO2 = input(56,0) + HR = input(34,0) + Contact = input(25,0) + ContactPoly = input(47,0) + ContactActive = input(48,0) + ContactPoly2 = input(55, 0) + CT = Contact + ContactPoly + ContactActive + ContactPoly2 + M1 = input(49,0) + V1 = input(50,0) + M2 = input(51,0) + V2 = input(61,0) + M3 = input(62,0) + V3 = input(30,0) + M4 = input(31,0) + CTM = input(35,0) + V4 = input(32,0) + M5 = input(33,0) + V5 = input(36,0) + M6 = input(37,0) + Glass = input(52,0) + Pads = input(26,0) + +# layers processing +######################## +info("Layers processing") + +# Bulk layer for terminal provisioning +bulk = polygon_layer + +active_in_nwell = active & nwell +pactive = active_in_nwell & pplus +ntie = active_in_nwell & nplus +pgate = pactive & poly +psd = pactive - pgate + +active_in_pwell = active & pwell +nactive = active_in_pwell & nplus +ptie = active_in_pwell & pplus +ngate = nactive & poly +nsd = nactive - ngate + + +cheat("cell_1rw", "dummy_cell_1rw", "replica_cell_1rw", "cell_2rw", "dummy_cell_2rw", "replica_cell_2rw", "pbitcell", "dummy_pbitcell", "replica_pbitcell", "dff", "wordline_driver*") { + +# PMOS transistor device extraction +extract_devices(mos4("p"), { "SD" => psd, "G" => pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell }) + +# NMOS transistor device extraction +extract_devices(mos4("n"), { "SD" => nsd, "G" => ngate, "tS" => nsd, "tD" => nsd, "tG" => poly, "W" => pwell }) + +} + +# Define connectivity for netlist extraction + +# Inter-layer +connect(nwell, ntie) +connect(pwell, ptie) +connect(CT, ntie) +connect(CT, ptie) +connect(psd, CT) +connect(nsd, CT) +connect(poly, CT) +connect(CT, M1) +connect(CT, M1) +connect(M1, V1) +connect(V1, M2) +connect(M2, V2) +connect(V2, M3) +connect(M3, V3) +connect(V3, M4) +connect(M4, V4) +connect(V4, M5) +connect(M5, V5) +connect(V5, M6) + + +# Global +schematic.simplify + +if $connect_supplies + connect_implicit("vdd") + connect_implicit("gnd") +end + +connect_global(pwell, "PWELL") +connect_global(nwell, "NWELL") +#connect_global(bulk, "BULK") + +for pat in %w(pinv* pnor* pnand* and?_dec* write_driver* port_address* replica_bitcell_array*) + connect_explicit(pat, [ "NWELL", "vdd" ]) + connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) +end + +# 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 + +# Tolerances for the devices extracted parameters +# tolerance(device_class_name, parameter_name [, :absolute => absolute_tolerance] [, :relative => relative_tolerance]) +tolerance("P", "W", :absolute => 1.nm, :relative => 0.001) +tolerance("N", "W", :absolute => 1.nm, :relative => 0.001) + +#max_res(1000000) +#min_caps(1e-15) + +max_branch_complexity(65536) +max_depth(16) + +if ! compare + #raise "ERROR : Netlists don't match" + puts "ERROR : Netlists don't match" +else + puts "CONGRATULATIONS! Netlists match." +end + +# time spent for the LVS +time = Time.now +hours = ((time - tstart)/3600).to_i +minutes = ((time - tstart)/60 - hours * 60).to_i +seconds = ((time - tstart) - (minutes * 60 + hours * 3600)).to_i +$stdout.write "LVS finished at : #{time.hour}:#{time.min}:#{time.sec} - LVS duration = #{hours} hrs. #{minutes} min. #{seconds} sec.\n" + diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index a8c44996..374ba4c8 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -428,5 +428,8 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa drc_name = "magic" lvs_name = "netgen" pex_name = "magic" +drc_name = "klayout" +lvs_name = "klayout" +pex_name = "klayout" blackbox_bitcell = False From bfb33ecbb49e49068b4cb1af18f0f02c2b45a755 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 22 Sep 2021 17:06:37 -0700 Subject: [PATCH 035/229] Add DRC rules and display files --- technology/scn4m_subm/tech/scn4m_subm.lydrc | 1621 +++++++++---------- 1 file changed, 810 insertions(+), 811 deletions(-) diff --git a/technology/scn4m_subm/tech/scn4m_subm.lydrc b/technology/scn4m_subm/tech/scn4m_subm.lydrc index afaf01a8..68804569 100644 --- a/technology/scn4m_subm/tech/scn4m_subm.lydrc +++ b/technology/scn4m_subm/tech/scn4m_subm.lydrc @@ -1,811 +1,810 @@ - - - - - drc - - - - false - false - - true - drc_scripts - tools_menu.drc.end - dsl - drc-dsl-xml - # -# MOSIS SCMOS DRC -# -######################## -tstart = Time.now - -# optionnal for a batch launch : klayout -b r drc_SCMOS.lydrc -rd input=my_layout.gds -rd topcell=your_topcell -rd output=SCMOS_DRC.lyrdb -if $input - if $topcell - source($input,$topcell) - else - source($input) - end -end - -if $output - report("SCMOS DRC runset", $output) -else - report("SCMOS DRC runset", "SCMOS_DRC.lyrdb") -end - - -# PROCESS OPTIONS -######################## -LAMBDA = 0.2 -SUBM = true -DEEP = false -NBR_OF_METALS = 6 - -DFM = false - -# design rules limits definitions -######################## -R1_3 = ( 6 *LAMBDA ).round(3) -R2_1 = ( 3 *LAMBDA ).round(3) -R2_2 = ( 3 *LAMBDA ).round(3) -R2_4 = ( 3 *LAMBDA ).round(3) -R2_5 = ( 4 *LAMBDA ).round(3) -R3_1 = ( 2 *LAMBDA ).round(3) -R3_5 = ( 1 *LAMBDA ).round(3) -R4_1 = ( 3 *LAMBDA ).round(3) -R4_2 = ( 2 *LAMBDA ).round(3) -R5_1 = ( 2 *LAMBDA ).round(3) -R5_2 = ( 1.5 *LAMBDA ).round(3) -R5_4 = ( 2 *LAMBDA ).round(3) -R5_2_b = ( 1 *LAMBDA ).round(3) -R5_6_b = ( 2 *LAMBDA ).round(3) -R5_7_b = ( 3 *LAMBDA ).round(3) -R6_1 = ( 2 *LAMBDA ).round(3) -R6_2 = ( 1.5 *LAMBDA ).round(3) -R6_4 = ( 2 *LAMBDA ).round(3) -R6_2_b = ( 1 *LAMBDA ).round(3) -R6_5_b = ( 5 *LAMBDA ).round(3) -R6_6_b = ( 2 *LAMBDA ).round(3) -R6_7_b = ( 3 *LAMBDA ).round(3) -R6_8_b = ( 4 *LAMBDA ).round(3) -R7_1 = ( 3 *LAMBDA ).round(3) -R7_3 = ( 1 *LAMBDA ).round(3) -R8_2 = ( 3 *LAMBDA ).round(3) -R8_3 = ( 1 *LAMBDA ).round(3) -R8_4 = ( 2 *LAMBDA ).round(3) -R9_1 = ( 3 *LAMBDA ).round(3) -R9_3 = ( 1 *LAMBDA ).round(3) -R10_1 = ( 60 *LAMBDA ).round(3) -R10_2 = ( 20 *LAMBDA ).round(3) -R10_3 = ( 6 *LAMBDA ).round(3) -R10_4 = ( 30 *LAMBDA ).round(3) -R10_5 = ( 15 *LAMBDA ).round(3) -R11_2 = ( 3 *LAMBDA ).round(3) -R11_4 = ( 2 *LAMBDA ).round(3) -R11_6 = ( 2 *LAMBDA ).round(3) -R12_1 = ( 2 *LAMBDA ).round(3) -R12_2 = ( 3 *LAMBDA ).round(3) -R12_3 = ( 2 *LAMBDA ).round(3) -R12_4 = ( 1 *LAMBDA ).round(3) -R12_5 = ( 2 *LAMBDA ).round(3) -R12_6 = ( 3 *LAMBDA ).round(3) -R13_1 = ( 2 *LAMBDA ).round(3) -R13_3 = ( 3 *LAMBDA ).round(3) -R13_4 = ( 2 *LAMBDA ).round(3) -R13_5 = ( 3 *LAMBDA ).round(3) -R14_2 = ( 3 *LAMBDA ).round(3) -R14_3 = ( 1 *LAMBDA ).round(3) -R14_4 = ( 2 *LAMBDA ).round(3) -if NBR_OF_METALS > 3 - R15_3 = ( 1 *LAMBDA ).round(3) -else - R15_3 = ( 2 *LAMBDA ).round(3) -end -R16_1 = ( 2 *LAMBDA ).round(3) -R16_2 = ( 3 *LAMBDA ).round(3) -R16_3 = ( 2 *LAMBDA ).round(3) -R16_4 = ( 4 *LAMBDA ).round(3) -R16_5 = ( 2 *LAMBDA ).round(3) -R16_6 = ( 2 *LAMBDA ).round(3) -R16_7 = ( 6 *LAMBDA ).round(3) -R16_8 = ( 4 *LAMBDA ).round(3) -R16_9 = ( 2 *LAMBDA ).round(3) -R16_10 = ( 3 *LAMBDA ).round(3) -R16_11 = ( 2 *LAMBDA ).round(3) -R18_1 = ( 3 *LAMBDA ).round(3) -R18_2 = ( 2 *LAMBDA ).round(3) -R18_3 = ( 3 *LAMBDA ).round(3) -R18_4 = ( 2 *LAMBDA ).round(3) -R18_5 = ( 6 *LAMBDA ).round(3) -R20_1 = ( 4 *LAMBDA ).round(3) -R20_2 = ( 4 *LAMBDA ).round(3) -R20_3 = ( 2 *LAMBDA ).round(3) -R20_4 = ( 2 *LAMBDA ).round(3) -R20_5 = ( 2 *LAMBDA ).round(3) -R20_7 = ( 5 *LAMBDA ).round(3) -R20_8 = ( 7 *LAMBDA ).round(3) -R20_9 = ( 2 *LAMBDA ).round(3) -R20_10 = ( 3 *LAMBDA ).round(3) -R21_2 = ( 3 *LAMBDA ).round(3) -R21_3 = ( 1 *LAMBDA ).round(3) -if NBR_OF_METALS > 4 - R22_3 = ( 1 *LAMBDA ).round(3) -else - R22_3 = ( 2 *LAMBDA ).round(3) -end -R23_1 = ( 8 *LAMBDA ).round(3) -R23_2 = ( 4 *LAMBDA ).round(3) -R23_3 = ( 8 *LAMBDA ).round(3) -R23_4 = ( 3 *LAMBDA ).round(3) -R23_5 = ( 2 *LAMBDA ).round(3) -R23_6 = ( 2 *LAMBDA ).round(3) -R23_7 = ( 2 *LAMBDA ).round(3) -R23_8 = ( 4 *LAMBDA ).round(3) -R23_9 = ( 2 *LAMBDA ).round(3) -R24_1 = ( 4 *LAMBDA ).round(3) -R24_2 = ( 4 *LAMBDA ).round(3) -R24_3 = ( 4 *LAMBDA ).round(3) -R24_4 = ( 4 *LAMBDA ).round(3) -R24_5 = ( 3 *LAMBDA ).round(3) -R27_1 = ( 4 *LAMBDA ).round(3) -R27_2 = ( 4 *LAMBDA ).round(3) -R27_3 = ( 2 *LAMBDA ).round(3) -R27_4 = ( 2 *LAMBDA ).round(3) -R27_5 = ( 2 *LAMBDA ).round(3) -R27_7 = ( 5 *LAMBDA ).round(3) -R27_8 = ( 7 *LAMBDA ).round(3) -R27_9 = ( 2 *LAMBDA ).round(3) - - -if !SUBM && !DEEP - R1_1 = ( 10 *LAMBDA ).round(3) - R1_2 = ( 6 *LAMBDA ).round(3) - #R1_2 = ( 9 *LAMBDA ).round(3) - R2_3 = ( 5 *LAMBDA ).round(3) - R3_2 = ( 2 *LAMBDA ).round(3) - R3_2_a = ( 2 *LAMBDA ).round(3) - R3_3 = ( 2 *LAMBDA ).round(3) - R3_4 = ( 3 *LAMBDA ).round(3) - R4_3 = ( 1 *LAMBDA ).round(3) - R4_4 = ( 2 *LAMBDA ).round(3) - R5_3 = ( 2 *LAMBDA ).round(3) - R5_5_b = ( 4 *LAMBDA ).round(3) - R6_3 = ( 2 *LAMBDA ).round(3) - R7_2 = ( 2 *LAMBDA ).round(3) - R7_4 = ( 4 *LAMBDA ).round(3) - R8_1 = ( 2 *LAMBDA ).round(3) - R8_5 = ( 2 *LAMBDA ).round(3) - R9_2 = ( 3 *LAMBDA ).round(3) - R9_4 = ( 6 *LAMBDA ).round(3) - R11_1 = ( 3 *LAMBDA ).round(3) - R11_3 = ( 2 *LAMBDA ).round(3) - R11_5 = ( 3 *LAMBDA ).round(3) - R13_2 = ( 2 *LAMBDA ).round(3) - R14_1 = ( 2 *LAMBDA ).round(3) - if NBR_OF_METALS > 3 - R15_1 = ( 3 *LAMBDA ).round(3) - R15_2 = ( 3 *LAMBDA ).round(3) - R15_4 = ( 6 *LAMBDA ).round(3) - else - R15_1 = ( 6 *LAMBDA ).round(3) - R15_2 = ( 4 *LAMBDA ).round(3) - R15_4 = ( 8 *LAMBDA ).round(3) - end - R17_1 = ( 10 *LAMBDA ).round(3) - R17_2 = ( 9 *LAMBDA ).round(3) - R17_3 = ( 5 *LAMBDA ).round(3) - R17_4 = ( 5 *LAMBDA ).round(3) - R20_11 = ( 3 *LAMBDA ).round(3) - R21_1 = ( 2 *LAMBDA ).round(3) - if NBR_OF_METALS > 4 - R22_1 = ( 3 *LAMBDA ).round(3) - R22_2 = ( 3 *LAMBDA ).round(3) - R22_4 = ( 6 *LAMBDA ).round(3) - else - R22_1 = ( 6 *LAMBDA ).round(3) - R22_2 = ( 6 *LAMBDA ).round(3) - R22_4 = ( 12 *LAMBDA ).round(3) - end -end - -if SUBM - R1_1 = ( 12 *LAMBDA ).round(3) - # We are assuming the wells are at the same potential since - # DRC can't tell otherwise - #R1_2 = ( 18 *LAMBDA ).round(3) - R1_2 = ( 6 *LAMBDA ).round(3) - R2_3 = ( 6 *LAMBDA ).round(3) - R3_2 = ( 3 *LAMBDA ).round(3) - R3_2_a = ( 3 *LAMBDA ).round(3) - R3_3 = ( 2 *LAMBDA ).round(3) - R3_4 = ( 3 *LAMBDA ).round(3) - R4_3 = ( 1 *LAMBDA ).round(3) - R4_4 = ( 2 *LAMBDA ).round(3) - R5_3 = ( 3 *LAMBDA ).round(3) - R5_5_b = ( 5 *LAMBDA ).round(3) - R6_3 = ( 3 *LAMBDA ).round(3) - R7_2 = ( 3 *LAMBDA ).round(3) - R7_4 = ( 6 *LAMBDA ).round(3) - R8_1 = ( 2 *LAMBDA ).round(3) - R8_5 = ( 2 *LAMBDA ).round(3) - R9_2 = ( 3 *LAMBDA ).round(3) - R9_4 = ( 6 *LAMBDA ).round(3) - R11_1 = ( 7 *LAMBDA ).round(3) - R11_3 = ( 5 *LAMBDA ).round(3) - R11_5 = ( 6 *LAMBDA ).round(3) - R13_2 = ( 3 *LAMBDA ).round(3) - R14_1 = ( 2 *LAMBDA ).round(3) - if NBR_OF_METALS > 3 - R15_1 = ( 3 *LAMBDA ).round(3) - R15_2 = ( 3 *LAMBDA ).round(3) - R15_4 = ( 6 *LAMBDA ).round(3) - else - R15_1 = ( 5 *LAMBDA ).round(3) - R15_2 = ( 3 *LAMBDA ).round(3) - R15_4 = ( 6 *LAMBDA ).round(3) - end - R17_1 = ( 12 *LAMBDA ).round(3) - R17_2 = ( 18 *LAMBDA ).round(3) - R17_3 = ( 6 *LAMBDA ).round(3) - R17_4 = ( 6 *LAMBDA ).round(3) - R20_11 = ( 5 *LAMBDA ).round(3) - R21_1 = ( 2 *LAMBDA ).round(3) - if NBR_OF_METALS > 4 - R22_1 = ( 3 *LAMBDA ).round(3) - R22_2 = ( 3 *LAMBDA ).round(3) - R22_4 = ( 6 *LAMBDA ).round(3) - else - R22_1 = ( 6 *LAMBDA ).round(3) - R22_2 = ( 6 *LAMBDA ).round(3) - R22_4 = ( 12 *LAMBDA ).round(3) - end - R25_1 = ( 2 *LAMBDA ).round(3) - R25_2 = ( 3 *LAMBDA ).round(3) - R25_3 = ( 1 *LAMBDA ).round(3) - if NBR_OF_METALS > 5 - R26_1 = ( 3 *LAMBDA ).round(3) - R26_2 = ( 3 *LAMBDA ).round(3) - R26_3 = ( 1 *LAMBDA ).round(3) - R26_4 = ( 6 *LAMBDA ).round(3) - else - R26_1 = ( 4 *LAMBDA ).round(3) - R26_2 = ( 4 *LAMBDA ).round(3) - R26_3 = ( 2 *LAMBDA ).round(3) - R26_4 = ( 8 *LAMBDA ).round(3) - end - R28_1 = ( 40 *LAMBDA ).round(3) - R28_2 = ( 12 *LAMBDA ).round(3) - R28_3 = ( 4 *LAMBDA ).round(3) - R28_4 = ( 3 *LAMBDA ).round(3) - R28_5 = ( 4 *LAMBDA ).round(3) - R28_6 = ( 2 *LAMBDA ).round(3) - R28_7 = ( 25 *LAMBDA ).round(3) - R28_8 = ( 4 *LAMBDA ).round(3) - R28_9 = ( 8 *LAMBDA ).round(3) - R28_10 = ( 20 *LAMBDA ).round(3) - R28_11 = ( 40 *LAMBDA ).round(3) - R29_1 = ( 3 *LAMBDA ).round(3) - R29_2 = ( 4 *LAMBDA ).round(3) - R29_3 = ( 1 *LAMBDA ).round(3) - R30_1 = ( 5 *LAMBDA ).round(3) - R30_2 = ( 5 *LAMBDA ).round(3) - R30_3 = ( 1 *LAMBDA ).round(3) - R30_4 = ( 10 *LAMBDA ).round(3) - R31_1 = ( 30 *LAMBDA ).round(3) - R31_2 = ( 50 *LAMBDA ).round(3) - R31_3 = ( 15 *LAMBDA ).round(3) - R31_4 = ( 20 *LAMBDA ).round(3) - R31_5 = ( 35 *LAMBDA ).round(3) - R31_6 = ( 5 *LAMBDA ).round(3) - R31_7 = ( 30 *LAMBDA ).round(3) - R31_8 = ( 10 *LAMBDA ).round(3) -end - -if DEEP - R1_1 = ( 12 *LAMBDA ).round(3) - # We are assuming the wells are at the same potential since - # DRC can't tell otherwise - #R1_2 = ( 18 *LAMBDA ).round(3) - R1_2 = ( 6 *LAMBDA ).round(3) - R2_3 = ( 6 *LAMBDA ).round(3) - R3_2 = ( 3 *LAMBDA ).round(3) - R3_2_a = ( 4 *LAMBDA ).round(3) - R3_3 = ( 2.5 *LAMBDA ).round(3) - R3_4 = ( 4 *LAMBDA ).round(3) - R4_3 = ( 1.5 *LAMBDA ).round(3) - R4_4 = ( 4 *LAMBDA ).round(3) - R5_3 = ( 4 *LAMBDA ).round(3) - R5_5_b = ( 5 *LAMBDA ).round(3) - R6_3 = ( 4 *LAMBDA ).round(3) - R7_2 = ( 3 *LAMBDA ).round(3) - R7_4 = ( 6 *LAMBDA ).round(3) - R8_1 = ( 3 *LAMBDA ).round(3) - R9_2 = ( 4 *LAMBDA ).round(3) - R9_4 = ( 8 *LAMBDA ).round(3) - R11_1 = ( 7 *LAMBDA ).round(3) - R11_3 = ( 5 *LAMBDA ).round(3) - R11_5 = ( 6 *LAMBDA ).round(3) - R13_2 = ( 3 *LAMBDA ).round(3) - R14_1 = ( 3 *LAMBDA ).round(3) - if NBR_OF_METALS > 3 - R15_1 = ( 3 *LAMBDA ).round(3) - R15_2 = ( 4 *LAMBDA ).round(3) - R15_4 = ( 8 *LAMBDA ).round(3) - else - R15_1 = ( 5 *LAMBDA ).round(3) - R15_2 = ( 3 *LAMBDA ).round(3) - R15_4 = ( 6 *LAMBDA ).round(3) - end - R17_1 = ( 12 *LAMBDA ).round(3) - R17_2 = ( 18 *LAMBDA ).round(3) - R17_3 = ( 6 *LAMBDA ).round(3) - R17_4 = ( 6 *LAMBDA ).round(3) - R20_11 = ( 5 *LAMBDA ).round(3) - R21_1 = ( 3 *LAMBDA ).round(3) - if NBR_OF_METALS > 4 - R22_1 = ( 3 *LAMBDA ).round(3) - R22_2 = ( 4 *LAMBDA ).round(3) - R22_4 = ( 8 *LAMBDA ).round(3) - else - R22_1 = ( 6 *LAMBDA ).round(3) - R22_2 = ( 6 *LAMBDA ).round(3) - R22_4 = ( 12 *LAMBDA ).round(3) - end - R25_1 = ( 3 *LAMBDA ).round(3) - R25_2 = ( 3 *LAMBDA ).round(3) - R25_3 = ( 1 *LAMBDA ).round(3) - if NBR_OF_METALS > 5 - R26_1 = ( 3 *LAMBDA ).round(3) - R26_2 = ( 4 *LAMBDA ).round(3) - R26_3 = ( 1 *LAMBDA ).round(3) - R26_4 = ( 8 *LAMBDA ).round(3) - else - R26_1 = ( 4 *LAMBDA ).round(3) - R26_2 = ( 4 *LAMBDA ).round(3) - R26_3 = ( 2 *LAMBDA ).round(3) - R26_4 = ( 8 *LAMBDA ).round(3) - end - R28_1 = ( 45 *LAMBDA ).round(3) - R28_2 = ( 14 *LAMBDA ).round(3) - R28_3 = ( 5 *LAMBDA ).round(3) - R28_4 = ( 3 *LAMBDA ).round(3) - R28_5 = ( 5 *LAMBDA ).round(3) - R28_6 = ( 2 *LAMBDA ).round(3) - R28_7 = ( 25 *LAMBDA ).round(3) - R28_8 = ( 5 *LAMBDA ).round(3) - R28_9 = ( 9 *LAMBDA ).round(3) - R28_10 = ( 23 *LAMBDA ).round(3) - R28_11 = ( 45 *LAMBDA ).round(3) - R29_1 = ( 4 *LAMBDA ).round(3) - R29_2 = ( 4 *LAMBDA ).round(3) - R29_3 = ( 1 *LAMBDA ).round(3) - R30_1 = ( 5 *LAMBDA ).round(3) - R30_2 = ( 5 *LAMBDA ).round(3) - R30_3 = ( 2 *LAMBDA ).round(3) - R30_4 = ( 10 *LAMBDA ).round(3) - R31_1 = ( 34 *LAMBDA ).round(3) - R31_2 = ( 56 *LAMBDA ).round(3) - R31_3 = ( 17 *LAMBDA ).round(3) - R31_4 = ( 23 *LAMBDA ).round(3) - R31_5 = ( 39 *LAMBDA ).round(3) - R31_6 = ( 6 *LAMBDA ).round(3) - R31_7 = ( 34 *LAMBDA ).round(3) - R31_8 = ( 13 *LAMBDA ).round(3) -end - - -# KLAYOUT setttings -######################## -# Use a tile size of 1mm -tiles(1000.um) -# Use a tile border of 10 micron: -tile_borders(1.um) -#no_borders - -# Use 4 CPU cores -threads(4) -verbose(true) - -# 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 - -# layers definitions -######################## -info("Layers definitions") - - DNW = input(38,0) - NW = input(42,0) - PW = input(41,0) - CW = input(59,0) - AA = input(43,0) - TA = input(60,0) - PBase = input(58,0) - PL = input(46,0) - SB = input(29,0) - Nselect = input(45,0) - Pselect = input(44,0) - PO2 = input(56,0) - HR = input(34,0) - Contact = input(25,0) - ContactPoly = input(47,0) - ContactActive = input(48,0) - ContactPoly2 = input(55, 0) - CT = Contact + ContactPoly + ContactActive + ContactPoly2 - M1 = input(49,0) - V1 = input(50,0) - M2 = input(51,0) - V2 = input(61,0) - M3 = input(62,0) - V3 = input(30,0) - M4 = input(31,0) - CTM = input(35,0) - V4 = input(32,0) - M5 = input(33,0) - V5 = input(36,0) - M6 = input(37,0) - Glass = input(52,0) - Pads = input(26,0) - -# layers processing -######################## -info("Layers processing") -#CHIP = extent.sized(1.0) -NP = AA & Nselect -PP = AA & Pselect -NSTP = NP.and(NW) -PSTP = PP.not(NW) -GATE = PL & AA - -# DRC section -######################## -info("DRC section") - -### Deep NWell -DNW.ongrid(0.5*LAMBDA).output("DNW_offgrid", "Offgrid vertex on DNW") -DNW.with_angle(0 .. 45).output("DNW_angle", "Non 45 degree angle DNW") -DNW.edges.and(PW).output("DNW_PW","DNW cannot cross PWell") -DNW.width(R31_1, euclidian).output("31.1 DNW_width", "31.1 : Min. DNW width : #{R31_1}um") -DNW.isolated(R31_2, euclidian).output("31.2 DNW_space", "31.2 : Min. DNW spacing : #{R31_2}um") -NW.enclosing(DNW, R31_3, euclidian).output("31.3 NW_enc_DNW", "31.3 : Min. NWell enclosing DNW : #{R31_3}um") -DNW.enclosing(NW, R31_4, euclidian).output("31.4 DNW_enc_NW", "31.4 : Min. DNW enclosing NWell : #{R31_4}um") -DNW.separation(NW, R31_5, euclidian).output("31.5 DNW_sep_NW", "31.5 : Min. DNW separation NWell : #{R31_5}um") -DNW.not(NW).enclosing(NP, R31_6, euclidian).output("31.6 DNW_enc_NP", "31.6 : Min. PW in DNW enclosing N+ : #{R31_6}um") -DNW.separation(NP, R31_7, euclidian).output("31.7 DNW_sep_NP", "31.7 : Min. DNW separation N+ : #{R31_7}um") - -### Nwell / Pwell -NW.ongrid(0.5*LAMBDA).output("NW_offgrid", "Offgrid vertex on NWell") -NW.with_angle(0 .. 45).output("NW_angle", "Non 45 degree angle NWell") -NW.and(PW).output("NW_PW","NW over PW not allowed") -NW.width(R1_1, euclidian).output("1.1 NW_width", "1.1 : Min. NWell width : #{R1_1}um") -NW.isolated(R1_2, euclidian).output("1.2 NW_space", "1.2 : Min. NWell spacing : #{R1_2}um") -NW.and(TA).isolated(18, euclidian).output("1.3 NW_TA_space", "1.3 : Min. NWell-TA spacing : #{R1_3}um") -PW.width(R1_1, euclidian).output("1.1 PW_width", "1.1 : Min. PWell width : #{R1_1}um") -PW.isolated(R1_2, euclidian).output("1.2 PW_space", "1.2 : Min. PWell spacing : #{R1_2}um") -PW.and(TA).isolated(R1_3, euclidian).output("1.3 PW_TA_space", "1.3 : Min. PWell-TA spacing : #{R1_3}um") - -### Active -AA.ongrid(0.5*LAMBDA).output("AA_offgrid", "Offgrid vertex on AA") -AA.with_angle(0 .. 45).output("AA_angle", "Non 45 degree angle AA") -AA.width(R2_1, euclidian).output("2.1 AA_width", "2.1 : Min. active width : #{R2_1}um") -AA.space(R2_2, euclidian).output("2.2 AA_space", "2.2 : Min. active spacing : #{R2_2}3um") -NW.enclosing(PP.interacting(GATE), R2_3, euclidian).output("2.3 NW_enc_PP", "2.3 : Min. NWell enclosing Source/Drain : #{R2_3}um") -PW.enclosing(NP.interacting(GATE), R2_3, euclidian).output("2.3 PW_enc_NP", "2.3 : Min. PWell enclosing Source/Drain : #{R2_3}um") -NW.enclosing(NP, R2_4, euclidian).output("2.4 NW_enc_NP", "2.4 : Min. NWell enclosing Nstrap : #{R2_4}um") -PW.enclosing(PP, R2_4, euclidian).output("2.4 PW_enc_PP", "2.4 : Min. PWell enclosing Pstrap : #{R2_4}um") -NP.separation(PP, R2_5, euclidian).polygons.without_area(0).output("2.5 NP_space_PP", "2.5 : Min. N+ space P+ : #{R2_5}um (if not abutted)") - -### TA Thick Active -TA.ongrid(0.5*LAMBDA).output("TA_offgrid", "Offgrid vertex on TA") -TA.with_angle(0 .. 45).output("TA_angle", "Non 45 degree angle TA") -TA.width(R24_1, euclidian).output("24.1 TA_width", "24.1 : Min. TA width : #{R24_1}um") -TA.space(R24_2, euclidian).output("24.2 TA_space", "24.2 : Min. TA spacing : #{R24_2}um") -TA.enclosing(AA, R24_3, euclidian).output("24.3 TA_enc_AA", "24.3 : Min. TA enclosing Active : #{R24_3}um") -TA.separation(AA, R24_4, euclidian).output("24.4 TA_space_AA", "24.4 : Min. TA spacing Active : #{R24_4}um") -TA.and(GATE).width(R24_5, euclidian).output("24.5 TA_gate_width", "24.5 : Min. TA Gate width : #{R24_5}um") -AA.edges.and(TA).output("24.6 AA_in_TA","24.6 : Active edge cannot cross TA") - -### Poly -PL.ongrid(0.5*LAMBDA).output("POLY_offgrid", "Offgrid vertex on Poly") -PL.with_angle(0 .. 45).output("POLY_angle", "Non 45 degree angle Poly") -PL.width(R3_1, euclidian).output("3.1 POLY_width", "3.1 : Min. Poly width : #{R3_1}um") -PL.space(R3_2, euclidian).output("3.2 Poly_space", "3.2 : Min. Poly spacing : #{R3_2}um") -GATE.space(R3_2_a, euclidian).output("3.2a Gate_space", "3.2a : Min. Gate spacing : #{R3_2_a}um") -PL.enclosing(GATE, R3_3, projection).polygons.without_area(0).output("3.3 PL_enc_GATE", "3.3 : Min. Poly extention Gate : #{R3_3}um") -AA.enclosing(GATE, R3_4, projection).polygons.without_area(0).output("3.4 AA_enc_GATE", "3.4 : Min. Source/Drain length : #{R3_4}um") -PL.not(AA).separation(AA, 1, euclidian).polygons.without_area(0).output("3.5 PL_space_AA", "3.5 : Min. Poly on Field spacing Active : #{R3_5}um") - -### Poly2 -if !DEEP -PO2.ongrid(0.5*LAMBDA).output("POLY2_offgrid", "Offgrid vertex on Poly2") -PO2.with_angle(0 .. 45).output("POLY2_angle", "Non 45 degree angle Poly2") -PO2.width(R12_1, euclidian).output("12.1 POLY2_width", "12.1 : Min. Poly2 width : #{R12_1}um") -PO2.space(R12_2, euclidian).output("12.2 POLY2_space", "12.2 : Min. Poly2 space : #{R12_2}um") -# rule R12.3 not coded -PO2.not(AA).separation(AA, R12_4, euclidian).output("12.4 POLY2_space_AA"," 12.4 : Min. Poly2 on Field spacing Active : #{R12_4}um") -PO2.not(PL).separation(PL, R12_5, euclidian).output("12.5 POLY2_space_PL"," 12.5 : Min. Poly2 spacing Poly : #{R12_5}um") -PO2.enclosing(PL, R12_5, euclidian).output("12.5 POLY2_overlap_PL"," 12.5 : Min. Poly2 overlap of Poly : #{R12_5}um") -PO2.separation(AA.or(PL).and(CT), R12_6, euclidian).output("12.6 POLY2_space_CT"," 12.5 : Min. Poly2 spacing Poly or Active contact: #{R12_6}um") -PO2cap = PL & PO2 -PO2cap.width(R11_1, euclidian).output("11.1 POLY2CAP_width", "11.1 : Min. Poly2 Capacitor width : #{R11_1}um") -PO2cap.space(R11_2, euclidian).output("11.2 POLY2CAP_space", "11.2 : Min. Poly2 Capacitor space : #{R11_2}um") -PL.enclosing(PO2cap, R11_3, euclidian).output("12.3 PL_overlap_POLY2CAP"," 11.3 : Min. Poly overlap of Poly2 Capacitor : #{R11_3}um") -PO2cap.edges.separation(AA.or(NW).edges, R11_4, euclidian).output("11.4 POLY2CAP_space_AA/NW"," 11.4 : Min. Poly2 Capacitor spacing Active or Well: #{R11_4}um") -PO2cap.separation(PL.and(CT), R11_5, euclidian).output("11.5 POLY2CAP_space_PLCT"," 11.5 : Min. Poly2 Capacitor spacing Poly contact: #{R11_5}um") -PO2cap.separation(M1.or(M2).or(M3), R11_6, euclidian).output("11.6 POLY2CAP_space_METAL"," 11.6 : Min. Poly2 Capacitor spacing any Metal: #{R11_6}um") -PO2cap.forget - -### Capacitor Well -CW.ongrid(0.5*LAMBDA).output("CW_offgrid", "Offgrid vertex on CapacitorWell") -CW.with_angle(0 .. 45).output("CW_angle", "Non 45 degree angle CapacitorWell") -CW.width(R17_1, euclidian).output("17.1 CW_width", "17.1 : Min. CapacitorWell width : #{R17_1}um") -CW.space(R17_2, euclidian).output("17.2 CW_space", "17.2 : Min. CapacitorWell space : #{R17_2}um") -AA.not(CW).separation(CW, R17_3, euclidian).output("17.3 CW_space_AA"," 17.3 : Min. CapacitorWell spacing Active : #{R17_3}um") -CW.enclosing(AA, R17_4, euclidian).output("17.4 CW_overlap_AA"," 17.4 : Min. CapacitorWell overlap of Active : #{R17_4}um") -LinCap = PL & CW -LinCap.width(R18_1, euclidian).output("18.1 LC_width", "18.1 : Min. Linear Capacitor width : #{R18_1}um") -LinCap.space(R18_2, euclidian).output("18.2 LC_space", "18.2 : Min. Linear Capacitor space : #{R18_2}um") -LinCap.separation(AA.and(CT), R18_3, euclidian).output("18.3 LC_space_AACT"," 18.3 : Min. Linear Capacitor spacing Active contact : #{R18_3}um") -LinCap.separation(PL.and(CT), R18_4, euclidian).output("18.4 LC_space_PLCT"," 18.4 : Min. Linear Capacitor spacing Poly contact : #{R18_4}um") -LinCap.forget -end - -### N+/P+ Select -Nselect.ongrid(0.5*LAMBDA).output("NSel_offgrid", "Offgrid vertex on Nselect") -Pselect.ongrid(0.5*LAMBDA).output("PSel_offgrid", "Offgrid vertex on Pselect") -Nselect.with_angle(0 .. 45).output("N+_angle", "Non 45 degree angle Nselect") -Pselect.with_angle(0 .. 45).output("N+_angle", "Non 45 degree angle Pselect") -NP.enclosing(GATE, R4_1, projection).polygons.without_area(0).output("4.1 N+_enc_GATE", "4.1 : Min. N+ extention Gate on Source/Drain : #{R4_1}um") -PP.enclosing(GATE, R4_1, projection).polygons.without_area(0).output("4.1 P+_enc_GATE", "4.1 : Min. P+ extention Gate on Source/Drain : #{R4_1}um") -Nselect.enclosing(AA, R4_2, euclidian).output("4.2 N+_enc_AA", "4.2 : Min. N+ enclosing Active : #{R4_2}um") -Pselect.enclosing(AA, R4_2, euclidian).output("4.2 P+_enc_AA", "4.2 : Min. P+ enclosing Active : #{R4_2}um") -Nselect.enclosing(CT, R4_3, euclidian).output("4. N+_enc_CT", "4.3 : Min. N+ enclosing Contact : #{R4_3}um") -Pselect.enclosing(CT, R4_3, euclidian).output("4.3 P+_enc_CT", "4.3 : Min. P+ enclosing Contact : #{R4_3}um") -Nselect.width(R4_4,euclidian).output("4.4 N+_width", "4.4 : Min. N+ width : #{R4_4}um") -Pselect.width(R4_4,euclidian).output("4.4 P+_width", "4.4 : Min. N+ width : #{R4_4}um") -Nselect.space(R4_4,euclidian).output("4.4 N+_space", "4.4 : Min. N+ spacing : #{R4_4}um") -Pselect.space(R4_4,euclidian).output("4.4 P+_space", "4.4 : Min. N+ spacing : #{R4_4}um") -Nselect.and(Pselect).output("4.4 N+_and_P+", "4.4 : N+ over P+ not allowed") - -### HR - High Resistive -HR.ongrid(0.5*LAMBDA).output("HR_offgrid", "Offgrid vertex on HighRes") -HR.with_angle(0 .. 45).output("HR_angle", "Non 45 degree angle HighRes") -HR.width(R27_1, euclidian).output("27.1 HR_width", "27.1 : Min. HiRes width : #{R27_1}um") -HR.space(R27_2, euclidian).output("27.2 HR_space", "27.2 : Min. HiRes spacing : #{R27_2}um") -HR.and(CT).output("27.3 CT_and_HR", "27.3 : Contact on HiRes not allowed") -HR.separation(CT, R27_3, euclidian).output("27.3 HR_space_CT", "27.3 : Min. HiRes space to Contact : #{R27_3}um") -HR.separation(AA, R27_5, euclidian).output("27.4 HR_space_AA", "27.4 : Min. HiRes space to Active : #{R27_4}um") -HR.separation(PO2, R27_5, euclidian).output("27.5 HR_space_PO2", "27.5 : Min. HiRes space to Poly2 : #{R27_5}um") -HR.and(PO2).and(AA).output("27.6 HR_and_active", "27.6 : HiRes Po2 over Active not allowed") -HR.and(PO2).and(NW.or(PW)).output("27.6 HR_and_Well", "27.6 : HiRes Po2 over Well not allowed") -HR.and(PO2).width(R27_7,euclidian).output("27.7 HRPO2_width", "27.7 : Min. HiRes Poly2 width : #{R27_7}um") -HR.and(PO2).space(R27_8,euclidian).output("27.8 HRPO2_space", "27.8 : Min. HiRes Poly2 space : #{R27_8}um") -HR.enclosing(PO2, R27_9, projection).output("27.9 HR_enc_PO2", "27.9 : Min. HiRes enclosing Poly2 : #{R27_9}um") - -### SB - Silicide block -SB.ongrid(0.5*LAMBDA).output("SB_offgrid", "Offgrid vertex on Sil. Block") -SB.with_angle(0 .. 45).output("SB_angle", "Non 45 degree angle Sil. Block") -SB.width(R20_1, euclidian).output("20.1 SB_width", "20.1 : Min. Sil. Block width : #{R20_1}um") -SB.space(R20_2, euclidian).output("20.2 SB_space", "20.2 : Min. Sil. Block spacing : #{R20_2}um") -SB.separation(CT, R20_3, euclidian).output("20.3 SB_space_CT", "20.3 : Min. Sil. Block space to Contact : #{R20_3}um") -SB.and(CT).output("20.3 SB_and_CT", "20.3 : Sil. Block over Contact not allowed") -SB.separation(AA, R20_4, euclidian).output("20.4 SB_space_AA", "20.4 : Min. Sil. Block space to Active : #{R20_4}um") -SB.separation(PL, R20_5, euclidian).output("20.5 SB_space_PL", "20.5 : Min. Sil. Block space to Poly : #{R20_5}um") -SB.and(GATE).output("20.6 SBres_overAA","20.6 : SB resistor over Active not allowed") -SB.and(PL).and(Nselect.or(Pselect)).output("20.6 SBres_over_WELL","20.6 : SB resistor over Well not allowed") -SB.and(PL).width(R20_7,euclidian).output("20.6 SBres_width", "20.7 : Min. SB resistor width : #{R20_7}um") -SB.and(PL).space(R20_7,euclidian).output("20.7 SBres_space", "20.7 : Min. SB resistor space : #{R20_7}um") -SB.enclosing(AA, R20_8, projection).polygons.without_area(0).output("20.8 SB_enc_AA", "20.8 : Min. Sil. Block enclosing Active : #{R20_8}um") -AA.enclosing(SB, R20_9, projection).polygons.without_area(0).output("20.9 AA_enc_SB", "20.9 : Min. Active enclosing Sil. Block : #{R20_9}um") -SB.enclosing(PL, R20_9, projection).output("20.8 SB_enc_PL", "20.8 : Min. Sil. Block enclosing Poly : #{R20_8}um") -PL.enclosing(SB, R20_8, projection).polygons.without_area(0).output("20.9 PL_enc_SB", "20.9 : Min. Poly enclosing Sil. Block : #{R20_9}um") -SB.separation(GATE, R20_11, euclidian).output("20.11 SB_space_GATE", "20.11 : Min. Sil. Block space to Gate : #{R20_11}um") - -### Contact -CT.ongrid(0.5*LAMBDA).output("CT_offgrid", "Offgrid vertex on Contact") -CT.with_angle(0 .. 90).output("CT_angle", "Non 90 degree angle Contact") -CT.and(GATE).output("CT_and_GATE", "Contact on Gate not allowed") -CT.not(M1).output("CT_not_M1", "Contact without Metal1 not recommended") -# CT.drc(length != R5_1).output("5.1 CT_width", "5.1 : Exact Contact width : #{R5_1}um") -CT.width(R5_1).output("5.1 CT_width", "5.1 : Exact Contact width : #{R5_1}um") -CT.without_area(R5_1*R5_1).output("5.1 CT_area", "5.1 : Exact Contact Area : #{R5_1*R5_1}um2") -CT.space(R5_3, euclidian).output("5.3 CT_space", "5.3 : Contact spacing : #{R5_3}um") -PL.enclosing(CT, R5_2_b, euclidian).output("5.2 PL_enc_CT", "5.2 : Min. Poly enclosing Contact : #{R5_2_b}um") -AA.enclosing(CT, R6_2_b, euclidian).output("6.2 AA_enc_CT", "6.2 : Min. Active enclosing Contact : #{R6_2_b}um") -PO2.enclosing(CT, R13_3, euclidian).output("13.3 PO2_enc_CT", "13.3 : Min. Poly2 enclosing Contact : #{R13_3}um") -CT.and(AA).separation(GATE, R5_4, euclidian).output("5.4 CTAA_space_GATE", "5.4 : Min. ActiveContact space to Gate : #{R5_4}um") -CT.and(PL).separation(PL, R5_5_b, euclidian).polygons.without_area(0).output("5.5.b CTPL_space_Poly", "5.5.b : Min. PolyContact space to Poly : #{R5_5_b}um") -CT.and(PL).separation(AA, R5_6_b, euclidian).output("5.6.b CTPL_space_AA", "5.6.b : Min. PolyContact space to AA : #{R5_6_b}um") -# rule 5.7.b not coded -CT.and(AA).separation(AA, R6_5_b, euclidian).polygons.without_area(0).output("6.5.b CTAA_space_AA", "6.5.b : Min. ActiveContact space to AA : #{R6_5_b}um") -CT.and(AA).separation(PL, R6_6_b, euclidian).output("6.6.b CTAA_space_PL", "6.6.b : Min. ActiveContact space to Poly : #{R6_6_b}um") -CT.and(AA).separation(CT.and(PL), R6_7_b, euclidian).output("6.7.b CTAA_space_CTPL", "6.7.b : Min. ActiveContact space to PolyContact : #{R6_7_b}um") -# rule 6.8.b not coded -CT.and(PO2).separation(AA, R13_5, euclidian).output("13.5 CTPO2_space_AA", "13.5 : Min. Poly2Contact space to AA : #{R13_5}um") -CT.and(PO2).separation(PL, R13_5, euclidian).output("13.5 CTPO2_space_PL", "13.5 : Min. Poly2Contact space to Poly : #{R13_5}um") -M1.enclosing(CT, R7_3, euclidian).output("7.3 M1_enc_CT", "7.3 : Min. Metal1 enclosing Contact : #{R7_3}um") - -### Metal 1 -M1.ongrid(0.5*LAMBDA).output("M1_offgrid", "Offgrid vertex on ME1") -M1.with_angle(0 .. 45).output("M1_angle", "Non 45 degree angle ME1") -M1.holes.with_area(0 .. R7_1*R7_1).output("M1_holes", "Min. Metal1 holes area : #{R7_1*R7_1}um2") -M1.width(R7_1, euclidian).output("7.1 M1_width", "7.1 : Min. Metal1 width : #{R7_1}um") -M1.space(R7_2, euclidian).output("7.2 M1_space", "7.2 : Min. Metal1 spacing : #{R7_2}um") -M1.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M1,R7_4,euclidian).polygons.without_area(0).output("7.4 M1_10_space", "7.4 : Space if at least one metal1 line width is > #{10*LAMBDA}um : #{R7_4}um") - -### Via 1 -V1.ongrid(0.5*LAMBDA).output("V1_offgrid", "Offgrid vertex on Via1") -V1.not(M1).output("V1_not_M1", "Via1 without Metal1 not allowed") -V1.not(M2).output("V1_not_M2", "Via1 without Metal2 not allowed") -V1.with_angle(0 .. 90).output("V1_angle", "Non 90 degree angle Via1") -V1.width(R8_1,square).output("8.1 V1_width", "8.1 : Exact Via1 width : #{R8_1}um") -V1.without_area(R8_1*R8_1).output("8.1 V1_width", "8.1 : Exact Via1 width : #{R8_1}um2") -V1.space(R8_2,euclidian).output("8.2 V1_space", "8.2 : Via1 spacing : #{R8_2}um") -M1.enclosing(V1, R8_3, euclidian).output("8.3 M1_enc_V1", "8.3 : Min. Metal1 enclosing Via1 : #{R8_3}um") -M2.enclosing(V1, R8_3, euclidian).output("9.3 M2_enc_V1", "9.3 : Min. Metal2 enclosing Via1 : #{R9_3}um") -if !DEEP && NBR_OF_METALS < 4 - V1.and(CT).or(V1.separation(CT, R8_4, euclidian).polygons).output("8.4 V1_space_CT", "8.4 : Via1 space CT : #{R8_4}um") - V1.separation(PL + AA, R8_5, euclidian).output("8.5 V1_space_PL/AAedges", "8.5 : Via1 space to Poly orActive edges : #{R8_5}um") -end -if DFM - M1.and(M2).not(V1).with_holes(1,1).output("2_V1", "Min. 2 Via1 are needed") -end - -### Metal 2 -M2.ongrid(0.5*LAMBDA).output("M2_offgrid", "Offgrid vertex on ME2") -M2.with_angle(0 .. 45).output("M2_angle", "Non 45 degree angle ME2") -M2.width(R9_1, euclidian).output("9.1 M2_width", "9.1 : Min. Metal2 width : #{R9_1}um") -M2.space(R9_2, euclidian).output("9.2 M2_space", "9.2 : Min. Metal2 spacing : #{R9_2}um") -M2.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M2,R9_4,euclidian).polygons.without_area(0).output("9.4 M2_10_space", "9.4 : Space if at least one metal2 line width is > #{10*LAMBDA}um : #{R9_4}um") - -### Via 2 -V2.ongrid(0.5*LAMBDA).output("V2_offgrid", "Offgrid vertex on Via2") -V2.not(M3).output("V2_not_M3", "Via2 without Metal3 not allowed") -V2.not(M2).output("V2_not_M2", "Via2 without Metal2 not allowed") -V2.with_angle(0 .. 90).output("V2_angle", "Non 90 degree angle Via2") -V2.width(R14_1, square).output("14.1 V2_width", "14.1 : Exact Via2 width : #{R14_1}um") -V2.without_area(R14_1*R14_1).output("14.1 V2_width", "14.1 : Exact Via2 width : #{R14_1}um2") -V2.space(R14_2, euclidian).output("14.2 V2_space", "14.2 : Via2 spacing : #{R14_2}um") -M2.enclosing(V2, R14_3, euclidian).output("14.3 M2_enc_V2", "14.3 : Min. Metal2 enclosing Via2 : #{R14_3}um") -M3.enclosing(V2, R15_3, euclidian).output("15.3 M3_enc_V2", "15.3 : Min. Metal3 enclosing Via2 : #{R15_3}um") -if !DEEP && NBR_OF_METALS < 4 - V2.and(V1).or(V2.separation(V1, R14_4, euclidian).polygons).output("14.4 V2_space_V1", "14.4 : Via2 space Via1 : #{R14_4}um") -end -if DFM - M2.and(M3).not(V2).with_holes(1,1).output("2_V2", "Min. 2 Via2 are needed") -end - -### Metal 3 -M3.ongrid(0.5*LAMBDA).output("M3_offgrid", "Offgrid vertex on ME3") -M3.with_angle(0 .. 45).output("M3_angle", "Non 45 degree angle ME3") -M3.width(R15_1, euclidian).output("15.1 M3_width", "15.1 : Min. Metal3 width : #{R15_1}um") -M3.space(R15_2, euclidian).output("15.2 M3_space", "15.2 : Min. Metal3 spacing : #{R15_2}um") -M3.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M3, R15_4, euclidian).polygons.without_area(0).output("15.4 M3_10_space", "15.4 : Space if at least one metal3 line width is > #{10*LAMBDA}um : #{R15_4}um") - -### Cap Top Metal -if SUBM || DEEP -CTM.ongrid(0.5*LAMBDA).output("CTM_offgrid", "Offgrid vertex on CTM") -CTM.with_angle(0 .. 45).output("CTM_angle", "Non 45 degree angle CTM") -CTM.width(R28_1, euclidian).output("28.1 CTM_width", "28.1 : Min. Cap Top Metal width : #{R28_1}um") -CTM.space(R28_2, euclidian).output("28.2 CTM_space", "28.2 : Min. Cap Top Metal spacing : #{R28_2}um") -if NBR_OF_METALS == 4 - TM = M4 - VT = V3 - TB = V2 -end -if NBR_OF_METALS == 5 - TM = M5 - VT = V4 - VB = V3 -end -if NBR_OF_METALS == 6 - TM = M6 - VT = V5 - VB = V4 -end -TM.enclosing(CTM, R28_3, euclidian).output("28.3 TM_overlap_CTM", "28.3 : Min. Top Metal overlap Cap Top Metal : #{R28_3}um") -CTM.enclosing(VT, R28_4, euclidian).output("28.4 CTM_overlap_VT", "28.4 : Min. Cap Top Metal overlap Top Via : #{R28_4}um") -CTM.separation(VB, R28_5, euclidian).output("28.5 CTM_space_VB", "28.5 : Min. Cap Top Metal space Bottom Via : #{R28_5}um") -CTM.separation(VT, R28_5, euclidian).output("28.5 CTM_space_VT", "28.5 : Min. Cap Top Metal space Top Via : #{R28_5}um") -TM.enclosing(VB, R28_6, euclidian).output("28.6 TM_overlap_VB", "28.6 : Min. Top Metal overlap Bottom Via : #{R28_6}um") -# rule 28.7 not coded -CTM.not_interacting(VT).width(R28_8, euclidian).output("28.8 CTMdummies_width", "28.8 : Min. dummies Cap Top Metal width : #{R28_8}um") -TM.interacting(CTM).space(R28_9, euclidian).output("28.9 VT_space", "28.9 : Min. Top Metal spacing : #{R28_9}um") -VT.interacting(CTM).space(R28_10, euclidian).output("28.10 VT_space", "28.10 : Min. Top Via spacing : #{R28_10}um") -VB.interacting(TM.interacting(CTM)).space(R28_11, euclidian).output("28.11 VB_space", "28.11 : Min. Bottom Via spacing : #{R28_11}um") -CTM.sized(-15.um).sized(15.um).output("28.12 CTM_width", "28.12 : Max. CTM width/length : 30um") -TM.interacting(CTM).sized(-17.5.um).sized(17.5.um).output("28.13 TM_width", "28.13 : Max. Top Metal width/length : 35um") -CTM.and(VB).output("28.14 CTM_VB", "28.14 : no VB under CTM allowed") -CTM.and(AA.or(PL)).output("28.15 CTM_AA", "28.15 : no active or passive circuitry under CTM allowed") -end - -### Via 3 -if NBR_OF_METALS > 3 -V3.ongrid(0.5*LAMBDA).output("V3_offgrid", "Offgrid vertex on Via3") -V3.not(M3).output("V3_not_M3", "Via3 without Metal3 not allowed") -V3.not(M4).output("V3_not_M4", "Via3 without Metal4 not allowed") -V3.with_angle(0 .. 90).output("V3_angle", "Non 90 degree angle Via3") -V3.width(R21_1, square).output("21.1 V3_width", "21.1 : Exact Via3 width : #{R21_1}um") -V3.without_area(R21_1*R21_1).output("21.1 V3_width", "21.1 : Exact Via3 width : #{R21_1}um2") -V3.space(R21_2, euclidian).output("21.2 V3_space", "21.2 : Via3 spacing : #{R21_2}um") -M3.enclosing(V3, R21_3, euclidian).output("21.3 M3_enc_V3", "21.3 : Min. Metal3 enclosing Via3 : #{R21_3}um") -M4.enclosing(V3, R22_3, euclidian).output("22.3 M4_enc_V3", "22.3 : Min. Metal4 enclosing Via3 : #{R22_3}um") -if DFM - M3.and(M4).not(V3).with_holes(1,1).output("2_V3", "Min. 2 Via3 are needed") -end - -### Metal 4 -M4.ongrid(0.5*LAMBDA).output("M4_offgrid", "Offgrid vertex on ME4") -M4.with_angle(0 .. 45).output("M4_angle", "Non 45 degree angle ME4") -M4.width(R22_1, euclidian).output("22.1 M4_width", "22.1 : Min. Metal4 width : #{R22_1}um") -M4.space(R22_2, euclidian).output("22.2 M4_space", "22.2 : Min. Metal4 spacing : #{R22_2}um") -M4.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M4, R22_4, euclidian).polygons.without_area(0).output("22.4 M4_10_space", "22.4 : Space if at least one metal4 line width is > #{10*LAMBDA}um : #{R22_4}um") - -### Via 4 -if NBR_OF_METALS > 4 -V4.ongrid(0.5*LAMBDA).output("V4_offgrid", "Offgrid vertex on Via4") -V4.not(M5).output("V4_not_M5", "Via4 without Metal5 not allowed") -V4.not(M4).output("V4_not_M4", "Via4 without Metal4 not allowed") -V4.with_angle(0 .. 90).output("V4_angle", "Non 90 degree angle Via4") -V4.width(R25_1, square).output("25.1 V4_width", "25.1 : Exact Via4 width : #{R25_1}um") -V4.without_area(R25_1*R25_1).output("25.1 V4_width", "25.1 : Via4 width : #{R25_1}um2") -V4.space(R25_2, euclidian).output("25.2 V4_space", "25.2 : Exact Via4 spacing : #{R25_2}um") -M4.enclosing(V4, R25_3, euclidian).output("25.3 M4_enc_V4", "25.3 : Min. Metal4 enclosing Via4 : #{R25_3}um") -M5.enclosing(V4, R26_3, euclidian).output("26.3 M5_enc_V4", "26.3 : Min. Metal5 enclosing Via4 : #{R26_3}um") -if DFM - M4.and(M5).not(V4).with_holes(1,1).output("2_V4", "Min. 2 Via4 are needed") -end - -### Metal 5 -M5.ongrid(0.5*LAMBDA).output("M5_offgrid", "Offgrid vertex on ME5") -M5.with_angle(0 .. 45).output("M5_angle", "Non 45 degree angle ME5") -M5.width(R26_1, euclidian).output("26.1 M5_width", "26.1 : Min. Metal5 width : #{R26_1}um") -M5.space(R26_2, euclidian).output("26.2 M5_space", "26.2 : Min. Metal5 spacing : #{R26_2}um") -M5.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M5, R26_4, euclidian).polygons.without_area(0).output("26.4 M5_10_space", "26 .4 : Space if at least one metal5 line width is > #{10*LAMBDA}um : #{R26_4}um") - -### Via 5 -if NBR_OF_METALS > 5 -V5.ongrid(0.5*LAMBDA).output("V5_offgrid", "Offgrid vertex on Via5") -V5.not(M5).output("V5_not_M5", "Via5 without Metal5 not allowed") -V5.not(M6).output("V5_not_M6", "Via5 without Metal6 not allowed") -V5.with_angle(0 .. 90).output("V4_angle", "Non 90 degree angle Via5") -V5.width(R29_1, square).output("29.1 V5_width", "29.1 : Exact Via5 width : #{R29_1}um") -V5.without_area(R29_1*R29_1).output("29.1 V5_width", "29.1 : Exact Via5 width : #{R29_1}um2") -V5.space(R29_2, euclidian).output("29.2 V5_space", "29.2 : Via5 spacing : #{R29_2}um") -M5.enclosing(V5, R29_3, euclidian).output("29.3 M5_enc_V5", "29.3 : Min. Metal5 enclosing Via5 : #{R29_3}um") -M6.enclosing(V5, R30_3, euclidian).output("30.3 M3_enc_V5", "30.3 : Min. Metal6 enclosing Via5 : #{R30_3}um") -if DFM - M5.and(M6).not(V5).with_holes(1,1).output("2_V5", "Min. 2 Via5 are needed") -end - -### Metal 6 -M6.ongrid(0.5*LAMBDA).output("M6_offgrid", "Offgrid vertex on ME6") -M6.with_angle(0 .. 45).output("M6_angle", "Non 45 degree angle ME5") -M6.width(R30_1, euclidian).output("30.1 M6_width", "30.1 : Min. Metal6 width : #{R30_1}um") -M6.space(R30_2, euclidian).output("30.2 M6_space", "30.2 : Min. Metal6 spacing : #{R30_2}um") -M6.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M5, 10, euclidian).polygons.without_area(0).output("30.4 M6_10_space", "30.4 : Space if at least one metal6 line width is > #{10*LAMBDA}um : #{R30_4}um") - -end -end -end - -# time spent for the DRC -time = Time.now -hours = ((time - tstart)/3600).to_i -minutes = ((time - tstart)/60 - hours * 60).to_i -seconds = ((time - tstart) - (minutes * 60 + hours * 3600)).to_i -$stdout.write "DRC finished at : #{time.hour}:#{time.min}:#{time.sec} - DRC duration = #{hours} hrs. #{minutes} min. #{seconds} sec.\n" - + + + + + drc + + + + false + false + + true + drc_scripts + tools_menu.drc.end + dsl + drc-dsl-xml + # +# MOSIS SCMOS DRC +# +######################## +tstart = Time.now + +# optionnal for a batch launch : klayout -b r drc_SCMOS.lydrc -rd input=my_layout.gds -rd topcell=your_topcell -rd output=SCMOS_DRC.lyrdb +if $input + if $topcell + source($input,$topcell) + else + source($input) + end +end + +if $output + report("SCMOS DRC runset", $output) +else + report("SCMOS DRC runset", "SCMOS_DRC.lyrdb") +end + + +# PROCESS OPTIONS +######################## +LAMBDA = 0.2 +SUBM = true +DEEP = false +NBR_OF_METALS = 6 + +DFM = false + +# design rules limits definitions +######################## +R1_3 = ( 6 *LAMBDA ).round(3) +R2_1 = ( 3 *LAMBDA ).round(3) +R2_2 = ( 3 *LAMBDA ).round(3) +R2_4 = ( 3 *LAMBDA ).round(3) +R2_5 = ( 4 *LAMBDA ).round(3) +R3_1 = ( 2 *LAMBDA ).round(3) +R3_5 = ( 1 *LAMBDA ).round(3) +R4_1 = ( 3 *LAMBDA ).round(3) +R4_2 = ( 2 *LAMBDA ).round(3) +R5_1 = ( 2 *LAMBDA ).round(3) +R5_2 = ( 1.5 *LAMBDA ).round(3) +R5_4 = ( 2 *LAMBDA ).round(3) +R5_2_b = ( 1 *LAMBDA ).round(3) +R5_6_b = ( 2 *LAMBDA ).round(3) +R5_7_b = ( 3 *LAMBDA ).round(3) +R6_1 = ( 2 *LAMBDA ).round(3) +R6_2 = ( 1.5 *LAMBDA ).round(3) +R6_4 = ( 2 *LAMBDA ).round(3) +R6_2_b = ( 1 *LAMBDA ).round(3) +R6_5_b = ( 5 *LAMBDA ).round(3) +R6_6_b = ( 2 *LAMBDA ).round(3) +R6_7_b = ( 3 *LAMBDA ).round(3) +R6_8_b = ( 4 *LAMBDA ).round(3) +R7_1 = ( 3 *LAMBDA ).round(3) +R7_3 = ( 1 *LAMBDA ).round(3) +R8_2 = ( 3 *LAMBDA ).round(3) +R8_3 = ( 1 *LAMBDA ).round(3) +R8_4 = ( 2 *LAMBDA ).round(3) +R9_1 = ( 3 *LAMBDA ).round(3) +R9_3 = ( 1 *LAMBDA ).round(3) +R10_1 = ( 60 *LAMBDA ).round(3) +R10_2 = ( 20 *LAMBDA ).round(3) +R10_3 = ( 6 *LAMBDA ).round(3) +R10_4 = ( 30 *LAMBDA ).round(3) +R10_5 = ( 15 *LAMBDA ).round(3) +R11_2 = ( 3 *LAMBDA ).round(3) +R11_4 = ( 2 *LAMBDA ).round(3) +R11_6 = ( 2 *LAMBDA ).round(3) +R12_1 = ( 2 *LAMBDA ).round(3) +R12_2 = ( 3 *LAMBDA ).round(3) +R12_3 = ( 2 *LAMBDA ).round(3) +R12_4 = ( 1 *LAMBDA ).round(3) +R12_5 = ( 2 *LAMBDA ).round(3) +R12_6 = ( 3 *LAMBDA ).round(3) +R13_1 = ( 2 *LAMBDA ).round(3) +R13_3 = ( 3 *LAMBDA ).round(3) +R13_4 = ( 2 *LAMBDA ).round(3) +R13_5 = ( 3 *LAMBDA ).round(3) +R14_2 = ( 3 *LAMBDA ).round(3) +R14_3 = ( 1 *LAMBDA ).round(3) +R14_4 = ( 2 *LAMBDA ).round(3) +if NBR_OF_METALS > 3 + R15_3 = ( 1 *LAMBDA ).round(3) +else + R15_3 = ( 2 *LAMBDA ).round(3) +end +R16_1 = ( 2 *LAMBDA ).round(3) +R16_2 = ( 3 *LAMBDA ).round(3) +R16_3 = ( 2 *LAMBDA ).round(3) +R16_4 = ( 4 *LAMBDA ).round(3) +R16_5 = ( 2 *LAMBDA ).round(3) +R16_6 = ( 2 *LAMBDA ).round(3) +R16_7 = ( 6 *LAMBDA ).round(3) +R16_8 = ( 4 *LAMBDA ).round(3) +R16_9 = ( 2 *LAMBDA ).round(3) +R16_10 = ( 3 *LAMBDA ).round(3) +R16_11 = ( 2 *LAMBDA ).round(3) +R18_1 = ( 3 *LAMBDA ).round(3) +R18_2 = ( 2 *LAMBDA ).round(3) +R18_3 = ( 3 *LAMBDA ).round(3) +R18_4 = ( 2 *LAMBDA ).round(3) +R18_5 = ( 6 *LAMBDA ).round(3) +R20_1 = ( 4 *LAMBDA ).round(3) +R20_2 = ( 4 *LAMBDA ).round(3) +R20_3 = ( 2 *LAMBDA ).round(3) +R20_4 = ( 2 *LAMBDA ).round(3) +R20_5 = ( 2 *LAMBDA ).round(3) +R20_7 = ( 5 *LAMBDA ).round(3) +R20_8 = ( 7 *LAMBDA ).round(3) +R20_9 = ( 2 *LAMBDA ).round(3) +R20_10 = ( 3 *LAMBDA ).round(3) +R21_2 = ( 3 *LAMBDA ).round(3) +R21_3 = ( 1 *LAMBDA ).round(3) +if NBR_OF_METALS > 4 + R22_3 = ( 1 *LAMBDA ).round(3) +else + R22_3 = ( 2 *LAMBDA ).round(3) +end +R23_1 = ( 8 *LAMBDA ).round(3) +R23_2 = ( 4 *LAMBDA ).round(3) +R23_3 = ( 8 *LAMBDA ).round(3) +R23_4 = ( 3 *LAMBDA ).round(3) +R23_5 = ( 2 *LAMBDA ).round(3) +R23_6 = ( 2 *LAMBDA ).round(3) +R23_7 = ( 2 *LAMBDA ).round(3) +R23_8 = ( 4 *LAMBDA ).round(3) +R23_9 = ( 2 *LAMBDA ).round(3) +R24_1 = ( 4 *LAMBDA ).round(3) +R24_2 = ( 4 *LAMBDA ).round(3) +R24_3 = ( 4 *LAMBDA ).round(3) +R24_4 = ( 4 *LAMBDA ).round(3) +R24_5 = ( 3 *LAMBDA ).round(3) +R27_1 = ( 4 *LAMBDA ).round(3) +R27_2 = ( 4 *LAMBDA ).round(3) +R27_3 = ( 2 *LAMBDA ).round(3) +R27_4 = ( 2 *LAMBDA ).round(3) +R27_5 = ( 2 *LAMBDA ).round(3) +R27_7 = ( 5 *LAMBDA ).round(3) +R27_8 = ( 7 *LAMBDA ).round(3) +R27_9 = ( 2 *LAMBDA ).round(3) + + +if !SUBM && !DEEP + R1_1 = ( 10 *LAMBDA ).round(3) + R1_2 = ( 9 *LAMBDA ).round(3) + R2_3 = ( 5 *LAMBDA ).round(3) + R3_2 = ( 2 *LAMBDA ).round(3) + R3_2_a = ( 2 *LAMBDA ).round(3) + R3_3 = ( 2 *LAMBDA ).round(3) + R3_4 = ( 3 *LAMBDA ).round(3) + R4_3 = ( 1 *LAMBDA ).round(3) + R4_4 = ( 2 *LAMBDA ).round(3) + R5_3 = ( 2 *LAMBDA ).round(3) + R5_5_b = ( 4 *LAMBDA ).round(3) + R6_3 = ( 2 *LAMBDA ).round(3) + R7_2 = ( 2 *LAMBDA ).round(3) + R7_4 = ( 4 *LAMBDA ).round(3) + R8_1 = ( 2 *LAMBDA ).round(3) + R8_5 = ( 2 *LAMBDA ).round(3) + R9_2 = ( 3 *LAMBDA ).round(3) + R9_4 = ( 6 *LAMBDA ).round(3) + R11_1 = ( 3 *LAMBDA ).round(3) + R11_3 = ( 2 *LAMBDA ).round(3) + R11_5 = ( 3 *LAMBDA ).round(3) + R13_2 = ( 2 *LAMBDA ).round(3) + R14_1 = ( 2 *LAMBDA ).round(3) + if NBR_OF_METALS > 3 + R15_1 = ( 3 *LAMBDA ).round(3) + R15_2 = ( 3 *LAMBDA ).round(3) + R15_4 = ( 6 *LAMBDA ).round(3) + else + R15_1 = ( 6 *LAMBDA ).round(3) + R15_2 = ( 4 *LAMBDA ).round(3) + R15_4 = ( 8 *LAMBDA ).round(3) + end + R17_1 = ( 10 *LAMBDA ).round(3) + R17_2 = ( 9 *LAMBDA ).round(3) + R17_3 = ( 5 *LAMBDA ).round(3) + R17_4 = ( 5 *LAMBDA ).round(3) + R20_11 = ( 3 *LAMBDA ).round(3) + R21_1 = ( 2 *LAMBDA ).round(3) + if NBR_OF_METALS > 4 + R22_1 = ( 3 *LAMBDA ).round(3) + R22_2 = ( 3 *LAMBDA ).round(3) + R22_4 = ( 6 *LAMBDA ).round(3) + else + R22_1 = ( 6 *LAMBDA ).round(3) + R22_2 = ( 6 *LAMBDA ).round(3) + R22_4 = ( 12 *LAMBDA ).round(3) + end +end + +if SUBM + R1_1 = ( 12 *LAMBDA ).round(3) + # We are assuming the wells are at the same potential since + # DRC can't tell otherwise + #R1_2 = ( 18 *LAMBDA ).round(3) + R1_2 = ( 6 *LAMBDA ).round(3) + R2_3 = ( 6 *LAMBDA ).round(3) + R3_2 = ( 3 *LAMBDA ).round(3) + R3_2_a = ( 3 *LAMBDA ).round(3) + R3_3 = ( 2 *LAMBDA ).round(3) + R3_4 = ( 3 *LAMBDA ).round(3) + R4_3 = ( 1 *LAMBDA ).round(3) + R4_4 = ( 2 *LAMBDA ).round(3) + R5_3 = ( 3 *LAMBDA ).round(3) + R5_5_b = ( 5 *LAMBDA ).round(3) + R6_3 = ( 3 *LAMBDA ).round(3) + R7_2 = ( 3 *LAMBDA ).round(3) + R7_4 = ( 6 *LAMBDA ).round(3) + R8_1 = ( 2 *LAMBDA ).round(3) + R8_5 = ( 2 *LAMBDA ).round(3) + R9_2 = ( 3 *LAMBDA ).round(3) + R9_4 = ( 6 *LAMBDA ).round(3) + R11_1 = ( 7 *LAMBDA ).round(3) + R11_3 = ( 5 *LAMBDA ).round(3) + R11_5 = ( 6 *LAMBDA ).round(3) + R13_2 = ( 3 *LAMBDA ).round(3) + R14_1 = ( 2 *LAMBDA ).round(3) + if NBR_OF_METALS > 3 + R15_1 = ( 3 *LAMBDA ).round(3) + R15_2 = ( 3 *LAMBDA ).round(3) + R15_4 = ( 6 *LAMBDA ).round(3) + else + R15_1 = ( 5 *LAMBDA ).round(3) + R15_2 = ( 3 *LAMBDA ).round(3) + R15_4 = ( 6 *LAMBDA ).round(3) + end + R17_1 = ( 12 *LAMBDA ).round(3) + R17_2 = ( 18 *LAMBDA ).round(3) + R17_3 = ( 6 *LAMBDA ).round(3) + R17_4 = ( 6 *LAMBDA ).round(3) + R20_11 = ( 5 *LAMBDA ).round(3) + R21_1 = ( 2 *LAMBDA ).round(3) + if NBR_OF_METALS > 4 + R22_1 = ( 3 *LAMBDA ).round(3) + R22_2 = ( 3 *LAMBDA ).round(3) + R22_4 = ( 6 *LAMBDA ).round(3) + else + R22_1 = ( 6 *LAMBDA ).round(3) + R22_2 = ( 6 *LAMBDA ).round(3) + R22_4 = ( 12 *LAMBDA ).round(3) + end + R25_1 = ( 2 *LAMBDA ).round(3) + R25_2 = ( 3 *LAMBDA ).round(3) + R25_3 = ( 1 *LAMBDA ).round(3) + if NBR_OF_METALS > 5 + R26_1 = ( 3 *LAMBDA ).round(3) + R26_2 = ( 3 *LAMBDA ).round(3) + R26_3 = ( 1 *LAMBDA ).round(3) + R26_4 = ( 6 *LAMBDA ).round(3) + else + R26_1 = ( 4 *LAMBDA ).round(3) + R26_2 = ( 4 *LAMBDA ).round(3) + R26_3 = ( 2 *LAMBDA ).round(3) + R26_4 = ( 8 *LAMBDA ).round(3) + end + R28_1 = ( 40 *LAMBDA ).round(3) + R28_2 = ( 12 *LAMBDA ).round(3) + R28_3 = ( 4 *LAMBDA ).round(3) + R28_4 = ( 3 *LAMBDA ).round(3) + R28_5 = ( 4 *LAMBDA ).round(3) + R28_6 = ( 2 *LAMBDA ).round(3) + R28_7 = ( 25 *LAMBDA ).round(3) + R28_8 = ( 4 *LAMBDA ).round(3) + R28_9 = ( 8 *LAMBDA ).round(3) + R28_10 = ( 20 *LAMBDA ).round(3) + R28_11 = ( 40 *LAMBDA ).round(3) + R29_1 = ( 3 *LAMBDA ).round(3) + R29_2 = ( 4 *LAMBDA ).round(3) + R29_3 = ( 1 *LAMBDA ).round(3) + R30_1 = ( 5 *LAMBDA ).round(3) + R30_2 = ( 5 *LAMBDA ).round(3) + R30_3 = ( 1 *LAMBDA ).round(3) + R30_4 = ( 10 *LAMBDA ).round(3) + R31_1 = ( 30 *LAMBDA ).round(3) + R31_2 = ( 50 *LAMBDA ).round(3) + R31_3 = ( 15 *LAMBDA ).round(3) + R31_4 = ( 20 *LAMBDA ).round(3) + R31_5 = ( 35 *LAMBDA ).round(3) + R31_6 = ( 5 *LAMBDA ).round(3) + R31_7 = ( 30 *LAMBDA ).round(3) + R31_8 = ( 10 *LAMBDA ).round(3) +end + +if DEEP + R1_1 = ( 12 *LAMBDA ).round(3) + # We are assuming the wells are at the same potential since + # DRC can't tell otherwise + #R1_2 = ( 18 *LAMBDA ).round(3) + R1_2 = ( 6 *LAMBDA ).round(3) + R2_3 = ( 6 *LAMBDA ).round(3) + R3_2 = ( 3 *LAMBDA ).round(3) + R3_2_a = ( 4 *LAMBDA ).round(3) + R3_3 = ( 2.5 *LAMBDA ).round(3) + R3_4 = ( 4 *LAMBDA ).round(3) + R4_3 = ( 1.5 *LAMBDA ).round(3) + R4_4 = ( 4 *LAMBDA ).round(3) + R5_3 = ( 4 *LAMBDA ).round(3) + R5_5_b = ( 5 *LAMBDA ).round(3) + R6_3 = ( 4 *LAMBDA ).round(3) + R7_2 = ( 3 *LAMBDA ).round(3) + R7_4 = ( 6 *LAMBDA ).round(3) + R8_1 = ( 3 *LAMBDA ).round(3) + R9_2 = ( 4 *LAMBDA ).round(3) + R9_4 = ( 8 *LAMBDA ).round(3) + R11_1 = ( 7 *LAMBDA ).round(3) + R11_3 = ( 5 *LAMBDA ).round(3) + R11_5 = ( 6 *LAMBDA ).round(3) + R13_2 = ( 3 *LAMBDA ).round(3) + R14_1 = ( 3 *LAMBDA ).round(3) + if NBR_OF_METALS > 3 + R15_1 = ( 3 *LAMBDA ).round(3) + R15_2 = ( 4 *LAMBDA ).round(3) + R15_4 = ( 8 *LAMBDA ).round(3) + else + R15_1 = ( 5 *LAMBDA ).round(3) + R15_2 = ( 3 *LAMBDA ).round(3) + R15_4 = ( 6 *LAMBDA ).round(3) + end + R17_1 = ( 12 *LAMBDA ).round(3) + R17_2 = ( 18 *LAMBDA ).round(3) + R17_3 = ( 6 *LAMBDA ).round(3) + R17_4 = ( 6 *LAMBDA ).round(3) + R20_11 = ( 5 *LAMBDA ).round(3) + R21_1 = ( 3 *LAMBDA ).round(3) + if NBR_OF_METALS > 4 + R22_1 = ( 3 *LAMBDA ).round(3) + R22_2 = ( 4 *LAMBDA ).round(3) + R22_4 = ( 8 *LAMBDA ).round(3) + else + R22_1 = ( 6 *LAMBDA ).round(3) + R22_2 = ( 6 *LAMBDA ).round(3) + R22_4 = ( 12 *LAMBDA ).round(3) + end + R25_1 = ( 3 *LAMBDA ).round(3) + R25_2 = ( 3 *LAMBDA ).round(3) + R25_3 = ( 1 *LAMBDA ).round(3) + if NBR_OF_METALS > 5 + R26_1 = ( 3 *LAMBDA ).round(3) + R26_2 = ( 4 *LAMBDA ).round(3) + R26_3 = ( 1 *LAMBDA ).round(3) + R26_4 = ( 8 *LAMBDA ).round(3) + else + R26_1 = ( 4 *LAMBDA ).round(3) + R26_2 = ( 4 *LAMBDA ).round(3) + R26_3 = ( 2 *LAMBDA ).round(3) + R26_4 = ( 8 *LAMBDA ).round(3) + end + R28_1 = ( 45 *LAMBDA ).round(3) + R28_2 = ( 14 *LAMBDA ).round(3) + R28_3 = ( 5 *LAMBDA ).round(3) + R28_4 = ( 3 *LAMBDA ).round(3) + R28_5 = ( 5 *LAMBDA ).round(3) + R28_6 = ( 2 *LAMBDA ).round(3) + R28_7 = ( 25 *LAMBDA ).round(3) + R28_8 = ( 5 *LAMBDA ).round(3) + R28_9 = ( 9 *LAMBDA ).round(3) + R28_10 = ( 23 *LAMBDA ).round(3) + R28_11 = ( 45 *LAMBDA ).round(3) + R29_1 = ( 4 *LAMBDA ).round(3) + R29_2 = ( 4 *LAMBDA ).round(3) + R29_3 = ( 1 *LAMBDA ).round(3) + R30_1 = ( 5 *LAMBDA ).round(3) + R30_2 = ( 5 *LAMBDA ).round(3) + R30_3 = ( 2 *LAMBDA ).round(3) + R30_4 = ( 10 *LAMBDA ).round(3) + R31_1 = ( 34 *LAMBDA ).round(3) + R31_2 = ( 56 *LAMBDA ).round(3) + R31_3 = ( 17 *LAMBDA ).round(3) + R31_4 = ( 23 *LAMBDA ).round(3) + R31_5 = ( 39 *LAMBDA ).round(3) + R31_6 = ( 6 *LAMBDA ).round(3) + R31_7 = ( 34 *LAMBDA ).round(3) + R31_8 = ( 13 *LAMBDA ).round(3) +end + + +# KLAYOUT setttings +######################## +# Use a tile size of 1mm +tiles(1000.um) +# Use a tile border of 10 micron: +tile_borders(1.um) +#no_borders + +# Use 4 CPU cores +threads(4) +verbose(true) + +# 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 + +# layers definitions +######################## +info("Layers definitions") + + DNW = input(38,0) + NW = input(42,0) + PW = input(41,0) + CW = input(59,0) + AA = input(43,0) + TA = input(60,0) + PBase = input(58,0) + PL = input(46,0) + SB = input(29,0) + Nselect = input(45,0) + Pselect = input(44,0) + PO2 = input(56,0) + HR = input(34,0) + Contact = input(25,0) + ContactPoly = input(47,0) + ContactActive = input(48,0) + ContactPoly2 = input(55, 0) + CT = Contact + ContactPoly + ContactActive + ContactPoly2 + M1 = input(49,0) + V1 = input(50,0) + M2 = input(51,0) + V2 = input(61,0) + M3 = input(62,0) + V3 = input(30,0) + M4 = input(31,0) + CTM = input(35,0) + V4 = input(32,0) + M5 = input(33,0) + V5 = input(36,0) + M6 = input(37,0) + Glass = input(52,0) + Pads = input(26,0) + +# layers processing +######################## +info("Layers processing") +#CHIP = extent.sized(1.0) +NP = AA & Nselect +PP = AA & Pselect +NSTP = NP.and(NW) +PSTP = PP.not(NW) +GATE = PL & AA + +# DRC section +######################## +info("DRC section") + +### Deep NWell +DNW.ongrid(0.5*LAMBDA).output("DNW_offgrid", "Offgrid vertex on DNW") +DNW.with_angle(0 .. 45).output("DNW_angle", "Non 45 degree angle DNW") +DNW.edges.and(PW).output("DNW_PW","DNW cannot cross PWell") +DNW.width(R31_1, euclidian).output("31.1 DNW_width", "31.1 : Min. DNW width : #{R31_1}um") +DNW.isolated(R31_2, euclidian).output("31.2 DNW_space", "31.2 : Min. DNW spacing : #{R31_2}um") +NW.enclosing(DNW, R31_3, euclidian).output("31.3 NW_enc_DNW", "31.3 : Min. NWell enclosing DNW : #{R31_3}um") +DNW.enclosing(NW, R31_4, euclidian).output("31.4 DNW_enc_NW", "31.4 : Min. DNW enclosing NWell : #{R31_4}um") +DNW.separation(NW, R31_5, euclidian).output("31.5 DNW_sep_NW", "31.5 : Min. DNW separation NWell : #{R31_5}um") +DNW.not(NW).enclosing(NP, R31_6, euclidian).output("31.6 DNW_enc_NP", "31.6 : Min. PW in DNW enclosing N+ : #{R31_6}um") +DNW.separation(NP, R31_7, euclidian).output("31.7 DNW_sep_NP", "31.7 : Min. DNW separation N+ : #{R31_7}um") + +### Nwell / Pwell +NW.ongrid(0.5*LAMBDA).output("NW_offgrid", "Offgrid vertex on NWell") +NW.with_angle(0 .. 45).output("NW_angle", "Non 45 degree angle NWell") +NW.and(PW).output("NW_PW","NW over PW not allowed") +NW.width(R1_1, euclidian).output("1.1 NW_width", "1.1 : Min. NWell width : #{R1_1}um") +NW.isolated(R1_2, euclidian).output("1.2 NW_space", "1.2 : Min. NWell spacing : #{R1_2}um") +NW.and(TA).isolated(18, euclidian).output("1.3 NW_TA_space", "1.3 : Min. NWell-TA spacing : #{R1_3}um") +PW.width(R1_1, euclidian).output("1.1 PW_width", "1.1 : Min. PWell width : #{R1_1}um") +PW.isolated(R1_2, euclidian).output("1.2 PW_space", "1.2 : Min. PWell spacing : #{R1_2}um") +PW.and(TA).isolated(R1_3, euclidian).output("1.3 PW_TA_space", "1.3 : Min. PWell-TA spacing : #{R1_3}um") + +### Active +AA.ongrid(0.5*LAMBDA).output("AA_offgrid", "Offgrid vertex on AA") +AA.with_angle(0 .. 45).output("AA_angle", "Non 45 degree angle AA") +AA.width(R2_1, euclidian).output("2.1 AA_width", "2.1 : Min. active width : #{R2_1}um") +AA.space(R2_2, euclidian).output("2.2 AA_space", "2.2 : Min. active spacing : #{R2_2}3um") +NW.enclosing(PP.interacting(GATE), R2_3, euclidian).output("2.3 NW_enc_PP", "2.3 : Min. NWell enclosing Source/Drain : #{R2_3}um") +PW.enclosing(NP.interacting(GATE), R2_3, euclidian).output("2.3 PW_enc_NP", "2.3 : Min. PWell enclosing Source/Drain : #{R2_3}um") +NW.enclosing(NP, R2_4, euclidian).output("2.4 NW_enc_NP", "2.4 : Min. NWell enclosing Nstrap : #{R2_4}um") +PW.enclosing(PP, R2_4, euclidian).output("2.4 PW_enc_PP", "2.4 : Min. PWell enclosing Pstrap : #{R2_4}um") +NP.separation(PP, R2_5, euclidian).polygons.without_area(0).output("2.5 NP_space_PP", "2.5 : Min. N+ space P+ : #{R2_5}um (if not abutted)") + +### TA Thick Active +TA.ongrid(0.5*LAMBDA).output("TA_offgrid", "Offgrid vertex on TA") +TA.with_angle(0 .. 45).output("TA_angle", "Non 45 degree angle TA") +TA.width(R24_1, euclidian).output("24.1 TA_width", "24.1 : Min. TA width : #{R24_1}um") +TA.space(R24_2, euclidian).output("24.2 TA_space", "24.2 : Min. TA spacing : #{R24_2}um") +TA.enclosing(AA, R24_3, euclidian).output("24.3 TA_enc_AA", "24.3 : Min. TA enclosing Active : #{R24_3}um") +TA.separation(AA, R24_4, euclidian).output("24.4 TA_space_AA", "24.4 : Min. TA spacing Active : #{R24_4}um") +TA.and(GATE).width(R24_5, euclidian).output("24.5 TA_gate_width", "24.5 : Min. TA Gate width : #{R24_5}um") +AA.edges.and(TA).output("24.6 AA_in_TA","24.6 : Active edge cannot cross TA") + +### Poly +PL.ongrid(0.5*LAMBDA).output("POLY_offgrid", "Offgrid vertex on Poly") +PL.with_angle(0 .. 45).output("POLY_angle", "Non 45 degree angle Poly") +PL.width(R3_1, euclidian).output("3.1 POLY_width", "3.1 : Min. Poly width : #{R3_1}um") +PL.space(R3_2, euclidian).output("3.2 Poly_space", "3.2 : Min. Poly spacing : #{R3_2}um") +GATE.space(R3_2_a, euclidian).output("3.2a Gate_space", "3.2a : Min. Gate spacing : #{R3_2_a}um") +PL.enclosing(GATE, R3_3, projection).polygons.without_area(0).output("3.3 PL_enc_GATE", "3.3 : Min. Poly extention Gate : #{R3_3}um") +AA.enclosing(GATE, R3_4, projection).polygons.without_area(0).output("3.4 AA_enc_GATE", "3.4 : Min. Source/Drain length : #{R3_4}um") +PL.not(AA).separation(AA, 1, euclidian).polygons.without_area(0).output("3.5 PL_space_AA", "3.5 : Min. Poly on Field spacing Active : #{R3_5}um") + +### Poly2 +if !DEEP +PO2.ongrid(0.5*LAMBDA).output("POLY2_offgrid", "Offgrid vertex on Poly2") +PO2.with_angle(0 .. 45).output("POLY2_angle", "Non 45 degree angle Poly2") +PO2.width(R12_1, euclidian).output("12.1 POLY2_width", "12.1 : Min. Poly2 width : #{R12_1}um") +PO2.space(R12_2, euclidian).output("12.2 POLY2_space", "12.2 : Min. Poly2 space : #{R12_2}um") +# rule R12.3 not coded +PO2.not(AA).separation(AA, R12_4, euclidian).output("12.4 POLY2_space_AA"," 12.4 : Min. Poly2 on Field spacing Active : #{R12_4}um") +PO2.not(PL).separation(PL, R12_5, euclidian).output("12.5 POLY2_space_PL"," 12.5 : Min. Poly2 spacing Poly : #{R12_5}um") +PO2.enclosing(PL, R12_5, euclidian).output("12.5 POLY2_overlap_PL"," 12.5 : Min. Poly2 overlap of Poly : #{R12_5}um") +PO2.separation(AA.or(PL).and(CT), R12_6, euclidian).output("12.6 POLY2_space_CT"," 12.5 : Min. Poly2 spacing Poly or Active contact: #{R12_6}um") +PO2cap = PL & PO2 +PO2cap.width(R11_1, euclidian).output("11.1 POLY2CAP_width", "11.1 : Min. Poly2 Capacitor width : #{R11_1}um") +PO2cap.space(R11_2, euclidian).output("11.2 POLY2CAP_space", "11.2 : Min. Poly2 Capacitor space : #{R11_2}um") +PL.enclosing(PO2cap, R11_3, euclidian).output("12.3 PL_overlap_POLY2CAP"," 11.3 : Min. Poly overlap of Poly2 Capacitor : #{R11_3}um") +PO2cap.edges.separation(AA.or(NW).edges, R11_4, euclidian).output("11.4 POLY2CAP_space_AA/NW"," 11.4 : Min. Poly2 Capacitor spacing Active or Well: #{R11_4}um") +PO2cap.separation(PL.and(CT), R11_5, euclidian).output("11.5 POLY2CAP_space_PLCT"," 11.5 : Min. Poly2 Capacitor spacing Poly contact: #{R11_5}um") +PO2cap.separation(M1.or(M2).or(M3), R11_6, euclidian).output("11.6 POLY2CAP_space_METAL"," 11.6 : Min. Poly2 Capacitor spacing any Metal: #{R11_6}um") +PO2cap.forget + +### Capacitor Well +CW.ongrid(0.5*LAMBDA).output("CW_offgrid", "Offgrid vertex on CapacitorWell") +CW.with_angle(0 .. 45).output("CW_angle", "Non 45 degree angle CapacitorWell") +CW.width(R17_1, euclidian).output("17.1 CW_width", "17.1 : Min. CapacitorWell width : #{R17_1}um") +CW.space(R17_2, euclidian).output("17.2 CW_space", "17.2 : Min. CapacitorWell space : #{R17_2}um") +AA.not(CW).separation(CW, R17_3, euclidian).output("17.3 CW_space_AA"," 17.3 : Min. CapacitorWell spacing Active : #{R17_3}um") +CW.enclosing(AA, R17_4, euclidian).output("17.4 CW_overlap_AA"," 17.4 : Min. CapacitorWell overlap of Active : #{R17_4}um") +LinCap = PL & CW +LinCap.width(R18_1, euclidian).output("18.1 LC_width", "18.1 : Min. Linear Capacitor width : #{R18_1}um") +LinCap.space(R18_2, euclidian).output("18.2 LC_space", "18.2 : Min. Linear Capacitor space : #{R18_2}um") +LinCap.separation(AA.and(CT), R18_3, euclidian).output("18.3 LC_space_AACT"," 18.3 : Min. Linear Capacitor spacing Active contact : #{R18_3}um") +LinCap.separation(PL.and(CT), R18_4, euclidian).output("18.4 LC_space_PLCT"," 18.4 : Min. Linear Capacitor spacing Poly contact : #{R18_4}um") +LinCap.forget +end + +### N+/P+ Select +Nselect.ongrid(0.5*LAMBDA).output("NSel_offgrid", "Offgrid vertex on Nselect") +Pselect.ongrid(0.5*LAMBDA).output("PSel_offgrid", "Offgrid vertex on Pselect") +Nselect.with_angle(0 .. 45).output("N+_angle", "Non 45 degree angle Nselect") +Pselect.with_angle(0 .. 45).output("N+_angle", "Non 45 degree angle Pselect") +NP.enclosing(GATE, R4_1, projection).polygons.without_area(0).output("4.1 N+_enc_GATE", "4.1 : Min. N+ extention Gate on Source/Drain : #{R4_1}um") +PP.enclosing(GATE, R4_1, projection).polygons.without_area(0).output("4.1 P+_enc_GATE", "4.1 : Min. P+ extention Gate on Source/Drain : #{R4_1}um") +Nselect.enclosing(AA, R4_2, euclidian).output("4.2 N+_enc_AA", "4.2 : Min. N+ enclosing Active : #{R4_2}um") +Pselect.enclosing(AA, R4_2, euclidian).output("4.2 P+_enc_AA", "4.2 : Min. P+ enclosing Active : #{R4_2}um") +Nselect.enclosing(CT, R4_3, euclidian).output("4. N+_enc_CT", "4.3 : Min. N+ enclosing Contact : #{R4_3}um") +Pselect.enclosing(CT, R4_3, euclidian).output("4.3 P+_enc_CT", "4.3 : Min. P+ enclosing Contact : #{R4_3}um") +Nselect.width(R4_4,euclidian).output("4.4 N+_width", "4.4 : Min. N+ width : #{R4_4}um") +Pselect.width(R4_4,euclidian).output("4.4 P+_width", "4.4 : Min. N+ width : #{R4_4}um") +Nselect.space(R4_4,euclidian).output("4.4 N+_space", "4.4 : Min. N+ spacing : #{R4_4}um") +Pselect.space(R4_4,euclidian).output("4.4 P+_space", "4.4 : Min. N+ spacing : #{R4_4}um") +Nselect.and(Pselect).output("4.4 N+_and_P+", "4.4 : N+ over P+ not allowed") + +### HR - High Resistive +HR.ongrid(0.5*LAMBDA).output("HR_offgrid", "Offgrid vertex on HighRes") +HR.with_angle(0 .. 45).output("HR_angle", "Non 45 degree angle HighRes") +HR.width(R27_1, euclidian).output("27.1 HR_width", "27.1 : Min. HiRes width : #{R27_1}um") +HR.space(R27_2, euclidian).output("27.2 HR_space", "27.2 : Min. HiRes spacing : #{R27_2}um") +HR.and(CT).output("27.3 CT_and_HR", "27.3 : Contact on HiRes not allowed") +HR.separation(CT, R27_3, euclidian).output("27.3 HR_space_CT", "27.3 : Min. HiRes space to Contact : #{R27_3}um") +HR.separation(AA, R27_5, euclidian).output("27.4 HR_space_AA", "27.4 : Min. HiRes space to Active : #{R27_4}um") +HR.separation(PO2, R27_5, euclidian).output("27.5 HR_space_PO2", "27.5 : Min. HiRes space to Poly2 : #{R27_5}um") +HR.and(PO2).and(AA).output("27.6 HR_and_active", "27.6 : HiRes Po2 over Active not allowed") +HR.and(PO2).and(NW.or(PW)).output("27.6 HR_and_Well", "27.6 : HiRes Po2 over Well not allowed") +HR.and(PO2).width(R27_7,euclidian).output("27.7 HRPO2_width", "27.7 : Min. HiRes Poly2 width : #{R27_7}um") +HR.and(PO2).space(R27_8,euclidian).output("27.8 HRPO2_space", "27.8 : Min. HiRes Poly2 space : #{R27_8}um") +HR.enclosing(PO2, R27_9, projection).output("27.9 HR_enc_PO2", "27.9 : Min. HiRes enclosing Poly2 : #{R27_9}um") + +### SB - Silicide block +SB.ongrid(0.5*LAMBDA).output("SB_offgrid", "Offgrid vertex on Sil. Block") +SB.with_angle(0 .. 45).output("SB_angle", "Non 45 degree angle Sil. Block") +SB.width(R20_1, euclidian).output("20.1 SB_width", "20.1 : Min. Sil. Block width : #{R20_1}um") +SB.space(R20_2, euclidian).output("20.2 SB_space", "20.2 : Min. Sil. Block spacing : #{R20_2}um") +SB.separation(CT, R20_3, euclidian).output("20.3 SB_space_CT", "20.3 : Min. Sil. Block space to Contact : #{R20_3}um") +SB.and(CT).output("20.3 SB_and_CT", "20.3 : Sil. Block over Contact not allowed") +SB.separation(AA, R20_4, euclidian).output("20.4 SB_space_AA", "20.4 : Min. Sil. Block space to Active : #{R20_4}um") +SB.separation(PL, R20_5, euclidian).output("20.5 SB_space_PL", "20.5 : Min. Sil. Block space to Poly : #{R20_5}um") +SB.and(GATE).output("20.6 SBres_overAA","20.6 : SB resistor over Active not allowed") +SB.and(PL).and(Nselect.or(Pselect)).output("20.6 SBres_over_WELL","20.6 : SB resistor over Well not allowed") +SB.and(PL).width(R20_7,euclidian).output("20.6 SBres_width", "20.7 : Min. SB resistor width : #{R20_7}um") +SB.and(PL).space(R20_7,euclidian).output("20.7 SBres_space", "20.7 : Min. SB resistor space : #{R20_7}um") +SB.enclosing(AA, R20_8, projection).polygons.without_area(0).output("20.8 SB_enc_AA", "20.8 : Min. Sil. Block enclosing Active : #{R20_8}um") +AA.enclosing(SB, R20_9, projection).polygons.without_area(0).output("20.9 AA_enc_SB", "20.9 : Min. Active enclosing Sil. Block : #{R20_9}um") +SB.enclosing(PL, R20_9, projection).output("20.8 SB_enc_PL", "20.8 : Min. Sil. Block enclosing Poly : #{R20_8}um") +PL.enclosing(SB, R20_8, projection).polygons.without_area(0).output("20.9 PL_enc_SB", "20.9 : Min. Poly enclosing Sil. Block : #{R20_9}um") +SB.separation(GATE, R20_11, euclidian).output("20.11 SB_space_GATE", "20.11 : Min. Sil. Block space to Gate : #{R20_11}um") + +### Contact +CT.ongrid(0.5*LAMBDA).output("CT_offgrid", "Offgrid vertex on Contact") +CT.with_angle(0 .. 90).output("CT_angle", "Non 90 degree angle Contact") +CT.and(GATE).output("CT_and_GATE", "Contact on Gate not allowed") +CT.not(M1).output("CT_not_M1", "Contact without Metal1 not recommended") +# CT.drc(length != R5_1).output("5.1 CT_width", "5.1 : Exact Contact width : #{R5_1}um") +CT.width(R5_1).output("5.1 CT_width", "5.1 : Exact Contact width : #{R5_1}um") +CT.without_area(R5_1*R5_1).output("5.1 CT_area", "5.1 : Exact Contact Area : #{R5_1*R5_1}um2") +CT.space(R5_3, euclidian).output("5.3 CT_space", "5.3 : Contact spacing : #{R5_3}um") +PL.enclosing(CT, R5_2_b, euclidian).output("5.2 PL_enc_CT", "5.2 : Min. Poly enclosing Contact : #{R5_2_b}um") +AA.enclosing(CT, R6_2_b, euclidian).output("6.2 AA_enc_CT", "6.2 : Min. Active enclosing Contact : #{R6_2_b}um") +PO2.enclosing(CT, R13_3, euclidian).output("13.3 PO2_enc_CT", "13.3 : Min. Poly2 enclosing Contact : #{R13_3}um") +CT.and(AA).separation(GATE, R5_4, euclidian).output("5.4 CTAA_space_GATE", "5.4 : Min. ActiveContact space to Gate : #{R5_4}um") +CT.and(PL).separation(PL, R5_5_b, euclidian).polygons.without_area(0).output("5.5.b CTPL_space_Poly", "5.5.b : Min. PolyContact space to Poly : #{R5_5_b}um") +CT.and(PL).separation(AA, R5_6_b, euclidian).output("5.6.b CTPL_space_AA", "5.6.b : Min. PolyContact space to AA : #{R5_6_b}um") +# rule 5.7.b not coded +CT.and(AA).separation(AA, R6_5_b, euclidian).polygons.without_area(0).output("6.5.b CTAA_space_AA", "6.5.b : Min. ActiveContact space to AA : #{R6_5_b}um") +CT.and(AA).separation(PL, R6_6_b, euclidian).output("6.6.b CTAA_space_PL", "6.6.b : Min. ActiveContact space to Poly : #{R6_6_b}um") +CT.and(AA).separation(CT.and(PL), R6_7_b, euclidian).output("6.7.b CTAA_space_CTPL", "6.7.b : Min. ActiveContact space to PolyContact : #{R6_7_b}um") +# rule 6.8.b not coded +CT.and(PO2).separation(AA, R13_5, euclidian).output("13.5 CTPO2_space_AA", "13.5 : Min. Poly2Contact space to AA : #{R13_5}um") +CT.and(PO2).separation(PL, R13_5, euclidian).output("13.5 CTPO2_space_PL", "13.5 : Min. Poly2Contact space to Poly : #{R13_5}um") +M1.enclosing(CT, R7_3, euclidian).output("7.3 M1_enc_CT", "7.3 : Min. Metal1 enclosing Contact : #{R7_3}um") + +### Metal 1 +M1.ongrid(0.5*LAMBDA).output("M1_offgrid", "Offgrid vertex on ME1") +M1.with_angle(0 .. 45).output("M1_angle", "Non 45 degree angle ME1") +M1.holes.with_area(0 .. R7_1*R7_1).output("M1_holes", "Min. Metal1 holes area : #{R7_1*R7_1}um2") +M1.width(R7_1, euclidian).output("7.1 M1_width", "7.1 : Min. Metal1 width : #{R7_1}um") +M1.space(R7_2, euclidian).output("7.2 M1_space", "7.2 : Min. Metal1 spacing : #{R7_2}um") +M1.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M1,R7_4,euclidian).polygons.without_area(0).output("7.4 M1_10_space", "7.4 : Space if at least one metal1 line width is > #{10*LAMBDA}um : #{R7_4}um") + +### Via 1 +V1.ongrid(0.5*LAMBDA).output("V1_offgrid", "Offgrid vertex on Via1") +V1.not(M1).output("V1_not_M1", "Via1 without Metal1 not allowed") +V1.not(M2).output("V1_not_M2", "Via1 without Metal2 not allowed") +V1.with_angle(0 .. 90).output("V1_angle", "Non 90 degree angle Via1") +V1.width(R8_1,square).output("8.1 V1_width", "8.1 : Exact Via1 width : #{R8_1}um") +V1.without_area(R8_1*R8_1).output("8.1 V1_width", "8.1 : Exact Via1 width : #{R8_1}um2") +V1.space(R8_2,euclidian).output("8.2 V1_space", "8.2 : Via1 spacing : #{R8_2}um") +M1.enclosing(V1, R8_3, euclidian).output("8.3 M1_enc_V1", "8.3 : Min. Metal1 enclosing Via1 : #{R8_3}um") +M2.enclosing(V1, R8_3, euclidian).output("9.3 M2_enc_V1", "9.3 : Min. Metal2 enclosing Via1 : #{R9_3}um") +if !DEEP && NBR_OF_METALS < 4 + V1.and(CT).or(V1.separation(CT, R8_4, euclidian).polygons).output("8.4 V1_space_CT", "8.4 : Via1 space CT : #{R8_4}um") + V1.separation(PL + AA, R8_5, euclidian).output("8.5 V1_space_PL/AAedges", "8.5 : Via1 space to Poly orActive edges : #{R8_5}um") +end +if DFM + M1.and(M2).not(V1).with_holes(1,1).output("2_V1", "Min. 2 Via1 are needed") +end + +### Metal 2 +M2.ongrid(0.5*LAMBDA).output("M2_offgrid", "Offgrid vertex on ME2") +M2.with_angle(0 .. 45).output("M2_angle", "Non 45 degree angle ME2") +M2.width(R9_1, euclidian).output("9.1 M2_width", "9.1 : Min. Metal2 width : #{R9_1}um") +M2.space(R9_2, euclidian).output("9.2 M2_space", "9.2 : Min. Metal2 spacing : #{R9_2}um") +M2.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M2,R9_4,euclidian).polygons.without_area(0).output("9.4 M2_10_space", "9.4 : Space if at least one metal2 line width is > #{10*LAMBDA}um : #{R9_4}um") + +### Via 2 +V2.ongrid(0.5*LAMBDA).output("V2_offgrid", "Offgrid vertex on Via2") +V2.not(M3).output("V2_not_M3", "Via2 without Metal3 not allowed") +V2.not(M2).output("V2_not_M2", "Via2 without Metal2 not allowed") +V2.with_angle(0 .. 90).output("V2_angle", "Non 90 degree angle Via2") +V2.width(R14_1, square).output("14.1 V2_width", "14.1 : Exact Via2 width : #{R14_1}um") +V2.without_area(R14_1*R14_1).output("14.1 V2_width", "14.1 : Exact Via2 width : #{R14_1}um2") +V2.space(R14_2, euclidian).output("14.2 V2_space", "14.2 : Via2 spacing : #{R14_2}um") +M2.enclosing(V2, R14_3, euclidian).output("14.3 M2_enc_V2", "14.3 : Min. Metal2 enclosing Via2 : #{R14_3}um") +M3.enclosing(V2, R15_3, euclidian).output("15.3 M3_enc_V2", "15.3 : Min. Metal3 enclosing Via2 : #{R15_3}um") +if !DEEP && NBR_OF_METALS < 4 + V2.and(V1).or(V2.separation(V1, R14_4, euclidian).polygons).output("14.4 V2_space_V1", "14.4 : Via2 space Via1 : #{R14_4}um") +end +if DFM + M2.and(M3).not(V2).with_holes(1,1).output("2_V2", "Min. 2 Via2 are needed") +end + +### Metal 3 +M3.ongrid(0.5*LAMBDA).output("M3_offgrid", "Offgrid vertex on ME3") +M3.with_angle(0 .. 45).output("M3_angle", "Non 45 degree angle ME3") +M3.width(R15_1, euclidian).output("15.1 M3_width", "15.1 : Min. Metal3 width : #{R15_1}um") +M3.space(R15_2, euclidian).output("15.2 M3_space", "15.2 : Min. Metal3 spacing : #{R15_2}um") +M3.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M3, R15_4, euclidian).polygons.without_area(0).output("15.4 M3_10_space", "15.4 : Space if at least one metal3 line width is > #{10*LAMBDA}um : #{R15_4}um") + +### Cap Top Metal +if SUBM || DEEP +CTM.ongrid(0.5*LAMBDA).output("CTM_offgrid", "Offgrid vertex on CTM") +CTM.with_angle(0 .. 45).output("CTM_angle", "Non 45 degree angle CTM") +CTM.width(R28_1, euclidian).output("28.1 CTM_width", "28.1 : Min. Cap Top Metal width : #{R28_1}um") +CTM.space(R28_2, euclidian).output("28.2 CTM_space", "28.2 : Min. Cap Top Metal spacing : #{R28_2}um") +if NBR_OF_METALS == 4 + TM = M4 + VT = V3 + TB = V2 +end +if NBR_OF_METALS == 5 + TM = M5 + VT = V4 + VB = V3 +end +if NBR_OF_METALS == 6 + TM = M6 + VT = V5 + VB = V4 +end +TM.enclosing(CTM, R28_3, euclidian).output("28.3 TM_overlap_CTM", "28.3 : Min. Top Metal overlap Cap Top Metal : #{R28_3}um") +CTM.enclosing(VT, R28_4, euclidian).output("28.4 CTM_overlap_VT", "28.4 : Min. Cap Top Metal overlap Top Via : #{R28_4}um") +CTM.separation(VB, R28_5, euclidian).output("28.5 CTM_space_VB", "28.5 : Min. Cap Top Metal space Bottom Via : #{R28_5}um") +CTM.separation(VT, R28_5, euclidian).output("28.5 CTM_space_VT", "28.5 : Min. Cap Top Metal space Top Via : #{R28_5}um") +TM.enclosing(VB, R28_6, euclidian).output("28.6 TM_overlap_VB", "28.6 : Min. Top Metal overlap Bottom Via : #{R28_6}um") +# rule 28.7 not coded +CTM.not_interacting(VT).width(R28_8, euclidian).output("28.8 CTMdummies_width", "28.8 : Min. dummies Cap Top Metal width : #{R28_8}um") +TM.interacting(CTM).space(R28_9, euclidian).output("28.9 VT_space", "28.9 : Min. Top Metal spacing : #{R28_9}um") +VT.interacting(CTM).space(R28_10, euclidian).output("28.10 VT_space", "28.10 : Min. Top Via spacing : #{R28_10}um") +VB.interacting(TM.interacting(CTM)).space(R28_11, euclidian).output("28.11 VB_space", "28.11 : Min. Bottom Via spacing : #{R28_11}um") +CTM.sized(-15.um).sized(15.um).output("28.12 CTM_width", "28.12 : Max. CTM width/length : 30um") +TM.interacting(CTM).sized(-17.5.um).sized(17.5.um).output("28.13 TM_width", "28.13 : Max. Top Metal width/length : 35um") +CTM.and(VB).output("28.14 CTM_VB", "28.14 : no VB under CTM allowed") +CTM.and(AA.or(PL)).output("28.15 CTM_AA", "28.15 : no active or passive circuitry under CTM allowed") +end + +### Via 3 +if NBR_OF_METALS > 3 +V3.ongrid(0.5*LAMBDA).output("V3_offgrid", "Offgrid vertex on Via3") +V3.not(M3).output("V3_not_M3", "Via3 without Metal3 not allowed") +V3.not(M4).output("V3_not_M4", "Via3 without Metal4 not allowed") +V3.with_angle(0 .. 90).output("V3_angle", "Non 90 degree angle Via3") +V3.width(R21_1, square).output("21.1 V3_width", "21.1 : Exact Via3 width : #{R21_1}um") +V3.without_area(R21_1*R21_1).output("21.1 V3_width", "21.1 : Exact Via3 width : #{R21_1}um2") +V3.space(R21_2, euclidian).output("21.2 V3_space", "21.2 : Via3 spacing : #{R21_2}um") +M3.enclosing(V3, R21_3, euclidian).output("21.3 M3_enc_V3", "21.3 : Min. Metal3 enclosing Via3 : #{R21_3}um") +M4.enclosing(V3, R22_3, euclidian).output("22.3 M4_enc_V3", "22.3 : Min. Metal4 enclosing Via3 : #{R22_3}um") +if DFM + M3.and(M4).not(V3).with_holes(1,1).output("2_V3", "Min. 2 Via3 are needed") +end + +### Metal 4 +M4.ongrid(0.5*LAMBDA).output("M4_offgrid", "Offgrid vertex on ME4") +M4.with_angle(0 .. 45).output("M4_angle", "Non 45 degree angle ME4") +M4.width(R22_1, euclidian).output("22.1 M4_width", "22.1 : Min. Metal4 width : #{R22_1}um") +M4.space(R22_2, euclidian).output("22.2 M4_space", "22.2 : Min. Metal4 spacing : #{R22_2}um") +M4.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M4, R22_4, euclidian).polygons.without_area(0).output("22.4 M4_10_space", "22.4 : Space if at least one metal4 line width is > #{10*LAMBDA}um : #{R22_4}um") + +### Via 4 +if NBR_OF_METALS > 4 +V4.ongrid(0.5*LAMBDA).output("V4_offgrid", "Offgrid vertex on Via4") +V4.not(M5).output("V4_not_M5", "Via4 without Metal5 not allowed") +V4.not(M4).output("V4_not_M4", "Via4 without Metal4 not allowed") +V4.with_angle(0 .. 90).output("V4_angle", "Non 90 degree angle Via4") +V4.width(R25_1, square).output("25.1 V4_width", "25.1 : Exact Via4 width : #{R25_1}um") +V4.without_area(R25_1*R25_1).output("25.1 V4_width", "25.1 : Via4 width : #{R25_1}um2") +V4.space(R25_2, euclidian).output("25.2 V4_space", "25.2 : Exact Via4 spacing : #{R25_2}um") +M4.enclosing(V4, R25_3, euclidian).output("25.3 M4_enc_V4", "25.3 : Min. Metal4 enclosing Via4 : #{R25_3}um") +M5.enclosing(V4, R26_3, euclidian).output("26.3 M5_enc_V4", "26.3 : Min. Metal5 enclosing Via4 : #{R26_3}um") +if DFM + M4.and(M5).not(V4).with_holes(1,1).output("2_V4", "Min. 2 Via4 are needed") +end + +### Metal 5 +M5.ongrid(0.5*LAMBDA).output("M5_offgrid", "Offgrid vertex on ME5") +M5.with_angle(0 .. 45).output("M5_angle", "Non 45 degree angle ME5") +M5.width(R26_1, euclidian).output("26.1 M5_width", "26.1 : Min. Metal5 width : #{R26_1}um") +M5.space(R26_2, euclidian).output("26.2 M5_space", "26.2 : Min. Metal5 spacing : #{R26_2}um") +M5.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M5, R26_4, euclidian).polygons.without_area(0).output("26.4 M5_10_space", "26 .4 : Space if at least one metal5 line width is > #{10*LAMBDA}um : #{R26_4}um") + +### Via 5 +if NBR_OF_METALS > 5 +V5.ongrid(0.5*LAMBDA).output("V5_offgrid", "Offgrid vertex on Via5") +V5.not(M5).output("V5_not_M5", "Via5 without Metal5 not allowed") +V5.not(M6).output("V5_not_M6", "Via5 without Metal6 not allowed") +V5.with_angle(0 .. 90).output("V4_angle", "Non 90 degree angle Via5") +V5.width(R29_1, square).output("29.1 V5_width", "29.1 : Exact Via5 width : #{R29_1}um") +V5.without_area(R29_1*R29_1).output("29.1 V5_width", "29.1 : Exact Via5 width : #{R29_1}um2") +V5.space(R29_2, euclidian).output("29.2 V5_space", "29.2 : Via5 spacing : #{R29_2}um") +M5.enclosing(V5, R29_3, euclidian).output("29.3 M5_enc_V5", "29.3 : Min. Metal5 enclosing Via5 : #{R29_3}um") +M6.enclosing(V5, R30_3, euclidian).output("30.3 M3_enc_V5", "30.3 : Min. Metal6 enclosing Via5 : #{R30_3}um") +if DFM + M5.and(M6).not(V5).with_holes(1,1).output("2_V5", "Min. 2 Via5 are needed") +end + +### Metal 6 +M6.ongrid(0.5*LAMBDA).output("M6_offgrid", "Offgrid vertex on ME6") +M6.with_angle(0 .. 45).output("M6_angle", "Non 45 degree angle ME5") +M6.width(R30_1, euclidian).output("30.1 M6_width", "30.1 : Min. Metal6 width : #{R30_1}um") +M6.space(R30_2, euclidian).output("30.2 M6_space", "30.2 : Min. Metal6 spacing : #{R30_2}um") +M6.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M5, 10, euclidian).polygons.without_area(0).output("30.4 M6_10_space", "30.4 : Space if at least one metal6 line width is > #{10*LAMBDA}um : #{R30_4}um") + +end +end +end + +# time spent for the DRC +time = Time.now +hours = ((time - tstart)/3600).to_i +minutes = ((time - tstart)/60 - hours * 60).to_i +seconds = ((time - tstart) - (minutes * 60 + hours * 3600)).to_i +$stdout.write "DRC finished at : #{time.hour}:#{time.min}:#{time.sec} - DRC duration = #{hours} hrs. #{minutes} min. #{seconds} sec.\n" + From 48e35588f4ddc569488c2c7793b898074ebaf549 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 3 Nov 2021 11:53:30 -0700 Subject: [PATCH 036/229] Fix cheat on wordline driver name. --- technology/freepdk45/tech/freepdk45.lylvs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index 97fbf85e..934a981c 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -206,13 +206,13 @@ connect(metal10, metal10_pin) schematic.simplify if $connect_supplies - connect_implicit("vdd") - connect_implicit("gnd") +connect_implicit("*", "vdd") +connect_implicit("*", "gnd") end -#connect_global(pwell, "PWELL") -#connect_global(nwell, "NWELL") -#connect_global(bulk, "BULK") +connect_global(pwell, "PWELL") +connect_global(nwell, "NWELL") +connect_global(bulk, "BULK") for pat in %w(pinv* pnor* pnand* and?_dec* write_driver* port_address* replica_bitcell_array*) connect_explicit(pat, [ "NWELL", "vdd" ]) From 32c7e90662d8c047a0984405f2e609f1cb3128b0 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 8 Nov 2021 14:27:41 -0800 Subject: [PATCH 037/229] Do not run same well spacing for backwards compatibility. Add pbitcell cheat. --- technology/scn4m_subm/tech/tech.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index 374ba4c8..ee63203c 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -428,8 +428,8 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa drc_name = "magic" lvs_name = "netgen" pex_name = "magic" -drc_name = "klayout" -lvs_name = "klayout" -pex_name = "klayout" +# drc_name = "klayout" +# lvs_name = "klayout" +# pex_name = "klayout" blackbox_bitcell = False From fc0516460d0c1ab6c9713c3b077ba8007845fb96 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 16 Nov 2021 14:37:24 -0800 Subject: [PATCH 038/229] Use klayout in SCMOS too. --- technology/scn4m_subm/tech/tech.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index ee63203c..374ba4c8 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -428,8 +428,8 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa drc_name = "magic" lvs_name = "netgen" pex_name = "magic" -# drc_name = "klayout" -# lvs_name = "klayout" -# pex_name = "klayout" +drc_name = "klayout" +lvs_name = "klayout" +pex_name = "klayout" blackbox_bitcell = False From 66c9501621666582c3e6d169b56194f11a5f6c0e Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 19 Nov 2021 13:43:54 -0800 Subject: [PATCH 039/229] Remove klayout from scmos --- technology/scn4m_subm/tech/tech.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index 374ba4c8..a8c44996 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -428,8 +428,5 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa drc_name = "magic" lvs_name = "netgen" pex_name = "magic" -drc_name = "klayout" -lvs_name = "klayout" -pex_name = "klayout" blackbox_bitcell = False From d8d8636d0fe035c854fde78462d1bf5b00c461c6 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 22 Nov 2021 15:54:22 -0800 Subject: [PATCH 040/229] Comment out calibre in freepdk45 --- technology/freepdk45/tech/tech.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index 9303ba3d..d351ae36 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -457,10 +457,10 @@ parameter["sa_inv_nmos_size"] = 0.27 # micro-meters parameter["bitcell_drain_cap"] = 0.1 # In Femto-Farad, approximation of drain capacitance # Spice Values uses to calculate analytical delay based on CACTI equations -spice["i_on_n"] = 0.0004463 # A/um +spice["i_on_n"] = 0.0004463 # A/um spice["i_on_p"] = 0.0000771 # A/um spice["tox"] = 0.00114 # microns -spice["eps_ox"] = 0.00245e-14 # F/um, calculated from CACTI 45nm data +spice["eps_ox"] = 0.00245e-14 # F/um, calculated from CACTI 45nm data spice["cox"] = spice["eps_ox"]/spice["tox"] # F/um^2 spice["c_g_ideal"] = spice["cox"]*drc["minlength_channel"] # F/um spice["c_overlap"] = 0.2*spice["c_g_ideal"] # F/um @@ -477,9 +477,10 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa # Technology Tool Preferences ################################################### -drc_name = "calibre" -lvs_name = "calibre" -pex_name = "calibre" +#drc_name = "calibre" +#lvs_name = "calibre" +#pex_name = "calibre" + drc_name = "klayout" lvs_name = "klayout" pex_name = "klayout" From 8eb6caa248f6b6e2331724d9f4969afba06cc6dd Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Tue, 14 Dec 2021 22:15:27 -0800 Subject: [PATCH 041/229] fix bitcell array opc errors --- technology/sky130/modules/sky130_bitcell_array.py | 13 ++++++++++--- technology/sky130/modules/sky130_dummy_array.py | 14 ++++++++++---- technology/sky130/modules/sky130_internal.py | 2 ++ technology/sky130/modules/sky130_replica_column.py | 6 ++++-- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/technology/sky130/modules/sky130_bitcell_array.py b/technology/sky130/modules/sky130_bitcell_array.py index 5d250f15..c71b6aa1 100644 --- a/technology/sky130/modules/sky130_bitcell_array.py +++ b/technology/sky130/modules/sky130_bitcell_array.py @@ -47,6 +47,8 @@ class sky130_bitcell_array(bitcell_array, sky130_bitcell_base_array): self.add_mod(self.strap2) self.strap3 = factory.create(module_type="internal", version="wlstrapa") self.add_mod(self.strap3) + self.strap4 = factory.create(module_type="internal", version="wlstrapa_p") + self.add_mod(self.strap4) def create_instances(self): """ Create the module instances used in this design """ @@ -71,9 +73,14 @@ class sky130_bitcell_array(bitcell_array, sky130_bitcell_base_array): self.connect_inst(self.get_bitcell_pins(row, col)) if col != self.column_size - 1: if alternate_strap: - row_layout.append(self.strap2) - self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), - mod=self.strap2) + if row % 2: + row_layout.append(self.strap4) + self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), + mod=self.strap4) + else: + row_layout.append(self.strap2) + self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), + mod=self.strap2) alternate_strap = 0 else: if row % 2: diff --git a/technology/sky130/modules/sky130_dummy_array.py b/technology/sky130/modules/sky130_dummy_array.py index 9f854dd8..063d5a79 100644 --- a/technology/sky130/modules/sky130_dummy_array.py +++ b/technology/sky130/modules/sky130_dummy_array.py @@ -52,6 +52,8 @@ class sky130_dummy_array(sky130_bitcell_base_array): self.add_mod(self.strap) self.strap2 = factory.create(module_type="internal", version="wlstrap_p") self.add_mod(self.strap2) + self.strap3 = factory.create(module_type="internal", version="wlstrapa") + self.add_mod(self.strap3) self.cell = factory.create(module_type=OPTS.bitcell, version="opt1") def create_instances(self): @@ -82,10 +84,14 @@ class sky130_dummy_array(sky130_bitcell_base_array): mod=self.strap2) alternate_strap = 0 else: - - row_layout.append(self.strap) - self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), - mod=self.strap) + if col % 2: + row_layout.append(self.strap) + self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), + mod=self.strap) + else: + row_layout.append(self.strap3) + self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), + mod=self.strap3) alternate_strap = 1 self.connect_inst(self.get_strap_pins(row, col)) if alternate_bitcell == 0: diff --git a/technology/sky130/modules/sky130_internal.py b/technology/sky130/modules/sky130_internal.py index c481195f..b8c0616f 100644 --- a/technology/sky130/modules/sky130_internal.py +++ b/technology/sky130/modules/sky130_internal.py @@ -22,6 +22,8 @@ class sky130_internal(design.design): self.name = "sky130_fd_bd_sram__sram_sp_wlstrap_p" elif version == "wlstrapa": self.name = "sky130_fd_bd_sram__sram_sp_wlstrapa" + elif version == "wlstrapa_p": + self.name = "sky130_fd_bd_sram__sram_sp_wlstrapa_p" else: debug.error("Invalid version", -1) design.design.__init__(self, name=self.name) diff --git a/technology/sky130/modules/sky130_replica_column.py b/technology/sky130/modules/sky130_replica_column.py index a900b0fe..7169ae6a 100644 --- a/technology/sky130/modules/sky130_replica_column.py +++ b/technology/sky130/modules/sky130_replica_column.py @@ -104,6 +104,8 @@ class sky130_replica_column(sky130_bitcell_base_array): self.add_mod(self.strap1) self.strap2 = factory.create(module_type="internal", version="wlstrap_p") self.add_mod(self.strap2) + self.strap3 = factory.create(module_type="internal", version="wlstrapa_p") + self.add_mod(self.strap3) self.colend = factory.create(module_type="col_cap", version="colend") self.edge_cell = self.colend @@ -140,8 +142,8 @@ class sky130_replica_column(sky130_bitcell_base_array): row_layout.append(self.replica_cell2) self.cell_inst[row]=self.add_inst(name=name, mod=self.replica_cell2) self.connect_inst(self.get_bitcell_pins(row, 0)) - row_layout.append(self.strap2) - self.add_inst(name=name + "_strap", mod=self.strap2) + row_layout.append(self.strap3) + self.add_inst(name=name + "_strap", mod=self.strap3) self.connect_inst(self.get_strap_pins(row, 0)) alternate_bitcell = 0 From ddb76c4affd3b5325579e06df20397a33f1750cf Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Wed, 15 Dec 2021 01:28:30 -0800 Subject: [PATCH 042/229] fix dummy array opc --- technology/sky130/modules/sky130_dummy_array.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/technology/sky130/modules/sky130_dummy_array.py b/technology/sky130/modules/sky130_dummy_array.py index 063d5a79..e1cb3dfd 100644 --- a/technology/sky130/modules/sky130_dummy_array.py +++ b/technology/sky130/modules/sky130_dummy_array.py @@ -54,6 +54,8 @@ class sky130_dummy_array(sky130_bitcell_base_array): self.add_mod(self.strap2) self.strap3 = factory.create(module_type="internal", version="wlstrapa") self.add_mod(self.strap3) + self.strap4 = factory.create(module_type="internal", version="wlstrapa_p") + self.add_mod(self.strap4) self.cell = factory.create(module_type=OPTS.bitcell, version="opt1") def create_instances(self): @@ -79,9 +81,14 @@ class sky130_dummy_array(sky130_bitcell_base_array): self.connect_inst(self.get_bitcell_pins(row, col)) if col != self.column_size - 1: if alternate_strap: - row_layout.append(self.strap2) - self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), - mod=self.strap2) + if col % 2: + row_layout.append(self.strap4) + self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), + mod=self.strap4) + else: + row_layout.append(self.strap4) + self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), + mod=self.strap4) alternate_strap = 0 else: if col % 2: From 4e5744df507998fe9b81eae07472cd55dcbbbab1 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Wed, 15 Dec 2021 01:36:56 -0800 Subject: [PATCH 043/229] remove add_mod() --- technology/sky130/modules/sky130_bitcell_array.py | 6 ------ technology/sky130/modules/sky130_col_cap_array.py | 6 ------ technology/sky130/modules/sky130_dummy_array.py | 6 ------ technology/sky130/modules/sky130_replica_column.py | 9 --------- technology/sky130/modules/sky130_row_cap_array.py | 8 -------- 5 files changed, 35 deletions(-) diff --git a/technology/sky130/modules/sky130_bitcell_array.py b/technology/sky130/modules/sky130_bitcell_array.py index c71b6aa1..648f22d6 100644 --- a/technology/sky130/modules/sky130_bitcell_array.py +++ b/technology/sky130/modules/sky130_bitcell_array.py @@ -38,17 +38,11 @@ class sky130_bitcell_array(bitcell_array, sky130_bitcell_base_array): """ Add the modules used in this design """ # Bitcell for port names only self.cell = factory.create(module_type=OPTS.bitcell, version="opt1") - self.add_mod(self.cell) self.cell2 = factory.create(module_type=OPTS.bitcell, version="opt1a") - self.add_mod(self.cell2) self.strap = factory.create(module_type="internal", version="wlstrap") - self.add_mod(self.strap) self.strap2 = factory.create(module_type="internal", version="wlstrap_p") - self.add_mod(self.strap2) self.strap3 = factory.create(module_type="internal", version="wlstrapa") - self.add_mod(self.strap3) self.strap4 = factory.create(module_type="internal", version="wlstrapa_p") - self.add_mod(self.strap4) def create_instances(self): """ Create the module instances used in this design """ diff --git a/technology/sky130/modules/sky130_col_cap_array.py b/technology/sky130/modules/sky130_col_cap_array.py index b1e9e35b..26d97ee2 100644 --- a/technology/sky130/modules/sky130_col_cap_array.py +++ b/technology/sky130/modules/sky130_col_cap_array.py @@ -49,18 +49,12 @@ class sky130_col_cap_array(sky130_bitcell_base_array): """ Add the modules used in this design """ if self.location == "top": self.colend1 = factory.create(module_type="col_cap", version="colend") - self.add_mod(self.colend1) self.colend2 = factory.create(module_type="col_cap", version="colend_p_cent") - self.add_mod(self.colend2) self.colend3 = factory.create(module_type="col_cap", version="colend_cent") - self.add_mod(self.colend3) elif self.location == "bottom": self.colend1 = factory.create(module_type="col_cap", version="colenda") - self.add_mod(self.colend1) self.colend2 = factory.create(module_type="col_cap", version="colenda_p_cent") - self.add_mod(self.colend2) self.colend3 = factory.create(module_type="col_cap", version="colenda_cent") - self.add_mod(self.colend3) self.cell = factory.create(module_type=OPTS.bitcell, version="opt1") diff --git a/technology/sky130/modules/sky130_dummy_array.py b/technology/sky130/modules/sky130_dummy_array.py index e1cb3dfd..c53b0fc3 100644 --- a/technology/sky130/modules/sky130_dummy_array.py +++ b/technology/sky130/modules/sky130_dummy_array.py @@ -45,17 +45,11 @@ class sky130_dummy_array(sky130_bitcell_base_array): def add_modules(self): """ Add the modules used in this design """ self.dummy_cell = factory.create(module_type=OPTS.dummy_bitcell, version="opt1") - self.add_mod(self.dummy_cell) self.dummy_cell2 = factory.create(module_type=OPTS.dummy_bitcell, version="opt1a") - self.add_mod(self.dummy_cell2) self.strap = factory.create(module_type="internal", version="wlstrap") - self.add_mod(self.strap) self.strap2 = factory.create(module_type="internal", version="wlstrap_p") - self.add_mod(self.strap2) self.strap3 = factory.create(module_type="internal", version="wlstrapa") - self.add_mod(self.strap3) self.strap4 = factory.create(module_type="internal", version="wlstrapa_p") - self.add_mod(self.strap4) self.cell = factory.create(module_type=OPTS.bitcell, version="opt1") def create_instances(self): diff --git a/technology/sky130/modules/sky130_replica_column.py b/technology/sky130/modules/sky130_replica_column.py index 7169ae6a..f5dddf5d 100644 --- a/technology/sky130/modules/sky130_replica_column.py +++ b/technology/sky130/modules/sky130_replica_column.py @@ -92,30 +92,21 @@ class sky130_replica_column(sky130_bitcell_base_array): def add_modules(self): self.replica_cell = factory.create(module_type="replica_bitcell_1port", version="opt1") - self.add_mod(self.replica_cell) self.cell = self.replica_cell self.replica_cell2 = factory.create(module_type="replica_bitcell_1port", version="opt1a") - self.add_mod(self.replica_cell2) self.dummy_cell = factory.create(module_type="dummy_bitcell_1port", version="opt1") self.dummy_cell2 = factory.create(module_type="dummy_bitcell_1port", version="opt1") self.strap1 = factory.create(module_type="internal", version="wlstrap") - self.add_mod(self.strap1) self.strap2 = factory.create(module_type="internal", version="wlstrap_p") - self.add_mod(self.strap2) self.strap3 = factory.create(module_type="internal", version="wlstrapa_p") - self.add_mod(self.strap3) self.colend = factory.create(module_type="col_cap", version="colend") self.edge_cell = self.colend - self.add_mod(self.colend) self.colenda = factory.create(module_type="col_cap", version="colenda") - self.add_mod(self.colenda) self.colend_p_cent = factory.create(module_type="col_cap", version="colend_p_cent") - self.add_mod(self.colend_p_cent) self.colenda_p_cent = factory.create(module_type="col_cap", version="colenda_p_cent") - self.add_mod(self.colenda_p_cent) def create_instances(self): self.cell_inst = {} diff --git a/technology/sky130/modules/sky130_row_cap_array.py b/technology/sky130/modules/sky130_row_cap_array.py index a82f5558..e5721da2 100644 --- a/technology/sky130/modules/sky130_row_cap_array.py +++ b/technology/sky130/modules/sky130_row_cap_array.py @@ -51,24 +51,16 @@ class sky130_row_cap_array(sky130_bitcell_base_array): """ Add the modules used in this design """ if self.column_offset == 0: self.top_corner = factory.create(module_type="corner", location="ul") - self.add_mod(self.top_corner) self.bottom_corner =factory.create(module_type="corner", location="ll") - self.add_mod(self.bottom_corner) self.rowend1 = factory.create(module_type="row_cap", version="rowend_replica") - self.add_mod(self.rowend1) self.rowend2 = factory.create(module_type="row_cap", version="rowenda_replica") - self.add_mod(self.rowend2) else: self.top_corner = factory.create(module_type="corner", location="ur") - self.add_mod(self.top_corner) self.bottom_corner = factory.create(module_type="corner", location="lr") - self.add_mod(self.bottom_corner) self.rowend1 = factory.create(module_type="row_cap", version="rowend") - self.add_mod(self.rowend1) self.rowend2 = factory.create(module_type="row_cap", version="rowenda") - self.add_mod(self.rowend2) self.cell = factory.create(module_type=OPTS.bitcell, version="opt1") From 8879820af4a59ef947d8a4cf46b3d43fbbe7161e Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Wed, 15 Dec 2021 14:19:52 -0800 Subject: [PATCH 044/229] replica col lvs fix --- compiler/modules/bitcell_base_array.py | 4 +- .../sky130/modules/sky130_bitcell_array.py | 11 ++- .../modules/sky130_bitcell_base_array.py | 19 +++-- .../sky130/modules/sky130_dummy_array.py | 15 ++-- .../modules/sky130_replica_bitcell_array.py | 80 +++++++++++++++++++ .../sky130/modules/sky130_replica_column.py | 20 ++--- technology/sky130/tech/tech.py | 2 +- 7 files changed, 119 insertions(+), 32 deletions(-) diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index f9eeaeb7..5bff2448 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -43,11 +43,11 @@ class bitcell_base_array(design.design): # Make a flat list too self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl] - def create_all_wordline_names(self, row_size=None): + def create_all_wordline_names(self, row_size=None, start_row=0): if row_size == None: row_size = self.row_size - for row in range(row_size): + for row in range(start_row, row_size): for port in self.all_ports: self.wordline_names[port].append("wl_{0}_{1}".format(port, row)) diff --git a/technology/sky130/modules/sky130_bitcell_array.py b/technology/sky130/modules/sky130_bitcell_array.py index 5d250f15..bd3a9457 100644 --- a/technology/sky130/modules/sky130_bitcell_array.py +++ b/technology/sky130/modules/sky130_bitcell_array.py @@ -71,21 +71,24 @@ class sky130_bitcell_array(bitcell_array, sky130_bitcell_base_array): self.connect_inst(self.get_bitcell_pins(row, col)) if col != self.column_size - 1: if alternate_strap: + name="row_{}_col_{}_wlstrap_p".format(row, col) row_layout.append(self.strap2) - self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), + self.add_inst(name=name.format(row, col), mod=self.strap2) alternate_strap = 0 else: if row % 2: + name="row_{}_col_{}_wlstrapa".format(row, col) row_layout.append(self.strap3) - self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), + self.add_inst(name=name.format(row, col), mod=self.strap3) else: + name="row_{}_col_{}_wlstrap".format(row, col) row_layout.append(self.strap) - self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), + self.add_inst(name=name.format(row, col), mod=self.strap) alternate_strap = 1 - self.connect_inst(self.get_strap_pins(row, col)) + self.connect_inst(self.get_strap_pins(row, col, name)) if alternate_bitcell == 0: alternate_bitcell = 1 else: diff --git a/technology/sky130/modules/sky130_bitcell_base_array.py b/technology/sky130/modules/sky130_bitcell_base_array.py index 5b0e39d4..b52d5eb9 100644 --- a/technology/sky130/modules/sky130_bitcell_base_array.py +++ b/technology/sky130/modules/sky130_bitcell_base_array.py @@ -77,21 +77,24 @@ class sky130_bitcell_base_array(bitcell_base_array): return bitcell_pins - def get_strap_pins(self, row, col): + def get_strap_pins(self, row, col, name=""): """ Creates a list of connections in the strap cell, indexed by column and row, for instance use in bitcell_array """ - strap_pins = ["vdd"] - return strap_pins - - def get_col_cap_pins(self, row, col): - """ - """ - strap_pins = ["gnd", "gnd", "vdd"] + if name and "_p" in name: + strap_pins = ["gnd"] + else: + strap_pins = ["vdd"] return strap_pins def get_col_cap_p_pins(self, row, col): + """ + """ + strap_pins = ["gnd", "vdd", "gnd"] + return strap_pins + + def get_col_cap_pins(self, row, col): """ """ strap_pins = [] diff --git a/technology/sky130/modules/sky130_dummy_array.py b/technology/sky130/modules/sky130_dummy_array.py index 9f854dd8..56f53d8b 100644 --- a/technology/sky130/modules/sky130_dummy_array.py +++ b/technology/sky130/modules/sky130_dummy_array.py @@ -77,17 +77,18 @@ class sky130_dummy_array(sky130_bitcell_base_array): self.connect_inst(self.get_bitcell_pins(row, col)) if col != self.column_size - 1: if alternate_strap: + name = "row_{}_col_{}_wlstrap_p".format(row, col) row_layout.append(self.strap2) - self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), + self.add_inst(name=name, mod=self.strap2) alternate_strap = 0 else: - + name="row_{}_col_{}_wlstrap".format(row, col) row_layout.append(self.strap) - self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), + self.add_inst(name=name, mod=self.strap) alternate_strap = 1 - self.connect_inst(self.get_strap_pins(row, col)) + self.connect_inst(self.get_strap_pins(row, col, name)) if alternate_bitcell == 0: alternate_bitcell = 1 else: @@ -96,11 +97,11 @@ class sky130_dummy_array(sky130_bitcell_base_array): def add_pins(self): # bitline pins are not added because they are floating + for bl_name in self.get_bitline_names(): + self.add_pin(bl_name, "INOUT") for wl_name in self.get_wordline_names(): self.add_pin(wl_name, "INPUT") - for bl in range(self.column_size): - self.add_pin("dummy_bl_{}".format(bl)) - self.add_pin("dummy_br_{}".format(bl)) + self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") diff --git a/technology/sky130/modules/sky130_replica_bitcell_array.py b/technology/sky130/modules/sky130_replica_bitcell_array.py index bc5d2036..28312c6c 100644 --- a/technology/sky130/modules/sky130_replica_bitcell_array.py +++ b/technology/sky130/modules/sky130_replica_bitcell_array.py @@ -338,3 +338,83 @@ class sky130_replica_bitcell_array(replica_bitcell_array, sky130_bitcell_base_ar width=pin.width(), height=self.height - 2 *(pin_height + drc_width*2)) return + + def add_wordline_pins(self): + + # Wordlines to ground + self.gnd_wordline_names = [] + + for port in self.all_ports: + for bit in self.all_ports: + self.rbl_wordline_names[port].append("rbl_wl_{0}_{1}".format(port, bit)) + if bit != port: + self.gnd_wordline_names.append("rbl_wl_{0}_{1}".format(port, bit)) + + self.all_rbl_wordline_names = [x for sl in self.rbl_wordline_names for x in sl] + + self.wordline_names = self.bitcell_array.wordline_names + self.all_wordline_names = self.bitcell_array.all_wordline_names + + # All wordlines including dummy and RBL + self.replica_array_wordline_names = [] + #self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap_top.get_wordline_names())) + for bit in range(self.rbl[0]): + self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[bit]]) + self.replica_array_wordline_names.extend(self.all_wordline_names) + for bit in range(self.rbl[1]): + self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[self.rbl[0] + bit]]) + #self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap_top.get_wordline_names())) + + for port in range(self.rbl[0]): + self.add_pin(self.rbl_wordline_names[port][port], "INPUT") + self.add_pin_list(self.all_wordline_names, "INPUT") + for port in range(self.rbl[0], self.rbl[0] + self.rbl[1]): + self.add_pin(self.rbl_wordline_names[port][port], "INPUT") + + def create_instances(self): + """ Create the module instances used in this design """ + self.supplies = ["vdd", "gnd"] + + # Used for names/dimensions only + # self.cell = factory.create(module_type=OPTS.bitcell) + + # Main array + self.bitcell_array_inst=self.add_inst(name="bitcell_array", + mod=self.bitcell_array) + self.connect_inst(self.all_bitline_names + self.all_wordline_names + self.supplies) + print("running\n\n\n") + # Replica columns + self.replica_col_insts = [] + for port in self.all_ports: + if port in self.rbls: + self.replica_col_insts.append(self.add_inst(name="replica_col_{}".format(port), + mod=self.replica_columns[port])) + self.connect_inst(self.rbl_bitline_names[port] + self.replica_array_wordline_names + self.supplies) + else: + self.replica_col_insts.append(None) + + # Dummy rows under the bitcell array (connected with with the replica cell wl) + self.dummy_row_replica_insts = [] + # Note, this is the number of left and right even if we aren't adding the columns to this bitcell array! + for port in self.all_ports: + self.dummy_row_replica_insts.append(self.add_inst(name="dummy_row_{}".format(port), + mod=self.dummy_row)) + self.connect_inst(self.all_bitline_names + [x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[port]] + self.supplies) + + # Top/bottom dummy rows or col caps + self.dummy_row_insts = [] + self.dummy_row_insts.append(self.add_inst(name="dummy_row_bot", + mod=self.col_cap_bottom)) + self.connect_inst(self.all_bitline_names + ["gnd"] * len(self.col_cap_bottom.get_wordline_names()) + self.supplies) + self.dummy_row_insts.append(self.add_inst(name="dummy_row_top", + mod=self.col_cap_top)) + self.connect_inst(self.all_bitline_names + ["gnd"] * len(self.col_cap_top.get_wordline_names()) + self.supplies) + + # Left/right Dummy columns + self.dummy_col_insts = [] + self.dummy_col_insts.append(self.add_inst(name="dummy_col_left", + mod=self.row_cap_left)) + self.connect_inst(["dummy_left_" + bl for bl in self.row_cap_left.all_bitline_names] + self.replica_array_wordline_names + self.supplies) + self.dummy_col_insts.append(self.add_inst(name="dummy_col_right", + mod=self.row_cap_right)) + self.connect_inst(["dummy_right_" + bl for bl in self.row_cap_right.all_bitline_names] + self.replica_array_wordline_names + self.supplies) diff --git a/technology/sky130/modules/sky130_replica_column.py b/technology/sky130/modules/sky130_replica_column.py index a900b0fe..db37d26f 100644 --- a/technology/sky130/modules/sky130_replica_column.py +++ b/technology/sky130/modules/sky130_replica_column.py @@ -81,9 +81,9 @@ class sky130_replica_column(sky130_bitcell_base_array): def add_pins(self): self.create_all_bitline_names() - self.create_all_wordline_names(self.row_size+2) + #self.create_all_wordline_names(self.row_size+2) # +2 to add fake wl pins for colends - + self.create_all_wordline_names(self.row_size+1, 1) self.add_pin_list(self.all_bitline_names, "OUTPUT") self.add_pin_list(self.all_wordline_names, "INPUT") @@ -132,8 +132,8 @@ class sky130_replica_column(sky130_bitcell_base_array): self.cell_inst[row]=self.add_inst(name=name, mod=self.replica_cell) self.connect_inst(self.get_bitcell_pins(row, 0)) row_layout.append(self.strap2) - self.add_inst(name=name + "_strap", mod=self.strap2) - self.connect_inst(self.get_strap_pins(row, 0)) + self.add_inst(name=name + "_strap_p", mod=self.strap2) + self.connect_inst(self.get_strap_pins(row, 0, name + "_strap_p")) alternate_bitcell = 1 else: @@ -141,24 +141,24 @@ class sky130_replica_column(sky130_bitcell_base_array): self.cell_inst[row]=self.add_inst(name=name, mod=self.replica_cell2) self.connect_inst(self.get_bitcell_pins(row, 0)) row_layout.append(self.strap2) - self.add_inst(name=name + "_strap", mod=self.strap2) - self.connect_inst(self.get_strap_pins(row, 0)) + self.add_inst(name=name + "_strap_p", mod=self.strap2) + self.connect_inst(self.get_strap_pins(row, 0, name + "_strap_p")) alternate_bitcell = 0 elif (row == 0): row_layout.append(self.colend) self.cell_inst[row]=self.add_inst(name=name, mod=self.colend) - self.connect_inst(self.get_col_cap_p_pins(row, 0)) + self.connect_inst(self.get_col_cap_pins(row, 0)) row_layout.append(self.colend_p_cent) self.add_inst(name=name + "_cap", mod=self.colend_p_cent) - self.connect_inst(self.get_col_cap_pins(row, 0)) + self.connect_inst(self.get_col_cap_p_pins(row, 0)) elif (row == self.total_size - 1): row_layout.append(self.colenda) self.cell_inst[row]=self.add_inst(name=name, mod=self.colenda) - self.connect_inst(self.get_col_cap_p_pins(row, 0)) + self.connect_inst(self.get_col_cap_pins(row, 0)) row_layout.append(self.colenda_p_cent) self.add_inst(name=name + "_cap", mod=self.colenda_p_cent) - self.connect_inst(self.get_col_cap_pins(row, 0)) + self.connect_inst(self.get_col_cap_p_pins(row, 0)) self.array_layout.append(row_layout) diff --git a/technology/sky130/tech/tech.py b/technology/sky130/tech/tech.py index a2c4d185..f82855c6 100644 --- a/technology/sky130/tech/tech.py +++ b/technology/sky130/tech/tech.py @@ -100,7 +100,7 @@ cell_properties.bitcell_2port.port_map = {'bl0': 'BL0', 'gnd': 'GND'} cell_properties.col_cap_1port_bitcell = cell(['br', 'vdd', 'gnd', 'bl'], - ['INPUT', 'INPUT', 'GROUND', 'POWER'], + ['INPUT', 'POWER', 'GROUND', 'INPUT'], {'bl': 'BL0', 'br': 'BL1', 'vdd': 'VPWR', From 94c14c602c920f414f0fb261d515fd26c0ea5cf9 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 16 Dec 2021 17:22:15 -0800 Subject: [PATCH 045/229] Add klayout to Makefile --- Makefile | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d585d52a..ad6bc1d2 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,7 @@ MAG_FILES := $(sort $(wildcard $(SRAM_LIBRARY)/cells/*/*.mag)) SPICE_SUFFIX := spice SPICE_LVS_SUFFIX := lvs.$(SPICE_SUFFIX) SPICE_CALIBRE_SUFFIX := lvs.calibre.$(SPICE_SUFFIX) +SPICE_KLAYOUT_SUFFIX := lvs.klayout.$(SPICE_SUFFIX) SPICE_BASE_SUFFIX := base.$(SPICE_SUFFIX) ALL_SPICE_FILES := $(sort $(wildcard $(SRAM_LIBRARY)/cells/*/*.$(SPICE_SUFFIX))) @@ -50,7 +51,7 @@ MAGICRC_FILE := $(OPEN_PDKS)/libs.tech/magic/sky130A.magicrc ALL_FILES := $(ALL_SPICE_FILES) $(GDS_FILES) $(MAG_FILES) $(MAGLEF_FILES) -INSTALL_BASE_DIRS := gds_lib mag_lib sp_lib lvs_lib calibre_lvs_lib lef_lib maglef_lib +INSTALL_BASE_DIRS := gds_lib mag_lib sp_lib lvs_lib calibre_lvs_lib klayout_lvs_lib lef_lib maglef_lib INSTALL_BASE := $(OPENRAM_HOME)/../technology/sky130 INSTALL_DIRS := $(addprefix $(INSTALL_BASE)/,$(INSTALL_BASE_DIRS)) @@ -133,6 +134,18 @@ $(INSTALL_BASE)/calibre_lvs_lib: $(filter %.$(SPICE_CALIBRE_SUFFIX),$(ALL_SPICE_ @echo "==================================================================" @echo +$(INSTALL_BASE)/klayout_lvs_lib: $(filter %.$(SPICE_KLAYOUT_SUFFIX),$(ALL_SPICE_FILES)) + @echo + @echo "Setting up klayout LVS library for OpenRAM." + @echo "==================================================================" + mkdir -p $@ + @for SP in $?; do \ + cp -va $$SP $@/$$(basename $$SP .$(SPICE_KLAYOUT_SUFFIX)).sp; \ + done + @echo "==================================================================" + @echo + + $(INSTALL_BASE)/sp_lib: $(filter-out %.$(SPICE_LVS_SUFFIX) %.$(SPICE_CALIBRE_SUFFIX),$(ALL_SPICE_FILES)) @echo @echo "Setting up spice simulation library for OpenRAM." From 4fa084f2720302756b81a663926d902fbb8fe2da Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 17 Dec 2021 10:18:20 -0800 Subject: [PATCH 046/229] Add 1rw decoder test --- compiler/tests/04_and2_dec_test.py | 11 ++++++++++- compiler/tests/04_and3_dec_test.py | 12 +++++++++++- compiler/tests/04_and4_dec_test.py | 11 ++++++++++- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/compiler/tests/04_and2_dec_test.py b/compiler/tests/04_and2_dec_test.py index 009a04f1..69bdd676 100755 --- a/compiler/tests/04_and2_dec_test.py +++ b/compiler/tests/04_and2_dec_test.py @@ -29,7 +29,16 @@ class and2_dec_test(openram_test): OPTS.num_w_ports = 0 globals.setup_bitcell() - debug.info(2, "Testing and2_dec gate") + debug.info(2, "Testing and2_dec 1rw/1r gate") + a = factory.create(module_type="and2_dec") + self.local_check(a) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + debug.info(2, "Testing and2_dec 1rw gate") a = factory.create(module_type="and2_dec") self.local_check(a) diff --git a/compiler/tests/04_and3_dec_test.py b/compiler/tests/04_and3_dec_test.py index a7cb6ef1..bcf4e85b 100755 --- a/compiler/tests/04_and3_dec_test.py +++ b/compiler/tests/04_and3_dec_test.py @@ -15,6 +15,7 @@ from globals import OPTS from sram_factory import factory import debug + class and3_dec_test(openram_test): def runTest(self): @@ -28,7 +29,16 @@ class and3_dec_test(openram_test): OPTS.num_w_ports = 0 globals.setup_bitcell() - debug.info(2, "Testing and3_dec gate") + debug.info(2, "Testing and3_dec 1rw/1r gate") + a = factory.create(module_type="and3_dec") + self.local_check(a) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + debug.info(2, "Testing and3_dec 1rw gate") a = factory.create(module_type="and3_dec") self.local_check(a) diff --git a/compiler/tests/04_and4_dec_test.py b/compiler/tests/04_and4_dec_test.py index ec76435f..4dbb2613 100755 --- a/compiler/tests/04_and4_dec_test.py +++ b/compiler/tests/04_and4_dec_test.py @@ -30,7 +30,16 @@ class and4_dec_test(openram_test): OPTS.num_w_ports = 0 globals.setup_bitcell() - debug.info(2, "Testing and4_dec gate") + debug.info(2, "Testing and4_dec 1rw/1r gate") + a = factory.create(module_type="and4_dec") + self.local_check(a) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + debug.info(2, "Testing and4_dec 1rw gate") a = factory.create(module_type="and4_dec") self.local_check(a) From e460eff014edd506ddcb52cf517fc72173ac9038 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 17 Dec 2021 10:21:34 -0800 Subject: [PATCH 047/229] Add per tool lvs directories --- compiler/base/hierarchy_spice.py | 53 +++++++++++++++++--------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index 33ac02b9..ee50ad4b 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -17,6 +17,7 @@ from wire_spice_model import wire_spice_model from power_data import power_data import logical_effort + class spice(): """ This provides a set of useful generic types for hierarchy @@ -36,14 +37,15 @@ class spice(): # If we have a separate lvs directory, then all the lvs files # should be in there (all or nothing!) try: - lvs_subdir = tech.lvs_lib - except AttributeError: - lvs_subdir = "lvs_lib" - lvs_dir = OPTS.openram_tech + lvs_subdir + "/" + from tech import lvs_name + lvs_dir = OPTS.openram_tech + lvs_name + "_lvs_lib/" + except ImportError: + lvs_dir = OPTS.openram_tech + "lvs_lib/" + if not os.path.exists(lvs_dir): + lvs_dir = OPTS.openram_tech + "lvs_lib/" - if os.path.exists(lvs_dir): - self.lvs_file = lvs_dir + cell_name + ".sp" - else: + self.lvs_file = lvs_dir + cell_name + ".sp" + if not os.path.exists(self.lvs_file): self.lvs_file = self.sp_file self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "BIAS", "POWER", "GROUND"] @@ -277,7 +279,10 @@ class spice(): # parses line into ports and remove subckt lvs_pins = subckt_line.split(" ")[2:] debug.check(lvs_pins == self.pins, - "Spice netlists for LVS and simulation have port mismatches: {0} (LVS) vs {1} (sim)".format(lvs_pins, self.pins)) + "Spice netlists for LVS and simulation have port mismatches:\n{0} (LVS {1})\nvs\n{2} (sim {3})".format(lvs_pins, + self.lvs_file, + self.pins, + self.sp_file)) def check_net_in_spice(self, net_name): """Checks if a net name exists in the current. Intended to be check nets in hand-made cells.""" @@ -419,7 +424,7 @@ class spice(): self.cacti_params = cacti_params # Get the r_on the the tx rd = self.get_on_resistance() - # Calculate the intrinsic capacitance + # Calculate the intrinsic capacitance c_intrinsic = self.get_intrinsic_capacitance() # Get wire values c_wire = self.module_wire_c() @@ -453,13 +458,13 @@ class spice(): def module_wire_c(self): """All devices assumed to have ideal capacitance (0). - Non-ideal cases should have this function re-defined. + Non-ideal cases should have this function re-defined. """ return 0 def module_wire_r(self): """All devices assumed to have ideal resistance (0). - Non-ideal cases should have this function re-defined. + Non-ideal cases should have this function re-defined. """ return 0 @@ -517,19 +522,19 @@ class spice(): self.cell_name)) return 0 - def cacti_rc_delay(self, + def cacti_rc_delay(self, inputramptime, # input rise time tf, # time constant of gate vs1, # threshold voltage vs2, # threshold voltage rise, # whether input rises or fall - extra_param_dict=None): + extra_param_dict=None): """By default, CACTI delay uses horowitz for gate delay. Can be overriden in cases like bitline if equation is different. """ return self.horowitz(inputramptime, tf, vs1, vs2, rise) - - def horowitz(self, + + def horowitz(self, inputramptime, # input rise time tf, # time constant of gate vs1, # threshold voltage @@ -549,17 +554,17 @@ class spice(): td = tf * math.sqrt(math.log(1.0 - vs1)*math.log(1.0 - vs1) + 2*a*b*(vs1)) + tf*(math.log(1.0 - vs1) - math.log(1.0 - vs2)) return td - - def tr_r_on(self, width, is_nchannel, stack, _is_cell): - + + def tr_r_on(self, width, is_nchannel, stack, _is_cell): + restrans = self.cacti_params["r_nch_on"] if is_nchannel else self.cacti_params["r_pch_on"] return stack * restrans / width def gate_c(self, width): - + return (tech.spice["c_g_ideal"] + tech.spice["c_overlap"] + 3*tech.spice["c_fringe"])*width +\ tech.drc["minlength_channel"]*tech.spice["cpolywire"] - + def drain_c_(self, width, stack, @@ -570,10 +575,10 @@ class spice(): c_fringe = 2*tech.spice["c_overlap"] c_overlap = 2*tech.spice["c_fringe"] drain_C_metal_connecting_folded_tr = 0 - + w_folded_tr = width/folds num_folded_tr = folds - + # Re-created some logic contact to get minwidth as importing the contact # module causes a failure if "minwidth_contact" in tech.drc: @@ -595,10 +600,10 @@ class spice(): if num_folded_tr%2 == 0: drain_h_for_sidewall = 0 - + total_drain_height_for_cap_wrt_gate *= num_folded_tr drain_C_metal_connecting_folded_tr = tech.spice["wire_c_per_um"] * total_drain_w - + drain_C_area = c_junc_area * total_drain_w * w_folded_tr drain_C_sidewall = c_junc_sidewall * (drain_h_for_sidewall + 2 * total_drain_w) From d555e67fb1c7837b6714127dc089769f729508fc Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 17 Dec 2021 10:27:13 -0800 Subject: [PATCH 048/229] Add initial sky130 LVS/DRC rules. --- technology/sky130/tech/sky130.lydrc | 922 ++++++++++++++++++++++++++++ technology/sky130/tech/sky130.lylvs | 278 +++++++++ 2 files changed, 1200 insertions(+) create mode 100644 technology/sky130/tech/sky130.lydrc create mode 100644 technology/sky130/tech/sky130.lylvs diff --git a/technology/sky130/tech/sky130.lydrc b/technology/sky130/tech/sky130.lydrc new file mode 100644 index 00000000..3c569c12 --- /dev/null +++ b/technology/sky130/tech/sky130.lydrc @@ -0,0 +1,922 @@ + + + + + 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 r drc_sky130.lydrc -rd input=my_layout.gds -rd topcell=your_topcell -rd output=drc_sky130.lyrdb +if $input + if $topcell + source($input,$topcell) + else + source($input) + end +end + +if $output + report("SKY130 DRC runset", $output) +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(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).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") +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/technology/sky130/tech/sky130.lylvs b/technology/sky130/tech/sky130.lylvs new file mode 100644 index 00000000..00526f9b --- /dev/null +++ b/technology/sky130/tech/sky130.lylvs @@ -0,0 +1,278 @@ + + + + + lvs + + + + false + false + + true + lvs_scripts + tools_menu.lvs.end + dsl + lvs-dsl-xml + # +tstart = Time.now +# Extraction for SKY130 +# +############################ + +# 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 lvs_sky130.lvs +if $input + source($input) +end + +if $report + report_lvs($report) +else + report_lvs("lvs_report.lvsdb") +end + +if $schematic +#reference netlist + schematic($schematic) +else + schematic(RBA::CellView::active.filename.sub(/\.(oas|gds|oas.gz|gds.gz)$/, ".sp")) +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 + +if $target_netlist + target_netlist($target_netlist) +else + target_netlist(File.join(File.dirname(RBA::CellView::active.filename), source.cell_name+"_extracted.cir"), write_spice(spice_with_net_names, spice_with_comments), "Extracted by KLayout on : #{Time.now.strftime("%d/%m/%Y %H:%M")}") +end + +# klayout setup +######################## +# Hierarchical mode +deep +# Use 4 CPU cores +threads(4) +# Print details +verbose(true) + +# layers definitions +######################## + + +# LVS section +######################## +info("LVS section") +# 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 +CORE_PGATE = PGATE & COREID +STD_PGATE = PGATE - HVTP - NCM - HVI - COREID +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 +CORE_NGATE = NGATE & COREID +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("sky130_fd_pr__special_pfet_latch"), { "SD" => PSD, "G" => CORE_PGATE, "tS" => PSD, "tD" => PSD, "tG" => POLY, "W" => NWELL }) +extract_devices(mos4("sky130_fd_pr__pfet_01v8"), { "SD" => PSD, "G" => STD_PGATE, "tS" => PSD, "tD" => PSD, "tG" => POLY, "W" => NWELL }) +extract_devices(mos4("sky130_fd_pr__pfet_01v8_hvt"), { "SD" => PSD, "G" => HVT_PGATE, "tS" => PSD, "tD" => PSD, "tG" => POLY, "W" => NWELL }) +extract_devices(mos4("sky130_fd_pr__pfet_g5v0d10v5"), { "SD" => PSD, "G" => HV5_PGATE, "tS" => PSD, "tD" => PSD, "tG" => POLY, "W" => NWELL }) + +# NMOS transistor device extraction +extract_devices(mos4("sky130_fd_pr__special_nfet_latch"), { "SD" => NSD, "G" => CORE_NGATE, "tS" => NSD, "tD" => NSD, "tG" => POLY, "W" => SUB }) +extract_devices(mos4("sky130_fd_pr__nfet_01v8"), { "SD" => NSD, "G" => STD_NGATE, "tS" => NSD, "tD" => NSD, "tG" => POLY, "W" => SUB }) +extract_devices(mos4("sky130_fd_pr__nfet_01v8_lvt"), { "SD" => NSD, "G" => LVT_NGATE, "tS" => NSD, "tD" => NSD, "tG" => POLY, "W" => SUB }) +extract_devices(mos4("sky130_fd_pr__nfet_g5v0d10v5"), { "SD" => NSD, "G" => HV5_NGATE, "tS" => NSD, "tD" => NSD, "tG" => POLY, "W" => SUB }) +extract_devices(mos4("sky130_fd_pr__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, "gnd") + +if $connect_supplies +connect_implicit("*", "vdd") +connect_implicit("*", "gnd") +end + +#connect_global(pwell, "PWELL") +#connect_global(nwell, "NWELL") +#connect_global(bulk, "BULK") + +# 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 +#schematic.simplify + +# Tolerances for the devices extracted parameters +# tolerance(device_class_name, parameter_name [, :absolute => absolute_tolerance] [, :relative => relative_tolerance]) +tolerance("pfet_01v8", "W", :absolute => 1.nm, :relative => 0.001) +tolerance("pfet_01v8", "L", :absolute => 1.nm, :relative => 0.001) +tolerance("pfet_01v8_hvt", "W", :absolute => 1.nm, :relative => 0.001) +tolerance("pfet_01v8_hvt", "L", :absolute => 1.nm, :relative => 0.001) +tolerance("nfet_01v8", "W", :absolute => 1.nm, :relative => 0.001) +tolerance("nfet_01v8", "L", :absolute => 1.nm, :relative => 0.001) +tolerance("nfet_01v8_lvt", "W", :absolute => 1.nm, :relative => 0.001) +tolerance("nfet_01v8_lvt", "L", :absolute => 1.nm, :relative => 0.001) + +#max_res(1000000) +#min_caps(1e-15) + +max_branch_complexity(65536) +max_depth(16) + +if ! compare + #raise "ERROR : Netlists don't match" + puts "ERROR : Netlists don't match" +else + puts "CONGRATULATIONS! Netlists match." +end + +# time spent for the LVS +time = Time.now +hours = ((time - tstart)/3600).to_i +minutes = ((time - tstart)/60 - hours * 60).to_i +seconds = ((time - tstart) - (minutes * 60 + hours * 3600)).to_i +$stdout.write "LVS finished at : #{time.hour}:#{time.min}:#{time.sec} - LVS duration = #{hours} hrs. #{minutes} min. #{seconds} sec.\n" + From 82a1a8d87f3876cebecab70a213cdf6c8382f74d Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 17 Dec 2021 10:28:12 -0800 Subject: [PATCH 049/229] Add exception for sky130 klayout LVS device output --- compiler/pgates/ptx.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index 77950b82..e6a8313d 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -156,13 +156,18 @@ class ptx(design.design): # self.tx_width, # drc("minwidth_poly")) # TEMP FIX: Use old device names if using Calibre. - + self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3} mult=1".format("nshort" if self.tx_type == "nmos" else "pshort", self.mults, self.tx_width, drc("minwidth_poly")) + + elif OPTS.lvs_exe and OPTS.lvs_exe[0] == "klayout": + self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3}".format(spice[self.tx_type], + self.mults, + self.tx_width, + drc("minwidth_poly")) elif cell_props.ptx.model_is_subckt: - # sky130 requires mult parameter too self.lvs_device = "X{{0}} {{1}} {0} m={1} w={2}u l={3}u".format(spice[self.tx_type], self.mults, self.tx_width, @@ -550,7 +555,7 @@ class ptx(design.design): def is_non_inverting(self): """Return input to output polarity for module""" - + return True def get_on_resistance(self): @@ -558,14 +563,14 @@ class ptx(design.design): is_nchannel = (self.tx_type == "nmos") stack = 1 is_cell = False - return self.tr_r_on(self.tx_width, is_nchannel, stack, is_cell) - + return self.tr_r_on(self.tx_width, is_nchannel, stack, is_cell) + def get_input_capacitance(self): """Input cap of input, passes width of gates to gate cap function""" - return self.gate_c(self.tx_width) + return self.gate_c(self.tx_width) def get_intrinsic_capacitance(self): """Get the drain capacitances of the TXs in the gate.""" - return self.drain_c_(self.tx_width*self.mults, + return self.drain_c_(self.tx_width*self.mults, 1, self.mults) From 02364c6cdfba213e5ae6ad36ca3f78eeaf1c46fc Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 17 Dec 2021 10:29:17 -0800 Subject: [PATCH 050/229] Add klayout option in config. No tool specific LVS libs --- technology/sky130/tech/tech.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/technology/sky130/tech/tech.py b/technology/sky130/tech/tech.py index a2c4d185..5a6ee672 100644 --- a/technology/sky130/tech/tech.py +++ b/technology/sky130/tech/tech.py @@ -460,6 +460,7 @@ drc["grid"] = 0.005 NDA_PDK_ROOT = os.environ.get("NDA_PDK_ROOT", False) use_calibre = bool(NDA_PDK_ROOT) use_calibre = False +use_klayout = False if use_calibre: # Correct order according to s8 pin_purpose = 16 @@ -747,8 +748,10 @@ if use_calibre: drc_name = "calibre" lvs_name = "calibre" pex_name = "calibre" - # Calibre automatically scales to micron to SI units and requires mult parameter - lvs_lib = "calibre_lvs_lib" +elif use_klayout: + drc_name = "klayout" + lvs_name = "klayout" + pex_name = "klayout" else: drc_name = "magic" lvs_name = "netgen" From 34dd46c918a8effbd8dff525016c9726c0d51cd0 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 17 Dec 2021 10:30:43 -0800 Subject: [PATCH 051/229] Exceptions for sky130 spare columns tests --- compiler/tests/18_port_data_test.py | 12 +++++++++++- compiler/tests/20_sram_1bank_nomux_test.py | 12 +++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/compiler/tests/18_port_data_test.py b/compiler/tests/18_port_data_test.py index 3b33466a..b9c7bcdb 100755 --- a/compiler/tests/18_port_data_test.py +++ b/compiler/tests/18_port_data_test.py @@ -13,6 +13,7 @@ from globals import OPTS from sram_factory import factory import debug + class port_data_test(openram_test): def runTest(self): @@ -20,8 +21,17 @@ class port_data_test(openram_test): globals.init_openram(config_file) from sram_config import sram_config + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=4, - num_words=16) + num_words=16, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=1 factory.reset() diff --git a/compiler/tests/20_sram_1bank_nomux_test.py b/compiler/tests/20_sram_1bank_nomux_test.py index 098b8b12..7a13b28b 100755 --- a/compiler/tests/20_sram_1bank_nomux_test.py +++ b/compiler/tests/20_sram_1bank_nomux_test.py @@ -22,9 +22,19 @@ class sram_1bank_nomux_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) from sram_config import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=4, num_words=16, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=1 c.recompute_sizes() From e6e9d09369eefd3d7e03f49360d7dc94038e1d28 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 17 Dec 2021 10:30:55 -0800 Subject: [PATCH 052/229] Remove add_mod from sky130 modules --- technology/sky130/modules/sky130_bitcell_array.py | 5 ----- technology/sky130/modules/sky130_col_cap_array.py | 6 ------ technology/sky130/modules/sky130_dummy_array.py | 4 ---- technology/sky130/modules/sky130_replica_column.py | 8 -------- technology/sky130/modules/sky130_row_cap_array.py | 8 -------- 5 files changed, 31 deletions(-) diff --git a/technology/sky130/modules/sky130_bitcell_array.py b/technology/sky130/modules/sky130_bitcell_array.py index 5d250f15..fb04e4a7 100644 --- a/technology/sky130/modules/sky130_bitcell_array.py +++ b/technology/sky130/modules/sky130_bitcell_array.py @@ -38,15 +38,10 @@ class sky130_bitcell_array(bitcell_array, sky130_bitcell_base_array): """ Add the modules used in this design """ # Bitcell for port names only self.cell = factory.create(module_type=OPTS.bitcell, version="opt1") - self.add_mod(self.cell) self.cell2 = factory.create(module_type=OPTS.bitcell, version="opt1a") - self.add_mod(self.cell2) self.strap = factory.create(module_type="internal", version="wlstrap") - self.add_mod(self.strap) self.strap2 = factory.create(module_type="internal", version="wlstrap_p") - self.add_mod(self.strap2) self.strap3 = factory.create(module_type="internal", version="wlstrapa") - self.add_mod(self.strap3) def create_instances(self): """ Create the module instances used in this design """ diff --git a/technology/sky130/modules/sky130_col_cap_array.py b/technology/sky130/modules/sky130_col_cap_array.py index b1e9e35b..26d97ee2 100644 --- a/technology/sky130/modules/sky130_col_cap_array.py +++ b/technology/sky130/modules/sky130_col_cap_array.py @@ -49,18 +49,12 @@ class sky130_col_cap_array(sky130_bitcell_base_array): """ Add the modules used in this design """ if self.location == "top": self.colend1 = factory.create(module_type="col_cap", version="colend") - self.add_mod(self.colend1) self.colend2 = factory.create(module_type="col_cap", version="colend_p_cent") - self.add_mod(self.colend2) self.colend3 = factory.create(module_type="col_cap", version="colend_cent") - self.add_mod(self.colend3) elif self.location == "bottom": self.colend1 = factory.create(module_type="col_cap", version="colenda") - self.add_mod(self.colend1) self.colend2 = factory.create(module_type="col_cap", version="colenda_p_cent") - self.add_mod(self.colend2) self.colend3 = factory.create(module_type="col_cap", version="colenda_cent") - self.add_mod(self.colend3) self.cell = factory.create(module_type=OPTS.bitcell, version="opt1") diff --git a/technology/sky130/modules/sky130_dummy_array.py b/technology/sky130/modules/sky130_dummy_array.py index 9f854dd8..1785d946 100644 --- a/technology/sky130/modules/sky130_dummy_array.py +++ b/technology/sky130/modules/sky130_dummy_array.py @@ -45,13 +45,9 @@ class sky130_dummy_array(sky130_bitcell_base_array): def add_modules(self): """ Add the modules used in this design """ self.dummy_cell = factory.create(module_type=OPTS.dummy_bitcell, version="opt1") - self.add_mod(self.dummy_cell) self.dummy_cell2 = factory.create(module_type=OPTS.dummy_bitcell, version="opt1a") - self.add_mod(self.dummy_cell2) self.strap = factory.create(module_type="internal", version="wlstrap") - self.add_mod(self.strap) self.strap2 = factory.create(module_type="internal", version="wlstrap_p") - self.add_mod(self.strap2) self.cell = factory.create(module_type=OPTS.bitcell, version="opt1") def create_instances(self): diff --git a/technology/sky130/modules/sky130_replica_column.py b/technology/sky130/modules/sky130_replica_column.py index a900b0fe..00ad1816 100644 --- a/technology/sky130/modules/sky130_replica_column.py +++ b/technology/sky130/modules/sky130_replica_column.py @@ -92,28 +92,20 @@ class sky130_replica_column(sky130_bitcell_base_array): def add_modules(self): self.replica_cell = factory.create(module_type="replica_bitcell_1port", version="opt1") - self.add_mod(self.replica_cell) self.cell = self.replica_cell self.replica_cell2 = factory.create(module_type="replica_bitcell_1port", version="opt1a") - self.add_mod(self.replica_cell2) self.dummy_cell = factory.create(module_type="dummy_bitcell_1port", version="opt1") self.dummy_cell2 = factory.create(module_type="dummy_bitcell_1port", version="opt1") self.strap1 = factory.create(module_type="internal", version="wlstrap") - self.add_mod(self.strap1) self.strap2 = factory.create(module_type="internal", version="wlstrap_p") - self.add_mod(self.strap2) self.colend = factory.create(module_type="col_cap", version="colend") self.edge_cell = self.colend - self.add_mod(self.colend) self.colenda = factory.create(module_type="col_cap", version="colenda") - self.add_mod(self.colenda) self.colend_p_cent = factory.create(module_type="col_cap", version="colend_p_cent") - self.add_mod(self.colend_p_cent) self.colenda_p_cent = factory.create(module_type="col_cap", version="colenda_p_cent") - self.add_mod(self.colenda_p_cent) def create_instances(self): self.cell_inst = {} diff --git a/technology/sky130/modules/sky130_row_cap_array.py b/technology/sky130/modules/sky130_row_cap_array.py index a82f5558..e5721da2 100644 --- a/technology/sky130/modules/sky130_row_cap_array.py +++ b/technology/sky130/modules/sky130_row_cap_array.py @@ -51,24 +51,16 @@ class sky130_row_cap_array(sky130_bitcell_base_array): """ Add the modules used in this design """ if self.column_offset == 0: self.top_corner = factory.create(module_type="corner", location="ul") - self.add_mod(self.top_corner) self.bottom_corner =factory.create(module_type="corner", location="ll") - self.add_mod(self.bottom_corner) self.rowend1 = factory.create(module_type="row_cap", version="rowend_replica") - self.add_mod(self.rowend1) self.rowend2 = factory.create(module_type="row_cap", version="rowenda_replica") - self.add_mod(self.rowend2) else: self.top_corner = factory.create(module_type="corner", location="ur") - self.add_mod(self.top_corner) self.bottom_corner = factory.create(module_type="corner", location="lr") - self.add_mod(self.bottom_corner) self.rowend1 = factory.create(module_type="row_cap", version="rowend") - self.add_mod(self.rowend1) self.rowend2 = factory.create(module_type="row_cap", version="rowenda") - self.add_mod(self.rowend2) self.cell = factory.create(module_type=OPTS.bitcell, version="opt1") From 79e6eea9769e8b5c68f1fff6fb68be4b4b7f860d Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 17 Dec 2021 10:39:04 -0800 Subject: [PATCH 053/229] Use local repo for development of sky130_fd_bd_sram --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ad6bc1d2..998a54e8 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,8 @@ TOP_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))) # Skywater PDK SRAM library #SRAM_LIBRARY ?= $(PDK_ROOT)/skywater-pdk/libraries/sky130_fd_bd_sram -SRAM_GIT_REPO ?= https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git +#SRAM_GIT_REPO ?= https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git +SRAM_GIT_REPO ?= git@github.com:VLSIDA/sky130_fd_bd_sram.git SRAM_LIBRARY ?= $(TOP_DIR)/sky130_fd_bd_sram # Open PDKs From 8a0450afac5fa24a8d70868ffe3d32231f7ba908 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Wed, 22 Dec 2021 15:46:03 -0800 Subject: [PATCH 054/229] adjust replica col wls --- technology/sky130/modules/sky130_replica_bitcell_array.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/technology/sky130/modules/sky130_replica_bitcell_array.py b/technology/sky130/modules/sky130_replica_bitcell_array.py index 28312c6c..0e7469de 100644 --- a/technology/sky130/modules/sky130_replica_bitcell_array.py +++ b/technology/sky130/modules/sky130_replica_bitcell_array.py @@ -382,7 +382,6 @@ class sky130_replica_bitcell_array(replica_bitcell_array, sky130_bitcell_base_ar self.bitcell_array_inst=self.add_inst(name="bitcell_array", mod=self.bitcell_array) self.connect_inst(self.all_bitline_names + self.all_wordline_names + self.supplies) - print("running\n\n\n") # Replica columns self.replica_col_insts = [] for port in self.all_ports: @@ -414,7 +413,7 @@ class sky130_replica_bitcell_array(replica_bitcell_array, sky130_bitcell_base_ar self.dummy_col_insts = [] self.dummy_col_insts.append(self.add_inst(name="dummy_col_left", mod=self.row_cap_left)) - self.connect_inst(["dummy_left_" + bl for bl in self.row_cap_left.all_bitline_names] + self.replica_array_wordline_names + self.supplies) + self.connect_inst(["dummy_left_" + bl for bl in self.row_cap_left.all_bitline_names] + ["gnd"] + self.replica_array_wordline_names + ["gnd"] + self.supplies) self.dummy_col_insts.append(self.add_inst(name="dummy_col_right", mod=self.row_cap_right)) - self.connect_inst(["dummy_right_" + bl for bl in self.row_cap_right.all_bitline_names] + self.replica_array_wordline_names + self.supplies) + self.connect_inst(["dummy_right_" + bl for bl in self.row_cap_right.all_bitline_names] + ["gnd"] + self.replica_array_wordline_names + ["gnd"] + self.supplies) From 468de963f678874d9265aefbe7c6af6cbae1de3b Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Wed, 22 Dec 2021 15:51:49 -0800 Subject: [PATCH 055/229] remove add_mod in sky130 --- technology/sky130/modules/sky130_bitcell_array.py | 5 ----- technology/sky130/modules/sky130_col_cap_array.py | 6 ------ technology/sky130/modules/sky130_dummy_array.py | 4 ---- technology/sky130/modules/sky130_replica_column.py | 8 -------- technology/sky130/modules/sky130_row_cap_array.py | 8 -------- 5 files changed, 31 deletions(-) diff --git a/technology/sky130/modules/sky130_bitcell_array.py b/technology/sky130/modules/sky130_bitcell_array.py index bd3a9457..32fd5e4b 100644 --- a/technology/sky130/modules/sky130_bitcell_array.py +++ b/technology/sky130/modules/sky130_bitcell_array.py @@ -38,15 +38,10 @@ class sky130_bitcell_array(bitcell_array, sky130_bitcell_base_array): """ Add the modules used in this design """ # Bitcell for port names only self.cell = factory.create(module_type=OPTS.bitcell, version="opt1") - self.add_mod(self.cell) self.cell2 = factory.create(module_type=OPTS.bitcell, version="opt1a") - self.add_mod(self.cell2) self.strap = factory.create(module_type="internal", version="wlstrap") - self.add_mod(self.strap) self.strap2 = factory.create(module_type="internal", version="wlstrap_p") - self.add_mod(self.strap2) self.strap3 = factory.create(module_type="internal", version="wlstrapa") - self.add_mod(self.strap3) def create_instances(self): """ Create the module instances used in this design """ diff --git a/technology/sky130/modules/sky130_col_cap_array.py b/technology/sky130/modules/sky130_col_cap_array.py index b1e9e35b..26d97ee2 100644 --- a/technology/sky130/modules/sky130_col_cap_array.py +++ b/technology/sky130/modules/sky130_col_cap_array.py @@ -49,18 +49,12 @@ class sky130_col_cap_array(sky130_bitcell_base_array): """ Add the modules used in this design """ if self.location == "top": self.colend1 = factory.create(module_type="col_cap", version="colend") - self.add_mod(self.colend1) self.colend2 = factory.create(module_type="col_cap", version="colend_p_cent") - self.add_mod(self.colend2) self.colend3 = factory.create(module_type="col_cap", version="colend_cent") - self.add_mod(self.colend3) elif self.location == "bottom": self.colend1 = factory.create(module_type="col_cap", version="colenda") - self.add_mod(self.colend1) self.colend2 = factory.create(module_type="col_cap", version="colenda_p_cent") - self.add_mod(self.colend2) self.colend3 = factory.create(module_type="col_cap", version="colenda_cent") - self.add_mod(self.colend3) self.cell = factory.create(module_type=OPTS.bitcell, version="opt1") diff --git a/technology/sky130/modules/sky130_dummy_array.py b/technology/sky130/modules/sky130_dummy_array.py index 56f53d8b..66116417 100644 --- a/technology/sky130/modules/sky130_dummy_array.py +++ b/technology/sky130/modules/sky130_dummy_array.py @@ -45,13 +45,9 @@ class sky130_dummy_array(sky130_bitcell_base_array): def add_modules(self): """ Add the modules used in this design """ self.dummy_cell = factory.create(module_type=OPTS.dummy_bitcell, version="opt1") - self.add_mod(self.dummy_cell) self.dummy_cell2 = factory.create(module_type=OPTS.dummy_bitcell, version="opt1a") - self.add_mod(self.dummy_cell2) self.strap = factory.create(module_type="internal", version="wlstrap") - self.add_mod(self.strap) self.strap2 = factory.create(module_type="internal", version="wlstrap_p") - self.add_mod(self.strap2) self.cell = factory.create(module_type=OPTS.bitcell, version="opt1") def create_instances(self): diff --git a/technology/sky130/modules/sky130_replica_column.py b/technology/sky130/modules/sky130_replica_column.py index db37d26f..482b22e2 100644 --- a/technology/sky130/modules/sky130_replica_column.py +++ b/technology/sky130/modules/sky130_replica_column.py @@ -92,28 +92,20 @@ class sky130_replica_column(sky130_bitcell_base_array): def add_modules(self): self.replica_cell = factory.create(module_type="replica_bitcell_1port", version="opt1") - self.add_mod(self.replica_cell) self.cell = self.replica_cell self.replica_cell2 = factory.create(module_type="replica_bitcell_1port", version="opt1a") - self.add_mod(self.replica_cell2) self.dummy_cell = factory.create(module_type="dummy_bitcell_1port", version="opt1") self.dummy_cell2 = factory.create(module_type="dummy_bitcell_1port", version="opt1") self.strap1 = factory.create(module_type="internal", version="wlstrap") - self.add_mod(self.strap1) self.strap2 = factory.create(module_type="internal", version="wlstrap_p") - self.add_mod(self.strap2) self.colend = factory.create(module_type="col_cap", version="colend") self.edge_cell = self.colend - self.add_mod(self.colend) self.colenda = factory.create(module_type="col_cap", version="colenda") - self.add_mod(self.colenda) self.colend_p_cent = factory.create(module_type="col_cap", version="colend_p_cent") - self.add_mod(self.colend_p_cent) self.colenda_p_cent = factory.create(module_type="col_cap", version="colenda_p_cent") - self.add_mod(self.colenda_p_cent) def create_instances(self): self.cell_inst = {} diff --git a/technology/sky130/modules/sky130_row_cap_array.py b/technology/sky130/modules/sky130_row_cap_array.py index a82f5558..e5721da2 100644 --- a/technology/sky130/modules/sky130_row_cap_array.py +++ b/technology/sky130/modules/sky130_row_cap_array.py @@ -51,24 +51,16 @@ class sky130_row_cap_array(sky130_bitcell_base_array): """ Add the modules used in this design """ if self.column_offset == 0: self.top_corner = factory.create(module_type="corner", location="ul") - self.add_mod(self.top_corner) self.bottom_corner =factory.create(module_type="corner", location="ll") - self.add_mod(self.bottom_corner) self.rowend1 = factory.create(module_type="row_cap", version="rowend_replica") - self.add_mod(self.rowend1) self.rowend2 = factory.create(module_type="row_cap", version="rowenda_replica") - self.add_mod(self.rowend2) else: self.top_corner = factory.create(module_type="corner", location="ur") - self.add_mod(self.top_corner) self.bottom_corner = factory.create(module_type="corner", location="lr") - self.add_mod(self.bottom_corner) self.rowend1 = factory.create(module_type="row_cap", version="rowend") - self.add_mod(self.rowend1) self.rowend2 = factory.create(module_type="row_cap", version="rowenda") - self.add_mod(self.rowend2) self.cell = factory.create(module_type=OPTS.bitcell, version="opt1") From cf8c486cea4513faf181ecf28626b544b4393d30 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Wed, 22 Dec 2021 16:00:59 -0800 Subject: [PATCH 056/229] merge sky130_dummy_array --- technology/sky130/modules/sky130_dummy_array.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/technology/sky130/modules/sky130_dummy_array.py b/technology/sky130/modules/sky130_dummy_array.py index f1097855..c53b0fc3 100644 --- a/technology/sky130/modules/sky130_dummy_array.py +++ b/technology/sky130/modules/sky130_dummy_array.py @@ -94,7 +94,7 @@ class sky130_dummy_array(sky130_bitcell_base_array): self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), mod=self.strap3) alternate_strap = 1 - self.connect_inst(self.get_strap_pins(row, col, name)) + self.connect_inst(self.get_strap_pins(row, col)) if alternate_bitcell == 0: alternate_bitcell = 1 else: @@ -103,11 +103,11 @@ class sky130_dummy_array(sky130_bitcell_base_array): def add_pins(self): # bitline pins are not added because they are floating - for bl_name in self.get_bitline_names(): - self.add_pin(bl_name, "INOUT") for wl_name in self.get_wordline_names(): self.add_pin(wl_name, "INPUT") - + for bl in range(self.column_size): + self.add_pin("dummy_bl_{}".format(bl)) + self.add_pin("dummy_br_{}".format(bl)) self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") From 8d9166a01b3cac8b2ed7abb2688ab9b040bb6c11 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Wed, 29 Dec 2021 12:43:02 -0800 Subject: [PATCH 057/229] only rba lvs errors is colend body extraction --- .../sky130/modules/sky130_bitcell_array.py | 14 ++--- .../modules/sky130_bitcell_base_array.py | 4 ++ .../sky130/modules/sky130_col_cap_array.py | 34 +++++++++- .../sky130/modules/sky130_dummy_array.py | 63 ++++++++++++++----- .../modules/sky130_replica_bitcell_array.py | 10 ++- .../sky130/modules/sky130_replica_column.py | 3 + technology/sky130/tech/tech.py | 7 ++- 7 files changed, 100 insertions(+), 35 deletions(-) diff --git a/technology/sky130/modules/sky130_bitcell_array.py b/technology/sky130/modules/sky130_bitcell_array.py index cbc2b2f9..d0d69c74 100644 --- a/technology/sky130/modules/sky130_bitcell_array.py +++ b/technology/sky130/modules/sky130_bitcell_array.py @@ -68,25 +68,23 @@ class sky130_bitcell_array(bitcell_array, sky130_bitcell_base_array): if col != self.column_size - 1: if alternate_strap: if row % 2: + name="row_{}_col_{}_wlstrapa_p".format(row, col) row_layout.append(self.strap4) - self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), - mod=self.strap4) + self.add_inst(name=name, mod=self.strap4) else: + name="row_{}_col_{}_wlstrap_p".format(row, col) row_layout.append(self.strap2) - self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), - mod=self.strap2) + self.add_inst(name=name, mod=self.strap2) alternate_strap = 0 else: if row % 2: name="row_{}_col_{}_wlstrapa".format(row, col) row_layout.append(self.strap3) - self.add_inst(name=name.format(row, col), - mod=self.strap3) + self.add_inst(name=name.format(row, col), mod=self.strap3) else: name="row_{}_col_{}_wlstrap".format(row, col) row_layout.append(self.strap) - self.add_inst(name=name.format(row, col), - mod=self.strap) + self.add_inst(name=name.format(row, col), mod=self.strap) alternate_strap = 1 self.connect_inst(self.get_strap_pins(row, col, name)) if alternate_bitcell == 0: diff --git a/technology/sky130/modules/sky130_bitcell_base_array.py b/technology/sky130/modules/sky130_bitcell_base_array.py index b52d5eb9..d472b264 100644 --- a/technology/sky130/modules/sky130_bitcell_base_array.py +++ b/technology/sky130/modules/sky130_bitcell_base_array.py @@ -103,6 +103,10 @@ class sky130_bitcell_base_array(bitcell_base_array): strap_pins.extend(["vdd", "gnd"]) for port in self.all_ports: strap_pins.extend([x for x in self.get_bitline_names(port) if "br" in x and x.endswith("_{0}".format(col))]) + if row == 0: + strap_pins.extend(["gate_top"]) + else: + strap_pins.extend(["gate_bottom"]) return strap_pins def get_row_cap_pins(self, row, col): diff --git a/technology/sky130/modules/sky130_col_cap_array.py b/technology/sky130/modules/sky130_col_cap_array.py index 26d97ee2..a363dda2 100644 --- a/technology/sky130/modules/sky130_col_cap_array.py +++ b/technology/sky130/modules/sky130_col_cap_array.py @@ -8,7 +8,8 @@ from sram_factory import factory from sky130_bitcell_base_array import sky130_bitcell_base_array from globals import OPTS - +import geometry +from tech import layer class sky130_col_cap_array(sky130_bitcell_base_array): """ @@ -41,7 +42,7 @@ class sky130_col_cap_array(sky130_bitcell_base_array): self.place_array("dummy_r{0}_c{1}", self.mirror) self.add_layout_pins() - + #self.add_supply_pins() self.add_boundary() self.DRC_LVS() @@ -77,6 +78,7 @@ class sky130_col_cap_array(sky130_bitcell_base_array): pins.append("vdd") pins.append("gnd") pins.append("fake_br_{}".format(bitline)) + pins.append("gate") bitline += 1 elif col % 4 == 1: row_layout.append(self.colend2) @@ -91,13 +93,14 @@ class sky130_col_cap_array(sky130_bitcell_base_array): pins.append("vdd") pins.append("gnd") pins.append("fake_br_{}".format(bitline)) + pins.append("gate") bitline += 1 elif col % 4 ==3: row_layout.append(self.colend2) self.cell_inst[col]=self.add_inst(name=name, mod=self.colend2) pins.append("gnd") pins.append("vdd") - pins.append("gnd") + pins.append("vnb") self.connect_inst(pins) @@ -131,6 +134,7 @@ class sky130_col_cap_array(sky130_bitcell_base_array): self.add_pin("fake_wl", "INPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") + self.add_pin("gate", "BIAS") def add_layout_pins(self): """ Add the layout pins """ @@ -167,6 +171,30 @@ class sky130_col_cap_array(sky130_bitcell_base_array): width=pin.width(), height=pin.height()) return + + def add_supply_pins(self): + for col in range(self.cols): + inst = self.cell_inst[col] + if 'VPB' in self.cell_inst[col].mod.pins: + pin = inst.get_pin("vpb") + self.objs.append(geometry.rectangle(layer["nwell"], + pin.ll(), + pin.width(), + pin.height())) + self.objs.append(geometry.label("vdd", layer["nwell"], pin.center())) + + if 'VNB' in self.cell_inst[col].mod.pins: + try: + from tech import layer_override + if layer_override['VNB']: + pin = inst.get_pin("vnb") + self.objs.append(geometry.label("gnd", layer["pwellp"], pin.center())) + self.objs.append(geometry.rectangle(layer["pwellp"], + pin.ll(), + pin.width(), + pin.height())) + except: + pin = inst.get_pin("vnb") def create_all_wordline_names(self, row_size=None): if row_size == None: diff --git a/technology/sky130/modules/sky130_dummy_array.py b/technology/sky130/modules/sky130_dummy_array.py index c53b0fc3..416e9f3d 100644 --- a/technology/sky130/modules/sky130_dummy_array.py +++ b/technology/sky130/modules/sky130_dummy_array.py @@ -8,7 +8,8 @@ from sky130_bitcell_base_array import sky130_bitcell_base_array from sram_factory import factory from globals import OPTS - +import geometry +from tech import layer class sky130_dummy_array(sky130_bitcell_base_array): """ @@ -37,7 +38,7 @@ class sky130_dummy_array(sky130_bitcell_base_array): self.place_array("dummy_r{0}_c{1}", self.mirror) self.add_layout_pins() - + self.add_supply_pins() self.add_boundary() self.DRC_LVS() @@ -76,25 +77,29 @@ class sky130_dummy_array(sky130_bitcell_base_array): if col != self.column_size - 1: if alternate_strap: if col % 2: + name="row_{}_col_{}_wlstrap_p".format(row, col) row_layout.append(self.strap4) - self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), + self.add_inst(name=name, mod=self.strap4) else: - row_layout.append(self.strap4) - self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), - mod=self.strap4) + name="row_{}_col_{}_wlstrapa_p".format(row, col) + row_layout.append(self.strap2) + self.add_inst(name=name, + mod=self.strap2) alternate_strap = 0 else: if col % 2: - row_layout.append(self.strap) - self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), - mod=self.strap) + name="row_{}_col_{}_wlstrap".format(row, col) + row_layout.append(self.strap) + self.add_inst(name=name, + mod=self.strap) else: - row_layout.append(self.strap3) - self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col), - mod=self.strap3) + name="row_{}_col_{}_wlstrapa".format(row, col) + row_layout.append(self.strap3) + self.add_inst(name=name, + mod=self.strap3) alternate_strap = 1 - self.connect_inst(self.get_strap_pins(row, col)) + self.connect_inst(self.get_strap_pins(row, col, name)) if alternate_bitcell == 0: alternate_bitcell = 1 else: @@ -106,10 +111,12 @@ class sky130_dummy_array(sky130_bitcell_base_array): for wl_name in self.get_wordline_names(): self.add_pin(wl_name, "INPUT") for bl in range(self.column_size): - self.add_pin("dummy_bl_{}".format(bl)) - self.add_pin("dummy_br_{}".format(bl)) + self.add_pin("bl_0_{}".format(bl)) + self.add_pin("br_0_{}".format(bl)) self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") + #self.add_pin("vpb", "BIAS") + #Sself.add_pin("vnb", "BIAS") def add_layout_pins(self): """ Add the layout pins """ @@ -154,6 +161,32 @@ class sky130_dummy_array(sky130_bitcell_base_array): for pin_name in ["vdd", "gnd"]: self.copy_layout_pin(inst, pin_name) + def add_supply_pins(self): + for row in range(self.row_size): + for col in range(self.column_size): + inst = self.cell_inst[row, col] + if 'VPB' in self.cell_inst[row, col].mod.pins: + pin = inst.get_pin("vpb") + self.objs.append(geometry.rectangle(layer["nwell"], + pin.ll(), + pin.width(), + pin.height())) + self.objs.append(geometry.label("vdd", layer["nwell"], pin.center())) + + if 'VNB' in self.cell_inst[row, col].mod.pins: + try: + from tech import layer_override + if layer_override['VNB']: + pin = inst.get_pin("vnb") + self.objs.append(geometry.label("gnd", layer["pwellp"], pin.center())) + self.objs.append(geometry.rectangle(layer["pwellp"], + pin.ll(), + pin.width(), + pin.height())) + except: + pin = inst.get_pin("vnb") + self.add_label("vdd", pin.layer, pin.center()) + def input_load(self): # FIXME: This appears to be old code from previous characterization. Needs to be updated. wl_wire = self.gen_wl_wire() diff --git a/technology/sky130/modules/sky130_replica_bitcell_array.py b/technology/sky130/modules/sky130_replica_bitcell_array.py index 0e7469de..0bc402ed 100644 --- a/technology/sky130/modules/sky130_replica_bitcell_array.py +++ b/technology/sky130/modules/sky130_replica_bitcell_array.py @@ -99,8 +99,6 @@ class sky130_replica_bitcell_array(replica_bitcell_array, sky130_bitcell_base_ar def add_pins(self): super().add_pins() - self.add_pin("vpb", "BIAS") - self.add_pin("vnb", "BIAS") def add_replica_columns(self): """ Add replica columns on left and right of array """ @@ -284,7 +282,7 @@ class sky130_replica_bitcell_array(replica_bitcell_array, sky130_bitcell_base_ar # start_layer=pin.layer) min_area = drc["minarea_{}".format('m3')] - for track,supply, offset in zip(range(1,5),['vdd','vpb','vnb','gnd'],[min_area * 6,min_area * 6, 0, 0]): + for track,supply, offset in zip(range(1,5),['vdd','vdd','gnd','gnd'],[min_area * 6,min_area * 6, 0, 0]): y_offset = track * (pin_height + drc_width*2) self.add_segment_center('m2', vector(0,-y_offset), vector(self.width, -y_offset), drc["minwidth_{}".format('m2')]) self.add_segment_center('m2', vector(0,self.height + y_offset), vector(self.width, self.height + y_offset), drc["minwidth_{}".format('m2')]) @@ -388,7 +386,7 @@ class sky130_replica_bitcell_array(replica_bitcell_array, sky130_bitcell_base_ar if port in self.rbls: self.replica_col_insts.append(self.add_inst(name="replica_col_{}".format(port), mod=self.replica_columns[port])) - self.connect_inst(self.rbl_bitline_names[port] + self.replica_array_wordline_names + self.supplies) + self.connect_inst(self.rbl_bitline_names[port] + self.replica_array_wordline_names + self.supplies + ["gnd"] + ["gnd"]) else: self.replica_col_insts.append(None) @@ -404,10 +402,10 @@ class sky130_replica_bitcell_array(replica_bitcell_array, sky130_bitcell_base_ar self.dummy_row_insts = [] self.dummy_row_insts.append(self.add_inst(name="dummy_row_bot", mod=self.col_cap_bottom)) - self.connect_inst(self.all_bitline_names + ["gnd"] * len(self.col_cap_bottom.get_wordline_names()) + self.supplies) + self.connect_inst(self.all_bitline_names + ["gnd"] * len(self.col_cap_bottom.get_wordline_names()) + self.supplies + ["gnd"]) self.dummy_row_insts.append(self.add_inst(name="dummy_row_top", mod=self.col_cap_top)) - self.connect_inst(self.all_bitline_names + ["gnd"] * len(self.col_cap_top.get_wordline_names()) + self.supplies) + self.connect_inst(self.all_bitline_names + ["gnd"] * len(self.col_cap_top.get_wordline_names()) + self.supplies + ["gnd"]) # Left/right Dummy columns self.dummy_col_insts = [] diff --git a/technology/sky130/modules/sky130_replica_column.py b/technology/sky130/modules/sky130_replica_column.py index 495f5a89..f3d1801b 100644 --- a/technology/sky130/modules/sky130_replica_column.py +++ b/technology/sky130/modules/sky130_replica_column.py @@ -90,6 +90,9 @@ class sky130_replica_column(sky130_bitcell_base_array): self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") + self.add_pin("gate_top", "BIAS") + self.add_pin("gate_bottom", "BIAS") + def add_modules(self): self.replica_cell = factory.create(module_type="replica_bitcell_1port", version="opt1") self.cell = self.replica_cell diff --git a/technology/sky130/tech/tech.py b/technology/sky130/tech/tech.py index e42c0d89..e81fe476 100644 --- a/technology/sky130/tech/tech.py +++ b/technology/sky130/tech/tech.py @@ -99,12 +99,13 @@ cell_properties.bitcell_2port.port_map = {'bl0': 'BL0', 'vdd': 'VDD', 'gnd': 'GND'} -cell_properties.col_cap_1port_bitcell = cell(['br', 'vdd', 'gnd', 'bl'], - ['INPUT', 'POWER', 'GROUND', 'INPUT'], +cell_properties.col_cap_1port_bitcell = cell(['br', 'vdd', 'gnd', 'bl', 'gate'], + ['INPUT', 'POWER', 'GROUND', 'INPUT', 'INPUT'], {'bl': 'BL0', 'br': 'BL1', 'vdd': 'VPWR', - 'gnd': 'VGND'}) + 'gnd': 'VGND', + 'gate': 'gate'}) cell_properties.col_cap_1port_bitcell.boundary_layer = "mem" cell_properties.col_cap_1port_strap_power = cell(['vdd', 'vpb', 'vnb'], From 014bca919955b1adffa43c5b31576cf50bf00c8d Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 29 Dec 2021 14:41:55 -0800 Subject: [PATCH 058/229] Update Makefile with some pdk checks --- Makefile | 59 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index f13aadca..aa03a24a 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,11 @@ OPEN_PDKS_GIT_REPO ?= https://github.com/RTimothyEdwards/open_pdks.git OPEN_PDKS_GIT_COMMIT ?= 1.0.156 SKY130_PDK ?= $(PDK_ROOT)/sky130A +# Skywater PDK +SKY130_PDKS_DIR ?= $(PDK_ROOT)/skywater-pdk +SKY130_PDKS_GIT_REPO ?= https://github.com/google/skywater-pdk.git +SKY130_PDKS_GIT_COMMIT ?= main + # Create lists of all the files to copy/link GDS_FILES := $(sort $(wildcard $(SRAM_LIB_DIR)/cells/*/*.gds)) MAG_FILES := $(sort $(wildcard $(SRAM_LIB_DIR)/cells/*/*.mag)) @@ -39,35 +44,52 @@ INSTALL_BASE_DIRS := gds_lib mag_lib sp_lib lvs_lib calibre_lvs_lib maglef_lib INSTALL_BASE := $(OPENRAM_HOME)/../technology/sky130 INSTALL_DIRS := $(addprefix $(INSTALL_BASE)/,$(INSTALL_BASE_DIRS)) -$(OPEN_PDKS_DIR): +check-pdk-root: +ifndef PDK_ROOT + $(error PDK_ROOT is undefined, please export it before running make) +endif + +$(SKY130_PDKS_DIR): check-pdk-root + git clone https://github.com/google/skywater-pdk.git $(PDK_ROOT)/skywater-pdk + cd $(SKY130_PDKS_DIR) && \ + git checkout main && git pull && \ + git checkout -qf $(SKY130_PDKS_GIT_COMMIT) && \ + git submodule update --init libraries/sky130_fd_pr/latest + +$(OPEN_PDKS_DIR): $(SKY130_PDKS_DIR) @echo "Cloning open_pdks..." git clone $(OPEN_PDKS_GIT_REPO) $(OPEN_PDKS_DIR) cd $(OPEN_PDKS_DIR) && git checkout $(OPEN_PDKS_GIT_COMMIT) $(SKY130_PDK): $(OPEN_PDKS_DIR) @echo "Installing open_pdks..." - cd $(OPEN_PDKS_DIR) &&\ - ./configure --enable-sky130-pdk=$(PDK_ROOT)/skywater-pdk/libraries \ - --disable-openlane --disable-irsim --disable-xschem --disable-qflow &&\ + cd $(OPEN_PDKS_DIR) && \ + ./configure --enable-sky130-pdk=$(PDK_ROOT)/skywater-pdk/libraries --with-sky130-local-path=$(PDK_ROOT) --enable-sram-sky130=$(INSTALL_SRAM) && \ cd sky130 && \ make veryclean && \ make && \ make SHARED_PDKS_PATH=$(PDK_ROOT) install -install: $(SRAM_LIB_DIR) $(SKY130_PDK) $(INSTALL_DIRS) +$(SRAM_LIB_DIR): check-pdk-root + @[ -d $(SRAM_LIB_DIR) ] || (\ + echo "Cloning SRAM library..." && git clone $(SRAM_LIB_GIT_REPO) $(SRAM_LIB_DIR) && \ + cd $(SRAM_LIB_DIR) && git checkout $(SRAM_LIB_GIT_COMMIT)) + +install: $(SRAM_LIB_DIR) + @[ -d $(PDK_ROOT)/sky130A ] || \ + (echo "Warning: $(PDK_ROOT)/sky130A not found!! Run make pdk first." && false) + @[ -d $(PDK_ROOT)/skywater-pdk ] || \ + (echo "Warning: $(PDK_ROOT)/skywater-pdk not found!! Run make pdk first." && false) @echo "Installing sky130 SRAM PDK..." @echo "PDK_ROOT='$(PDK_ROOT)'" @echo "SRAM_LIB_DIR='$(SRAM_LIB_DIR)'" @echo "SKY130_PDK='$(SKY130_PDK)'" - @true + @make $(INSTALL_DIRS) .PHONY: install -$(SRAM_LIB_DIR): - @echo "Cloning SRAM library..." - git clone $(SRAM_LIB_GIT_REPO) $(SRAM_LIB_DIR) - cd $(SRAM_LIB_DIR) && git checkout $(SRAM_LIB_GIT_COMMIT) - -.PHONY: $(INSTALL_DIRS) +pdk: $(SKY130_PDK) + @true +.PHONY: pdk $(INSTALL_BASE)/gds_lib: $(GDS_FILES) @echo @@ -171,9 +193,14 @@ uninstall: clean # wipe the entire repos wipe: uninstall - @echo "Wiping PDK repos in 5 sec... (ctrl-c to quit)" + @echo $(SKY130_PDK) + @echo $(SRAM_LIB_DIR) + @echo $(OPEN_PDKS_DIR) + @echo $(SKY130_PDKS_DIR) + @echo "Wiping above PDK repos in 5 sec... (ctrl-c to quit)" @sleep 5 - rm -rf $(SKY130_PDK) - rm -rf $(SRAM_LIB_DIR) - rm -rf $(OPEN_PDKS_DIR) + @rm -rf $(SKY130_PDK) + @rm -rf $(SRAM_LIB_DIR) + @rm -rf $(OPEN_PDKS_DIR) + @rm -rf $(SKY130_PDKS_DIR) .PHONY: wipe From e90ea4e737ed19be68f88080328c7268788f9172 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 13 Jan 2022 14:38:59 -0800 Subject: [PATCH 059/229] Remove label Q_bar from replica_cell_1rw due to Magic port bug --- .../scn4m_subm/gds_lib/replica_cell_1rw.gds | Bin 5948 -> 5906 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/technology/scn4m_subm/gds_lib/replica_cell_1rw.gds b/technology/scn4m_subm/gds_lib/replica_cell_1rw.gds index 7eee11792aa3f83da7b1176d744c52959d873781..53525453da5d3e71b9bc506b7936044fb6beeffb 100644 GIT binary patch delta 75 zcmdm^H%U*4fsKKQDS|HiHPtE{$OAb UeZasa$rc!&lvuRcQRE^M0Ll#!p#T5? From aeb9594877d16a2a5dc002fe3c9f553b0c7296b4 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 13 Jan 2022 14:39:34 -0800 Subject: [PATCH 060/229] Do not extract bb (bounding box) layer in SCN4M_SUBM tech file --- technology/scn4m_subm/tech/SCN4M_SUBM.20.tech | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/technology/scn4m_subm/tech/SCN4M_SUBM.20.tech b/technology/scn4m_subm/tech/SCN4M_SUBM.20.tech index 7207f681..3d83bb96 100644 --- a/technology/scn4m_subm/tech/SCN4M_SUBM.20.tech +++ b/technology/scn4m_subm/tech/SCN4M_SUBM.20.tech @@ -333,7 +333,7 @@ style lambda=0.20(p) templayer TCSB nwsd,nwsc grow 40 and-not TNWR - + layer CSB nwsd,nwsc,nwr grow 140 and-not TCSB @@ -375,7 +375,7 @@ style lambda=0.20(p) bloat-or pdiff,apres,rpd,pdc/a * 40 nsd,nsc/a 0 or TPS -#final pselect +#final pselect templayer FSP bloat-or pdiff,apres,rpd,pfet,psd,pdc/a,psc/a,pfet * 40 ndiff,anres,rnd,ndc/a,nsd,nsc/a,nfet 0 or XDP @@ -772,7 +772,7 @@ style lambda=0.20(cp) templayer TCSB nwsd,nwsc grow 40 and-not TNWR - + layer CSB nwsd,nwsc,nwr grow 140 and-not TCSB @@ -814,7 +814,7 @@ style lambda=0.20(cp) bloat-or pdiff,apres,rpd,pdc/a * 40 nsd,nsc/a 0 or TPS -#final pselect +#final pselect templayer FSP bloat-or pdiff,apres,rpd,pfet,psd,pdc/a,psc/a,pfet * 40 ndiff,anres,rnd,ndc/a,nsd,nsc/a,nfet 0 or XDP @@ -1119,7 +1119,7 @@ style lambda=0.20(c) templayer TCSB nwsd,nwsc grow 40 and-not TNWR - + layer CSB nwsd,nwsc,nwr grow 140 and-not TCSB @@ -1151,7 +1151,7 @@ style lambda=0.20(c) bloat-or pdiff,apres,rpd,pdc/a * 40 nsd,nsc/a 0 or TPS -#final pselect +#final pselect templayer FSP bloat-or pdiff,apres,rpd,pfet,psd,pdc/a,psc/a,pfet * 40 ndiff,anres,rnd,ndc/a,nsd,nsc/a,nfet 0 or XDP @@ -1456,7 +1456,7 @@ style lambda=0.20() templayer TCSB nwsd,nwsc grow 40 and-not TNWR - + layer CSB nwsd,nwsc,nwr grow 140 and-not TCSB @@ -1488,7 +1488,7 @@ style lambda=0.20() bloat-or pdiff,apres,rpd,pdc/a * 40 nsd,nsc/a 0 or TPS -#final pselect +#final pselect templayer FSP bloat-or pdiff,apres,rpd,pfet,psd,pdc/a,psc/a,pfet * 40 ndiff,anres,rnd,ndc/a,nsd,nsc/a,nfet 0 or XDP @@ -6471,7 +6471,7 @@ end mzrouter style irouter -# layer hCost vCost jogCost hintCost +# layer hCost vCost jogCost hintCost layer metal4 2 1 2 1 layer metal3 1 2 2 1 layer metal2 2 1 2 1 @@ -6944,7 +6944,7 @@ drc "Silicide-Block overlap of Silicide-Block polyR/activeR < 2 (Mosis #20.15)" edge4way sb,pres,anres,apres diff,ndiff,rnd,nfet,nsd,nwsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,nwsc/a,pdc/a,psc/a 3 diff,ndiff,rnd,nfet,nsd,nwsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,nwsc/a,pdc/a,psc/a 0 0 \ - "Diffusion overhang of Silicide-Block < 3 (Mosis #20.17) + "Diffusion overhang of Silicide-Block < 3 (Mosis #20.17) spacing gv3 gv3 3 touching_ok \ "GV3 via spacing < 3 (Mosis #21.2)" @@ -7145,7 +7145,7 @@ drc spacing m4p m4p 4 touching_ok \ "Metal4 PIN spacing < 4 (do_pins)" -#CC cifstyle lambda=0.20(p) +#CC cifstyle lambda=0.20(p) #CC cifwidth CWN 240 \ #CC "generated CIF layer CWN width will be < 12 (';cif see CWN')" #CC cifspacing CWN CWN 120 touching_ok \ @@ -7223,6 +7223,7 @@ extract resist (m2,fm2,rm2,m2c,m3c,m3c)/metal2 70 resist (m3,fm3,rm3,m3c,m4c,m4c)/metal3 80 resist (m4,fm4,rm4,m4c,pad)/metal4 40 + resist bb None contact ndc 4 4100 contact pdc 4 3400 @@ -7288,25 +7289,25 @@ extract sideoverlap (m1,fm1,rm1,ndc,pdc,pc,m2c)/metal1 ~(m1,fm1,rm1,ndc,pdc,pc,m2c)/metal1 ~space/w 2.226 ~space/a #rnw - overlap (m1,fm1,rm1,ndc,pdc,pc,m2c)/metal1 rnw,nwr/active 1.666 - sideoverlap (m1,fm1,rm1,ndc,pdc,pc,m2c)/metal1 ~(m1,fm1,rm1,ndc,pdc,pc,m2c)/metal1 rnw,nwr/active 2.226 + overlap (m1,fm1,rm1,ndc,pdc,pc,m2c)/metal1 rnw,nwr/active 1.666 + sideoverlap (m1,fm1,rm1,ndc,pdc,pc,m2c)/metal1 ~(m1,fm1,rm1,ndc,pdc,pc,m2c)/metal1 rnw,nwr/active 2.226 -#metal1-diff blocked by - overlap (m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 (ndiff,anres,rnd,ndc)/active 1.640 - sideoverlap (m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 (ndiff,anres,rnd,ndc)/active 2.226 - overlap (m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 (pdiff,apres,rpd,pdc)/active 1.640 - sideoverlap (m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 (pdiff,apres,rpd,pdc)/active 2.226 +#metal1-diff blocked by + overlap (m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 (ndiff,anres,rnd,ndc)/active 1.640 + sideoverlap (m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 (ndiff,anres,rnd,ndc)/active 2.226 + overlap (m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 (pdiff,apres,rpd,pdc)/active 1.640 + sideoverlap (m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 (pdiff,apres,rpd,pdc)/active 2.226 -#metal1-poly blocked by - overlap (m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 (poly,fp,pres,rp,pc,nfet,pfet,fet)/active 1.687 - sideoverlap (m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 (poly,fp,pres,rp,pc,nfet,pfet,fet)/active 2.250 - sideoverlap (poly,fp,pres,rp,pc,nfet,pfet,fet)/active ~(poly,fp,pres,rp,pc,nfet,pfet,fet)/active (m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 2.250 +#metal1-poly blocked by + overlap (m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 (poly,fp,pres,rp,pc,nfet,pfet,fet)/active 1.687 + sideoverlap (m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 (poly,fp,pres,rp,pc,nfet,pfet,fet)/active 2.250 + sideoverlap (poly,fp,pres,rp,pc,nfet,pfet,fet)/active ~(poly,fp,pres,rp,pc,nfet,pfet,fet)/active (m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c)/metal1 2.250 #metal2 sidewall (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 (m2,fm2,rm2,m2c,m3c)/metal2 23.532 areacap (m2,fm2,rm2,m3c)/metal2 0.581 -#metal2-sub blocked by +#metal2-sub blocked by overlap (m2,fm2,rm2,m3c)/metal2 ~space/w 0.581 ~space/a,~space/m1 perimc (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 0.836 sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 ~space/w 0.836 ~space/a,~space/m1 @@ -7732,4 +7733,3 @@ style gremlin pc/a,ndc/a,pdc/a,psc/a,nsc/a,nwsc/a,gc,gc,gc,gv1 X end - From 663d57447aa1664773c6bfcd8e6f44f1b0d8fec4 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 13 Jan 2022 14:40:52 -0800 Subject: [PATCH 061/229] Update to newer Magic version --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index d117456d..e36140e6 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -34,7 +34,7 @@ RUN ./build.sh -qt5 \ RUN rm -rf /root/klayout ### Magic ### -ARG MAGIC_COMMIT=8.3.197 +ARG MAGIC_COMMIT=8.3.254 WORKDIR /root RUN git clone git://opencircuitdesign.com/magic-8.3 magic WORKDIR /root/magic From 06d391b3e365127628434b98044035232615f4b0 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 13 Jan 2022 14:41:24 -0800 Subject: [PATCH 062/229] Keep files during runs in Makefile --- compiler/tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 460b7fcc..0e378d39 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -3,7 +3,7 @@ include $(TOP_DIR)/openram.mk .DEFAULT_GOAL := regress -ARGS ?= "" +ARGS ?= "-k" TEST_DIR = $(TOP_DIR)/compiler/tests TEST_SRCS=$(sort $(notdir $(wildcard $(TEST_DIR)/*_test.py))) From 902695185abbcdc64240391895d1a28aab296bbd Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 1 Feb 2022 13:20:02 -0800 Subject: [PATCH 063/229] Fix path for klayout --- docker/Dockerfile | 1 + docker/set-paths.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index e36140e6..9503fed1 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -95,5 +95,6 @@ RUN mkdir /home/cad-user RUN useradd cad-user RUN chown -R cad-user /home/cad-user RUN chgrp -R cad-user /home/cad-user +ADD set-paths.sh /home/cad-user/.bashrc USER cad-user WORKDIR /home/cad-user diff --git a/docker/set-paths.sh b/docker/set-paths.sh index 96582dbd..7083d0a0 100644 --- a/docker/set-paths.sh +++ b/docker/set-paths.sh @@ -4,7 +4,7 @@ export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/ga export SWROOT=/software # Klayout -export PATH=$PATH:/usr/local/klayout/bin +export PATH=$PATH:/usr/local/klayout # Xyce export XYCE_HOME=$SWROOT/Xyce/Parallel From 83d7c2a1fb19d509ccee5578c876021a2824b987 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 1 Feb 2022 13:31:43 -0800 Subject: [PATCH 064/229] Need LD_LIBRARY_PATH for klayout too --- docker/set-paths.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docker/set-paths.sh b/docker/set-paths.sh index 7083d0a0..5d6e76cc 100644 --- a/docker/set-paths.sh +++ b/docker/set-paths.sh @@ -4,7 +4,9 @@ export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/ga export SWROOT=/software # Klayout -export PATH=$PATH:/usr/local/klayout +export KLAYOUT_HOME=/usr/local/klayout +export PATH=$PATH:$KLAYOUT_HOME +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$KLAYOUT_HOME # Xyce export XYCE_HOME=$SWROOT/Xyce/Parallel From 548178e343fd0081af8a712cd017e223e909a52a Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 4 Feb 2022 14:38:35 -0800 Subject: [PATCH 065/229] Change Makefile to use docker in parallel instead of regress.py --- compiler/tests/Makefile | 88 ++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 45 deletions(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 6933f165..30e0c044 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -1,14 +1,20 @@ TOP_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))../..) include $(TOP_DIR)/openram.mk -.DEFAULT_GOAL := regress +.DEFAULT_GOAL := all -ARGS ?= "-k" +ARGS ?= +TECH ?= scn4m_subm +TECHS := scn4m_subm freepdk45 +# sky130 -TEST_DIR = $(TOP_DIR)/compiler/tests -TEST_SRCS=$(sort $(notdir $(wildcard $(TEST_DIR)/*_test.py))) -TEST_DIRS=$(basename $(TEST_SRCS)) -TEST_STAMPS=$(addsuffix .ok,$(TEST_DIRS)) +TEST_DIR = $(TOP_DIR)/compiler/tests +TEST_SRCS = $(sort $(notdir $(wildcard $(TEST_DIR)/*_test.py))) +TEST_BASES = $(basename $(TEST_SRCS)) +TEST_STAMPS= $(addsuffix .ok,$(TEST_BASES)) + +OPENRAM_DIR := /openram/compiler/tests +RESULTS_DIR := $(OPENRAM_DIR)/results TEST_BROKEN := \ 50_riscv_1k_1rw1r_func_test.py \ @@ -29,55 +35,48 @@ TEST_BROKEN := \ WORKING_TEST_STAMPS=$(filter-out $(addsuffix .ok, (TEST_BROKEN)), $(TEST_STAMPS)) -$(TEST_DIRS): + +$(TEST_BASES): @$(MAKE) --no-print-directory $@.ok -tests: - @echo "Running the following tests" - @for S in $(WORKING_TEST_STAMPS); do echo " - $$S"; done - @sleep 5 - @$(MAKE) $(WORKING_TEST_STAMPS) -.PHONY: +gettech = $(word 1,$(subst /, ,$*)) +getfile = $(word 2,$(subst /, ,$*)) +WORKING_TECH_TEST_STAMPS=$(foreach T, $(TECHS),$(addprefix $T/,$(WORKING_TEST_STAMPS))) +all: $(WORKING_TECH_TEST_STAMPS) + +# To run individual tests %.ok: %.py - @echo "Running $*" - @mkdir -p $(TOP_DIR)/compiler/tests/results/$* + @$(MAKE) --no-print-directory $(TECH)/$*.ok + +# To run a test in a given technology +%.ok: +# @echo "Running $(gettech) $(getfile) ... " + @mkdir -p results/$* @docker run \ -v $(TOP_DIR):/openram \ -v $(FREEPDK45):/pdk/freepdk45\ -v $(PDK_ROOT):/pdk \ --user $(UID):$(GID) \ + -e OPENRAM_TMP=$(OPENRAM_DIR)/results/$* \ vlsida/openram-ubuntu:latest \ - sh -c ". ~/.bashrc && python3 -u /openram/compiler/tests/$*.py $(ARGS) && touch $@" - + sh -c ". ~/.bashrc && python3 -u $(OPENRAM_DIR)/$(getfile).py -t $(gettech) -k $(ARGS) > $(OPENRAM_DIR)/results/$*.out 2>&1 && touch $(OPENRAM_DIR)/results/$*.ok" + @test -f $(TOP_DIR)/compiler/tests/results/$*.ok && echo "$* ... PASS!" || echo "$* ... FAIL!" .DELETE_ON_ERROR: $(TEST_STAMPS) -TECHS := scn4m_subm freepdk45 -#sky130 - -$(TECHS): - docker run \ - -v $(TOP_DIR):/openram \ - -v $(FREEPDK45):/pdk/freepdk45 \ - -v $(PDK_ROOT):/pdk \ - --user $(UID):$(GID) \ - -e OPENRAM_TMP=/openram/compiler/tests/tmp_$@/$* \ - vlsida/openram-ubuntu:latest \ - sh -c ". ~/.bashrc && python3 -u /openram/compiler/tests/regress.py $(ARGS) -t $@" -.PHONY: $(TECHS) - -regress: $(TECHS) -.PHONY: regress - -foo: - docker run \ - -v $(TOP_DIR):/openram \ - -v $(FREEPDK45):/pdk/freepdk45 \ - -v $(PDK_ROOT):/pdk \ - --user $(UID):$(GID) \ - vlsida/openram-ubuntu:latest \ - sh -c ". ~/.bashrc && env" -.PHONY: foo +#$(TECHS): +# @echo "Running $*" +# docker run \ +# -v $(TOP_DIR):/openram \ +# -v $(FREEPDK45):/pdk/freepdk45 \ +# -v $(PDK_ROOT):/pdk \ +# --user $(UID):$(GID) \ +# -e OPENRAM_TMP=$(OPENRAM_DIR)/results/$@ \ +# vlsida/openram-ubuntu:latest \ +# sh -c ". ~/.bashrc && python3 -u $(OPENRAM_DIR)/regress.py -t $@ $(ARGS)" +#.PHONY: $(TECHS) +#regress: $(TECHS) +#.PHONY: regress mount: docker run -it \ @@ -89,6 +88,5 @@ mount: .PHONY: mount clean: - @rm -rf $(TEST_STAMPS) - @rm -rf $(TEST_DIRS) + @rm -rf $(TOP_DIR)/compiler/tests/results .PHONE: clean From 1a6cb91608a4577ec33ec1104943349bc896bd4c Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 4 Feb 2022 14:39:53 -0800 Subject: [PATCH 066/229] Rename tests to end with test. --- ...array_test_pbitcell.py => 09_sense_amp_array_pbitcell_test.py} | 0 ...nk_global_bitline.py => 19_single_bank_global_bitline_test.py} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename compiler/tests/{09_sense_amp_array_test_pbitcell.py => 09_sense_amp_array_pbitcell_test.py} (100%) rename compiler/tests/{19_single_bank_global_bitline.py => 19_single_bank_global_bitline_test.py} (100%) diff --git a/compiler/tests/09_sense_amp_array_test_pbitcell.py b/compiler/tests/09_sense_amp_array_pbitcell_test.py similarity index 100% rename from compiler/tests/09_sense_amp_array_test_pbitcell.py rename to compiler/tests/09_sense_amp_array_pbitcell_test.py diff --git a/compiler/tests/19_single_bank_global_bitline.py b/compiler/tests/19_single_bank_global_bitline_test.py similarity index 100% rename from compiler/tests/19_single_bank_global_bitline.py rename to compiler/tests/19_single_bank_global_bitline_test.py From a56d1f62ee5393df6b0c64ae4fa4dba8356e8d80 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 4 Feb 2022 15:03:53 -0800 Subject: [PATCH 067/229] Fix parallel option for Makefile tests --- compiler/tests/Makefile | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 30e0c044..aba058b1 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -3,9 +3,9 @@ include $(TOP_DIR)/openram.mk .DEFAULT_GOAL := all -ARGS ?= +ARGS ?= TECH ?= scn4m_subm -TECHS := scn4m_subm freepdk45 +TECHS = scn4m_subm freepdk45 # sky130 TEST_DIR = $(TOP_DIR)/compiler/tests @@ -13,10 +13,10 @@ TEST_SRCS = $(sort $(notdir $(wildcard $(TEST_DIR)/*_test.py))) TEST_BASES = $(basename $(TEST_SRCS)) TEST_STAMPS= $(addsuffix .ok,$(TEST_BASES)) -OPENRAM_DIR := /openram/compiler/tests -RESULTS_DIR := $(OPENRAM_DIR)/results +OPENRAM_DIR = /openram/compiler/tests +RESULTS_DIR = $(OPENRAM_DIR)/results -TEST_BROKEN := \ +TEST_BROKEN = \ 50_riscv_1k_1rw1r_func_test.py \ 50_riscv_1k_1rw_func_test.py \ 50_riscv_1rw1r_func_test.py \ @@ -36,18 +36,19 @@ TEST_BROKEN := \ WORKING_TEST_STAMPS=$(filter-out $(addsuffix .ok, (TEST_BROKEN)), $(TEST_STAMPS)) -$(TEST_BASES): - @$(MAKE) --no-print-directory $@.ok - gettech = $(word 1,$(subst /, ,$*)) getfile = $(word 2,$(subst /, ,$*)) WORKING_TECH_TEST_STAMPS=$(foreach T, $(TECHS),$(addprefix $T/,$(WORKING_TEST_STAMPS))) all: $(WORKING_TECH_TEST_STAMPS) +.PHONY: all -# To run individual tests -%.ok: %.py - @$(MAKE) --no-print-directory $(TECH)/$*.ok +# Targets for each individual test +# e.g. make 04_pinv_1x_test +$(TEST_BASES): +# @echo "Running $(TECH) $@ ... " + @$(MAKE) --no-print-directory $(TECH)/$@.ok +.PHONY: $(TEST_BASES) # To run a test in a given technology %.ok: @@ -64,6 +65,8 @@ all: $(WORKING_TECH_TEST_STAMPS) @test -f $(TOP_DIR)/compiler/tests/results/$*.ok && echo "$* ... PASS!" || echo "$* ... FAIL!" .DELETE_ON_ERROR: $(TEST_STAMPS) +# This would use the regress.py script to run in parallel instead of +# the Makefile. #$(TECHS): # @echo "Running $*" # docker run \ @@ -78,6 +81,7 @@ all: $(WORKING_TECH_TEST_STAMPS) #regress: $(TECHS) #.PHONY: regress +# Mount environment for debug mount: docker run -it \ -v $(TOP_DIR):/openram \ From 049751ae1f8691b46f1ec22ae312dac037d9c238 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 3 Feb 2022 10:19:28 -0800 Subject: [PATCH 068/229] FreePDK45 running with klayout and Sky130 running with magic. --- Makefile | 2 +- compiler/pgates/ptx.py | 6 ----- compiler/tests/Makefile | 42 +++++++++++++++++++++++--------- docker/set-paths.sh | 9 ++++++- technology/freepdk45/__init__.py | 6 ++++- 5 files changed, 44 insertions(+), 21 deletions(-) diff --git a/Makefile b/Makefile index 6f1fe0f4..af52eb2f 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ MAGICRC_FILE := $(SKY130_PDK)/libs.tech/magic/sky130A.magicrc ALL_FILES := $(ALL_SPICE_FILES) $(GDS_FILES) $(MAG_FILES) $(MAGLEF_FILES) -INSTALL_BASE_DIRS := gds_lib mag_lib sp_lib lvs_lib calibre_lvs_lib klayout_lvs_lib lef_lib maglef_lib +INSTALL_BASE_DIRS := gds_lib mag_lib sp_lib lvs_lib calibre_lvs_lib klayout_lvs_lib maglef_lib INSTALL_BASE := $(OPENRAM_HOME)/../technology/sky130 INSTALL_DIRS := $(addprefix $(INSTALL_BASE)/,$(INSTALL_BASE_DIRS)) diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index e6a8313d..e49df518 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -161,12 +161,6 @@ class ptx(design.design): self.mults, self.tx_width, drc("minwidth_poly")) - - elif OPTS.lvs_exe and OPTS.lvs_exe[0] == "klayout": - self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3}".format(spice[self.tx_type], - self.mults, - self.tx_width, - drc("minwidth_poly")) elif cell_props.ptx.model_is_subckt: self.lvs_device = "X{{0}} {{1}} {0} m={1} w={2}u l={3}u".format(spice[self.tx_type], self.mults, diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 0e378d39..6933f165 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -42,15 +42,13 @@ tests: %.ok: %.py @echo "Running $*" @mkdir -p $(TOP_DIR)/compiler/tests/results/$* - @docker run -v $(TOP_DIR):/openram \ - -v $(SKY130_PDK):$(SKY130_PDK) \ - -e PDK_ROOT=$(PDK_ROOT) \ - -e OPENRAM_HOME=/openram/compiler \ - -e OPENRAM_TECH=/openram/technology \ - -e OPENRAM_TMP=/openram/compiler/tests/results/$* \ + @docker run \ + -v $(TOP_DIR):/openram \ + -v $(FREEPDK45):/pdk/freepdk45\ + -v $(PDK_ROOT):/pdk \ --user $(UID):$(GID) \ - vlsida/openram-ubuntu:latest \ - python3 -u /openram/compiler/tests/$*.py $(ARGS) && touch $@ + vlsida/openram-ubuntu:latest \ + sh -c ". ~/.bashrc && python3 -u /openram/compiler/tests/$*.py $(ARGS) && touch $@" .DELETE_ON_ERROR: $(TEST_STAMPS) @@ -58,18 +56,38 @@ TECHS := scn4m_subm freepdk45 #sky130 $(TECHS): - @docker run -v $(TOP_DIR):/openram \ - -e OPENRAM_HOME=/openram/compiler \ - -e OPENRAM_TECH=/openram/technology \ + docker run \ + -v $(TOP_DIR):/openram \ + -v $(FREEPDK45):/pdk/freepdk45 \ + -v $(PDK_ROOT):/pdk \ --user $(UID):$(GID) \ -e OPENRAM_TMP=/openram/compiler/tests/tmp_$@/$* \ vlsida/openram-ubuntu:latest \ - sh -c "python3 -u /openram/compiler/tests/regress.py $(ARGS) -t $@" + sh -c ". ~/.bashrc && python3 -u /openram/compiler/tests/regress.py $(ARGS) -t $@" .PHONY: $(TECHS) regress: $(TECHS) .PHONY: regress +foo: + docker run \ + -v $(TOP_DIR):/openram \ + -v $(FREEPDK45):/pdk/freepdk45 \ + -v $(PDK_ROOT):/pdk \ + --user $(UID):$(GID) \ + vlsida/openram-ubuntu:latest \ + sh -c ". ~/.bashrc && env" +.PHONY: foo + +mount: + docker run -it \ + -v $(TOP_DIR):/openram \ + -v $(FREEPDK45):/pdk/freepdk45 \ + -v $(PDK_ROOT):/pdk \ + --user $(UID):$(GID) \ + vlsida/openram-ubuntu:latest +.PHONY: mount + clean: @rm -rf $(TEST_STAMPS) @rm -rf $(TEST_DIRS) diff --git a/docker/set-paths.sh b/docker/set-paths.sh index 5d6e76cc..40bfaeb8 100644 --- a/docker/set-paths.sh +++ b/docker/set-paths.sh @@ -17,6 +17,13 @@ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$XYCE_LIB export XYCE_NO_TRACKING="anything at all" # PDKs -export FREEPDK45=/home/PDKs/FreePDK45 +export FREEPDK45=/PDK/freepdk45 # Set to the PDK you want to use export PDK_DIR=$FREEPDK45 + +# Skywater PDK +export PDK_ROOT=/pdk + +# OpenRAM +export OPENRAM_HOME=/openram/compiler +export OPENRAM_TECH=/openram/technology diff --git a/technology/freepdk45/__init__.py b/technology/freepdk45/__init__.py index b86b17be..6d9e759d 100644 --- a/technology/freepdk45/__init__.py +++ b/technology/freepdk45/__init__.py @@ -13,13 +13,17 @@ the trunk import sys import os +import debug TECHNOLOGY = "freepdk45" ########################## # FreePDK45 paths -PDK_DIR=os.path.abspath(os.environ.get("FREEPDK45")) +PDK_PATH=os.environ.get("FREEPDK45") +if PDK_PATH==None: + debug.error("Must define FREEPDK45 to point to PDK.", -1) +PDK_DIR=os.path.abspath(PDK_PATH) os.environ["PDK_DIR"] = PDK_DIR os.environ["SYSTEM_CDS_LIB_DIR"] = "{0}/ncsu_basekit/cdssetup".format(PDK_DIR) os.environ["CDS_SITE"] = PDK_DIR From e45e2f77c9e536f2a72151adeaff958e9a8a4d13 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 4 Feb 2022 14:38:35 -0800 Subject: [PATCH 069/229] Rework regression to use docker. --- .github/workflows/ci.yml | 66 +++++++----- Makefile | 7 +- ...py => 09_sense_amp_array_pbitcell_test.py} | 0 ... => 19_single_bank_global_bitline_test.py} | 0 compiler/tests/21_hspice_delay_test.py | 1 + compiler/tests/21_hspice_setuphold_test.py | 1 + compiler/tests/Makefile | 101 +++++++++--------- 7 files changed, 98 insertions(+), 78 deletions(-) rename compiler/tests/{09_sense_amp_array_test_pbitcell.py => 09_sense_amp_array_pbitcell_test.py} (100%) rename compiler/tests/{19_single_bank_global_bitline.py => 19_single_bank_global_bitline_test.py} (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed86160b..ec4f2934 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,44 +1,56 @@ name: ci on: [push] jobs: - scn4me_subm: + regress: runs-on: self-hosted steps: - name: Checkout code uses: actions/checkout@v1 - - name: SCMOS test + - name: Docker pull + run: docker pull vlsida/openram-ubuntu:latest + - name: PDK Install run: | - . /home/github-runner/setup-paths.sh export OPENRAM_HOME="${{ github.workspace }}/compiler" - export OPENRAM_TECH="${{ github.workspace }}/technology:/software/PDKs/skywater-tech" - export OPENRAM_TMP="${{ github.workspace }}/scn4me_subm_temp" + export OPENRAM_TECH="${{ github.workspace }}/technology" + #cd $OPENRAM_HOME/tests + #export PDK_ROOT="${{ github.workspace }}/pdk" + #make pdk + #make install + - name: Regress + run: | + export OPENRAM_HOME="${{ github.workspace }}/compiler" + export OPENRAM_TECH="${{ github.workspace }}/technology" + #cd $OPENRAM_HOME/.. && make pdk && make install + #export OPENRAM_TMP="${{ github.workspace }}/scn4me_subm_temp" #python3-coverage run -p $OPENRAM_HOME/tests/regress.py -j 12 -t scn4m_subm - $OPENRAM_HOME/tests/regress.py -j 24 -t scn4m_subm + #$OPENRAM_HOME/tests/regress.py -j 24 -t scn4m_subm + cd $OPENRAM_HOME/tests + make -j 36 - name: Archive if: ${{ failure() }} uses: actions/upload-artifact@v2 with: - name: scn4me_subm Archives - path: ${{ github.workspace }}/*.zip - freepdk45: - runs-on: self-hosted - steps: - - name: Checkout code - uses: actions/checkout@v1 - - name: FreePDK45 test - run: | - . /home/github-runner/setup-paths.sh - export OPENRAM_HOME="${{ github.workspace }}/compiler" - export OPENRAM_TECH="${{ github.workspace }}/technology:/software/PDKs/skywater-tech" - export OPENRAM_TMP="${{ github.workspace }}/freepdk45_temp" - #python3-coverage run -p $OPENRAM_HOME/tests/regress.py -j 12 -t freepdk45 - $OPENRAM_HOME/tests/regress.py -j 24 -t freepdk45 - - name: Archive - if: ${{ failure() }} - uses: actions/upload-artifact@v2 - with: - name: FreePDK45 Archives - path: ${{ github.workspace }}/*.zip + name: Regress Archives + path: ${{ github.workspace }}/compiler/tests/results/*.zip +# freepdk45: +# runs-on: self-hosted +# steps: +# - name: Checkout code +# uses: actions/checkout@v1 +# - name: FreePDK45 test +# run: | +# . /home/github-runner/setup-paths.sh +# export OPENRAM_HOME="${{ github.workspace }}/compiler" +# export OPENRAM_TECH="${{ github.workspace }}/technology:/software/PDKs/skywater-tech" +# export OPENRAM_TMP="${{ github.workspace }}/freepdk45_temp" +# #python3-coverage run -p $OPENRAM_HOME/tests/regress.py -j 12 -t freepdk45 +# $OPENRAM_HOME/tests/regress.py -j 24 -t freepdk45 +# - name: Archive +# if: ${{ failure() }} +# uses: actions/upload-artifact@v2 +# with: +# name: FreePDK45 Archives +# path: ${{ github.workspace }}/*.zip # coverage_stats: # if: ${{ always() }} # needs: [scn4me_subm, freepdk45] diff --git a/Makefile b/Makefile index af52eb2f..1f603a41 100644 --- a/Makefile +++ b/Makefile @@ -186,10 +186,11 @@ mount: @docker run -it -v $(TOP_DIR):/openram \ -v $(SKY130_PDK):$(SKY130_PDK) \ -e PDK_ROOT=$(PDK_ROOT) \ - -e OPENRAM_HOME=/openram/compiler \ - -e OPENRAM_TECH=/openram/technology \ + -e OPENRAM_HOME=/openram/compiler \ + -e OPENRAM_TECH=/openram/technology \ + -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \ --user $(UID):$(GID) \ - vlsida/openram-ubuntu:latest + vlsida/openram-ubuntu:latest .PHONY: mount clean: diff --git a/compiler/tests/09_sense_amp_array_test_pbitcell.py b/compiler/tests/09_sense_amp_array_pbitcell_test.py similarity index 100% rename from compiler/tests/09_sense_amp_array_test_pbitcell.py rename to compiler/tests/09_sense_amp_array_pbitcell_test.py diff --git a/compiler/tests/19_single_bank_global_bitline.py b/compiler/tests/19_single_bank_global_bitline_test.py similarity index 100% rename from compiler/tests/19_single_bank_global_bitline.py rename to compiler/tests/19_single_bank_global_bitline_test.py diff --git a/compiler/tests/21_hspice_delay_test.py b/compiler/tests/21_hspice_delay_test.py index 584e705f..4f8ba8ec 100755 --- a/compiler/tests/21_hspice_delay_test.py +++ b/compiler/tests/21_hspice_delay_test.py @@ -15,6 +15,7 @@ from globals import OPTS from sram_factory import factory import debug +@unittest.skip("SKIPPING 21_hspice_delay_test") class timing_sram_test(openram_test): def runTest(self): diff --git a/compiler/tests/21_hspice_setuphold_test.py b/compiler/tests/21_hspice_setuphold_test.py index 9154502e..76f47d1a 100755 --- a/compiler/tests/21_hspice_setuphold_test.py +++ b/compiler/tests/21_hspice_setuphold_test.py @@ -14,6 +14,7 @@ import globals from globals import OPTS +@unittest.skip("SKIPPING 21_hspice_setuphold_test") class timing_setup_test(openram_test): def runTest(self): diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 6933f165..eca04336 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -1,16 +1,22 @@ TOP_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))../..) include $(TOP_DIR)/openram.mk -.DEFAULT_GOAL := regress +.DEFAULT_GOAL := all -ARGS ?= "-k" +ARGS ?= +TECH ?= scn4m_subm +TECHS = scn4m_subm freepdk45 +# sky130 -TEST_DIR = $(TOP_DIR)/compiler/tests -TEST_SRCS=$(sort $(notdir $(wildcard $(TEST_DIR)/*_test.py))) -TEST_DIRS=$(basename $(TEST_SRCS)) -TEST_STAMPS=$(addsuffix .ok,$(TEST_DIRS)) +TEST_DIR = $(TOP_DIR)/compiler/tests +TEST_SRCS = $(sort $(notdir $(wildcard $(TEST_DIR)/*_test.py))) +TEST_BASES = $(basename $(TEST_SRCS)) +TEST_STAMPS= $(addsuffix .ok,$(TEST_BASES)) -TEST_BROKEN := \ +OPENRAM_DIR = /openram/compiler/tests +RESULTS_DIR = $(OPENRAM_DIR)/results + +TEST_BROKEN = \ 50_riscv_1k_1rw1r_func_test.py \ 50_riscv_1k_1rw_func_test.py \ 50_riscv_1rw1r_func_test.py \ @@ -29,66 +35,65 @@ TEST_BROKEN := \ WORKING_TEST_STAMPS=$(filter-out $(addsuffix .ok, (TEST_BROKEN)), $(TEST_STAMPS)) -$(TEST_DIRS): - @$(MAKE) --no-print-directory $@.ok -tests: - @echo "Running the following tests" - @for S in $(WORKING_TEST_STAMPS); do echo " - $$S"; done - @sleep 5 - @$(MAKE) $(WORKING_TEST_STAMPS) -.PHONY: +gettech = $(word 1,$(subst /, ,$*)) +getfile = $(word 2,$(subst /, ,$*)) +WORKING_TECH_TEST_STAMPS=$(foreach T, $(TECHS),$(addprefix $T/,$(WORKING_TEST_STAMPS))) -%.ok: %.py - @echo "Running $*" - @mkdir -p $(TOP_DIR)/compiler/tests/results/$* +all: $(WORKING_TECH_TEST_STAMPS) +.PHONY: all + +# Targets for each individual test +# e.g. make 04_pinv_1x_test +$(TEST_BASES): +# @echo "Running $(TECH) $@ ... " + @$(MAKE) --no-print-directory $(TECH)/$@.ok +.PHONY: $(TEST_BASES) + +# To run a test in a given technology +%.ok: +# @echo "Running $(gettech) $(getfile) ... " + @mkdir -p results/$*/tmp @docker run \ -v $(TOP_DIR):/openram \ -v $(FREEPDK45):/pdk/freepdk45\ -v $(PDK_ROOT):/pdk \ + -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \ --user $(UID):$(GID) \ + -e OPENRAM_TMP=$(OPENRAM_DIR)/results/$*/tmp \ vlsida/openram-ubuntu:latest \ - sh -c ". ~/.bashrc && python3 -u /openram/compiler/tests/$*.py $(ARGS) && touch $@" - + sh -c ". /home/cad-user/.bashrc && python3 -u $(OPENRAM_DIR)/$(getfile).py \ + -t $(gettech) -k $(ARGS) -p $(OPENRAM_DIR)/results/$* > $(OPENRAM_DIR)/results/$*.out 2>&1 && touch $(OPENRAM_DIR)/results/$*.ok" + @test -f $(TOP_DIR)/compiler/tests/results/$*.ok && echo "$* ... PASS!" || echo "$* ... FAIL!" .DELETE_ON_ERROR: $(TEST_STAMPS) -TECHS := scn4m_subm freepdk45 -#sky130 - -$(TECHS): - docker run \ - -v $(TOP_DIR):/openram \ - -v $(FREEPDK45):/pdk/freepdk45 \ - -v $(PDK_ROOT):/pdk \ - --user $(UID):$(GID) \ - -e OPENRAM_TMP=/openram/compiler/tests/tmp_$@/$* \ - vlsida/openram-ubuntu:latest \ - sh -c ". ~/.bashrc && python3 -u /openram/compiler/tests/regress.py $(ARGS) -t $@" -.PHONY: $(TECHS) - -regress: $(TECHS) -.PHONY: regress - -foo: - docker run \ - -v $(TOP_DIR):/openram \ - -v $(FREEPDK45):/pdk/freepdk45 \ - -v $(PDK_ROOT):/pdk \ - --user $(UID):$(GID) \ - vlsida/openram-ubuntu:latest \ - sh -c ". ~/.bashrc && env" -.PHONY: foo +# This would use the regress.py script to run in parallel instead of +# the Makefile. +#$(TECHS): +# @echo "Running $*" +# docker run \ +# -v $(TOP_DIR):/openram \ +# -v $(FREEPDK45):/pdk/freepdk45 \ +# -v $(PDK_ROOT):/pdk \ +# --user $(UID):$(GID) \ +# -e OPENRAM_TMP=$(OPENRAM_DIR)/results/$@ \ +# vlsida/openram-ubuntu:latest \ +# sh -c ". /home/cad-user/.bashrc && python3 -u $(OPENRAM_DIR)/regress.py -t $@ $(ARGS)" +#.PHONY: $(TECHS) +#regress: $(TECHS) +#.PHONY: regress +# Mount environment for debug mount: docker run -it \ -v $(TOP_DIR):/openram \ -v $(FREEPDK45):/pdk/freepdk45 \ -v $(PDK_ROOT):/pdk \ + -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \ --user $(UID):$(GID) \ vlsida/openram-ubuntu:latest .PHONY: mount clean: - @rm -rf $(TEST_STAMPS) - @rm -rf $(TEST_DIRS) + @rm -rf $(TOP_DIR)/compiler/tests/results .PHONE: clean From d716a1c36180e38af9f5dbbeee28ac0a9e313c21 Mon Sep 17 00:00:00 2001 From: mrg Date: Sat, 5 Feb 2022 07:50:06 -0800 Subject: [PATCH 070/229] Don't stop on fail, archive all results, create .bad file on fail. --- .github/workflows/ci.yml | 4 ++-- compiler/tests/Makefile | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ec4f2934..578a13f3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,13 +25,13 @@ jobs: #python3-coverage run -p $OPENRAM_HOME/tests/regress.py -j 12 -t scn4m_subm #$OPENRAM_HOME/tests/regress.py -j 24 -t scn4m_subm cd $OPENRAM_HOME/tests - make -j 36 + make -k -j 36 - name: Archive if: ${{ failure() }} uses: actions/upload-artifact@v2 with: name: Regress Archives - path: ${{ github.workspace }}/compiler/tests/results/*.zip + path: ${{ github.workspace }}/compiler/tests/results/* # freepdk45: # runs-on: self-hosted # steps: diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index eca04336..a20f61f3 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -63,11 +63,11 @@ $(TEST_BASES): -e OPENRAM_TMP=$(OPENRAM_DIR)/results/$*/tmp \ vlsida/openram-ubuntu:latest \ sh -c ". /home/cad-user/.bashrc && python3 -u $(OPENRAM_DIR)/$(getfile).py \ - -t $(gettech) -k $(ARGS) -p $(OPENRAM_DIR)/results/$* > $(OPENRAM_DIR)/results/$*.out 2>&1 && touch $(OPENRAM_DIR)/results/$*.ok" + -t $(gettech) -k $(ARGS) -p $(OPENRAM_DIR)/results/$* > $(OPENRAM_DIR)/results/$*.out 2>&1 && touch $(OPENRAM_DIR)/results/$*.ok || touch $(OPENRAM_DIR)/results/$*.bad" @test -f $(TOP_DIR)/compiler/tests/results/$*.ok && echo "$* ... PASS!" || echo "$* ... FAIL!" .DELETE_ON_ERROR: $(TEST_STAMPS) -# This would use the regress.py script to run in parallel instead of +# This would use the regress.py script to run in parallel instead of # the Makefile. #$(TECHS): # @echo "Running $*" From 723523275eb4f5f93a1c80a3da17d7695f12e18d Mon Sep 17 00:00:00 2001 From: mrg Date: Sun, 6 Feb 2022 09:04:38 -0800 Subject: [PATCH 071/229] Add Xyce to docker image --- .github/workflows/ci.yml | 2 +- docker/Dockerfile | 78 ++++++++++++++++++++++++++++++++-------- docker/set-paths.sh | 4 +-- 3 files changed, 65 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 578a13f3..36ab8aae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: #python3-coverage run -p $OPENRAM_HOME/tests/regress.py -j 12 -t scn4m_subm #$OPENRAM_HOME/tests/regress.py -j 24 -t scn4m_subm cd $OPENRAM_HOME/tests - make -k -j 36 + make -k -j 48 - name: Archive if: ${{ failure() }} uses: actions/upload-artifact@v2 diff --git a/docker/Dockerfile b/docker/Dockerfile index 9503fed1..14950d19 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -67,30 +67,78 @@ RUN ./configure \ && make install RUN rm -rf /root/netgen -#ARG XYCE_COMMIT=b7bb12d81f11d8b50141262537299b09d64b5565 -#ARG TRILINOS_COMIT= +### Trilinos ### +ARG TRILINOS_COMMIT=trilinos-release-12-12-1 +WORKDIR /root +RUN apt-get install --no-install-recommends -y cmake libfftw3-dev mpich libblas-dev liblapack-dev libsuitesparse-dev libfl-dev openmpi-bin libopenmpi-dev gfortran +RUN git clone --depth 1 --branch ${TRILINOS_COMMIT} https://github.com/trilinos/Trilinos.git +RUN mkdir /root/Trilinos/build +WORKDIR /root/Trilinos/build +RUN cmake \ + -G "Unix Makefiles" \ + -DCMAKE_C_COMPILER=mpicc \ + -DCMAKE_CXX_COMPILER=mpic++ \ + -DCMAKE_Fortran_COMPILER=mpif77 \ + -DCMAKE_CXX_FLAGS="-O3 -fPIC" \ + -DCMAKE_C_FLAGS="-O3 -fPIC" \ + -DCMAKE_Fortran_FLAGS="-O3 -fPIC" \ + -DCMAKE_INSTALL_PREFIX=/usr/local/XyceLibs/Parallel \ + -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=ON \ + -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 \ + /root/Trilinos +RUN make -j 4 +RUN make install + +ARG XYCE_COMMIT=b7bb12d81f11d8b50141262537299b09d64b5565 +WORKDIR /root +RUN git clone https://github.com/Xyce/Xyce.git +WORKDIR /root/Xyce +RUN git checkout ${XYCE_COMMIT} +RUN ./bootstrap +RUN mkdir /root/Xyce/build +WORKDIR /root/Xyce/build +RUN ../configure CXXFLAGS="-O3 -std=c++11" \ + ARCHDIR="/usr/local/XyceLibs/Parallel" \ + CPPFLAGS="-I/usr/include/suitesparse" \ + --enable-mpi CXX=mpicxx CC=mpicc F77=mpif77 \ + --prefix=/usr/local/Xyce/Parallel --enable-shared --enable-xyce-shareable +RUN make -j 4 install ### CLEAN UP ### # Remove development tools to save space -RUN apt-get remove -y build-essential autoconf automake libtool bison flex tcl-dev tk-dev +RUN apt-get remove -y build-essential autoconf automake libtool bison flex tcl-dev tk-dev cmake # Cleanup to save some space RUN apt-get clean RUN rm -rf /var/lib/apt/lists/* # ### SET UP A GENERIC USER ### -# WORKDIR /p -# RUN echo "cd ~" >> /etc/skel/.bashrc -# RUN echo "source /set-paths.sh" >> /etc/skel/.bashrc -# ADD set-paths.sh /set-paths.sh -# RUN chmod 755 /set-paths.sh - -### ADD ENTRY POINT ### -# COPY entrypoint.sh /usr/local/bin/entrypoint.sh -# RUN chmod 755 /usr/local/bin/entrypoint.sh -# ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] -# CMD ["/bin/bash"] - RUN mkdir /home/cad-user RUN useradd cad-user RUN chown -R cad-user /home/cad-user diff --git a/docker/set-paths.sh b/docker/set-paths.sh index 40bfaeb8..1cebef48 100644 --- a/docker/set-paths.sh +++ b/docker/set-paths.sh @@ -1,15 +1,13 @@ export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin -export SWROOT=/software - # Klayout export KLAYOUT_HOME=/usr/local/klayout export PATH=$PATH:$KLAYOUT_HOME export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$KLAYOUT_HOME # Xyce -export XYCE_HOME=$SWROOT/Xyce/Parallel +export XYCE_HOME=/usr/local/Xyce/Parallel export XYCE_PATH=$XYCE_HOME/bin export PATH=$PATH:$XYCE_PATH export XYCE_LIB=$XYCE_HOME/lib From 8653b882062603f56585740b46b54510d82ae4f6 Mon Sep 17 00:00:00 2001 From: mrg Date: Sun, 6 Feb 2022 09:06:20 -0800 Subject: [PATCH 072/229] Remove working temp directories --- compiler/tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index a20f61f3..2f6f36c4 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -64,7 +64,7 @@ $(TEST_BASES): vlsida/openram-ubuntu:latest \ sh -c ". /home/cad-user/.bashrc && python3 -u $(OPENRAM_DIR)/$(getfile).py \ -t $(gettech) -k $(ARGS) -p $(OPENRAM_DIR)/results/$* > $(OPENRAM_DIR)/results/$*.out 2>&1 && touch $(OPENRAM_DIR)/results/$*.ok || touch $(OPENRAM_DIR)/results/$*.bad" - @test -f $(TOP_DIR)/compiler/tests/results/$*.ok && echo "$* ... PASS!" || echo "$* ... FAIL!" + @test -f $(TOP_DIR)/compiler/tests/results/$*.ok && echo "$* ... PASS!" && rm -rf $(OPENRAM_DIR)/results/$* || echo "$* ... FAIL!" .DELETE_ON_ERROR: $(TEST_STAMPS) # This would use the regress.py script to run in parallel instead of From 93c6565b66bf1124b68a2a2fc62e9cdb2c52809c Mon Sep 17 00:00:00 2001 From: mrg Date: Sun, 6 Feb 2022 09:13:36 -0800 Subject: [PATCH 073/229] Add total failure of tests --- compiler/tests/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 2f6f36c4..c86a6fa5 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -41,6 +41,7 @@ getfile = $(word 2,$(subst /, ,$*)) WORKING_TECH_TEST_STAMPS=$(foreach T, $(TECHS),$(addprefix $T/,$(WORKING_TEST_STAMPS))) all: $(WORKING_TECH_TEST_STAMPS) + @test -f $(TOP_DIR)/compiler/tests/results/*.bad && echo "Regression had a failure." && exit 1 || "Regression passed." .PHONY: all # Targets for each individual test From 89688de3cf9c2a8bf06a8c9e6e8bc6ddb53226c9 Mon Sep 17 00:00:00 2001 From: mrg Date: Sun, 6 Feb 2022 09:48:30 -0800 Subject: [PATCH 074/229] Remove outside of docker space --- compiler/tests/21_ngspice_delay_global_test.py | 1 + compiler/tests/Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/tests/21_ngspice_delay_global_test.py b/compiler/tests/21_ngspice_delay_global_test.py index 78b764f4..b71313f8 100755 --- a/compiler/tests/21_ngspice_delay_global_test.py +++ b/compiler/tests/21_ngspice_delay_global_test.py @@ -16,6 +16,7 @@ from sram_factory import factory import debug +@unittest.skip("SKIPPING 21_ngspice_delay_global_test") class timing_sram_test(openram_test): def runTest(self): diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index c86a6fa5..ac0c2ff2 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -65,7 +65,7 @@ $(TEST_BASES): vlsida/openram-ubuntu:latest \ sh -c ". /home/cad-user/.bashrc && python3 -u $(OPENRAM_DIR)/$(getfile).py \ -t $(gettech) -k $(ARGS) -p $(OPENRAM_DIR)/results/$* > $(OPENRAM_DIR)/results/$*.out 2>&1 && touch $(OPENRAM_DIR)/results/$*.ok || touch $(OPENRAM_DIR)/results/$*.bad" - @test -f $(TOP_DIR)/compiler/tests/results/$*.ok && echo "$* ... PASS!" && rm -rf $(OPENRAM_DIR)/results/$* || echo "$* ... FAIL!" + @test -f $(TOP_DIR)/compiler/tests/results/$*.ok && echo "$* ... PASS!" && rm -rf $(TOP_DIR)/compiler/tests/results/$* || echo "$* ... FAIL!" .DELETE_ON_ERROR: $(TEST_STAMPS) # This would use the regress.py script to run in parallel instead of From ee97d87bdf6941384dbe03b460e6dfeaa1780c36 Mon Sep 17 00:00:00 2001 From: mrg Date: Sun, 6 Feb 2022 12:36:22 -0800 Subject: [PATCH 075/229] Fix total regress pass or fail check. --- compiler/tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index ac0c2ff2..2fb7f4e1 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -41,7 +41,7 @@ getfile = $(word 2,$(subst /, ,$*)) WORKING_TECH_TEST_STAMPS=$(foreach T, $(TECHS),$(addprefix $T/,$(WORKING_TEST_STAMPS))) all: $(WORKING_TECH_TEST_STAMPS) - @test -f $(TOP_DIR)/compiler/tests/results/*.bad && echo "Regression had a failure." && exit 1 || "Regression passed." + @ls $(TOP_DIR)/compiler/tests/results/*.bad 1> /dev/null 2>&1 && echo "REGRESSION FAIL" && exit 1 || echo "REGRESSION PASS" .PHONY: all # Targets for each individual test From a3d3aa514bf529805d6a06c2c1d9c3f464589c15 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 7 Feb 2022 11:27:10 -0800 Subject: [PATCH 076/229] Add target for all technologies --- compiler/tests/Makefile | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 2fb7f4e1..16a0d677 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -6,7 +6,7 @@ include $(TOP_DIR)/openram.mk ARGS ?= TECH ?= scn4m_subm TECHS = scn4m_subm freepdk45 -# sky130 +ALL_TECHS = scn4m_subm freepdk45 sky130 TEST_DIR = $(TOP_DIR)/compiler/tests TEST_SRCS = $(sort $(notdir $(wildcard $(TEST_DIR)/*_test.py))) @@ -40,14 +40,20 @@ gettech = $(word 1,$(subst /, ,$*)) getfile = $(word 2,$(subst /, ,$*)) WORKING_TECH_TEST_STAMPS=$(foreach T, $(TECHS),$(addprefix $T/,$(WORKING_TEST_STAMPS))) +# Run all technologies all: $(WORKING_TECH_TEST_STAMPS) @ls $(TOP_DIR)/compiler/tests/results/*.bad 1> /dev/null 2>&1 && echo "REGRESSION FAIL" && exit 1 || echo "REGRESSION PASS" .PHONY: all +# Run a given technology +# e.g. make freepdk45 +$(ALL_TECHS): + @$(MAKE) --no-print-directory $(addprefix $@/,$(WORKING_TEST_STAMPS)) +.PHONY: $(TECHS) + # Targets for each individual test # e.g. make 04_pinv_1x_test $(TEST_BASES): -# @echo "Running $(TECH) $@ ... " @$(MAKE) --no-print-directory $(TECH)/$@.ok .PHONY: $(TEST_BASES) @@ -68,23 +74,8 @@ $(TEST_BASES): @test -f $(TOP_DIR)/compiler/tests/results/$*.ok && echo "$* ... PASS!" && rm -rf $(TOP_DIR)/compiler/tests/results/$* || echo "$* ... FAIL!" .DELETE_ON_ERROR: $(TEST_STAMPS) -# This would use the regress.py script to run in parallel instead of -# the Makefile. -#$(TECHS): -# @echo "Running $*" -# docker run \ -# -v $(TOP_DIR):/openram \ -# -v $(FREEPDK45):/pdk/freepdk45 \ -# -v $(PDK_ROOT):/pdk \ -# --user $(UID):$(GID) \ -# -e OPENRAM_TMP=$(OPENRAM_DIR)/results/$@ \ -# vlsida/openram-ubuntu:latest \ -# sh -c ". /home/cad-user/.bashrc && python3 -u $(OPENRAM_DIR)/regress.py -t $@ $(ARGS)" -#.PHONY: $(TECHS) -#regress: $(TECHS) -#.PHONY: regress - # Mount environment for debug +# mount: docker run -it \ -v $(TOP_DIR):/openram \ From b641bc8eef3720f12f1ab8b8eb58cd633f8b14e0 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 7 Feb 2022 16:30:18 -0800 Subject: [PATCH 077/229] Check proper subdir for bad files --- compiler/tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 16a0d677..9f1d0dc6 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -42,7 +42,7 @@ WORKING_TECH_TEST_STAMPS=$(foreach T, $(TECHS),$(addprefix $T/,$(WORKING_TEST_ST # Run all technologies all: $(WORKING_TECH_TEST_STAMPS) - @ls $(TOP_DIR)/compiler/tests/results/*.bad 1> /dev/null 2>&1 && echo "REGRESSION FAIL" && exit 1 || echo "REGRESSION PASS" + @ls $(TOP_DIR)/compiler/tests/results/*/*.bad 1> /dev/null 2>&1 && echo "REGRESSION FAIL" && exit 1 || echo "REGRESSION PASS" .PHONY: all # Run a given technology From 833278b7a6bc977647f19f7ab0fd105edd4f5ed0 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 7 Feb 2022 16:30:25 -0800 Subject: [PATCH 078/229] Add iverilog to docker image --- docker/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker/Dockerfile b/docker/Dockerfile index 14950d19..07093a3d 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -130,6 +130,8 @@ RUN ../configure CXXFLAGS="-O3 -std=c++11" \ --prefix=/usr/local/Xyce/Parallel --enable-shared --enable-xyce-shareable RUN make -j 4 install +RUN apt-get install --no-install-recommends -y iverilog + ### CLEAN UP ### # Remove development tools to save space RUN apt-get remove -y build-essential autoconf automake libtool bison flex tcl-dev tk-dev cmake From b1e1763e14988785380c72316eb561ccb1d38149 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 8 Feb 2022 11:35:29 -0800 Subject: [PATCH 079/229] Fix PDK path for freepdk45 and list FAILED tests explicitly at end. --- compiler/tests/Makefile | 2 ++ docker/set-paths.sh | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 9f1d0dc6..4f438fe3 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -43,6 +43,8 @@ WORKING_TECH_TEST_STAMPS=$(foreach T, $(TECHS),$(addprefix $T/,$(WORKING_TEST_ST # Run all technologies all: $(WORKING_TECH_TEST_STAMPS) @ls $(TOP_DIR)/compiler/tests/results/*/*.bad 1> /dev/null 2>&1 && echo "REGRESSION FAIL" && exit 1 || echo "REGRESSION PASS" + @echo "FAILING TESTS:" + @ls $(TOP_DIR)/compiler/tests/results/*/*.bad .PHONY: all # Run a given technology diff --git a/docker/set-paths.sh b/docker/set-paths.sh index 1cebef48..dc9b03ce 100644 --- a/docker/set-paths.sh +++ b/docker/set-paths.sh @@ -15,7 +15,7 @@ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$XYCE_LIB export XYCE_NO_TRACKING="anything at all" # PDKs -export FREEPDK45=/PDK/freepdk45 +export FREEPDK45=/pdk/freepdk45 # Set to the PDK you want to use export PDK_DIR=$FREEPDK45 From 4d62cbd34557de98e9495a360417854613d09db9 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 8 Feb 2022 12:05:39 -0800 Subject: [PATCH 080/229] Move pdk paths to docker invocation --- compiler/tests/Makefile | 5 +++++ docker/set-paths.sh | 8 -------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 4f438fe3..4b1e45de 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -66,7 +66,10 @@ $(TEST_BASES): @docker run \ -v $(TOP_DIR):/openram \ -v $(FREEPDK45):/pdk/freepdk45\ + -e FREEPDK45=/pdk/freepdk45\ -v $(PDK_ROOT):/pdk \ + -e PDK_ROOT=/pdk \ + -e PDKPATH=/pdk/sky130A \ -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \ --user $(UID):$(GID) \ -e OPENRAM_TMP=$(OPENRAM_DIR)/results/$*/tmp \ @@ -83,6 +86,8 @@ mount: -v $(TOP_DIR):/openram \ -v $(FREEPDK45):/pdk/freepdk45 \ -v $(PDK_ROOT):/pdk \ + -e PDK_ROOT=/pdk \ + -e PDKPATH=/pdk/sky130A \ -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \ --user $(UID):$(GID) \ vlsida/openram-ubuntu:latest diff --git a/docker/set-paths.sh b/docker/set-paths.sh index dc9b03ce..386872b5 100644 --- a/docker/set-paths.sh +++ b/docker/set-paths.sh @@ -14,14 +14,6 @@ export XYCE_LIB=$XYCE_HOME/lib export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$XYCE_LIB export XYCE_NO_TRACKING="anything at all" -# PDKs -export FREEPDK45=/pdk/freepdk45 -# Set to the PDK you want to use -export PDK_DIR=$FREEPDK45 - -# Skywater PDK -export PDK_ROOT=/pdk - # OpenRAM export OPENRAM_HOME=/openram/compiler export OPENRAM_TECH=/openram/technology From 16238af5840a2f3f370e21ee31dc4cca18802ed1 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 8 Feb 2022 13:07:37 -0800 Subject: [PATCH 081/229] Print failing tests before exit --- compiler/tests/Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 4b1e45de..11c4c1f8 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -42,9 +42,7 @@ WORKING_TECH_TEST_STAMPS=$(foreach T, $(TECHS),$(addprefix $T/,$(WORKING_TEST_ST # Run all technologies all: $(WORKING_TECH_TEST_STAMPS) - @ls $(TOP_DIR)/compiler/tests/results/*/*.bad 1> /dev/null 2>&1 && echo "REGRESSION FAIL" && exit 1 || echo "REGRESSION PASS" - @echo "FAILING TESTS:" - @ls $(TOP_DIR)/compiler/tests/results/*/*.bad + @ls $(TOP_DIR)/compiler/tests/results/*/*.bad 1> /dev/null 2>&1 && echo "FAILING TESTS" && ls $(TOP_DIR)/compiler/tests/results/*/*.bad && exit 1 .PHONY: all # Run a given technology From 40f671acfd59bed0716597cf011c2d6beaa084d7 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 8 Feb 2022 16:04:18 -0800 Subject: [PATCH 082/229] Make clean before make --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 36ab8aae..8dbf8380 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,6 +25,7 @@ jobs: #python3-coverage run -p $OPENRAM_HOME/tests/regress.py -j 12 -t scn4m_subm #$OPENRAM_HOME/tests/regress.py -j 24 -t scn4m_subm cd $OPENRAM_HOME/tests + make clean make -k -j 48 - name: Archive if: ${{ failure() }} From c75968401c54d8c75a1fb6b5d43fe0c2af113d0a Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 8 Feb 2022 16:04:43 -0800 Subject: [PATCH 083/229] Update for detailed skips. Added some sky130 skips. --- compiler/tests/Makefile | 70 ++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 11c4c1f8..854f531d 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -16,29 +16,57 @@ TEST_STAMPS= $(addsuffix .ok,$(TEST_BASES)) OPENRAM_DIR = /openram/compiler/tests RESULTS_DIR = $(OPENRAM_DIR)/results -TEST_BROKEN = \ - 50_riscv_1k_1rw1r_func_test.py \ - 50_riscv_1k_1rw_func_test.py \ - 50_riscv_1rw1r_func_test.py \ - 50_riscv_1rw1r_phys_test.py \ - 50_riscv_1rw_func_test.py \ - 50_riscv_1rw_phys_test.py \ - 50_riscv_2k_1rw1r_func_test.py \ - 50_riscv_2k_1rw_func_test.py \ - 50_riscv_4k_1rw1r_func_test.py \ - 50_riscv_4k_1rw_func_test.py \ - 50_riscv_512b_1rw1r_func_test.py \ - 50_riscv_512b_1rw_func_test.py \ - 50_riscv_8k_1rw1r_func_test.py \ - 50_riscv_8k_1rw_func_test.py - - -WORKING_TEST_STAMPS=$(filter-out $(addsuffix .ok, (TEST_BROKEN)), $(TEST_STAMPS)) - +# Use % for all techs: +# %/test.py +# or a specific tech: +# freepdk45/test.py +BROKEN_STAMPS = \ + sky130/01_library_test.ok \ + sky130/04_column_mux_pbitcell_test.ok \ + sky130/04_dummy_pbitcell_test.ok \ + sky130/04_pbitcell_test.ok \ + sky130/04_pnand4_test.ok \ + sky130/04_precharge_pbitcell_test.ok \ + sky130/04_replica_pbitcell_test.ok \ + sky130/05_pbitcell_array_test.ok \ + sky130/05_bitcell_array_test.ok \ + sky130/05_bitcell_array_1rw_1r_test.ok \ + sky130/05_dummy_array_test.ok \ + sky130/07_column_mux_array_pbitcell_test.ok \ + sky130/19_pmulti_bank_test.ok \ + sky130/19_psingle_bank_test.ok \ + sky130/19_bank_select_pbitcell_test.ok \ + sky130/20_psram_1bank_2mux_1rw_1w_test.ok \ + sky130/20_psram_1bank_2mux_1rw_1w_wmask_test.ok \ + sky130/20_psram_1bank_2mux_1w_1r_test.ok \ + sky130/20_psram_1bank_2mux_test.ok \ + sky130/20_psram_1bank_4mux_1rw_1r_test.ok \ + sky130/22_psram_1bank_2mux_func_test.ok \ + sky130/22_psram_1bank_4mux_func_test.ok \ + sky130/22_psram_1bank_8mux_func_test.ok \ + sky130/22_psram_1bank_nomux_func_test.ok \ + %/50_riscv_1k_1rw1r_func_test.ok \ + %/50_riscv_1k_1rw_func_test.ok \ + %/50_riscv_1rw1r_func_test.ok \ + %/50_riscv_1rw1r_phys_test.ok \ + %/50_riscv_1rw_func_test.ok \ + %/50_riscv_1rw_phys_test.ok \ + %/50_riscv_2k_1rw1r_func_test.ok \ + %/50_riscv_2k_1rw_func_test.ok \ + %/50_riscv_4k_1rw1r_func_test.ok \ + %/50_riscv_4k_1rw_func_test.ok \ + %/50_riscv_512b_1rw1r_func_test.ok \ + %/50_riscv_512b_1rw_func_test.ok \ + %/50_riscv_8k_1rw1r_func_test.ok \ + %/50_riscv_8k_1rw_func_test.ok gettech = $(word 1,$(subst /, ,$*)) getfile = $(word 2,$(subst /, ,$*)) -WORKING_TECH_TEST_STAMPS=$(foreach T, $(TECHS),$(addprefix $T/,$(WORKING_TEST_STAMPS))) +TECH_TEST_STAMPS=$(foreach T, $(TECHS), $(addprefix $T/, $(TEST_STAMPS))) + +# Filter out the tests after creating the tech stamps +WORKING_TECH_TEST_STAMPS=$(filter-out $(BROKEN_STAMPS), $(TECH_TEST_STAMPS)) + # Run all technologies all: $(WORKING_TECH_TEST_STAMPS) @@ -48,7 +76,7 @@ all: $(WORKING_TECH_TEST_STAMPS) # Run a given technology # e.g. make freepdk45 $(ALL_TECHS): - @$(MAKE) --no-print-directory $(addprefix $@/,$(WORKING_TEST_STAMPS)) + @$(MAKE) --no-print-directory $(filter-out $(BROKEN_STAMPS), $(addprefix $@/, $(TEST_STAMPS))) .PHONY: $(TECHS) # Targets for each individual test From 2d2620d21a64f2b48e8a4ee9d5833bee7da12453 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 2 Feb 2022 07:11:13 -0800 Subject: [PATCH 084/229] Remove dir from bad tests --- compiler/tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 854f531d..d384d52f 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -70,7 +70,7 @@ WORKING_TECH_TEST_STAMPS=$(filter-out $(BROKEN_STAMPS), $(TECH_TEST_STAMPS)) # Run all technologies all: $(WORKING_TECH_TEST_STAMPS) - @ls $(TOP_DIR)/compiler/tests/results/*/*.bad 1> /dev/null 2>&1 && echo "FAILING TESTS" && ls $(TOP_DIR)/compiler/tests/results/*/*.bad && exit 1 + @ls $(TOP_DIR)/compiler/tests/results/*/*.bad 1> /dev/null 2>&1 && echo "FAILING TESTS" && ls $(TOP_DIR)/compiler/tests/results/*/*.bad && sed -e "s/^.*\/results\///" && exit 1 .PHONY: all # Run a given technology From 8fdd4966a79121b437c8d11b08d042491a7efd73 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 2 Feb 2022 09:36:05 -0800 Subject: [PATCH 085/229] Initial update of new psdm/nsdm implants --- compiler/pgates/pgate.py | 58 +++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index 19a027e9..68e8a883 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -208,8 +208,9 @@ class pgate(design.design): # from the top of the well # OR align the active with the top of PMOS active. max_y_offset = self.height + 0.5 * self.m1_width - contact_yoffset = min(pmos_pos.y + pmos.active_height - pmos.active_contact.first_layer_height, - max_y_offset - pmos.active_contact.first_layer_height / 2 - self.nwell_enclose_active) + contact_yoffset = self.height - 0.5 * self.implant_width \ + - pmos.active_contact.first_layer_height \ + - self.implant_enclose_active contact_offset = vector(contact_xoffset, contact_yoffset) # Offset by half a contact in x and y contact_offset += vector(0.5 * pmos.active_contact.first_layer_width, @@ -276,24 +277,34 @@ class pgate(design.design): rightx=rightx, topy=self.height) - try: - ntap_insts = [self.nwell_contact] - self.add_enclosure(ntap_insts, - layer="nimplant", - extend=self.implant_enclose_active, - rightx=self.width, - topy=self.height) - except AttributeError: - pass - try: - ptap_insts = [self.pwell_contact] - self.add_enclosure(ptap_insts, - layer="pimplant", - extend=self.implant_enclose_active, - rightx=self.width, - boty=0) - except AttributeError: - pass + self.add_rect(layer="pimplant", + offset=vector(0, self.height - 0.5 * self.implant_width), + width=self.width, + height=self.implant_width) + self.add_rect(layer="nimplant", + offset=vector(0, -0.5 * self.implant_width), + width=self.width, + height=self.implant_width) + + +# try: +# ntap_insts = [self.nwell_contact] +# self.add_enclosure(ntap_insts, +# layer="nimplant", +# extend=self.implant_enclose_active, +# rightx=self.width, +# topy=self.height) +# except AttributeError: +# pass +# try: +# ptap_insts = [self.pwell_contact] +# self.add_enclosure(ptap_insts, +# layer="pimplant", +# extend=self.implant_enclose_active, +# rightx=self.width, +# boty=0) +# except AttributeError: +# pass def add_pwell_contact(self, nmos, nmos_pos): """ Add an pwell contact next to the given nmos device. """ @@ -303,11 +314,8 @@ class pgate(design.design): # To the right a spacing away from the nmos right active edge contact_xoffset = nmos_pos.x + nmos.active_width \ + self.active_space - # Must be at least an well enclosure of active up - # from the bottom of the well - contact_yoffset = max(nmos_pos.y, - self.nwell_enclose_active \ - - nmos.active_contact.first_layer_height / 2) + # Allow an nimplant below it under the rail + contact_yoffset = 0.5 * self.implant_width + self.implant_enclose_active contact_offset = vector(contact_xoffset, contact_yoffset) # Offset by half a contact From 39f1199b63fa830bcb4f5e0ef81c3a0a6dd5f694 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 2 Feb 2022 09:36:19 -0800 Subject: [PATCH 086/229] Always delete result subdir to prevent bad and ok simultaneously --- compiler/tests/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index d384d52f..cbe79439 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -3,6 +3,7 @@ include $(TOP_DIR)/openram.mk .DEFAULT_GOAL := all +RM ?= "rm -rf" ARGS ?= TECH ?= scn4m_subm TECHS = scn4m_subm freepdk45 @@ -88,6 +89,7 @@ $(TEST_BASES): # To run a test in a given technology %.ok: # @echo "Running $(gettech) $(getfile) ... " + @rm -rf results/$* @mkdir -p results/$*/tmp @docker run \ -v $(TOP_DIR):/openram \ @@ -102,7 +104,8 @@ $(TEST_BASES): vlsida/openram-ubuntu:latest \ sh -c ". /home/cad-user/.bashrc && python3 -u $(OPENRAM_DIR)/$(getfile).py \ -t $(gettech) -k $(ARGS) -p $(OPENRAM_DIR)/results/$* > $(OPENRAM_DIR)/results/$*.out 2>&1 && touch $(OPENRAM_DIR)/results/$*.ok || touch $(OPENRAM_DIR)/results/$*.bad" - @test -f $(TOP_DIR)/compiler/tests/results/$*.ok && echo "$* ... PASS!" && rm -rf $(TOP_DIR)/compiler/tests/results/$* || echo "$* ... FAIL!" + @test -f $(TOP_DIR)/compiler/tests/results/$*.ok && echo "$* ... PASS!" && \ + $(RM) $(TOP_DIR)/compiler/tests/results/$* || echo "$* ... FAIL!" .DELETE_ON_ERROR: $(TEST_STAMPS) # Mount environment for debug From 51097b2c8b94c3f1e436d950d2e1a26f3b44bd82 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 2 Feb 2022 09:38:27 -0800 Subject: [PATCH 087/229] Revert rm in makefile --- compiler/tests/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index cbe79439..9a90d16d 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -3,7 +3,6 @@ include $(TOP_DIR)/openram.mk .DEFAULT_GOAL := all -RM ?= "rm -rf" ARGS ?= TECH ?= scn4m_subm TECHS = scn4m_subm freepdk45 @@ -105,7 +104,7 @@ $(TEST_BASES): sh -c ". /home/cad-user/.bashrc && python3 -u $(OPENRAM_DIR)/$(getfile).py \ -t $(gettech) -k $(ARGS) -p $(OPENRAM_DIR)/results/$* > $(OPENRAM_DIR)/results/$*.out 2>&1 && touch $(OPENRAM_DIR)/results/$*.ok || touch $(OPENRAM_DIR)/results/$*.bad" @test -f $(TOP_DIR)/compiler/tests/results/$*.ok && echo "$* ... PASS!" && \ - $(RM) $(TOP_DIR)/compiler/tests/results/$* || echo "$* ... FAIL!" + rm -rf $(TOP_DIR)/compiler/tests/results/$* || echo "$* ... FAIL!" .DELETE_ON_ERROR: $(TEST_STAMPS) # Mount environment for debug From c471823626c87c6c416ce406c3904c628dbce7f5 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 10 Feb 2022 11:18:52 -0800 Subject: [PATCH 088/229] Run individual tests on all technologies by default --- compiler/tests/Makefile | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 9a90d16d..6649cc34 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -4,9 +4,8 @@ include $(TOP_DIR)/openram.mk .DEFAULT_GOAL := all ARGS ?= -TECH ?= scn4m_subm -TECHS = scn4m_subm freepdk45 -ALL_TECHS = scn4m_subm freepdk45 sky130 +TEST_TECHS = scn4m_subm freepdk45 +TECHS ?= scn4m_subm freepdk45 sky130 TEST_DIR = $(TOP_DIR)/compiler/tests TEST_SRCS = $(sort $(notdir $(wildcard $(TEST_DIR)/*_test.py))) @@ -62,7 +61,7 @@ BROKEN_STAMPS = \ gettech = $(word 1,$(subst /, ,$*)) getfile = $(word 2,$(subst /, ,$*)) -TECH_TEST_STAMPS=$(foreach T, $(TECHS), $(addprefix $T/, $(TEST_STAMPS))) +TECH_TEST_STAMPS=$(foreach T, $(TEST_TECHS), $(addprefix $T/, $(TEST_STAMPS))) # Filter out the tests after creating the tech stamps WORKING_TECH_TEST_STAMPS=$(filter-out $(BROKEN_STAMPS), $(TECH_TEST_STAMPS)) @@ -75,14 +74,14 @@ all: $(WORKING_TECH_TEST_STAMPS) # Run a given technology # e.g. make freepdk45 -$(ALL_TECHS): +$(TECHS): @$(MAKE) --no-print-directory $(filter-out $(BROKEN_STAMPS), $(addprefix $@/, $(TEST_STAMPS))) .PHONY: $(TECHS) -# Targets for each individual test +# Targets for each individual test in all technologies # e.g. make 04_pinv_1x_test $(TEST_BASES): - @$(MAKE) --no-print-directory $(TECH)/$@.ok + @$(MAKE) --no-print-directory $(foreach T, $(TECHS), $(addprefix $T/, $@.ok)) .PHONY: $(TEST_BASES) # To run a test in a given technology From a35ab45843e710ddf79ef319d93de93ac01ee9bd Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 10 Feb 2022 11:30:20 -0800 Subject: [PATCH 089/229] Conditionally set TEST_TECHS. Skip pand4 for sky130. --- compiler/tests/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 6649cc34..c18e1f98 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -4,7 +4,7 @@ include $(TOP_DIR)/openram.mk .DEFAULT_GOAL := all ARGS ?= -TEST_TECHS = scn4m_subm freepdk45 +TEST_TECHS ?= scn4m_subm freepdk45 TECHS ?= scn4m_subm freepdk45 sky130 TEST_DIR = $(TOP_DIR)/compiler/tests @@ -25,6 +25,7 @@ BROKEN_STAMPS = \ sky130/04_dummy_pbitcell_test.ok \ sky130/04_pbitcell_test.ok \ sky130/04_pnand4_test.ok \ + sky130/04_pand4_test.ok \ sky130/04_precharge_pbitcell_test.ok \ sky130/04_replica_pbitcell_test.ok \ sky130/05_pbitcell_array_test.ok \ From ab3acb99dae2876c00940c27fda329303911826f Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 11 Feb 2022 12:09:42 -0800 Subject: [PATCH 090/229] Fix offsets of new nwell/pwell contacts. --- compiler/pgates/pgate.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index 68e8a883..6a92fa0e 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -208,9 +208,10 @@ class pgate(design.design): # from the top of the well # OR align the active with the top of PMOS active. max_y_offset = self.height + 0.5 * self.m1_width - contact_yoffset = self.height - 0.5 * self.implant_width \ - - pmos.active_contact.first_layer_height \ - - self.implant_enclose_active + contact_yoffset = min(self.height - 0.5 * self.implant_width, + self.get_tx_insts("pmos")[0].uy()) \ + - pmos.active_contact.first_layer_height \ + - self.implant_enclose_active contact_offset = vector(contact_xoffset, contact_yoffset) # Offset by half a contact in x and y contact_offset += vector(0.5 * pmos.active_contact.first_layer_width, @@ -315,7 +316,8 @@ class pgate(design.design): contact_xoffset = nmos_pos.x + nmos.active_width \ + self.active_space # Allow an nimplant below it under the rail - contact_yoffset = 0.5 * self.implant_width + self.implant_enclose_active + contact_yoffset = max(0.5 * self.implant_width + self.implant_enclose_active, + self.get_tx_insts("nmos")[0].by()) contact_offset = vector(contact_xoffset, contact_yoffset) # Offset by half a contact From a75d9fcc76cba41491b024416ef33de273ec06e5 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 11 Feb 2022 13:11:24 -0800 Subject: [PATCH 091/229] Fix failing test output of Makefile --- compiler/tests/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index c18e1f98..a57b4478 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -70,7 +70,7 @@ WORKING_TECH_TEST_STAMPS=$(filter-out $(BROKEN_STAMPS), $(TECH_TEST_STAMPS)) # Run all technologies all: $(WORKING_TECH_TEST_STAMPS) - @ls $(TOP_DIR)/compiler/tests/results/*/*.bad 1> /dev/null 2>&1 && echo "FAILING TESTS" && ls $(TOP_DIR)/compiler/tests/results/*/*.bad && sed -e "s/^.*\/results\///" && exit 1 + @ls -1 $(TOP_DIR)/compiler/tests/results/*/*.bad 1> /dev/null 2>&1 && echo "FAILING TESTS" && ls -1 $(TOP_DIR)/compiler/tests/results/*/*.bad | sed -e "s#^.*results\/##" && exit 1 || exit 0 .PHONY: all # Run a given technology @@ -89,6 +89,7 @@ $(TEST_BASES): %.ok: # @echo "Running $(gettech) $(getfile) ... " @rm -rf results/$* + @rm -rf results/$*.* @mkdir -p results/$*/tmp @docker run \ -v $(TOP_DIR):/openram \ From bb24503f32eafd7c60b55a2b541512410c7464de Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 11 Feb 2022 13:48:52 -0800 Subject: [PATCH 092/229] Add back klayout lvs model install. --- Makefile | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index dc813e9c..1f603a41 100644 --- a/Makefile +++ b/Makefile @@ -29,6 +29,7 @@ MAG_FILES := $(sort $(wildcard $(SRAM_LIB_DIR)/cells/*/*.mag)) SPICE_SUFFIX := spice SPICE_LVS_SUFFIX := lvs.$(SPICE_SUFFIX) SPICE_CALIBRE_SUFFIX := lvs.calibre.$(SPICE_SUFFIX) +SPICE_KLAYOUT_SUFFIX := lvs.klayout.$(SPICE_SUFFIX) SPICE_BASE_SUFFIX := base.$(SPICE_SUFFIX) ALL_SPICE_FILES := $(sort $(wildcard $(SRAM_LIB_DIR)/cells/*/*.$(SPICE_SUFFIX))) @@ -49,7 +50,7 @@ ifndef PDK_ROOT $(error PDK_ROOT is undefined, please export it before running make) endif -$(SKY130_PDKS_DIR): check-pdk-root +$(SKY130_PDKS_DIR): check-pdk-root git clone https://github.com/google/skywater-pdk.git $(PDK_ROOT)/skywater-pdk cd $(SKY130_PDKS_DIR) && \ git checkout main && git pull && \ @@ -148,6 +149,18 @@ $(INSTALL_BASE)/calibre_lvs_lib: $(filter %.$(SPICE_CALIBRE_SUFFIX),$(ALL_SPICE_ @echo "==================================================================" @echo +$(INSTALL_BASE)/klayout_lvs_lib: $(filter %.$(SPICE_KLAYOUT_SUFFIX),$(ALL_SPICE_FILES)) + @echo + @echo "Setting up klayout LVS library for OpenRAM." + @echo "==================================================================" + mkdir -p $@ + @for SP in $?; do \ + cp -va $$SP $@/$$(basename $$SP .$(SPICE_KLAYOUT_SUFFIX)).sp; \ + done + @echo "==================================================================" + @echo + + $(INSTALL_BASE)/sp_lib: $(filter-out %.$(SPICE_LVS_SUFFIX) %.$(SPICE_CALIBRE_SUFFIX),$(ALL_SPICE_FILES)) @echo @echo "Setting up spice simulation library for OpenRAM." From a54eb9037112e60e71472e575f07290155f89714 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Tue, 15 Feb 2022 14:37:07 -0800 Subject: [PATCH 093/229] place decoder rail contacts at least m2 min spacing away --- compiler/modules/hierarchical_decoder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index c0f42ac8..d6dd77d2 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -692,7 +692,7 @@ class hierarchical_decoder(design.design): drc_error = 0 for and_input in self.predecode_bus_rail_pos: if and_input.x == rail_pos.x: - if (abs(y_offset - and_input.y) < total_buffer_space) or (abs(y_offset - and_input.y) < via.height): + if (abs(y_offset - and_input.y) < total_buffer_space) or (abs(y_offset - and_input.y) < via.height) or (abs(y_offset - drc("minwidth_{}".format(cur_layer)) - pin_pos.y - via.height/2) < drc("{0}_to_{0}".format(cur_layer)) ): drc_error = 1 if drc_error == 0: break From 80a4fc7e8412613b61a443590a5093d905ee9fae Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 18 Feb 2022 15:02:16 -0800 Subject: [PATCH 094/229] Add PYTHONPATH in setup file --- setpaths.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/setpaths.sh b/setpaths.sh index 44485f14..280594f5 100755 --- a/setpaths.sh +++ b/setpaths.sh @@ -6,3 +6,10 @@ export OPENRAM_HOME="`pwd`/compiler" export OPENRAM_TECH="`pwd`/technology" +export PYTHONPATH=$OPENRAM_HOME +for dir in `pwd`/compiler/* +do + if [ -d $dir ]; then + export PYTHONPATH=$PYTHONPATH:$dir + fi; +done From abac5a11abb57afd0b48ac6a0f5d9299173e8bcf Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 18 Feb 2022 15:02:45 -0800 Subject: [PATCH 095/229] Move power supply stack to design --- compiler/base/design.py | 8 ++++++++ compiler/sram/sram_base.py | 7 ------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/base/design.py b/compiler/base/design.py index 70a9047b..f8ca0cb1 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -68,6 +68,14 @@ class design(hierarchy_design): self.setup_multiport_constants() + try: + from tech import power_grid + self.supply_stack = power_grid + except ImportError: + # if no power_grid is specified by tech we use sensible defaults + # Route a M3/M4 grid + self.supply_stack = self.m3_stack + def check_pins(self): for pin_name in self.pins: pins = self.get_pins(pin_name) diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index 72c5e3fe..ec690610 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -41,13 +41,6 @@ class sram_base(design, verilog, lef): if not self.num_spare_cols: self.num_spare_cols = 0 - try: - from tech import power_grid - self.supply_stack = power_grid - except ImportError: - # if no power_grid is specified by tech we use sensible defaults - # Route a M3/M4 grid - self.supply_stack = self.m3_stack def add_pins(self): """ Add pins for entire SRAM. """ From 53e4c45038469d8464818be801f67e47acec975e Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 23 Feb 2022 09:30:31 -0800 Subject: [PATCH 096/229] Add tap to nand in pnand --- compiler/pgates/pand2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/pgates/pand2.py b/compiler/pgates/pand2.py index 7e8f4043..b8d1feed 100644 --- a/compiler/pgates/pand2.py +++ b/compiler/pgates/pand2.py @@ -32,7 +32,7 @@ class pand2(pgate.pgate): def create_modules(self): self.nand = factory.create(module_type="pnand2", height=self.height, - add_wells=self.vertical) + add_wells=self.add_wells) self.inv = factory.create(module_type="pdriver", size_list=[self.size], From 16d54e4fcbd90d72afd6541d3d8e425dc1dbec5c Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 23 Feb 2022 10:19:46 -0800 Subject: [PATCH 097/229] Use vlsida repo for sram library --- Makefile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 1f603a41..5dc053d0 100644 --- a/Makefile +++ b/Makefile @@ -8,13 +8,15 @@ PDK_ROOT ?= $(TOP_DIR) # Skywater PDK SRAM library SRAM_LIB_DIR ?= $(PDK_ROOT)/sky130_fd_bd_sram -SRAM_LIB_GIT_REPO ?= https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git +SRAM_LIB_GIT_REPO ?= https://github.com/vlsida/sky130_fd_bd_sram.git +#SRAM_LIB_GIT_REPO ?= https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git SRAM_LIB_GIT_COMMIT ?= main # Open PDKs OPEN_PDKS_DIR ?= $(PDK_ROOT)/open_pdks OPEN_PDKS_GIT_REPO ?= https://github.com/RTimothyEdwards/open_pdks.git -OPEN_PDKS_GIT_COMMIT ?= 1.0.156 +#OPEN_PDKS_GIT_COMMIT ?= 1.0.156 +OPEN_PDKS_GIT_COMMIT ?= master SKY130_PDK ?= $(PDK_ROOT)/sky130A # Skywater PDK @@ -50,7 +52,7 @@ ifndef PDK_ROOT $(error PDK_ROOT is undefined, please export it before running make) endif -$(SKY130_PDKS_DIR): check-pdk-root +$(SKY130_PDKS_DIR): check-pdk-root git clone https://github.com/google/skywater-pdk.git $(PDK_ROOT)/skywater-pdk cd $(SKY130_PDKS_DIR) && \ git checkout main && git pull && \ From b71230efd73c8fcf53325e6b0c19a4ee057966d2 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 23 Feb 2022 10:20:18 -0800 Subject: [PATCH 098/229] Update Magic and klayout versions in docker --- docker/Dockerfile | 73 ++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 07093a3d..5ac3b3d0 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -24,7 +24,7 @@ RUN apt-get install --no-install-recommends -y libx11-dev libcairo2-dev RUN apt-get install --no-install-recommends -y qt5-default qtcreator ruby-full ruby-dev python3-dev qtmultimedia5-dev libqt5multimediawidgets5 libqt5multimedia5-plugins libqt5multimedia5 libqt5svg5-dev libqt5designer5 libqt5designercomponents5 libqt5xmlpatterns5-dev qttools5-dev ### Klayout ### -ARG KLAYOUT_COMMIT=ea1bf40a1ee1c1c934e47a0020417503ab3d7e7e +ARG KLAYOUT_COMMIT=v0.27.8 WORKDIR /root RUN git clone https://github.com/KLayout/klayout WORKDIR /root/klayout @@ -33,43 +33,10 @@ RUN ./build.sh -qt5 \ && cp -r bin-release /usr/local/klayout RUN rm -rf /root/klayout -### Magic ### -ARG MAGIC_COMMIT=8.3.254 -WORKDIR /root -RUN git clone git://opencircuitdesign.com/magic-8.3 magic -WORKDIR /root/magic -RUN git checkout ${MAGIC_COMMIT} -RUN ./configure \ - && make \ - && make install -RUN rm -rf /root/magic - -### Ngspice ### -ARG NGSPICE_COMIT=032b1c32c4dbad45ff132bcfac1dbecadbd8abb0 -WORKDIR /root -RUN git clone git://git.code.sf.net/p/ngspice/ngspice -WORKDIR /root/ngspice -RUN git checkout ${NGSPICE_COMMIT} -RUN ./autogen.sh \ - && ./configure --enable-openmp --with-readline \ - && make \ - && make install -RUN rm -rf /root/ngspice - -### Netgen ### -ARG NETGEN_COMMIT=88d53fab15eb611cffc024eebf8743fae5cf8cb7 -WORKDIR /root -RUN git clone git://opencircuitdesign.com/netgen-1.5 netgen -WORKDIR /root/netgen -RUN git checkout ${NETGEN_COMMIT} -RUN ./configure \ - && make -j$(nproc) \ - && make install -RUN rm -rf /root/netgen - ### Trilinos ### ARG TRILINOS_COMMIT=trilinos-release-12-12-1 WORKDIR /root +RUN apt-get update RUN apt-get install --no-install-recommends -y cmake libfftw3-dev mpich libblas-dev liblapack-dev libsuitesparse-dev libfl-dev openmpi-bin libopenmpi-dev gfortran RUN git clone --depth 1 --branch ${TRILINOS_COMMIT} https://github.com/trilinos/Trilinos.git RUN mkdir /root/Trilinos/build @@ -130,6 +97,42 @@ RUN ../configure CXXFLAGS="-O3 -std=c++11" \ --prefix=/usr/local/Xyce/Parallel --enable-shared --enable-xyce-shareable RUN make -j 4 install + +### Magic ### +ARG MAGIC_COMMIT=8.3.260 +WORKDIR /root +RUN git clone https://github.com/RTimothyEdwards/magic.git magic +WORKDIR /root/magic +RUN git checkout ${MAGIC_COMMIT} +RUN ./configure \ + && make \ + && make install +RUN rm -rf /root/magic + +### Ngspice ### +ARG NGSPICE_COMIT=032b1c32c4dbad45ff132bcfac1dbecadbd8abb0 +WORKDIR /root +RUN git clone git://git.code.sf.net/p/ngspice/ngspice +WORKDIR /root/ngspice +RUN git checkout ${NGSPICE_COMMIT} +RUN ./autogen.sh \ + && ./configure --enable-openmp --with-readline \ + && make \ + && make install +RUN rm -rf /root/ngspice + +### Netgen ### +ARG NETGEN_COMMIT=1.5.219 +WORKDIR /root +RUN git clone https://github.com/RTimothyEdwards/netgen.git netgen +WORKDIR /root/netgen +RUN git checkout ${NETGEN_COMMIT} +RUN ./configure \ + && make -j$(nproc) \ + && make install +RUN rm -rf /root/netgen + +### iVerilog ### RUN apt-get install --no-install-recommends -y iverilog ### CLEAN UP ### From 1742927751de68ef52869a1fbeb10d9e84b622ea Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 23 Feb 2022 11:12:32 -0800 Subject: [PATCH 099/229] Split port data tests into individual tests --- .../tests/18_port_data_16mux_1rw_1r_test.py | 50 ++++++++++++++++++ compiler/tests/18_port_data_16mux_test.py | 52 +++++++++++++++++++ .../tests/18_port_data_2mux_1rw_1r_test.py | 49 +++++++++++++++++ compiler/tests/18_port_data_2mux_test.py | 51 ++++++++++++++++++ .../tests/18_port_data_4mux_1rw_1r_test.py | 49 +++++++++++++++++ compiler/tests/18_port_data_4mux_test.py | 51 ++++++++++++++++++ ...st.py => 18_port_data_8mux_1rw_1r_test.py} | 29 ----------- ...data_test.py => 18_port_data_8mux_test.py} | 23 -------- .../tests/18_port_data_nomux_1rw_1r_test.py | 48 +++++++++++++++++ compiler/tests/18_port_data_nomux_test.py | 50 ++++++++++++++++++ 10 files changed, 400 insertions(+), 52 deletions(-) create mode 100755 compiler/tests/18_port_data_16mux_1rw_1r_test.py create mode 100755 compiler/tests/18_port_data_16mux_test.py create mode 100755 compiler/tests/18_port_data_2mux_1rw_1r_test.py create mode 100755 compiler/tests/18_port_data_2mux_test.py create mode 100755 compiler/tests/18_port_data_4mux_1rw_1r_test.py create mode 100755 compiler/tests/18_port_data_4mux_test.py rename compiler/tests/{18_port_data_1rw_1r_test.py => 18_port_data_8mux_1rw_1r_test.py} (58%) rename compiler/tests/{18_port_data_test.py => 18_port_data_8mux_test.py} (67%) create mode 100755 compiler/tests/18_port_data_nomux_1rw_1r_test.py create mode 100755 compiler/tests/18_port_data_nomux_test.py diff --git a/compiler/tests/18_port_data_16mux_1rw_1r_test.py b/compiler/tests/18_port_data_16mux_1rw_1r_test.py new file mode 100755 index 00000000..83a453d0 --- /dev/null +++ b/compiler/tests/18_port_data_16mux_1rw_1r_test.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class port_data_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + c = sram_config(word_size=4, + num_words=16) + + c.word_size=2 + c.num_words=128 + c.words_per_row=16 + factory.reset() + c.recompute_sizes() + debug.info(1, "Sixteen way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + a = factory.create("port_data", sram_config=c, port=1) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/18_port_data_16mux_test.py b/compiler/tests/18_port_data_16mux_test.py new file mode 100755 index 00000000..de0f2394 --- /dev/null +++ b/compiler/tests/18_port_data_16mux_test.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class port_data_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + + c = sram_config(word_size=4, + num_words=16, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) + + c.word_size=2 + c.num_words=128 + c.words_per_row=16 + factory.reset() + c.recompute_sizes() + debug.info(1, "Sixteen way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/18_port_data_2mux_1rw_1r_test.py b/compiler/tests/18_port_data_2mux_1rw_1r_test.py new file mode 100755 index 00000000..70e5e7df --- /dev/null +++ b/compiler/tests/18_port_data_2mux_1rw_1r_test.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class port_data_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + c = sram_config(word_size=4, + num_words=16) + + c.num_words=32 + c.words_per_row=2 + factory.reset() + c.recompute_sizes() + debug.info(1, "Two way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + a = factory.create("port_data", sram_config=c, port=1) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/18_port_data_2mux_test.py b/compiler/tests/18_port_data_2mux_test.py new file mode 100755 index 00000000..f9b8916c --- /dev/null +++ b/compiler/tests/18_port_data_2mux_test.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class port_data_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + + c = sram_config(word_size=4, + num_words=16, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) + + c.num_words=32 + c.words_per_row=2 + factory.reset() + c.recompute_sizes() + debug.info(1, "Two way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/18_port_data_4mux_1rw_1r_test.py b/compiler/tests/18_port_data_4mux_1rw_1r_test.py new file mode 100755 index 00000000..ddca3075 --- /dev/null +++ b/compiler/tests/18_port_data_4mux_1rw_1r_test.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class port_data_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + c = sram_config(word_size=4, + num_words=16) + + c.num_words=64 + c.words_per_row=4 + factory.reset() + c.recompute_sizes() + debug.info(1, "Four way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + a = factory.create("port_data", sram_config=c, port=1) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/18_port_data_4mux_test.py b/compiler/tests/18_port_data_4mux_test.py new file mode 100755 index 00000000..82cbe5d1 --- /dev/null +++ b/compiler/tests/18_port_data_4mux_test.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class port_data_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + + c = sram_config(word_size=4, + num_words=16, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) + + c.num_words=64 + c.words_per_row=4 + factory.reset() + c.recompute_sizes() + debug.info(1, "Four way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/18_port_data_1rw_1r_test.py b/compiler/tests/18_port_data_8mux_1rw_1r_test.py similarity index 58% rename from compiler/tests/18_port_data_1rw_1r_test.py rename to compiler/tests/18_port_data_8mux_1rw_1r_test.py index e42ac452..cc67c810 100755 --- a/compiler/tests/18_port_data_1rw_1r_test.py +++ b/compiler/tests/18_port_data_8mux_1rw_1r_test.py @@ -29,35 +29,6 @@ class port_data_1rw_1r_test(openram_test): c = sram_config(word_size=4, num_words=16) - c.words_per_row=1 - factory.reset() - c.recompute_sizes() - debug.info(1, "No column mux") - a = factory.create("port_data", sram_config=c, port=0) - self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) - self.local_check(a) - - c.num_words=32 - c.words_per_row=2 - factory.reset() - c.recompute_sizes() - debug.info(1, "Two way column mux") - a = factory.create("port_data", sram_config=c, port=0) - self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) - self.local_check(a) - - c.num_words=64 - c.words_per_row=4 - factory.reset() - c.recompute_sizes() - debug.info(1, "Four way column mux") - a = factory.create("port_data", sram_config=c, port=0) - self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) - self.local_check(a) - c.word_size=2 c.num_words=128 c.words_per_row=8 diff --git a/compiler/tests/18_port_data_test.py b/compiler/tests/18_port_data_8mux_test.py similarity index 67% rename from compiler/tests/18_port_data_test.py rename to compiler/tests/18_port_data_8mux_test.py index b9c7bcdb..ec669f02 100755 --- a/compiler/tests/18_port_data_test.py +++ b/compiler/tests/18_port_data_8mux_test.py @@ -33,29 +33,6 @@ class port_data_test(openram_test): num_spare_cols=num_spare_cols, num_spare_rows=num_spare_rows) - c.words_per_row=1 - factory.reset() - c.recompute_sizes() - debug.info(1, "No column mux") - a = factory.create("port_data", sram_config=c, port=0) - self.local_check(a) - - c.num_words=32 - c.words_per_row=2 - factory.reset() - c.recompute_sizes() - debug.info(1, "Two way column mux") - a = factory.create("port_data", sram_config=c, port=0) - self.local_check(a) - - c.num_words=64 - c.words_per_row=4 - factory.reset() - c.recompute_sizes() - debug.info(1, "Four way column mux") - a = factory.create("port_data", sram_config=c, port=0) - self.local_check(a) - c.word_size=2 c.num_words=128 c.words_per_row=8 diff --git a/compiler/tests/18_port_data_nomux_1rw_1r_test.py b/compiler/tests/18_port_data_nomux_1rw_1r_test.py new file mode 100755 index 00000000..67a6b6eb --- /dev/null +++ b/compiler/tests/18_port_data_nomux_1rw_1r_test.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class port_data_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + c = sram_config(word_size=4, + num_words=16) + + c.words_per_row=1 + factory.reset() + c.recompute_sizes() + debug.info(1, "No column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + a = factory.create("port_data", sram_config=c, port=1) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/18_port_data_nomux_test.py b/compiler/tests/18_port_data_nomux_test.py new file mode 100755 index 00000000..34298d8b --- /dev/null +++ b/compiler/tests/18_port_data_nomux_test.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class port_data_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + + c = sram_config(word_size=4, + num_words=16, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) + + c.words_per_row=1 + factory.reset() + c.recompute_sizes() + debug.info(1, "No column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From 744dfc5fa7472f1e1b5c730c7ddfd6b30ed7ab85 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 23 Feb 2022 13:04:53 -0800 Subject: [PATCH 100/229] Use older version of netgen --- docker/Dockerfile | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 5ac3b3d0..0ea64cae 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -97,18 +97,6 @@ RUN ../configure CXXFLAGS="-O3 -std=c++11" \ --prefix=/usr/local/Xyce/Parallel --enable-shared --enable-xyce-shareable RUN make -j 4 install - -### Magic ### -ARG MAGIC_COMMIT=8.3.260 -WORKDIR /root -RUN git clone https://github.com/RTimothyEdwards/magic.git magic -WORKDIR /root/magic -RUN git checkout ${MAGIC_COMMIT} -RUN ./configure \ - && make \ - && make install -RUN rm -rf /root/magic - ### Ngspice ### ARG NGSPICE_COMIT=032b1c32c4dbad45ff132bcfac1dbecadbd8abb0 WORKDIR /root @@ -122,7 +110,8 @@ RUN ./autogen.sh \ RUN rm -rf /root/ngspice ### Netgen ### -ARG NETGEN_COMMIT=1.5.219 +#ARG NETGEN_COMMIT=1.5.219 +ARG NETGEN_COMMIT=88d53fab15eb611cffc024eebf8743fae5cf8cb7 WORKDIR /root RUN git clone https://github.com/RTimothyEdwards/netgen.git netgen WORKDIR /root/netgen @@ -135,6 +124,19 @@ RUN rm -rf /root/netgen ### iVerilog ### RUN apt-get install --no-install-recommends -y iverilog +### Magic ### +ARG MAGIC_COMMIT=8.3.260 +#ARG MAGIC_COMMIT=8.3.254 +WORKDIR /root +RUN git clone https://github.com/RTimothyEdwards/magic.git magic +WORKDIR /root/magic +RUN git checkout ${MAGIC_COMMIT} +RUN ./configure \ + && make \ + && make install +RUN rm -rf /root/magic + + ### CLEAN UP ### # Remove development tools to save space RUN apt-get remove -y build-essential autoconf automake libtool bison flex tcl-dev tk-dev cmake From 6a295aeb38f91a88776fa32990a8251b8e1217cc Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 23 Feb 2022 13:05:03 -0800 Subject: [PATCH 101/229] Give feedback warnings in magic output --- compiler/verify/magic.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 8f9ece29..a9c2dc08 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -122,6 +122,8 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa if OPTS.tech_name=="sky130": f.write(pre + "extract style ngspice(si)\n") f.write(pre + "extract\n") + f.write(pre + "select top cell\n") + f.write(pre + "feedback why\n") f.write('puts "Finished extract"\n') # f.write(pre + "ext2spice hierarchy on\n") # f.write(pre + "ext2spice scale off\n") @@ -141,6 +143,8 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa # but they all seem compatible enough. f.write(pre + "ext2spice format ngspice\n") f.write(pre + "ext2spice {}\n".format(cell_name)) + f.write(pre + "select top cell\n") + f.write(pre + "feedback why\n") f.write('puts "Finished ext2spice"\n') f.write("quit -noprompt\n") From 5451a8d07a423cf12d13d04df6e260cea8060c37 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 23 Feb 2022 14:06:01 -0800 Subject: [PATCH 102/229] Don't make internal bus pins because magic will extract ports --- compiler/modules/hierarchical_decoder.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index d6dd77d2..f7b721f2 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -495,11 +495,11 @@ class hierarchical_decoder(design.design): if (self.num_inputs >= 4): # This leaves an offset for the predecoder output jogs input_bus_names = ["predecode_{0}".format(i) for i in range(self.total_number_of_predecoder_outputs)] - self.predecode_bus = self.create_vertical_pin_bus(layer=self.bus_layer, - pitch=self.bus_pitch, - offset=vector(self.bus_pitch, 0), - names=input_bus_names, - length=self.height) + self.predecode_bus = self.create_vertical_bus(layer=self.bus_layer, + pitch=self.bus_pitch, + offset=vector(self.bus_pitch, 0), + names=input_bus_names, + length=self.height) self.route_bus_to_decoder() self.route_predecodes_to_bus() From d4c14d7d19967e0b770900342e8b146e2ee26faf Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 23 Feb 2022 14:06:19 -0800 Subject: [PATCH 103/229] Add horizontal pin helper function --- compiler/base/hierarchy_layout.py | 33 +++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index c30408c7..d65fe17d 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -422,6 +422,35 @@ class layout(): for pin_name in self.pin_map.keys(): self.copy_layout_pin(instance, pin_name, prefix + pin_name) + def route_horizontal_pin(self, name): + """ + Route together all of the pins of a given name that horizontally align. + """ + bins = {} + + for i in range(len(self.local_insts)): + inst = self.local_insts[i] + for pin in inst.get_pins(name): + try: + bins[pin.cy()].append(pin) + except KeyError: + bins[pin.cy()] = [pin] + + for y, v in bins.items(): + left_x = min([x.lx() for x in v]) + right_x = max([x.rx() for x in v]) + + last_via = None + for pin in v: + last_via = self.add_via_stack_center(from_layer=pin.layer, + to_layer=self.supply_stack[0], + offset=pin.center()) + + self.add_layout_pin_segment_center(text=name, + layer=self.supply_stack[0], + start=vector(left_x, y), + end=vector(right_x, y)) + def add_layout_pin_segment_center(self, text, layer, start, end, width=None): """ Creates a path like pin with center-line convention @@ -450,8 +479,8 @@ class layout(): return self.add_layout_pin(text=text, layer=layer, offset=ll_offset, - width=bbox_width, - height=bbox_height) + width=max(bbox_width, layer_width), + height=max(bbox_height, layer_width)) def add_layout_pin_rect_center(self, text, layer, offset, width=None, height=None): """ Creates a path like pin with center-line convention """ From baf369fc966b27184046d8d475d9217971ef9a3c Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 23 Feb 2022 14:06:49 -0800 Subject: [PATCH 104/229] Convert power to rails rather than pins in sense amp and precharge --- compiler/modules/precharge_array.py | 3 ++- compiler/modules/sense_amp_array.py | 8 ++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index 4ff6930e..4de5259e 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -93,13 +93,14 @@ class precharge_array(design.design): self.add_via_stack_center(from_layer=en_pin.layer, to_layer=self.en_bar_layer, offset=inst.get_pin("en_bar").center()) - self.copy_layout_pin(inst, "vdd") + self.route_horizontal_pin("vdd") for i in range(len(self.local_insts)): inst = self.local_insts[i] self.copy_layout_pin(inst, "bl", "bl_{0}".format(i)) self.copy_layout_pin(inst, "br", "br_{0}".format(i)) + def create_insts(self): """Creates a precharge array by horizontally tiling the precharge cell""" self.local_insts = [] diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index fbfd0c5a..edda67f4 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -75,6 +75,8 @@ class sense_amp_array(design.design): self.width = self.local_insts[-1].rx() self.add_layout_pins() + self.route_horizontal_pin("vdd") + self.route_horizontal_pin("gnd") self.route_rails() self.add_boundary() @@ -150,12 +152,6 @@ class sense_amp_array(design.design): for i in range(len(self.local_insts)): inst = self.local_insts[i] - for gnd_pin in inst.get_pins("gnd"): - self.copy_power_pin(gnd_pin) - - for vdd_pin in inst.get_pins("vdd"): - self.copy_power_pin(vdd_pin) - bl_pin = inst.get_pin(inst.mod.get_bl_names()) br_pin = inst.get_pin(inst.mod.get_br_names()) dout_pin = inst.get_pin(inst.mod.dout_name) From 6389d4ac82c70cf8726b2b1a1e9622434500ece1 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 23 Feb 2022 15:31:15 -0800 Subject: [PATCH 105/229] Skip all func tests --- .../tests/07_column_mux_array_1rw_1r_test.py | 61 ------------------- ...> 07_column_mux_array_2mux_1rw_1r_test.py} | 17 +++--- .../tests/07_column_mux_array_2mux_test.py | 36 +++++++++++ ...py => 19_single_bank_nomux_1rw_1r_test.py} | 25 -------- ...k_test.py => 19_single_bank_nomux_test.py} | 36 +++-------- compiler/tests/Makefile | 14 +++++ 6 files changed, 69 insertions(+), 120 deletions(-) delete mode 100755 compiler/tests/07_column_mux_array_1rw_1r_test.py rename compiler/tests/{07_column_mux_array_test.py => 07_column_mux_array_2mux_1rw_1r_test.py} (78%) create mode 100755 compiler/tests/07_column_mux_array_2mux_test.py rename compiler/tests/{19_single_bank_1rw_1r_test.py => 19_single_bank_nomux_1rw_1r_test.py} (65%) rename compiler/tests/{19_single_bank_test.py => 19_single_bank_nomux_test.py} (61%) diff --git a/compiler/tests/07_column_mux_array_1rw_1r_test.py b/compiler/tests/07_column_mux_array_1rw_1r_test.py deleted file mode 100755 index d31e4fec..00000000 --- a/compiler/tests/07_column_mux_array_1rw_1r_test.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python3 -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2021 Regents of the University of California and The Board -# of Regents for the Oklahoma Agricultural and Mechanical College -# (acting for and on behalf of Oklahoma State University) -# All rights reserved. -# -from testutils import * -import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) -import globals -from globals import OPTS -from sram_factory import factory -import debug - - -class column_mux_test(openram_test): - - def runTest(self): - config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) - globals.init_openram(config_file) - - OPTS.num_rw_ports = 1 - OPTS.num_r_ports = 1 - OPTS.num_w_ports = 0 - globals.setup_bitcell() - - debug.info(1, "Testing sample for 2-way column_mux_array port 0") - a = factory.create(module_type="column_mux_array", columns=8, word_size=4, bitcell_bl="bl0", bitcell_br="br0") - self.local_check(a) - - debug.info(1, "Testing sample for 2-way column_mux_array port 1") - a = factory.create(module_type="column_mux_array", columns=8, word_size=4, bitcell_bl="bl1", bitcell_br="br1") - self.local_check(a) - - debug.info(1, "Testing sample for 4-way column_mux_array port 0") - a = factory.create(module_type="column_mux_array", columns=8, word_size=2, bitcell_bl="bl0", bitcell_br="br0") - self.local_check(a) - - debug.info(1, "Testing sample for 4-way column_mux_array port 1") - a = factory.create(module_type="column_mux_array", columns=8, word_size=2, bitcell_bl="bl1", bitcell_br="br1") - self.local_check(a) - - debug.info(1, "Testing sample for 8-way column_mux_array port 0") - a = factory.create(module_type="column_mux_array", columns=16, word_size=2, bitcell_bl="bl0", bitcell_br="br0") - self.local_check(a) - - debug.info(1, "Testing sample for 8-way column_mux_array port 1") - a = factory.create(module_type="column_mux_array", columns=16, word_size=2, bitcell_bl="bl1", bitcell_br="br1") - self.local_check(a) - - globals.end_openram() - - -# run the test from the command line -if __name__ == "__main__": - (OPTS, args) = globals.parse_args() - del sys.argv[1:] - header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/07_column_mux_array_test.py b/compiler/tests/07_column_mux_array_2mux_1rw_1r_test.py similarity index 78% rename from compiler/tests/07_column_mux_array_test.py rename to compiler/tests/07_column_mux_array_2mux_1rw_1r_test.py index a3bd8c39..10012e81 100755 --- a/compiler/tests/07_column_mux_array_test.py +++ b/compiler/tests/07_column_mux_array_2mux_1rw_1r_test.py @@ -21,16 +21,17 @@ class column_mux_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - debug.info(1, "Testing sample for 2-way column_mux_array") - a = factory.create(module_type="column_mux_array", columns=16, word_size=8) + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + debug.info(1, "Testing sample for 2-way column_mux_array port 0") + a = factory.create(module_type="column_mux_array", columns=8, word_size=4, bitcell_bl="bl0", bitcell_br="br0") self.local_check(a) - debug.info(1, "Testing sample for 4-way column_mux_array") - a = factory.create(module_type="column_mux_array", columns=16, word_size=4) - self.local_check(a) - - debug.info(1, "Testing sample for 8-way column_mux_array") - a = factory.create(module_type="column_mux_array", columns=32, word_size=4) + debug.info(1, "Testing sample for 2-way column_mux_array port 1") + a = factory.create(module_type="column_mux_array", columns=8, word_size=4, bitcell_bl="bl1", bitcell_br="br1") self.local_check(a) globals.end_openram() diff --git a/compiler/tests/07_column_mux_array_2mux_test.py b/compiler/tests/07_column_mux_array_2mux_test.py new file mode 100755 index 00000000..e8303c45 --- /dev/null +++ b/compiler/tests/07_column_mux_array_2mux_test.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class column_mux_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + debug.info(1, "Testing sample for 2-way column_mux_array") + a = factory.create(module_type="column_mux_array", columns=16, word_size=8) + self.local_check(a) + + globals.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/19_single_bank_1rw_1r_test.py b/compiler/tests/19_single_bank_nomux_1rw_1r_test.py similarity index 65% rename from compiler/tests/19_single_bank_1rw_1r_test.py rename to compiler/tests/19_single_bank_nomux_1rw_1r_test.py index 7c94d7a5..f165f991 100755 --- a/compiler/tests/19_single_bank_1rw_1r_test.py +++ b/compiler/tests/19_single_bank_nomux_1rw_1r_test.py @@ -38,31 +38,6 @@ class single_bank_1rw_1r_test(openram_test): a = factory.create(module_type="bank", sram_config=c) self.local_check(a) - c.num_words=32 - c.words_per_row=2 - factory.reset() - c.recompute_sizes() - debug.info(1, "Two way column mux") - a = factory.create(module_type="bank", sram_config=c) - self.local_check(a) - - c.num_words=64 - c.words_per_row=4 - factory.reset() - c.recompute_sizes() - debug.info(1, "Four way column mux") - a = factory.create(module_type="bank", sram_config=c) - self.local_check(a) - - c.word_size=2 - c.num_words=128 - c.words_per_row=8 - factory.reset() - c.recompute_sizes() - debug.info(1, "Eight way column mux") - a = factory.create(module_type="bank", sram_config=c) - self.local_check(a) - globals.end_openram() # run the test from the command line diff --git a/compiler/tests/19_single_bank_test.py b/compiler/tests/19_single_bank_nomux_test.py similarity index 61% rename from compiler/tests/19_single_bank_test.py rename to compiler/tests/19_single_bank_nomux_test.py index c8db9e2f..1df7103d 100755 --- a/compiler/tests/19_single_bank_test.py +++ b/compiler/tests/19_single_bank_nomux_test.py @@ -23,8 +23,17 @@ class single_bank_test(openram_test): globals.init_openram(config_file) from sram_config import sram_config + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=4, - num_words=16) + num_words=16, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=1 factory.reset() @@ -33,31 +42,6 @@ class single_bank_test(openram_test): a = factory.create("bank", sram_config=c) self.local_check(a) - c.num_words=32 - c.words_per_row=2 - factory.reset() - c.recompute_sizes() - debug.info(1, "Two way column mux") - a = factory.create("bank", sram_config=c) - self.local_check(a) - - c.num_words=64 - c.words_per_row=4 - factory.reset() - c.recompute_sizes() - debug.info(1, "Four way column mux") - a = factory.create("bank", sram_config=c) - self.local_check(a) - - c.word_size=2 - c.num_words=128 - c.words_per_row=8 - factory.reset() - c.recompute_sizes() - debug.info(1, "Eight way column mux") - a = factory.create("bank", sram_config=c) - self.local_check(a) - globals.end_openram() # run the test from the command line diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index a57b4478..494018da 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -45,6 +45,20 @@ BROKEN_STAMPS = \ sky130/22_psram_1bank_4mux_func_test.ok \ sky130/22_psram_1bank_8mux_func_test.ok \ sky130/22_psram_1bank_nomux_func_test.ok \ + %/22_psram_1bank_2mux_func_test.ok \ + %/22_psram_1bank_4mux_func_test.ok \ + %/22_psram_1bank_8mux_func_test.ok \ + %/22_psram_1bank_nomux_func_test.ok \ + %/22_sram_1bank_2mux_func_test.ok \ + %/22_sram_1bank_2mux_global_func_test.ok \ + %/22_sram_1bank_2mux_sparecols_func_test.ok \ + %/22_sram_1bank_4mux_func_test.ok \ + %/22_sram_1bank_8mux_func_test.ok \ + %/22_sram_1bank_nomux_1rw_1r_func_test.ok \ + %/22_sram_1bank_nomux_func_test.ok \ + %/22_sram_1bank_nomux_sparecols_func_test.ok \ + %/22_sram_1bank_wmask_1rw_1r_func_test.ok \ + %/22_sram_wmask_func_test.ok \ %/50_riscv_1k_1rw1r_func_test.ok \ %/50_riscv_1k_1rw_func_test.ok \ %/50_riscv_1rw1r_func_test.ok \ From 5376b5bf2010b3393cb7907a3229e57039be34cd Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 23 Feb 2022 15:38:11 -0800 Subject: [PATCH 106/229] Fix offset to center select signal between bitlines --- compiler/modules/column_mux_array.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/modules/column_mux_array.py b/compiler/modules/column_mux_array.py index 895ffca6..0fa35af0 100644 --- a/compiler/modules/column_mux_array.py +++ b/compiler/modules/column_mux_array.py @@ -173,14 +173,12 @@ class column_mux_array(design.design): sel_index = col % self.words_per_row # Add the column x offset to find the right select bit gate_offset = self.mux_inst[col].get_pin("sel").bc() - # height to connect the gate to the correct horizontal row - # sel_height = self.get_pin("sel_{}".format(sel_index)).by() # use the y offset from the sel pin and the x offset from the gate offset = vector(gate_offset.x, self.get_pin("sel_{}".format(sel_index)).cy()) - bl_offset = offset + vector((self.mux_inst[col].get_pin("br_out").bc().x - self.mux_inst[col].get_pin("bl_out").bc().x)/2, 0) + bl_offset = offset.scale(0, 1) + vector((self.mux_inst[col].get_pin("br_out").cx() + self.mux_inst[col].get_pin("bl_out").cx())/2, 0) self.add_via_stack_center(from_layer="poly", to_layer=self.sel_layer, offset=bl_offset, From 82c2bc329f3c9ff7fc7660517257504ebb774f1c Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 23 Feb 2022 15:39:32 -0800 Subject: [PATCH 107/229] Split bank and col mux tests. --- .../07_column_mux_array_16mux_1rw_1r_test.py | 45 ++++++++++++++++ .../tests/07_column_mux_array_16mux_test.py | 36 +++++++++++++ .../07_column_mux_array_4mux_1rw_1r_test.py | 45 ++++++++++++++++ .../tests/07_column_mux_array_4mux_test.py | 36 +++++++++++++ .../07_column_mux_array_8mux_1rw_1r_test.py | 45 ++++++++++++++++ .../tests/07_column_mux_array_8mux_test.py | 36 +++++++++++++ .../tests/19_single_bank_16mux_1rw_1r_test.py | 48 +++++++++++++++++ compiler/tests/19_single_bank_16mux_test.py | 54 +++++++++++++++++++ .../tests/19_single_bank_2mux_1rw_1r_test.py | 49 +++++++++++++++++ compiler/tests/19_single_bank_2mux_test.py | 44 +++++++++++++++ .../tests/19_single_bank_4mux_1rw_1r_test.py | 49 +++++++++++++++++ compiler/tests/19_single_bank_4mux_test.py | 44 +++++++++++++++ .../tests/19_single_bank_8mux_1rw_1r_test.py | 50 +++++++++++++++++ compiler/tests/19_single_bank_8mux_test.py | 54 +++++++++++++++++++ 14 files changed, 635 insertions(+) create mode 100755 compiler/tests/07_column_mux_array_16mux_1rw_1r_test.py create mode 100755 compiler/tests/07_column_mux_array_16mux_test.py create mode 100755 compiler/tests/07_column_mux_array_4mux_1rw_1r_test.py create mode 100755 compiler/tests/07_column_mux_array_4mux_test.py create mode 100755 compiler/tests/07_column_mux_array_8mux_1rw_1r_test.py create mode 100755 compiler/tests/07_column_mux_array_8mux_test.py create mode 100755 compiler/tests/19_single_bank_16mux_1rw_1r_test.py create mode 100755 compiler/tests/19_single_bank_16mux_test.py create mode 100755 compiler/tests/19_single_bank_2mux_1rw_1r_test.py create mode 100755 compiler/tests/19_single_bank_2mux_test.py create mode 100755 compiler/tests/19_single_bank_4mux_1rw_1r_test.py create mode 100755 compiler/tests/19_single_bank_4mux_test.py create mode 100755 compiler/tests/19_single_bank_8mux_1rw_1r_test.py create mode 100755 compiler/tests/19_single_bank_8mux_test.py diff --git a/compiler/tests/07_column_mux_array_16mux_1rw_1r_test.py b/compiler/tests/07_column_mux_array_16mux_1rw_1r_test.py new file mode 100755 index 00000000..9ef7da3e --- /dev/null +++ b/compiler/tests/07_column_mux_array_16mux_1rw_1r_test.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class column_mux_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + debug.info(1, "Testing sample for 16-way column_mux_array port 0") + a = factory.create(module_type="column_mux_array", columns=32, word_size=2, bitcell_bl="bl0", bitcell_br="br0") + self.local_check(a) + + debug.info(1, "Testing sample for 16-way column_mux_array port 1") + a = factory.create(module_type="column_mux_array", columns=32, word_size=2, bitcell_bl="bl1", bitcell_br="br1") + self.local_check(a) + + globals.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/07_column_mux_array_16mux_test.py b/compiler/tests/07_column_mux_array_16mux_test.py new file mode 100755 index 00000000..67a7f9a4 --- /dev/null +++ b/compiler/tests/07_column_mux_array_16mux_test.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class column_mux_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + debug.info(1, "Testing sample for 16-way column_mux_array") + a = factory.create(module_type="column_mux_array", columns=64, word_size=4) + self.local_check(a) + + globals.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/07_column_mux_array_4mux_1rw_1r_test.py b/compiler/tests/07_column_mux_array_4mux_1rw_1r_test.py new file mode 100755 index 00000000..96123cae --- /dev/null +++ b/compiler/tests/07_column_mux_array_4mux_1rw_1r_test.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class column_mux_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + debug.info(1, "Testing sample for 4-way column_mux_array port 0") + a = factory.create(module_type="column_mux_array", columns=8, word_size=2, bitcell_bl="bl0", bitcell_br="br0") + self.local_check(a) + + debug.info(1, "Testing sample for 4-way column_mux_array port 1") + a = factory.create(module_type="column_mux_array", columns=8, word_size=2, bitcell_bl="bl1", bitcell_br="br1") + self.local_check(a) + + globals.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/07_column_mux_array_4mux_test.py b/compiler/tests/07_column_mux_array_4mux_test.py new file mode 100755 index 00000000..655bda54 --- /dev/null +++ b/compiler/tests/07_column_mux_array_4mux_test.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class column_mux_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + debug.info(1, "Testing sample for 4-way column_mux_array") + a = factory.create(module_type="column_mux_array", columns=16, word_size=4) + self.local_check(a) + + globals.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/07_column_mux_array_8mux_1rw_1r_test.py b/compiler/tests/07_column_mux_array_8mux_1rw_1r_test.py new file mode 100755 index 00000000..9f85e3ac --- /dev/null +++ b/compiler/tests/07_column_mux_array_8mux_1rw_1r_test.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class column_mux_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + debug.info(1, "Testing sample for 8-way column_mux_array port 0") + a = factory.create(module_type="column_mux_array", columns=16, word_size=2, bitcell_bl="bl0", bitcell_br="br0") + self.local_check(a) + + debug.info(1, "Testing sample for 8-way column_mux_array port 1") + a = factory.create(module_type="column_mux_array", columns=16, word_size=2, bitcell_bl="bl1", bitcell_br="br1") + self.local_check(a) + + globals.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/07_column_mux_array_8mux_test.py b/compiler/tests/07_column_mux_array_8mux_test.py new file mode 100755 index 00000000..eab6560a --- /dev/null +++ b/compiler/tests/07_column_mux_array_8mux_test.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class column_mux_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + debug.info(1, "Testing sample for 8-way column_mux_array") + a = factory.create(module_type="column_mux_array", columns=32, word_size=4) + self.local_check(a) + + globals.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/19_single_bank_16mux_1rw_1r_test.py b/compiler/tests/19_single_bank_16mux_1rw_1r_test.py new file mode 100755 index 00000000..6133ccad --- /dev/null +++ b/compiler/tests/19_single_bank_16mux_1rw_1r_test.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class single_bank_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + c = sram_config(word_size=2, + num_words=128) + + c.words_per_row=16 + factory.reset() + c.recompute_sizes() + debug.info(1, "Sixteen way column mux") + a = factory.create(module_type="bank", sram_config=c) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/19_single_bank_16mux_test.py b/compiler/tests/19_single_bank_16mux_test.py new file mode 100755 index 00000000..010703a9 --- /dev/null +++ b/compiler/tests/19_single_bank_16mux_test.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class single_bank_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + + c = sram_config(word_size=4, + num_words=16, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) + + c.word_size=2 + c.num_words=128 + c.words_per_row=16 + factory.reset() + c.recompute_sizes() + debug.info(1, "Sixteen way column mux") + a = factory.create("bank", sram_config=c) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/19_single_bank_2mux_1rw_1r_test.py b/compiler/tests/19_single_bank_2mux_1rw_1r_test.py new file mode 100755 index 00000000..15664c81 --- /dev/null +++ b/compiler/tests/19_single_bank_2mux_1rw_1r_test.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class single_bank_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + c = sram_config(word_size=4, + num_words=16) + + c.num_words=32 + c.words_per_row=2 + factory.reset() + c.recompute_sizes() + debug.info(1, "Two way column mux") + a = factory.create(module_type="bank", sram_config=c) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/19_single_bank_2mux_test.py b/compiler/tests/19_single_bank_2mux_test.py new file mode 100755 index 00000000..d29de4e6 --- /dev/null +++ b/compiler/tests/19_single_bank_2mux_test.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class single_bank_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + c = sram_config(word_size=4, + num_words=16) + + c.num_words=32 + c.words_per_row=2 + factory.reset() + c.recompute_sizes() + debug.info(1, "Two way column mux") + a = factory.create("bank", sram_config=c) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/19_single_bank_4mux_1rw_1r_test.py b/compiler/tests/19_single_bank_4mux_1rw_1r_test.py new file mode 100755 index 00000000..9518373c --- /dev/null +++ b/compiler/tests/19_single_bank_4mux_1rw_1r_test.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class single_bank_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + c = sram_config(word_size=4, + num_words=16) + + c.num_words=64 + c.words_per_row=4 + factory.reset() + c.recompute_sizes() + debug.info(1, "Four way column mux") + a = factory.create(module_type="bank", sram_config=c) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/19_single_bank_4mux_test.py b/compiler/tests/19_single_bank_4mux_test.py new file mode 100755 index 00000000..77459ff9 --- /dev/null +++ b/compiler/tests/19_single_bank_4mux_test.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class single_bank_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + c = sram_config(word_size=4, + num_words=16) + + c.num_words=64 + c.words_per_row=4 + factory.reset() + c.recompute_sizes() + debug.info(1, "Four way column mux") + a = factory.create("bank", sram_config=c) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/19_single_bank_8mux_1rw_1r_test.py b/compiler/tests/19_single_bank_8mux_1rw_1r_test.py new file mode 100755 index 00000000..11b74350 --- /dev/null +++ b/compiler/tests/19_single_bank_8mux_1rw_1r_test.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class single_bank_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + c = sram_config(word_size=4, + num_words=16) + + c.word_size=2 + c.num_words=128 + c.words_per_row=8 + factory.reset() + c.recompute_sizes() + debug.info(1, "Eight way column mux") + a = factory.create(module_type="bank", sram_config=c) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/19_single_bank_8mux_test.py b/compiler/tests/19_single_bank_8mux_test.py new file mode 100755 index 00000000..1317fd61 --- /dev/null +++ b/compiler/tests/19_single_bank_8mux_test.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class single_bank_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + + c = sram_config(word_size=4, + num_words=16, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) + + c.word_size=2 + c.num_words=128 + c.words_per_row=8 + factory.reset() + c.recompute_sizes() + debug.info(1, "Eight way column mux") + a = factory.create("bank", sram_config=c) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From 12a6f1f2ee54f89b19c847087d0c5f334abd86d2 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 25 Feb 2022 10:44:40 -0800 Subject: [PATCH 108/229] Add missing well tap --- .../scn4m_subm/gds_lib/write_driver.gds | Bin 10204 -> 10404 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/technology/scn4m_subm/gds_lib/write_driver.gds b/technology/scn4m_subm/gds_lib/write_driver.gds index 9e201f2402bc21fcd17da3b25c62a80d3ffc20b1..c9431117748f7e5a288f06759fd81cb2dd7263d7 100644 GIT binary patch literal 10404 zcmbW7PmGmU8OGnv3^N1X;(&#M#W;-`YNap*Os85~lvU=yfx#8(AzWKz_ zzyI~_lh0n?clD1iem!<=X!xf`{Zq3M)AvurqcOdCA|m$8O}_WuztfA&`T-@TH4)4JNz^zXjyexzUR?e)XD+B58b zY!E-d5|9Bz&rggFO&)kZ5@oEHo>3GEExdE+Cfkap8g0h@C^UE;jv--b+8_KXNhagVx2SfBRbcA5tG?W+P1N z;;?_u@chkQiTLSC1bpLf5%)hopmnkIGylswa{f+V%keX2T51}V?{napSZdFh{6 zig-bNhRpXi)nQr}OF#L_JVWMvr-stBJ~sa&W%IgVx2S|6|wE|A|L3zG+=-`e`%qDZk;ufY!y*|9`9>3nTff zabNvcj{omo%lM{saX9{nf0O!5If(B=*9WxT^3R=4Kg7?toA~?B%lPEYZ>O^Tmo8`f zP3vOmr`?o;_-Marz2&EUl!N$aziGYYr~N;8KHGo(cDCQNE;idwIogkp_M6sQ{<+f` zAL66^CjS2OX8aTK5dS+DGrnnEEd5i;`7dew;9-s5^q~Q*i=}_l-Sk8J9j#v`{{HjQ zzhxo)5Z~4t1LE&LFa50hdzH6vp_BbEt&63fb(eAwAMG`*xBMTzntq6n_L}(n&&&AR z?nLZc(|22Zd@tg9A?snATf<@}6=K zANvo}ddpAVy&jo=KU>ZGGp&om{ogzM{biqdWhwWY@2qEh)4JI7bIx-;><92c>tpA? zk@%c9ex*J@&W)RI4`^L1<1=n=9nbM2F5_of7n}Y|3+bmkYldlEEd9KHzf@l#?WO&u zb+PIH#i8_5ep>%Ft&63f{O{^7q&$Apx>)*|x8*xIf1JCSH`BUU`Z@n`PV1cmRS$lA z(7IUqnRm)V;xc}w^;Ud*#Bn|313qZI6`yv0PHlBR7)N~2x>&Y<=2pZrY6Ill$vR?M z7fV0q-52DA_*h3w>tgBebR)icDA#Su<2S8~P5+TQ>8CvHFs+NFpL6rE`8+=}ZXS1N zT`c{4?~X=(_b6{4v@Vu@`v08b!Xxs~f77~H`kA*cT+jJqzF1F9>tg9AZ=Sf2`9r>N zelo3#rJwiY;8MOX#3R0GT`c{~7v&-SrT?aNvFU$GFfi>F;zS9?_UVe!pWJOzUFl-+Ckc5FhV@iNF86 z^b>ctV!9pp@j>fi=_lWa0qHOKWLg(XKXKXfxE=JLxX`*-`ia5sRS=)s4Xul%pZzj( z1&PP{Z(0|J{riUZFYFgD-OGLB>c#y1!?Z4ze$KyL{e?fjkmG1t7fV0=K6*3z|COce zziC};`ai#%{-@M`#?7=YmVUldi-+=i^`ype>RNd1o1O)4EvtJKfAV z$h+Iin?A|K{_|n~{^9wf%pX>>j(6s>4%50=`Z+iKelgEaZ{N&y$h0n&e%h@4aj)&( zH=EYQ($Btw-x(mkJCMJo^|9X{M*7cKAC@2TyCeB*S{KXstoN*Ukad&uhiP4G`q}g1 z=iH3nv_5uz9%+B4o9_%{FUkCytV#Xn!|@;Q&;P->$=olk$h&b__YnU`US3I`>F476 z)uVg3e1DmD-eb-$tRbd#vFRrse#-McnAXMGKR^0AJbrwz_#NKkknNZM<+Xf|y?-~Y zi)DP~k2sL`hIPrbK6Vc<5}$8|&pU4&&wC8h`q(*W#7|uA>!9xsOzUI!cq9G?SJDrO z$32>fzyG}1|FgF;KIQS7*2U7laXI(>ko${HcR=>F{pY2helt&yc#OYky)}Q-e`4Xk zaeDO-m-?)WW&FwY+_yvSKX?aC_VfMcrJr?>`w~dJ-n!PO^|5=Dk@;gCCJyxdi)mdf z@3=i$pRe1GkMoM_VLk7i zXGH5`=a`ZB#9`fs?BB_E)4EuWAM-{(A?2Ar)A|SXpK`PxAMs7=E&rB#gZ)0|2kwr{ z;v6v2f9{`jPU_u5QGWa!)qh_0pMB7NjX$Iw{HArW^i%)t+Zmto_)Y6#>1Q9qeI3Nd ze%7=;c8@pGfA$TOgP&C&7*ErB%TN11)y?+PUgDe9#j^eQAJSjQ{UQA~t&63fesg~a ziAQ|X`q(|>|MZ_Y^q;u&-?ZL}&-+FkNdD|t9MF0zKK;hyaUec%p>?tBKR(ucxb04Q zOzUFlXS~?E!%cT{98BwC&)?CuLjMm*S1!~3qY!}QMSQ|Csa92nkhv%6za>tnl&5kFtK*B0|D_r_9wWlig18NbubuM_mw(d4Vu ze_r}IT^&|A=+)JlehZ)-csvg(@!?xcXpZ9#nMl9@CP!7)MHu~d;WfwX#59R z((~Vp*`3oT&zx(N<127rm2$6~JJ~2lhCh4bgUeB$c4VsW)swCII6Zv3S6{mvdGzO5 xvi-Z?uY1c`reErOU5dBt^wN literal 10204 zcmai)Pi!4m6~<3($8pMQaYB7^GevdjjR@AuC8^yW=;ZxUHQ=bQP?Irq=Z z+&hyPkC7OS>4!$*&6v>N1Mx)c*YBM;s3TK4HaRl>=JMrVUp#+d`SKeVm*cU~T`zp| z-Dl7I=i|H2y>$Ed+CN|YK}_$e_{WF+V-peMkBr2VG5+XCL>!$Q{p6GXtw)^QiI~=p zd1W(oQ~KE6h@xMydVcfBR{BlpP5%?^{8u*9Z+^I%ep7nYe`G8D=Gh&$%XJL-pBm(k zcxWZ!-EPEV3j@Bdg3(PKZ|1+xfAwzq&EL$X-;`eT@7|1fbuHr2$pOzVM4+2GUi6PF zM!e9k-#k4Pfo@7K`eP&FDdjuV;K>zrfc|ajc-8;py@=0Tk1&bnxKMi4e_&nhoro|W zSMB&r=}rI9_V_KSy^NoE=~ni?DZS`-Khyv8HzW?aDZS_)QLV42_Wkmhj3>G&z38WI z#_f=rY%*@>W^4S0+D|`CAI|YJzjRx{q?^)<`Q6X-Km84fwN~=|%sZrHFI05uNUU#6dT8yyzd@ ziTM6%&VTdA>JM~NdeuL#^AD=e%x_;$zbU=wXPzC~j+mMo@I>VNGj+V`KdO9t@9BZi zC-EE?O0W7qcPsOoUz|z5DZT2a_FZpf3`iXEnmXR}&koJMorsnHrr-SA+u47n^rHV^ z)r#*^w+F{5LNi&G~OiFZ!8(_?UktK6JC@XP)C@-kbQ)&6=Nf|L`w4f6X6F zXMdQ|%k|$)f2TVjKIVg2^E2M$W&WD@(9N2kbr;v)f%O5I_vq$>=KtqE%J!OHcqYf+ zlwNE<^Bf=THSwXFH9zwlAMG{qp_?^7^Bf=R2NNH<+43K2K0jIStuChD{9q^7fu{6k z`|tC!f0|g${SzdP)lXi=$s~^B!dian{F-W~zf9t| zUH#+5{JS?JUQ`aQcawb|x+%TrXTSN1&gFVH@ipHENH6+3-H7kar{5$Fx+%TtKfRs# zOyW2$lwS0+Pd$4$``@Jh&`s$@KhLc*k$#gn=%)0dpZdO|T=buLdOPbkr5F8-(>HGC z^VVb>J+A%ZML+Z7*|+lfZ!(WOulmP}ey*Em7Bjy|9q6X?qMv!fd9>f8AJ9$dRsZud z>i?+-lQ@nGr5F8-6Ya%s5(nLsUi5R{It?fbA9mcmcBQ+mV4JtpVEu|PB-Ts^M^Uun@2M_f7rwHk2n1%n&XG(A1itN zn;)olbW?iK&pzkxb9uip-`~jnk14(Ar^a_8=bQQ4em$o2qM!8z?+uv0ChrZ<&DQ&a zq4xLoDe^OqPxZ-rKXg-iF+cZx?sx1TOzxZLru3?xwJ&~?eJ_5qwf`NezthcYhjHf` zf~+0UP3g`2PdCS(>x^;YS~uBupqtXG{+riwzM8~wTqwQlKb-HaneV*EhQ#6eF-*P`|Df86kMB<=b)cIyKY6Zfrr#uv>*^mb_TQeRT&H%r z1M=Mf-E8e2hUzCi<4*fc>gea~@j>H%ZZ^+1SvR{bD7{$!=uWQxxz<>>Lw|QLTkHR! z`nmt{-Gcj-Nge2B>-)u!pZhO)d3KoOMK^2tsh{u8_)X%tUH#+L_Ve9@cALa;T-f@4 za$o)IGkW<=d8nT_JsvLiKgWCf7TvE+;`Mz!w)QVW`N_+Dp80OFZbvtz7u(M`(Qd}i zBo4ayp!VY_e~~o&`s&Z_H&;;5&7&f ziGyxRFZ#)IWGnq9anMcaML+8lzMHXLHSwXFt?y?;?PuM9kNz^hs@l=bnx8tq+|B$Z z?QpyL$BXrI{Biy8>^A+~&XivC(@wtA(SDOU&`s$@KkXzh?KjDbZr1X%P9pEr+z@8!sV-#^LQSdT;aUe zuU@E}$DDuZ&V$b*p4NPd_r`@BXy`$2|P^M2sIA|Jg6ft!0Y1_lKd0%dumAu6 From 7b773789273b80c82fe4c70abd6ec01260d63ca9 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 25 Feb 2022 10:45:25 -0800 Subject: [PATCH 109/229] Add layer to horizontal pin help and use in precharge --- compiler/base/hierarchy_layout.py | 20 ++++++++++++++++---- compiler/modules/precharge_array.py | 24 +++++++++++++----------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index d65fe17d..5adc163a 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -422,10 +422,12 @@ class layout(): for pin_name in self.pin_map.keys(): self.copy_layout_pin(instance, pin_name, prefix + pin_name) - def route_horizontal_pin(self, name): + def route_horizontal_pin(self, name, layer=None): """ Route together all of the pins of a given name that horizontally align. """ + + bins = {} for i in range(len(self.local_insts)): @@ -442,14 +444,24 @@ class layout(): last_via = None for pin in v: + if layer: + pin_layer = layer + else: + pin_layer = self.supply_stack[0] last_via = self.add_via_stack_center(from_layer=pin.layer, - to_layer=self.supply_stack[0], + to_layer=pin_layer, offset=pin.center()) + if last_via: + via_height=last_via.mod.second_layer_height + else: + via_height=None + self.add_layout_pin_segment_center(text=name, - layer=self.supply_stack[0], + layer=pin_layer, start=vector(left_x, y), - end=vector(right_x, y)) + end=vector(right_x, y), + width=via_height) def add_layout_pin_segment_center(self, text, layer, start, end, width=None): """ diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index 4de5259e..ff2801f5 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -81,18 +81,20 @@ class precharge_array(design.design): def add_layout_pins(self): - en_pin = self.pc_cell.get_pin("en_bar") - start_offset = en_pin.lc().scale(0, 1) - end_offset = start_offset + vector(self.width, 0) - self.add_layout_pin_segment_center(text="en_bar", - layer=self.en_bar_layer, - start=start_offset, - end=end_offset) +# en_pin = self.pc_cell.get_pin("en_bar") +# start_offset = en_pin.lc().scale(0, 1) +# end_offset = start_offset + vector(self.width, 0) +# self.add_layout_pin_segment_center(text="en_bar", +# layer=self.en_bar_layer, +# start=start_offset, +# end=end_offset) - for inst in self.local_insts: - self.add_via_stack_center(from_layer=en_pin.layer, - to_layer=self.en_bar_layer, - offset=inst.get_pin("en_bar").center()) +# for inst in self.local_insts: +# self.add_via_stack_center(from_layer=en_pin.layer, +# to_layer=self.en_bar_layer, +# offset=inst.get_pin("en_bar").center()) + + self.route_horizontal_pin("en_bar", layer=self.en_bar_layer) self.route_horizontal_pin("vdd") for i in range(len(self.local_insts)): From 9b90a44d4a9447b391f8e1c8ccb34d205ba233b4 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 25 Feb 2022 16:20:47 -0800 Subject: [PATCH 110/229] Move output in freepdk45 sense amp down to prevent router conflict with supply --- technology/freepdk45/gds_lib/sense_amp.gds | Bin 14318 -> 14318 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/technology/freepdk45/gds_lib/sense_amp.gds b/technology/freepdk45/gds_lib/sense_amp.gds index edff18ab758dbd712a4b7cae6bdb3703ee1307e5..da3fcc4aadc12da6270362f04d48fcb65610ad1d 100644 GIT binary patch delta 166 zcmaEt|1MvNfsKKQDS|w%9H#M#SBYUZL?5FpL?4WXi8IXJoMhI+2mtf4 B7)t;E delta 166 zcmaEt|1MvNfsKKQDS| Date: Fri, 25 Feb 2022 16:21:12 -0800 Subject: [PATCH 111/229] Remove commented code in precharge array --- compiler/modules/precharge_array.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index ff2801f5..be64b7cf 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -81,19 +81,6 @@ class precharge_array(design.design): def add_layout_pins(self): -# en_pin = self.pc_cell.get_pin("en_bar") -# start_offset = en_pin.lc().scale(0, 1) -# end_offset = start_offset + vector(self.width, 0) -# self.add_layout_pin_segment_center(text="en_bar", -# layer=self.en_bar_layer, -# start=start_offset, -# end=end_offset) - -# for inst in self.local_insts: -# self.add_via_stack_center(from_layer=en_pin.layer, -# to_layer=self.en_bar_layer, -# offset=inst.get_pin("en_bar").center()) - self.route_horizontal_pin("en_bar", layer=self.en_bar_layer) self.route_horizontal_pin("vdd") From 8b4ef9b6c1b9caa0abcb199cfeea544907d4b5a0 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 28 Feb 2022 09:11:09 -0800 Subject: [PATCH 112/229] Upgrade to newest magic bug fixes --- docker/Dockerfile | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 0ea64cae..10a6e1ca 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -113,7 +113,8 @@ RUN rm -rf /root/ngspice #ARG NETGEN_COMMIT=1.5.219 ARG NETGEN_COMMIT=88d53fab15eb611cffc024eebf8743fae5cf8cb7 WORKDIR /root -RUN git clone https://github.com/RTimothyEdwards/netgen.git netgen +#RUN git clone https://github.com/RTimothyEdwards/netgen.git netgen +RUN git clone git://opencircuitdesign.com/netgen netgen WORKDIR /root/netgen RUN git checkout ${NETGEN_COMMIT} RUN ./configure \ @@ -125,10 +126,11 @@ RUN rm -rf /root/netgen RUN apt-get install --no-install-recommends -y iverilog ### Magic ### -ARG MAGIC_COMMIT=8.3.260 -#ARG MAGIC_COMMIT=8.3.254 +#ARG MAGIC_COMMIT=db4fa65bfc096e63954b37b188ea27b90ab31839 +ARG MAGIC_COMMIT=8.3.273 WORKDIR /root -RUN git clone https://github.com/RTimothyEdwards/magic.git magic +#RUN git clone https://github.com/RTimothyEdwards/magic.git magic +RUN git clone git://opencircuitdesign.com/magic magic WORKDIR /root/magic RUN git checkout ${MAGIC_COMMIT} RUN ./configure \ From 54bd022efc83de17cc3d90dfbacf2afd19c2a84d Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 28 Feb 2022 11:36:10 -0800 Subject: [PATCH 113/229] Rework precharge route supply horizontally --- compiler/base/hierarchy_layout.py | 13 ++++++------ compiler/pgates/precharge.py | 35 +++++++++++++------------------ 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 5adc163a..0ff95483 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -434,23 +434,24 @@ class layout(): inst = self.local_insts[i] for pin in inst.get_pins(name): try: - bins[pin.cy()].append(pin) + bins[pin.cy()].append((inst,pin)) except KeyError: - bins[pin.cy()] = [pin] + bins[pin.cy()] = [(inst,pin)] for y, v in bins.items(): - left_x = min([x.lx() for x in v]) - right_x = max([x.rx() for x in v]) + left_x = min([inst.lx() for (inst,pin) in v]) + right_x = max([inst.rx() for (inst,pin) in v]) last_via = None - for pin in v: + for inst,pin in v: if layer: pin_layer = layer else: pin_layer = self.supply_stack[0] last_via = self.add_via_stack_center(from_layer=pin.layer, to_layer=pin_layer, - offset=pin.center()) + offset=pin.center(), + min_area=True) if last_via: via_height=last_via.mod.second_layer_height diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index 2042dc7c..aa1f1a70 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -71,7 +71,7 @@ class precharge(design.design): self.connect_poly() self.route_en() self.place_nwell_and_contact() - self.route_vdd_rail() + self.route_vdd() self.route_bitlines() self.connect_to_bitlines() self.add_boundary() @@ -91,34 +91,29 @@ class precharge(design.design): mults=self.ptx_mults, tx_type="pmos") - def route_vdd_rail(self): + def route_vdd(self): """ Adds a vdd rail at the top of the cell """ - # Adds the rail across the width of the cell - vdd_position = vector(0.5 * self.width, self.height) - layer_width = drc("minwidth_" + self.en_layer) - self.add_rect_center(layer=self.en_layer, - offset=vdd_position, - width=self.width, - height=layer_width) - pmos_pin = self.upper_pmos2_inst.get_pin("S") - - # center of vdd rail - pmos_vdd_pos = vector(pmos_pin.cx(), vdd_position.y) - self.add_path(self.en_layer, [pmos_pin.center(), pmos_vdd_pos]) - - self.add_power_pin("vdd", - self.well_contact_pos, - directions=("V", "V")) + pmos_pos = pmos_pin.center() + self.add_path(pmos_pin.layer, [pmos_pos, self.well_contact_pos]) self.add_via_stack_center(from_layer=pmos_pin.layer, - to_layer=self.en_layer, - offset=pmos_pin.center(), + to_layer=self.supply_stack[0], + offset=self.well_contact_pos, directions=("V", "V")) + self.add_min_area_rect_center(layer=self.en_layer, + offset=self.well_contact_pos, + width=self.well_contact.mod.second_layer_width) + + self.add_layout_pin_rect_center(text="vdd", + layer=self.supply_stack[0], + offset=self.well_contact_pos) + + def create_ptx(self): """ Create both the upper_pmos and lower_pmos to the module From 27b4d2edb1499eca6fe090095f7e9f471fd24bd1 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 28 Feb 2022 11:53:24 -0800 Subject: [PATCH 114/229] Add 16 way mux SRAM tests --- .../tests/20_sram_1bank_16mux_1rw_1r_test.py | 56 +++++++++++++++++++ compiler/tests/20_sram_1bank_16mux_test.py | 50 +++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100755 compiler/tests/20_sram_1bank_16mux_1rw_1r_test.py create mode 100755 compiler/tests/20_sram_1bank_16mux_test.py diff --git a/compiler/tests/20_sram_1bank_16mux_1rw_1r_test.py b/compiler/tests/20_sram_1bank_16mux_1rw_1r_test.py new file mode 100755 index 00000000..072a3f8d --- /dev/null +++ b/compiler/tests/20_sram_1bank_16mux_1rw_1r_test.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class sram_1bank_8mux_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + c = sram_config(word_size=2, + num_words=256, + num_banks=1) + + c.words_per_row=16 + c.recompute_sizes() + debug.info(1, "Layout test for {}rw,{}r,{}w sram " + "with {} bit words, {} words, {} words per " + "row, {} banks".format(OPTS.num_rw_ports, + OPTS.num_r_ports, + OPTS.num_w_ports, + c.word_size, + c.num_words, + c.words_per_row, + c.num_banks)) + a = factory.create(module_type="sram", sram_config=c) + self.local_check(a, final_verification=True) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_sram_1bank_16mux_test.py b/compiler/tests/20_sram_1bank_16mux_test.py new file mode 100755 index 00000000..66d13869 --- /dev/null +++ b/compiler/tests/20_sram_1bank_16mux_test.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class sram_1bank_8mux_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + c = sram_config(word_size=2, + num_words=256, + num_banks=1) + + c.words_per_row=16 + c.recompute_sizes() + debug.info(1, "Layout test for {}rw,{}r,{}w sram " + "with {} bit words, {} words, {} words per " + "row, {} banks".format(OPTS.num_rw_ports, + OPTS.num_r_ports, + OPTS.num_w_ports, + c.word_size, + c.num_words, + c.words_per_row, + c.num_banks)) + a = factory.create(module_type="sram", sram_config=c) + self.local_check(a, final_verification=True) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From 184888b3709219c4b6efb143b8d9c2a7252edaa9 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 28 Feb 2022 12:03:01 -0800 Subject: [PATCH 115/229] Skip 16 way test for now --- compiler/tests/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 494018da..201bf94e 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -36,6 +36,8 @@ BROKEN_STAMPS = \ sky130/19_pmulti_bank_test.ok \ sky130/19_psingle_bank_test.ok \ sky130/19_bank_select_pbitcell_test.ok \ + %/20_sram_1bank_16mux_1rw_1w_test.ok \ + %/20_sram_1bank_16mux_test.ok \ sky130/20_psram_1bank_2mux_1rw_1w_test.ok \ sky130/20_psram_1bank_2mux_1rw_1w_wmask_test.ok \ sky130/20_psram_1bank_2mux_1w_1r_test.ok \ From c223c1ad1c6ec6bc8a54ad5916a73309dd0b5ed6 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 1 Mar 2022 10:33:40 -0800 Subject: [PATCH 116/229] Run docker pull before running all tests for regression --- compiler/tests/Makefile | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 201bf94e..ac377176 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -36,12 +36,14 @@ BROKEN_STAMPS = \ sky130/19_pmulti_bank_test.ok \ sky130/19_psingle_bank_test.ok \ sky130/19_bank_select_pbitcell_test.ok \ + %/19_single_bank_16mux_1rw_1r_test.ok \ + %/19_single_bank_16mux_test.ok \ %/20_sram_1bank_16mux_1rw_1w_test.ok \ %/20_sram_1bank_16mux_test.ok \ - sky130/20_psram_1bank_2mux_1rw_1w_test.ok \ - sky130/20_psram_1bank_2mux_1rw_1w_wmask_test.ok \ - sky130/20_psram_1bank_2mux_1w_1r_test.ok \ - sky130/20_psram_1bank_2mux_test.ok \ + %/20_psram_1bank_2mux_1rw_1w_test.ok \ + %/20_psram_1bank_2mux_1rw_1w_wmask_test.ok \ + %/20_psram_1bank_2mux_1w_1r_test.ok \ + %/20_psram_1bank_2mux_test.ok \ sky130/20_psram_1bank_4mux_1rw_1r_test.ok \ sky130/22_psram_1bank_2mux_func_test.ok \ sky130/22_psram_1bank_4mux_func_test.ok \ @@ -85,13 +87,13 @@ WORKING_TECH_TEST_STAMPS=$(filter-out $(BROKEN_STAMPS), $(TECH_TEST_STAMPS)) # Run all technologies -all: $(WORKING_TECH_TEST_STAMPS) +all: docker-pull $(WORKING_TECH_TEST_STAMPS) @ls -1 $(TOP_DIR)/compiler/tests/results/*/*.bad 1> /dev/null 2>&1 && echo "FAILING TESTS" && ls -1 $(TOP_DIR)/compiler/tests/results/*/*.bad | sed -e "s#^.*results\/##" && exit 1 || exit 0 .PHONY: all # Run a given technology # e.g. make freepdk45 -$(TECHS): +$(TECHS): docker-pull @$(MAKE) --no-print-directory $(filter-out $(BROKEN_STAMPS), $(addprefix $@/, $(TEST_STAMPS))) .PHONY: $(TECHS) @@ -102,7 +104,7 @@ $(TEST_BASES): .PHONY: $(TEST_BASES) # To run a test in a given technology -%.ok: +%.ok: # @echo "Running $(gettech) $(getfile) ... " @rm -rf results/$* @rm -rf results/$*.* @@ -117,13 +119,17 @@ $(TEST_BASES): -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \ --user $(UID):$(GID) \ -e OPENRAM_TMP=$(OPENRAM_DIR)/results/$*/tmp \ - vlsida/openram-ubuntu:latest \ + vlsida/openram-ubuntu:latest \ sh -c ". /home/cad-user/.bashrc && python3 -u $(OPENRAM_DIR)/$(getfile).py \ -t $(gettech) -k $(ARGS) -p $(OPENRAM_DIR)/results/$* > $(OPENRAM_DIR)/results/$*.out 2>&1 && touch $(OPENRAM_DIR)/results/$*.ok || touch $(OPENRAM_DIR)/results/$*.bad" @test -f $(TOP_DIR)/compiler/tests/results/$*.ok && echo "$* ... PASS!" && \ rm -rf $(TOP_DIR)/compiler/tests/results/$* || echo "$* ... FAIL!" .DELETE_ON_ERROR: $(TEST_STAMPS) +.PHONY: docker-pull +docker-pull: + docker pull vlsida/openram-ubuntu:latest + # Mount environment for debug # mount: From 38494458e38966b2f34d2c4eb409a272195b7064 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 1 Mar 2022 10:44:56 -0800 Subject: [PATCH 117/229] Fix incorrect port 1w to 1r --- compiler/tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index ac377176..4b155bd4 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -38,7 +38,7 @@ BROKEN_STAMPS = \ sky130/19_bank_select_pbitcell_test.ok \ %/19_single_bank_16mux_1rw_1r_test.ok \ %/19_single_bank_16mux_test.ok \ - %/20_sram_1bank_16mux_1rw_1w_test.ok \ + %/20_sram_1bank_16mux_1rw_1r_test.ok \ %/20_sram_1bank_16mux_test.ok \ %/20_psram_1bank_2mux_1rw_1w_test.ok \ %/20_psram_1bank_2mux_1rw_1w_wmask_test.ok \ From c12c0067996e0177cd6132c17a9e5500b0c7651d Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 1 Mar 2022 10:50:49 -0800 Subject: [PATCH 118/229] Add verbose option --- compiler/tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 4b155bd4..b828323a 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -121,7 +121,7 @@ $(TEST_BASES): -e OPENRAM_TMP=$(OPENRAM_DIR)/results/$*/tmp \ vlsida/openram-ubuntu:latest \ sh -c ". /home/cad-user/.bashrc && python3 -u $(OPENRAM_DIR)/$(getfile).py \ - -t $(gettech) -k $(ARGS) -p $(OPENRAM_DIR)/results/$* > $(OPENRAM_DIR)/results/$*.out 2>&1 && touch $(OPENRAM_DIR)/results/$*.ok || touch $(OPENRAM_DIR)/results/$*.bad" + -t $(gettech) -k -v $(ARGS) -p $(OPENRAM_DIR)/results/$* > $(OPENRAM_DIR)/results/$*.out 2>&1 && touch $(OPENRAM_DIR)/results/$*.ok || touch $(OPENRAM_DIR)/results/$*.bad" @test -f $(TOP_DIR)/compiler/tests/results/$*.ok && echo "$* ... PASS!" && \ rm -rf $(TOP_DIR)/compiler/tests/results/$* || echo "$* ... FAIL!" .DELETE_ON_ERROR: $(TEST_STAMPS) From 0908aa9e255470918837d78dcb70801bb3ac3647 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 1 Mar 2022 14:37:09 -0800 Subject: [PATCH 119/229] Add route vertical pins --- compiler/base/hierarchy_layout.py | 44 ++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 0ff95483..b5ca9d2e 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -422,7 +422,49 @@ class layout(): for pin_name in self.pin_map.keys(): self.copy_layout_pin(instance, pin_name, prefix + pin_name) - def route_horizontal_pin(self, name, layer=None): + def route_vertical_pins(self, name, layer=None): + """ + Route together all of the pins of a given name that vertically align. + """ + + + bins = {} + + for i in range(len(self.local_insts)): + inst = self.local_insts[i] + for pin in inst.get_pins(name): + try: + bins[pin.cx()].append((inst,pin)) + except KeyError: + bins[pin.cx()] = [(inst,pin)] + + for x, v in bins.items(): + bot_x = min([inst.by() for (inst,pin) in v]) + top_x = max([inst.uy() for (inst,pin) in v]) + + last_via = None + for inst,pin in v: + if layer: + pin_layer = layer + else: + pin_layer = self.supply_stack[2] + last_via = self.add_via_stack_center(from_layer=pin.layer, + to_layer=pin_layer, + offset=pin.center(), + min_area=True) + + if last_via: + via_width=last_via.mod.second_layer_width + else: + via_width=None + + self.add_layout_pin_segment_center(text=name, + layer=pin_layer, + start=vector(x, bot_y), + end=vector(x, top_y), + width=via_width) + + def route_horizontal_pins(self, name, layer=None): """ Route together all of the pins of a given name that horizontally align. """ From 36bbf81624bbf9cd5c31d70c58b702e02eb393ad Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 1 Mar 2022 14:37:30 -0800 Subject: [PATCH 120/229] Upgrade to magic 8.3.274 --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 10a6e1ca..a56d96b5 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -127,7 +127,7 @@ RUN apt-get install --no-install-recommends -y iverilog ### Magic ### #ARG MAGIC_COMMIT=db4fa65bfc096e63954b37b188ea27b90ab31839 -ARG MAGIC_COMMIT=8.3.273 +ARG MAGIC_COMMIT=8.3.274 WORKDIR /root #RUN git clone https://github.com/RTimothyEdwards/magic.git magic RUN git clone git://opencircuitdesign.com/magic magic From f7e3672c891c7583cd5bc4155c404cd5de39ee03 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 1 Mar 2022 14:37:51 -0800 Subject: [PATCH 121/229] Route horizontal supplies in write driver. --- compiler/modules/precharge_array.py | 4 +- compiler/modules/replica_column.py | 5 ++- compiler/modules/sense_amp_array.py | 4 +- compiler/modules/write_driver_array.py | 37 ++++++++++-------- compiler/verify/magic.py | 2 + technology/scn4m_subm/gds_lib/cell_2rw.gds | Bin 6326 -> 6326 bytes .../scn4m_subm/gds_lib/dummy_cell_2rw.gds | Bin 6082 -> 6082 bytes .../scn4m_subm/gds_lib/replica_cell_2rw.gds | Bin 6278 -> 6278 bytes 8 files changed, 29 insertions(+), 23 deletions(-) diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index be64b7cf..d2864ff4 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -81,8 +81,8 @@ class precharge_array(design.design): def add_layout_pins(self): - self.route_horizontal_pin("en_bar", layer=self.en_bar_layer) - self.route_horizontal_pin("vdd") + self.route_horizontal_pins("en_bar", layer=self.en_bar_layer) + self.route_horizontal_pins("vdd") for i in range(len(self.local_insts)): inst = self.local_insts[i] diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index b50acfa9..a3de3a38 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -189,8 +189,9 @@ class replica_column(bitcell_base_array): for (index, inst) in enumerate(self.cell_inst): for pin_name in ["vdd", "gnd"]: if inst in [self.cell_inst[0], self.cell_inst[self.total_size - 1]]: - for pin in inst.get_pins(pin_name): - self.copy_power_pin(pin) + #for pin in inst.get_pins(pin_name): + # self.copy_power_pin(pin) + self.copy_power_pins(inst, pin_name) else: self.copy_layout_pin(inst, pin_name) diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index edda67f4..025328ec 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -75,8 +75,8 @@ class sense_amp_array(design.design): self.width = self.local_insts[-1].rx() self.add_layout_pins() - self.route_horizontal_pin("vdd") - self.route_horizontal_pin("gnd") + self.route_horizontal_pins("vdd") + self.route_horizontal_pins("gnd") self.route_rails() self.add_boundary() diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 7c4ea52a..c94f3009 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -69,7 +69,7 @@ class write_driver_array(design.design): def create_layout(self): self.place_write_array() - self.width = self.driver_insts[-1].rx() + self.width = self.local_insts[-1].rx() self.height = self.driver.height self.add_layout_pins() self.add_boundary() @@ -100,13 +100,13 @@ class write_driver_array(design.design): self.bitcell = factory.create(module_type=OPTS.bitcell) def create_write_array(self): - self.driver_insts = [] + self.local_insts = [] w = 0 windex=0 for i in range(0, self.columns, self.words_per_row): name = "write_driver{}".format(i) index = int(i / self.words_per_row) - self.driver_insts.append(self.add_inst(name=name, + self.local_insts.append(self.add_inst(name=name, mod=self.driver)) if self.write_size: @@ -139,7 +139,7 @@ class write_driver_array(design.design): else: offset = 1 name = "write_driver{}".format(self.columns + i) - self.driver_insts.append(self.add_inst(name=name, + self.local_insts.append(self.add_inst(name=name, mod=self.driver)) self.connect_inst([self.data_name + "_{0}".format(index), @@ -166,7 +166,7 @@ class write_driver_array(design.design): mirror = "" base = vector(xoffset, 0) - self.driver_insts[i].place(offset=base, mirror=mirror) + self.local_insts[i].place(offset=base, mirror=mirror) # place spare write drivers (if spare columns are specified) for i, xoffset in enumerate(self.offsets[self.columns:]): @@ -179,11 +179,11 @@ class write_driver_array(design.design): mirror = "" base = vector(xoffset, 0) - self.driver_insts[index].place(offset=base, mirror=mirror) + self.local_insts[index].place(offset=base, mirror=mirror) def add_layout_pins(self): for i in range(self.word_size + self.num_spare_cols): - inst = self.driver_insts[i] + inst = self.local_insts[i] din_pin = inst.get_pin(inst.mod.din_name) self.add_layout_pin(text=self.data_name + "_{0}".format(i), layer=din_pin.layer, @@ -204,14 +204,17 @@ class write_driver_array(design.design): width=br_pin.width(), height=br_pin.height()) - for n in ["vdd", "gnd"]: - pin_list = self.driver_insts[i].get_pins(n) - for pin in pin_list: - self.copy_power_pin(pin, directions=("V", "V")) + self.route_horizontal_pins("vdd") + self.route_horizontal_pins("gnd") +# Old pin routing +# for n in ["vdd", "gnd"]: +# pin_list = self.local_insts[i].get_pins(n) +# for pin in pin_list: +# self.copy_power_pin(pin, directions=("V", "V")) if self.write_size: for bit in range(self.num_wmasks): - inst = self.driver_insts[bit * self.write_size] + inst = self.local_insts[bit * self.write_size] en_pin = inst.get_pin(inst.mod.en_name) # Determine width of wmask modified en_pin with/without col mux wmask_en_len = self.words_per_row * (self.write_size * self.driver_spacing) @@ -227,7 +230,7 @@ class write_driver_array(design.design): height=en_pin.height()) for i in range(self.num_spare_cols): - inst = self.driver_insts[self.word_size + i] + inst = self.local_insts[self.word_size + i] en_pin = inst.get_pin(inst.mod.en_name) self.add_layout_pin(text=self.en_name + "_{0}".format(i + self.num_wmasks), layer="m1", @@ -235,9 +238,9 @@ class write_driver_array(design.design): elif self.num_spare_cols and not self.write_size: # shorten enable rail to accomodate those for spare write drivers - left_inst = self.driver_insts[0] + left_inst = self.local_insts[0] left_en_pin = left_inst.get_pin(inst.mod.en_name) - right_inst = self.driver_insts[-self.num_spare_cols - 1] + right_inst = self.local_insts[-self.num_spare_cols - 1] right_en_pin = right_inst.get_pin(inst.mod.en_name) self.add_layout_pin(text=self.en_name + "_{0}".format(0), layer="m1", @@ -246,14 +249,14 @@ class write_driver_array(design.design): # individual enables for every spare write driver for i in range(self.num_spare_cols): - inst = self.driver_insts[self.word_size + i] + inst = self.local_insts[self.word_size + i] en_pin = inst.get_pin(inst.mod.en_name) self.add_layout_pin(text=self.en_name + "_{0}".format(i + 1), layer="m1", offset=en_pin.lr() + vector(-drc("minwidth_m1"), 0)) else: - inst = self.driver_insts[0] + inst = self.local_insts[0] self.add_layout_pin(text=self.en_name, layer="m1", offset=inst.get_pin(inst.mod.en_name).ll().scale(0, 1), diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index a9c2dc08..69429ab7 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -94,6 +94,8 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa f.write("set SUB gnd\n") #f.write("gds polygon subcell true\n") f.write("gds warning default\n") + # Flatten the transistors + f.write("gds flatglob *_?mos_m*\n") # These two options are temporarily disabled until Tim fixes a bug in magic related # to flattening channel routes and vias (hierarchy with no devices in it). Otherwise, # they appear to be disconnected. diff --git a/technology/scn4m_subm/gds_lib/cell_2rw.gds b/technology/scn4m_subm/gds_lib/cell_2rw.gds index a45c34e937349dd6945d67a6fedc0debce9c7eab..0a0e0f8dd79ae21d52569758fc389a38f91532f5 100644 GIT binary patch delta 97 zcmdmHxXn=bd V>3J!WCyL5X?hsAbEFiXw2>`u85X%4n delta 93 zcmdmHxXn=bd V>3J!W=ZeTro+6U4Sw?gj69AyA5H$2 delta 93 zcmZoOY%^41U}IonieQjoWMY59z|FwRz`?-GV1Ue?sAMRPLuzBzE0M`HqA8Pih)QsB S%wXV Date: Tue, 1 Mar 2022 14:44:04 -0800 Subject: [PATCH 122/229] Skip hspice tests in docker --- compiler/tests/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index b828323a..5ddcf862 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -44,6 +44,8 @@ BROKEN_STAMPS = \ %/20_psram_1bank_2mux_1rw_1w_wmask_test.ok \ %/20_psram_1bank_2mux_1w_1r_test.ok \ %/20_psram_1bank_2mux_test.ok \ + %/21_hspice_delay_test.ok \ + %/21_hspice_setuphold_test.ok \ sky130/20_psram_1bank_4mux_1rw_1r_test.ok \ sky130/22_psram_1bank_2mux_func_test.ok \ sky130/22_psram_1bank_4mux_func_test.ok \ @@ -63,6 +65,7 @@ BROKEN_STAMPS = \ %/22_sram_1bank_nomux_sparecols_func_test.ok \ %/22_sram_1bank_wmask_1rw_1r_func_test.ok \ %/22_sram_wmask_func_test.ok \ + %/26_hspice_pex_pinv_test.ok \ %/50_riscv_1k_1rw1r_func_test.ok \ %/50_riscv_1k_1rw_func_test.ok \ %/50_riscv_1rw1r_func_test.ok \ From 51ba88d896e4f02b7bf5953bd2468ac303f8c721 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 2 Mar 2022 16:29:43 -0800 Subject: [PATCH 123/229] Port address with vertical power stripes --- compiler/base/hierarchy_layout.py | 49 +++++++++++++------ compiler/modules/hierarchical_decoder.py | 40 +++++++++------- compiler/modules/hierarchical_predecode.py | 10 ++-- compiler/modules/port_address.py | 4 +- compiler/modules/wordline_driver_array.py | 55 +++++++++------------- 5 files changed, 89 insertions(+), 69 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index b5ca9d2e..9ab12827 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -422,25 +422,36 @@ class layout(): for pin_name in self.pin_map.keys(): self.copy_layout_pin(instance, pin_name, prefix + pin_name) - def route_vertical_pins(self, name, layer=None): + def route_vertical_pins(self, name, insts=None, layer=None, side=None): """ Route together all of the pins of a given name that vertically align. + Uses local_insts if insts not specified. + Uses center of pin by default, or right or left if specified. """ bins = {} + if not insts: + insts = self.local_insts - for i in range(len(self.local_insts)): - inst = self.local_insts[i] + for inst in insts: for pin in inst.get_pins(name): + + if side == "right": + x = pin.rx() + elif side == "left": + x = pin.lx() + else: + x = pin.cx() + try: - bins[pin.cx()].append((inst,pin)) + bins[x].append((inst,pin)) except KeyError: - bins[pin.cx()] = [(inst,pin)] + bins[x] = [(inst,pin)] for x, v in bins.items(): - bot_x = min([inst.by() for (inst,pin) in v]) - top_x = max([inst.uy() for (inst,pin) in v]) + bot_y = min([inst.by() for (inst,pin) in v]) + top_y = max([inst.uy() for (inst,pin) in v]) last_via = None for inst,pin in v: @@ -450,7 +461,7 @@ class layout(): pin_layer = self.supply_stack[2] last_via = self.add_via_stack_center(from_layer=pin.layer, to_layer=pin_layer, - offset=pin.center(), + offset=vector(x, pin.cy()), min_area=True) if last_via: @@ -464,21 +475,31 @@ class layout(): end=vector(x, top_y), width=via_width) - def route_horizontal_pins(self, name, layer=None): + def route_horizontal_pins(self, name, insts=None, layer=None, side=None): """ Route together all of the pins of a given name that horizontally align. + Uses local_insts if insts not specified. + Uses center of pin by default, or top or botom if specified. """ bins = {} + if not insts: + insts = self.local_insts - for i in range(len(self.local_insts)): - inst = self.local_insts[i] + for inst in insts: for pin in inst.get_pins(name): + if side == "top": + y = pin.uy() + elif side == "bottom": + y = pin.by() + else: + y = pin.cy() + try: - bins[pin.cy()].append((inst,pin)) + bins[y].append((inst,pin)) except KeyError: - bins[pin.cy()] = [(inst,pin)] + bins[y] = [(inst,pin)] for y, v in bins.items(): left_x = min([inst.lx() for (inst,pin) in v]) @@ -492,7 +513,7 @@ class layout(): pin_layer = self.supply_stack[0] last_via = self.add_via_stack_center(from_layer=pin.layer, to_layer=pin_layer, - offset=pin.center(), + offset=vector(pin.cx(), y), min_area=True) if last_via: diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index f7b721f2..7bddb3a3 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -28,6 +28,7 @@ class hierarchical_decoder(design.design): self.pre2x4_inst = [] self.pre3x8_inst = [] self.pre4x16_inst = [] + self.local_insts = [] b = factory.create(module_type=OPTS.bitcell) self.cell_height = b.height @@ -57,11 +58,12 @@ class hierarchical_decoder(design.design): self.route_inputs() self.route_outputs() self.route_decoder_bus() - self.route_vdd_gnd() self.offset_x_coordinates() - self.width = self.and_inst[0].rx() + 0.5 * self.m1_width + self.width = self.and_inst[0].rx() + + self.route_vdd_gnd() self.add_boundary() self.DRC_LVS() @@ -188,7 +190,7 @@ class hierarchical_decoder(design.design): self.output_layer_pitch = getattr(self, self.output_layer + "_pitch") # Two extra pitches between modules on left and right - self.internal_routing_width = self.total_number_of_predecoder_outputs * self.bus_pitch + self.bus_pitch + self.internal_routing_width = self.total_number_of_predecoder_outputs * self.bus_pitch + 2 * self.bus_pitch self.row_decoder_height = self.and2.height * self.num_outputs # Extra bus space for supply contacts @@ -592,8 +594,13 @@ class hierarchical_decoder(design.design): Add a pin for each row of vdd/gnd which are must-connects next level up. """ - if layer_props.hierarchical_decoder.vertical_supply: + pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst + self.route_vertical_pins("vdd", insts=pre_insts) + self.route_vertical_pins("gnd", insts=pre_insts) + self.route_vertical_pins("vdd", insts=self.and_inst) + self.route_vertical_pins("gnd", insts=self.and_inst) + return for n in ["vdd", "gnd"]: pins = self.and_inst[0].get_pins(n) for pin in pins: @@ -612,19 +619,20 @@ class hierarchical_decoder(design.design): for i in self.pre2x4_inst + self.pre3x8_inst: self.copy_layout_pin(i, n) else: - # The vias will be placed at the right of the cells. - xoffset = max(x.rx() for x in self.and_inst) + 0.5 * self.m1_space - for row in range(0, self.num_outputs): - for pin_name in ["vdd", "gnd"]: - # The nand and inv are the same height rows... - supply_pin = self.and_inst[row].get_pin(pin_name) - pin_pos = vector(xoffset, supply_pin.cy()) - self.copy_power_pin(supply_pin, loc=pin_pos) + pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst + self.route_vertical_pins("vdd", insts=pre_insts) + self.route_vertical_pins("gnd", insts=pre_insts) + self.route_vertical_pins("vdd", insts=self.and_inst, side="right") + self.route_vertical_pins("gnd", insts=self.and_inst, side="left") + + # Widen the rails to cover any gap + for inst in self.and_inst: + for name in ["vdd", "gnd"]: + supply_pin = inst.get_pin(name) + self.add_segment_center(layer=supply_pin.layer, + start=vector(0, supply_pin.cy()), + end=vector(self.width, supply_pin.cy())) - # Copy the pins from the predecoders - for pre in self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst: - for pin_name in ["vdd", "gnd"]: - self.copy_layout_pin(pre, pin_name) def route_predecode_bus_outputs(self, rail_name, pin, row): """ diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index a8da372a..f3dd8e7e 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -413,7 +413,9 @@ class hierarchical_predecode(design.design): end=vector(self.width, and_pin.cy())) # Add pins in two locations - for xoffset in [self.inv_inst[0].lx() - self.bus_space, - self.and_inst[0].lx() - self.bus_space]: - pin_pos = vector(xoffset, and_pin.cy()) - self.copy_power_pin(and_pin, loc=pin_pos) + if n == "vdd": + xoffset = self.and_inst[0].lx() - self.bus_space + else: + xoffset = self.inv_inst[0].lx() - self.bus_space + pin_pos = vector(xoffset, and_pin.cy()) + self.copy_power_pin(and_pin, loc=pin_pos) diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index 27dd7e6a..e06d6857 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -77,8 +77,8 @@ class port_address(design.design): def route_supplies(self): """ Propagate all vdd/gnd pins up to this level for all modules """ for inst in [self.wordline_driver_array_inst, self.row_decoder_inst]: - self.copy_power_pins(inst, "vdd") - self.copy_power_pins(inst, "gnd") + self.copy_layout_pin(inst, "vdd") + self.copy_layout_pin(inst, "gnd") for rbl_vdd_pin in self.rbl_driver_inst.get_pins("vdd"): if layer_props.port_address.supply_offset: diff --git a/compiler/modules/wordline_driver_array.py b/compiler/modules/wordline_driver_array.py index 4faf622f..4fe9cc95 100644 --- a/compiler/modules/wordline_driver_array.py +++ b/compiler/modules/wordline_driver_array.py @@ -44,9 +44,9 @@ class wordline_driver_array(design.design): self.route_layer = "m1" self.place_drivers() self.route_layout() - self.route_vdd_gnd() self.offset_x_coordinates() self.add_boundary() + self.route_vdd_gnd() self.DRC_LVS() def add_pins(self): @@ -67,35 +67,23 @@ class wordline_driver_array(design.design): def route_vdd_gnd(self): """ - Add a pin for each row of vdd/gnd which - are must-connects next level up. + Add vertical power rails. """ if layer_props.wordline_driver.vertical_supply: - for name in ["vdd", "gnd"]: - supply_pins = self.wld_inst[0].get_pins(name) - for pin in supply_pins: - self.add_layout_pin_segment_center(text=name, - layer=pin.layer, - start=pin.bc(), - end=vector(pin.cx(), self.height)) + self.route_vertical_pins("vdd", insts=self.wld_inst) + self.route_vertical_pins("gnd", insts=self.wld_inst) else: - # Find the x offsets for where the vias/pins should be placed - xoffset_list = [self.wld_inst[0].rx()] - for num in range(self.rows): - # this will result in duplicate polygons for rails, but who cares + self.route_vertical_pins("vdd", insts=self.wld_inst, side="left") + self.route_vertical_pins("gnd", insts=self.wld_inst, side="right") - # use the inverter offset even though it will be the and's too - (gate_offset, y_dir) = self.get_gate_offset(0, - self.wl_driver.height, - num) - # Route both supplies + # Widen the rails to cover any gap + for num in range(self.rows): for name in ["vdd", "gnd"]: supply_pin = self.wld_inst[num].get_pin(name) + self.add_segment_center(layer=supply_pin.layer, + start=vector(0, supply_pin.cy()), + end=vector(self.width, supply_pin.cy())) - # Add pins in two locations - for xoffset in xoffset_list: - pin_pos = vector(xoffset, supply_pin.cy()) - self.copy_power_pin(supply_pin, loc=pin_pos) def create_drivers(self): self.wld_inst = [] @@ -105,8 +93,8 @@ class wordline_driver_array(design.design): # add and2 self.wld_inst.append(self.add_inst(name=name_and, mod=self.wl_driver)) - self.connect_inst(["in_{0}".format(row), - "en", + self.connect_inst(["en", + "in_{0}".format(row), "wl_{0}".format(row), "vdd", "gnd"]) @@ -135,24 +123,25 @@ class wordline_driver_array(design.design): """ Route all of the signals """ # Wordline enable connection - en_pin = self.wld_inst[0].get_pin("B") - en_bottom_pos = vector(en_pin.lx(), 0) - en_pin = self.add_layout_pin(text="en", - layer="m2", - offset=en_bottom_pos, - height=self.height) + en_pin = self.wld_inst[0].get_pin("A") + en_bottom_pos = vector(en_pin.cx(), 0) + en_top_pos = vector(en_pin.cx(), self.height) + en_pin = self.add_layout_pin_segment_center(text="en", + layer="m2", + start=en_bottom_pos, + end=en_top_pos) for row in range(self.rows): and_inst = self.wld_inst[row] # Drop a via - b_pin = and_inst.get_pin("B") + b_pin = and_inst.get_pin("A") self.add_via_stack_center(from_layer=b_pin.layer, to_layer="m2", offset=b_pin.center()) # connect the decoder input pin to and2 A - self.copy_layout_pin(and_inst, "A", "in_{0}".format(row)) + self.copy_layout_pin(and_inst, "B", "in_{0}".format(row)) # output each WL on the right wl_offset = and_inst.get_pin("Z").rc() From 7654cd729540727f6216dc41797d859a50382117 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 2 Mar 2022 16:47:17 -0800 Subject: [PATCH 124/229] Allow supply pins on m4 too --- compiler/base/hierarchy_layout.py | 26 +++++++++++++------------- compiler/modules/write_driver_array.py | 5 ----- compiler/sram/sram_1bank.py | 2 +- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 9ab12827..a003c174 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -67,9 +67,9 @@ class layout(): try: from tech import power_grid - self.pwr_grid_layer = power_grid[0] + self.pwr_grid_layers = [power_grid[0], power_grid[2]] except ImportError: - self.pwr_grid_layer = "m3" + self.pwr_grid_layers = ["m3", "m4"] ############################################################ # GDS layout @@ -1373,7 +1373,7 @@ class layout(): for pin in pins: if new_name == "": new_name = pin.name - if pin.layer == self.pwr_grid_layer: + if pin.layer in self.pwr_grid_layers: self.add_layout_pin(new_name, pin.layer, pin.ll(), @@ -1398,22 +1398,22 @@ class layout(): def add_power_pin(self, name, loc, directions=None, start_layer="m1"): # Hack for min area if OPTS.tech_name == "sky130": - min_area = drc["minarea_{}".format(self.pwr_grid_layer)] + min_area = drc["minarea_{}".format(self.pwr_grid_layers[2])] width = round_to_grid(sqrt(min_area)) height = round_to_grid(min_area / width) else: width = None height = None - if start_layer == self.pwr_grid_layer: + if start_layer in self.pwr_grid_layers: self.add_layout_pin_rect_center(text=name, - layer=self.pwr_grid_layer, + layer=start_layer, offset=loc, width=width, height=height) else: via = self.add_via_stack_center(from_layer=start_layer, - to_layer=self.pwr_grid_layer, + to_layer=self.pwr_grid_layers[0], offset=loc, directions=directions) @@ -1422,7 +1422,7 @@ class layout(): if not height: height = via.height self.add_layout_pin_rect_center(text=name, - layer=self.pwr_grid_layer, + layer=self.pwr_grid_layers[0], offset=loc, width=width, height=height) @@ -1441,22 +1441,22 @@ class layout(): # Hack for min area if OPTS.tech_name == "sky130": - min_area = drc["minarea_{}".format(self.pwr_grid_layer)] + min_area = drc["minarea_{}".format(self.pwr_grid_layers[1])] width = round_to_grid(sqrt(min_area)) height = round_to_grid(min_area / width) else: width = None height = None - if pin.layer == self.pwr_grid_layer: + if pin.layer in self.pwr_grid_layers: self.add_layout_pin_rect_center(text=new_name, - layer=self.pwr_grid_layer, + layer=pin.layer, offset=loc, width=width, height=height) else: via = self.add_via_stack_center(from_layer=pin.layer, - to_layer=self.pwr_grid_layer, + to_layer=self.pwr_grid_layers[0], offset=loc, directions=directions) @@ -1465,7 +1465,7 @@ class layout(): if not height: height = via.height self.add_layout_pin_rect_center(text=new_name, - layer=self.pwr_grid_layer, + layer=self.pwr_grid_layers[0], offset=loc, width=width, height=height) diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index c94f3009..e4192f4a 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -206,11 +206,6 @@ class write_driver_array(design.design): self.route_horizontal_pins("vdd") self.route_horizontal_pins("gnd") -# Old pin routing -# for n in ["vdd", "gnd"]: -# pin_list = self.local_insts[i].get_pins(n) -# for pin in pin_list: -# self.copy_power_pin(pin, directions=("V", "V")) if self.write_size: for bit in range(self.num_wmasks): diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index a6abeba6..ce10eb4f 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -260,7 +260,7 @@ class sram_1bank(sram_base): if add_vias: pin_layer = None else: - pin_layer = self.pwr_grid_layer + pin_layer = self.pwr_grid_layers[0] # Connect the control pins as inputs for signal in self.control_logic_inputs[port]: From febf7031b1ae3a3d41bcbc1c484a793fd13ac123 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 2 Mar 2022 17:04:54 -0800 Subject: [PATCH 125/229] Fix wrong power layer for min area constraint --- compiler/base/hierarchy_layout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index a003c174..ff0d7a3d 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -1398,7 +1398,7 @@ class layout(): def add_power_pin(self, name, loc, directions=None, start_layer="m1"): # Hack for min area if OPTS.tech_name == "sky130": - min_area = drc["minarea_{}".format(self.pwr_grid_layers[2])] + min_area = drc["minarea_{}".format(self.pwr_grid_layers[1])] width = round_to_grid(sqrt(min_area)) height = round_to_grid(min_area / width) else: From ff471740ede6cb30b3e2c3e06722bc8492a7733a Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 3 Mar 2022 09:01:12 -0800 Subject: [PATCH 126/229] Build docker from config instead of pulling it --- .github/workflows/ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8dbf8380..be5b1d1f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,8 +6,10 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v1 - - name: Docker pull - run: docker pull vlsida/openram-ubuntu:latest + - name: Docker build + run: | + cd ${{ github.workspace }}/docker + make build - name: PDK Install run: | export OPENRAM_HOME="${{ github.workspace }}/compiler" From 053392077728b5ac2cc7fbd5bbb5d899ca654f84 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 3 Mar 2022 09:49:20 -0800 Subject: [PATCH 127/229] Revert to old magic until substrate bug is fixed. --- docker/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index a56d96b5..b4d67404 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -127,7 +127,8 @@ RUN apt-get install --no-install-recommends -y iverilog ### Magic ### #ARG MAGIC_COMMIT=db4fa65bfc096e63954b37b188ea27b90ab31839 -ARG MAGIC_COMMIT=8.3.274 +#ARG MAGIC_COMMIT=8.3.274 +ARG MAGIC_COMMIT=8.3.211 WORKDIR /root #RUN git clone https://github.com/RTimothyEdwards/magic.git magic RUN git clone git://opencircuitdesign.com/magic magic From e139b4aa818e240854b4d2104a21f131fbac056e Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 3 Mar 2022 09:53:24 -0800 Subject: [PATCH 128/229] Swap A and B pins in wordline driver. --- compiler/modules/wordline_driver_array.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/modules/wordline_driver_array.py b/compiler/modules/wordline_driver_array.py index 4fe9cc95..95a7d007 100644 --- a/compiler/modules/wordline_driver_array.py +++ b/compiler/modules/wordline_driver_array.py @@ -123,7 +123,7 @@ class wordline_driver_array(design.design): """ Route all of the signals """ # Wordline enable connection - en_pin = self.wld_inst[0].get_pin("A") + en_pin = self.wld_inst[0].get_pin("B") en_bottom_pos = vector(en_pin.cx(), 0) en_top_pos = vector(en_pin.cx(), self.height) en_pin = self.add_layout_pin_segment_center(text="en", @@ -141,7 +141,7 @@ class wordline_driver_array(design.design): offset=b_pin.center()) # connect the decoder input pin to and2 A - self.copy_layout_pin(and_inst, "B", "in_{0}".format(row)) + self.copy_layout_pin(and_inst, "A", "in_{0}".format(row)) # output each WL on the right wl_offset = and_inst.get_pin("Z").rc() From 10bec414e892c9d59026314cbcc03407e33b4fa8 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 4 Mar 2022 14:21:58 -0800 Subject: [PATCH 129/229] Update usage instructions --- README.md | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 28c62a58..688f22da 100644 --- a/README.md +++ b/README.md @@ -60,18 +60,27 @@ You may also wish to add OPENRAM\_HOME to your PYTHONPATH: ``` export PYTHONPATH="$PYTHONPATH:$OPENRAM_HOME" -``` We include the tech files necessary for [SCMOS] SCN4M_SUBM, -[FreePDK45], and [Sky130]. The [SCMOS] spice models, however, are +[FreePDK45]. The [SCMOS] spice models, however, are generic and should be replaced with foundry models. You may get the entire [FreePDK45 PDK here][FreePDK45]. -To install [Sky130], simply run: -``` -make install ``` +### Sky130 Setup +To install [Sky130], you must have the open_pdks files installed in $PDK_ROOT. +To install this automatically, you can run: + + cd $HOME/openram + make pdk + +Then you must also install the [Sky130] SRAM build space and the appropriate cell views +by running: + + cd $HOME/openram + make install +``` # Basic Usage Once you have defined the environment, you can run OpenRAM from the command line @@ -80,7 +89,6 @@ using a single configuration file written in Python. For example, create a file called *myconfig.py* specifying the following parameters for your memory: -``` # Data word size word_size = 2 # Number of words in the memory @@ -130,23 +138,24 @@ use the following command to run all regression tests: ``` cd openram/compiler/tests -make regress +make -j 3 ``` +The -j can run with 3 threads. By default, this will run in all technologies. To run a specific test: ``` ce openram/compiler/tests make 05_bitcell_array_test -``` + +To run a specific technology: + +cd openram/compiler/tests +TECHS=scn4m_subm make 05_bitcell_array_test To increase the verbosity of the test, add one (or more) -v options and pass it as an argument to OpenRAM: ``` -make 05_bitcell_array_test ARGS="-v -t scn4m_subm" -``` -To specify a particular technology use "-t " such as -"-t freepdk45". The default for a unit test is scn4m_subm. -The default for openram.py is specified in the configuration file. +ARGS="-v" make 05_bitcell_array_test # Get Involved From 8b3c10ae796dcf17aa23d392b4db19b6b1dbc895 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 4 Mar 2022 15:44:07 -0800 Subject: [PATCH 130/229] Improvements to power routing. Improved the route horizontal and vertical pin functions to create a single pin at the end. Swapped A and B on wordline driver input for cleaner routing in most technologies. Fixed vertical supply routing in port_address. --- compiler/base/hierarchy_layout.py | 96 +++++++++++++++-------- compiler/modules/hierarchical_decoder.py | 12 +-- compiler/modules/port_address.py | 12 ++- compiler/modules/replica_bitcell_array.py | 5 ++ compiler/modules/wordline_driver_array.py | 26 +++--- 5 files changed, 92 insertions(+), 59 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index ff0d7a3d..93d2de51 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -74,24 +74,30 @@ class layout(): ############################################################ # GDS layout ############################################################ - def offset_all_coordinates(self): + def offset_all_coordinates(self, offset=None): """ This function is called after everything is placed to shift the origin in the lowest left corner """ - offset = self.find_lowest_coords() - self.translate_all(offset) - return offset + if not offset: + offset = vector(0, 0) + ll = self.find_lowest_coords() + real_offset = ll + offset + self.translate_all(real_offset) + return real_offset - def offset_x_coordinates(self): + def offset_x_coordinates(self, offset=None): """ This function is called after everything is placed to shift the origin to the furthest left point. Y offset is unchanged. """ - offset = self.find_lowest_coords() - self.translate_all(offset.scale(1, 0)) - return offset + if not offset: + offset = vector(0, 0) + ll = self.find_lowest_coords() + real_offset = ll.scale(1, 0) + offset + self.translate_all(real_offset) + return real_offset def get_gate_offset(self, x_offset, height, inv_num): """ @@ -422,7 +428,7 @@ class layout(): for pin_name in self.pin_map.keys(): self.copy_layout_pin(instance, pin_name, prefix + pin_name) - def route_vertical_pins(self, name, insts=None, layer=None, side=None): + def route_vertical_pins(self, name, insts=None, layer=None, xside="cx", yside="cy"): """ Route together all of the pins of a given name that vertically align. Uses local_insts if insts not specified. @@ -437,19 +443,17 @@ class layout(): for inst in insts: for pin in inst.get_pins(name): - if side == "right": - x = pin.rx() - elif side == "left": - x = pin.lx() - else: - x = pin.cx() - + x = getattr(pin, xside)() try: bins[x].append((inst,pin)) except KeyError: bins[x] = [(inst,pin)] for x, v in bins.items(): + # Not enough to route a pin + if len(v) < 2: + continue + bot_y = min([inst.by() for (inst,pin) in v]) top_y = max([inst.uy() for (inst,pin) in v]) @@ -459,9 +463,12 @@ class layout(): pin_layer = layer else: pin_layer = self.supply_stack[2] + + y = getattr(pin, yside)() + last_via = self.add_via_stack_center(from_layer=pin.layer, to_layer=pin_layer, - offset=vector(x, pin.cy()), + offset=vector(x, y), min_area=True) if last_via: @@ -469,13 +476,22 @@ class layout(): else: via_width=None - self.add_layout_pin_segment_center(text=name, - layer=pin_layer, - start=vector(x, bot_y), - end=vector(x, top_y), - width=via_width) + top_pos = vector(x, top_y) + bot_pos = vector(x, bot_y) + self.add_segment_center(layer=pin_layer, + start=bot_pos, + end=top_pos, + width=via_width) - def route_horizontal_pins(self, name, insts=None, layer=None, side=None): + self.add_layout_pin_rect_center(text=name, + layer=pin_layer, + offset=top_pos) +# self.add_layout_pin_rect_center(text=name, +# layer=pin_layer, +# offset=bot_pos) + + + def route_horizontal_pins(self, name, insts=None, layer=None, xside="cx", yside="cy"): """ Route together all of the pins of a given name that horizontally align. Uses local_insts if insts not specified. @@ -489,19 +505,20 @@ class layout(): for inst in insts: for pin in inst.get_pins(name): - if side == "top": - y = pin.uy() - elif side == "bottom": - y = pin.by() - else: - y = pin.cy() + y = getattr(pin, yside)() try: bins[y].append((inst,pin)) except KeyError: bins[y] = [(inst,pin)] + # Filter the small bins + for y, v in bins.items(): + # Not enough to route a pin + if len(v) < 2: + continue + left_x = min([inst.lx() for (inst,pin) in v]) right_x = max([inst.rx() for (inst,pin) in v]) @@ -511,6 +528,9 @@ class layout(): pin_layer = layer else: pin_layer = self.supply_stack[0] + + x = getattr(pin, xside)() + last_via = self.add_via_stack_center(from_layer=pin.layer, to_layer=pin_layer, offset=vector(pin.cx(), y), @@ -521,11 +541,19 @@ class layout(): else: via_height=None - self.add_layout_pin_segment_center(text=name, - layer=pin_layer, - start=vector(left_x, y), - end=vector(right_x, y), - width=via_height) + left_pos = vector(left_x, y) + right_pos = vector(right_x, y) + self.add_segment_center(layer=pin_layer, + start=left_pos, + end=right_pos, + width=via_height) + + self.add_layout_pin_rect_center(text=name, + layer=pin_layer, + offset=left_pos) +# self.add_layout_pin_rect_center(text=name, +# layer=pin_layer, +# offset=right_pos) def add_layout_pin_segment_center(self, text, layer, start, end, width=None): """ diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index 7bddb3a3..e9f8bbd8 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -596,10 +596,10 @@ class hierarchical_decoder(design.design): """ if layer_props.hierarchical_decoder.vertical_supply: pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst - self.route_vertical_pins("vdd", insts=pre_insts) - self.route_vertical_pins("gnd", insts=pre_insts) - self.route_vertical_pins("vdd", insts=self.and_inst) - self.route_vertical_pins("gnd", insts=self.and_inst) + self.route_vertical_pins("vdd", insts=pre_insts, yside="by") + self.route_vertical_pins("gnd", insts=pre_insts, yside="by") + self.route_vertical_pins("vdd", insts=self.and_inst, yside="by") + self.route_vertical_pins("gnd", insts=self.and_inst, yside="by") return for n in ["vdd", "gnd"]: pins = self.and_inst[0].get_pins(n) @@ -622,8 +622,8 @@ class hierarchical_decoder(design.design): pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst self.route_vertical_pins("vdd", insts=pre_insts) self.route_vertical_pins("gnd", insts=pre_insts) - self.route_vertical_pins("vdd", insts=self.and_inst, side="right") - self.route_vertical_pins("gnd", insts=self.and_inst, side="left") + self.route_vertical_pins("vdd", insts=self.and_inst, xside="rx") + self.route_vertical_pins("gnd", insts=self.and_inst, xside="lx") # Widen the rails to cover any gap for inst in self.and_inst: diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index e06d6857..5e0b74fa 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -228,17 +228,15 @@ class port_address(design.design): wordline_driver_array_offset = vector(self.row_decoder_inst.rx(), 0) self.wordline_driver_array_inst.place(wordline_driver_array_offset) - # The wordline driver also had an extra gap on the right, so use this offset - well_gap = 2 * drc("pwell_to_nwell") + drc("nwell_enclose_active") - x_offset = self.wordline_driver_array_inst.rx() - well_gap - self.rbl_driver.width + # This m4_pitch corresponds to the offset space for jog routing in the + # wordline_driver_array + rbl_driver_offset = wordline_driver_array_offset + vector(self.m4_pitch, 0) if self.port == 0: - rbl_driver_offset = vector(x_offset, - 0) self.rbl_driver_inst.place(rbl_driver_offset, "MX") else: - rbl_driver_offset = vector(x_offset, - self.wordline_driver_array.height) + rbl_driver_offset += vector(0, + self.wordline_driver_array.height) self.rbl_driver_inst.place(rbl_driver_offset) # Pass this up diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index a459c266..88701161 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -463,6 +463,11 @@ class replica_bitcell_array(bitcell_base_array): supply_insts = self.dummy_col_insts + self.dummy_row_insts for pin_name in self.supplies: + #self.route_vertical_pins(name=pin_name, insts=supply_insts) + self.route_horizontal_pins(name=pin_name, insts=supply_insts) + + #self.route_vertical_pins(name=pin_name, insts=self.replica_col_insts) + #self.route_horizontal_pins(name=pin_name, insts=self.replica_col_insts) for inst in supply_insts: pin_list = inst.get_pins(pin_name) for pin in pin_list: diff --git a/compiler/modules/wordline_driver_array.py b/compiler/modules/wordline_driver_array.py index 95a7d007..31b60887 100644 --- a/compiler/modules/wordline_driver_array.py +++ b/compiler/modules/wordline_driver_array.py @@ -42,9 +42,16 @@ class wordline_driver_array(design.design): self.route_layer = "li" else: self.route_layer = "m1" + self.place_drivers() self.route_layout() - self.offset_x_coordinates() + self.offset_x_coordinates(vector(-self.m4_pitch, 0)) + + # Leave a well gap to separate the bitcell array well from this well + well_gap = 2 * drc("pwell_to_nwell") + drc("nwell_enclose_active") + self.width = self.wld_inst[-1].rx() + well_gap + self.height = self.wld_inst[-1].uy() + self.add_boundary() self.route_vdd_gnd() self.DRC_LVS() @@ -73,8 +80,8 @@ class wordline_driver_array(design.design): self.route_vertical_pins("vdd", insts=self.wld_inst) self.route_vertical_pins("gnd", insts=self.wld_inst) else: - self.route_vertical_pins("vdd", insts=self.wld_inst, side="left") - self.route_vertical_pins("gnd", insts=self.wld_inst, side="right") + self.route_vertical_pins("vdd", insts=self.wld_inst, xside="lx") + self.route_vertical_pins("gnd", insts=self.wld_inst, xside="rx") # Widen the rails to cover any gap for num in range(self.rows): @@ -93,8 +100,8 @@ class wordline_driver_array(design.design): # add and2 self.wld_inst.append(self.add_inst(name=name_and, mod=self.wl_driver)) - self.connect_inst(["en", - "in_{0}".format(row), + self.connect_inst(["in_{0}".format(row), + "en", "wl_{0}".format(row), "vdd", "gnd"]) @@ -114,18 +121,13 @@ class wordline_driver_array(design.design): self.wld_inst[row].place(offset=and2_offset, mirror=inst_mirror) - # Leave a well gap to separate the bitcell array well from this well - well_gap = 2 * drc("pwell_to_nwell") + drc("nwell_enclose_active") - self.width = self.wl_driver.width + well_gap - self.height = self.wl_driver.height * self.rows - def route_layout(self): """ Route all of the signals """ # Wordline enable connection en_pin = self.wld_inst[0].get_pin("B") en_bottom_pos = vector(en_pin.cx(), 0) - en_top_pos = vector(en_pin.cx(), self.height) + en_top_pos = vector(en_pin.cx(), self.wld_inst[-1].uy()) en_pin = self.add_layout_pin_segment_center(text="en", layer="m2", start=en_bottom_pos, @@ -135,7 +137,7 @@ class wordline_driver_array(design.design): and_inst = self.wld_inst[row] # Drop a via - b_pin = and_inst.get_pin("A") + b_pin = and_inst.get_pin("B") self.add_via_stack_center(from_layer=b_pin.layer, to_layer="m2", offset=b_pin.center()) From d69e55c2e37040d00a453374fb23b94ee6f91cd3 Mon Sep 17 00:00:00 2001 From: mrg Date: Sun, 6 Mar 2022 09:56:00 -0800 Subject: [PATCH 131/229] Power routing changes. Make the power rails an "experimental_power" option and conditional. Rename route_vdd_gnd to route_supplies everywhere for consistency. --- compiler/base/hierarchy_layout.py | 34 +++++---- compiler/modules/hierarchical_decoder.py | 89 +++++++++++++--------- compiler/modules/hierarchical_predecode.py | 4 +- compiler/modules/port_address.py | 2 +- compiler/modules/precharge_array.py | 13 +++- compiler/modules/replica_bitcell_array.py | 37 ++++++--- compiler/modules/sense_amp_array.py | 18 ++++- compiler/modules/wordline_driver_array.py | 56 ++++++++++---- compiler/modules/write_driver_array.py | 18 ++++- compiler/options.py | 3 + compiler/pgates/precharge.py | 53 +++++++++---- 11 files changed, 227 insertions(+), 100 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 93d2de51..b3eff27d 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -478,17 +478,17 @@ class layout(): top_pos = vector(x, top_y) bot_pos = vector(x, bot_y) - self.add_segment_center(layer=pin_layer, - start=bot_pos, - end=top_pos, - width=via_width) - - self.add_layout_pin_rect_center(text=name, - layer=pin_layer, - offset=top_pos) + rect = self.add_layout_pin_rect_center(text=name, + layer=pin_layer, + offset=top_pos) # self.add_layout_pin_rect_center(text=name, # layer=pin_layer, # offset=bot_pos) + self.add_segment_center(layer=pin_layer, + start=vector(rect.cx(), bot_pos.y), + end=rect.bc(), + width=via_width) + def route_horizontal_pins(self, name, insts=None, layer=None, xside="cx", yside="cy"): @@ -543,17 +543,21 @@ class layout(): left_pos = vector(left_x, y) right_pos = vector(right_x, y) - self.add_segment_center(layer=pin_layer, - start=left_pos, - end=right_pos, - width=via_height) - self.add_layout_pin_rect_center(text=name, - layer=pin_layer, - offset=left_pos) + rect = self.add_layout_pin_rect_center(text=name, + layer=pin_layer, + offset=left_pos) # self.add_layout_pin_rect_center(text=name, # layer=pin_layer, # offset=right_pos) + # This is made to not overlap with the pin above + # so that the power router will only select a small pin. + # Otherwise it adds big blockages over the rails. + self.add_segment_center(layer=pin_layer, + start=rect.rc(), + end=vector(right_pos.x, rect.cy()), + width=via_height) + def add_layout_pin_segment_center(self, text, layer, start, end, width=None): """ diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index e9f8bbd8..0db5acbb 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -63,7 +63,7 @@ class hierarchical_decoder(design.design): self.width = self.and_inst[0].rx() - self.route_vdd_gnd() + self.route_supplies() self.add_boundary() self.DRC_LVS() @@ -589,50 +589,67 @@ class hierarchical_decoder(design.design): output_index) output_index = output_index + 1 - def route_vdd_gnd(self): + def route_supplies(self): """ Add a pin for each row of vdd/gnd which are must-connects next level up. """ - if layer_props.hierarchical_decoder.vertical_supply: - pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst - self.route_vertical_pins("vdd", insts=pre_insts, yside="by") - self.route_vertical_pins("gnd", insts=pre_insts, yside="by") - self.route_vertical_pins("vdd", insts=self.and_inst, yside="by") - self.route_vertical_pins("gnd", insts=self.and_inst, yside="by") - return - for n in ["vdd", "gnd"]: - pins = self.and_inst[0].get_pins(n) - for pin in pins: - self.add_rect(layer=pin.layer, - offset=pin.ll() + vector(0, self.bus_space), - width=pin.width(), - height=self.height - 2 * self.bus_space) - # This adds power vias at the top of each cell - # (except the last to keep them inside the boundary) - for i in self.and_inst[:-1]: - pins = i.get_pins(n) - for pin in pins: - self.copy_power_pin(pin, loc=pin.uc()) + # This is an experiment with power rails + if OPTS.experimental_power: + if layer_props.hierarchical_decoder.vertical_supply: + pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst + self.route_vertical_pins("vdd", insts=pre_insts, yside="by") + self.route_vertical_pins("gnd", insts=pre_insts, yside="by") + self.route_vertical_pins("vdd", insts=self.and_inst, yside="by") + self.route_vertical_pins("gnd", insts=self.and_inst, yside="by") + else: + pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst + self.route_vertical_pins("vdd", insts=pre_insts) + self.route_vertical_pins("gnd", insts=pre_insts) + self.route_vertical_pins("vdd", insts=self.and_inst, xside="rx") + self.route_vertical_pins("gnd", insts=self.and_inst, xside="lx") - for i in self.pre2x4_inst + self.pre3x8_inst: - self.copy_layout_pin(i, n) + # Widen the rails to cover any gap + for inst in self.and_inst: + for name in ["vdd", "gnd"]: + supply_pin = inst.get_pin(name) + self.add_segment_center(layer=supply_pin.layer, + start=vector(0, supply_pin.cy()), + end=vector(self.width, supply_pin.cy())) else: - pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst - self.route_vertical_pins("vdd", insts=pre_insts) - self.route_vertical_pins("gnd", insts=pre_insts) - self.route_vertical_pins("vdd", insts=self.and_inst, xside="rx") - self.route_vertical_pins("gnd", insts=self.and_inst, xside="lx") + if layer_props.hierarchical_decoder.vertical_supply: + for n in ["vdd", "gnd"]: + pins = self.and_inst[0].get_pins(n) + for pin in pins: + self.add_rect(layer=pin.layer, + offset=pin.ll() + vector(0, self.bus_space), + width=pin.width(), + height=self.height - 2 * self.bus_space) - # Widen the rails to cover any gap - for inst in self.and_inst: - for name in ["vdd", "gnd"]: - supply_pin = inst.get_pin(name) - self.add_segment_center(layer=supply_pin.layer, - start=vector(0, supply_pin.cy()), - end=vector(self.width, supply_pin.cy())) + # This adds power vias at the top of each cell + # (except the last to keep them inside the boundary) + for i in self.and_inst[:-1]: + pins = i.get_pins(n) + for pin in pins: + self.copy_power_pin(pin, loc=pin.uc()) + for i in self.pre2x4_inst + self.pre3x8_inst: + self.copy_layout_pin(i, n) + else: + # The vias will be placed at the right of the cells. + xoffset = max(x.rx() for x in self.and_inst) + 0.5 * self.m1_space + for row in range(0, self.num_outputs): + for pin_name in ["vdd", "gnd"]: + # The nand and inv are the same height rows... + supply_pin = self.and_inst[row].get_pin(pin_name) + pin_pos = vector(xoffset, supply_pin.cy()) + self.copy_power_pin(supply_pin, loc=pin_pos) + + # Copy the pins from the predecoders + for pre in self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst: + for pin_name in ["vdd", "gnd"]: + self.copy_layout_pin(pre, pin_name) def route_predecode_bus_outputs(self, rail_name, pin, row): """ diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index f3dd8e7e..706fc58e 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -189,7 +189,7 @@ class hierarchical_predecode(design.design): self.route_output_inverters() self.route_inputs_to_rails() self.route_output_ands() - self.route_vdd_gnd() + self.route_supplies() def route_inputs_to_rails(self): """ Route the uninverted inputs to the second set of rails """ @@ -378,7 +378,7 @@ class hierarchical_predecode(design.design): offset=pin_pos, directions=direction) - def route_vdd_gnd(self): + def route_supplies(self): """ Add a pin for each row of vdd/gnd which are must-connects next level up. """ # We may ahve vertical power supply rails diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index 5e0b74fa..7c3af51c 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -230,7 +230,7 @@ class port_address(design.design): # This m4_pitch corresponds to the offset space for jog routing in the # wordline_driver_array - rbl_driver_offset = wordline_driver_array_offset + vector(self.m4_pitch, 0) + rbl_driver_offset = wordline_driver_array_offset + vector(2 * self.m4_pitch, 0) if self.port == 0: self.rbl_driver_inst.place(rbl_driver_offset, "MX") diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index d2864ff4..0215d76a 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -68,6 +68,7 @@ class precharge_array(design.design): self.height = self.pc_cell.height self.add_layout_pins() + self.route_supplies() self.add_boundary() self.DRC_LVS() @@ -81,14 +82,24 @@ class precharge_array(design.design): def add_layout_pins(self): + en_pin = self.pc_cell.get_pin("en_bar") self.route_horizontal_pins("en_bar", layer=self.en_bar_layer) - self.route_horizontal_pins("vdd") + for inst in self.local_insts: + self.add_via_stack_center(from_layer=en_pin.layer, + to_layer=self.en_bar_layer, + offset=inst.get_pin("en_bar").center()) for i in range(len(self.local_insts)): inst = self.local_insts[i] self.copy_layout_pin(inst, "bl", "bl_{0}".format(i)) self.copy_layout_pin(inst, "br", "br_{0}".format(i)) + def route_supplies(self): + if OPTS.experimental_power: + self.route_horizontal_pins("vdd") + else: + for inst in self.local_insts: + self.copy_layout_pin(inst, "vdd") def create_insts(self): """Creates a precharge array by horizontally tiling the precharge cell""" diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 88701161..57a58d79 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -462,20 +462,33 @@ class replica_bitcell_array(bitcell_base_array): # replica column should only have a vdd/gnd in the dummy cell on top/bottom supply_insts = self.dummy_col_insts + self.dummy_row_insts - for pin_name in self.supplies: - #self.route_vertical_pins(name=pin_name, insts=supply_insts) - self.route_horizontal_pins(name=pin_name, insts=supply_insts) - #self.route_vertical_pins(name=pin_name, insts=self.replica_col_insts) - #self.route_horizontal_pins(name=pin_name, insts=self.replica_col_insts) - for inst in supply_insts: - pin_list = inst.get_pins(pin_name) - for pin in pin_list: - self.copy_power_pin(pin) + if OPTS.experimental_power: + for pin_name in self.supplies: + #self.route_vertical_pins(name=pin_name, insts=supply_insts) + self.route_horizontal_pins(name=pin_name, insts=supply_insts) + + #self.route_vertical_pins(name=pin_name, insts=self.replica_col_insts) + #self.route_horizontal_pins(name=pin_name, insts=self.replica_col_insts) + for inst in supply_insts: + pin_list = inst.get_pins(pin_name) + for pin in pin_list: + self.copy_power_pin(pin) + + for inst in self.replica_col_insts: + if inst: + self.copy_layout_pin(inst, pin_name) + else: + for pin_name in self.supplies: + for inst in supply_insts: + pin_list = inst.get_pins(pin_name) + for pin in pin_list: + self.copy_power_pin(pin) + + for inst in self.replica_col_insts: + if inst: + self.copy_layout_pin(inst, pin_name) - for inst in self.replica_col_insts: - if inst: - self.copy_layout_pin(inst, pin_name) def analytical_power(self, corner, load): """Power of Bitcell array and bitline in nW.""" diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index 025328ec..a481679f 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -75,8 +75,8 @@ class sense_amp_array(design.design): self.width = self.local_insts[-1].rx() self.add_layout_pins() - self.route_horizontal_pins("vdd") - self.route_horizontal_pins("gnd") + + self.route_supplies() self.route_rails() self.add_boundary() @@ -173,6 +173,20 @@ class sense_amp_array(design.design): width=dout_pin.width(), height=dout_pin.height()) + def route_supplies(self): + if OPTS.experimental_power: + self.route_horizontal_pins("vdd") + self.route_horizontal_pins("gnd") + else: + for i in range(len(self.local_insts)): + inst = self.local_insts[i] + + for gnd_pin in inst.get_pins("gnd"): + self.copy_power_pin(gnd_pin) + + for vdd_pin in inst.get_pins("vdd"): + self.copy_power_pin(vdd_pin) + def route_rails(self): # Add enable across the array en_pin = self.amp.get_pin(self.amp.en_name) diff --git a/compiler/modules/wordline_driver_array.py b/compiler/modules/wordline_driver_array.py index 31b60887..a13f4bcd 100644 --- a/compiler/modules/wordline_driver_array.py +++ b/compiler/modules/wordline_driver_array.py @@ -45,7 +45,7 @@ class wordline_driver_array(design.design): self.place_drivers() self.route_layout() - self.offset_x_coordinates(vector(-self.m4_pitch, 0)) + self.offset_x_coordinates(vector(-2*self.m4_pitch, 0)) # Leave a well gap to separate the bitcell array well from this well well_gap = 2 * drc("pwell_to_nwell") + drc("nwell_enclose_active") @@ -76,20 +76,50 @@ class wordline_driver_array(design.design): """ Add vertical power rails. """ - if layer_props.wordline_driver.vertical_supply: - self.route_vertical_pins("vdd", insts=self.wld_inst) - self.route_vertical_pins("gnd", insts=self.wld_inst) - else: - self.route_vertical_pins("vdd", insts=self.wld_inst, xside="lx") - self.route_vertical_pins("gnd", insts=self.wld_inst, xside="rx") - # Widen the rails to cover any gap - for num in range(self.rows): + # Experiment with power straps + if OPTS.experimental_power: + if layer_props.wordline_driver.vertical_supply: + self.route_vertical_pins("vdd", insts=self.wld_inst) + self.route_vertical_pins("gnd", insts=self.wld_inst) + else: + self.route_vertical_pins("vdd", insts=self.wld_inst, xside="lx") + self.route_vertical_pins("gnd", insts=self.wld_inst, xside="rx") + + # Widen the rails to cover any gap + for num in range(self.rows): + for name in ["vdd", "gnd"]: + supply_pin = self.wld_inst[num].get_pin(name) + self.add_segment_center(layer=supply_pin.layer, + start=vector(0, supply_pin.cy()), + end=vector(self.width, supply_pin.cy())) + else: + if layer_props.wordline_driver.vertical_supply: for name in ["vdd", "gnd"]: - supply_pin = self.wld_inst[num].get_pin(name) - self.add_segment_center(layer=supply_pin.layer, - start=vector(0, supply_pin.cy()), - end=vector(self.width, supply_pin.cy())) + supply_pins = self.wld_inst[0].get_pins(name) + for pin in supply_pins: + self.add_layout_pin_segment_center(text=name, + layer=pin.layer, + start=pin.bc(), + end=vector(pin.cx(), self.height)) + else: + # Find the x offsets for where the vias/pins should be placed + xoffset_list = [self.wld_inst[0].rx()] + for num in range(self.rows): + # this will result in duplicate polygons for rails, but who cares + + # use the inverter offset even though it will be the and's too + (gate_offset, y_dir) = self.get_gate_offset(0, + self.wl_driver.height, + num) + # Route both supplies + for name in ["vdd", "gnd"]: + supply_pin = self.wld_inst[num].get_pin(name) + + # Add pins in two locations + for xoffset in xoffset_list: + pin_pos = vector(xoffset, supply_pin.cy()) + self.copy_power_pin(supply_pin, loc=pin_pos) def create_drivers(self): diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index e4192f4a..f232c129 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -72,6 +72,7 @@ class write_driver_array(design.design): self.width = self.local_insts[-1].rx() self.height = self.driver.height self.add_layout_pins() + self.route_supplies() self.add_boundary() self.DRC_LVS() @@ -204,9 +205,6 @@ class write_driver_array(design.design): width=br_pin.width(), height=br_pin.height()) - self.route_horizontal_pins("vdd") - self.route_horizontal_pins("gnd") - if self.write_size: for bit in range(self.num_wmasks): inst = self.local_insts[bit * self.write_size] @@ -256,3 +254,17 @@ class write_driver_array(design.design): layer="m1", offset=inst.get_pin(inst.mod.en_name).ll().scale(0, 1), width=self.width) + + def route_supplies(self): + if OPTS.experimental_power: + self.route_horizontal_pins("vdd") + self.route_horizontal_pins("gnd") + else: + for i in range(self.word_size + self.num_spare_cols): + inst = self.local_insts[i] + for n in ["vdd", "gnd"]: + pin_list = inst.get_pins(n) + for pin in pin_list: + self.copy_power_pin(pin, directions=("V", "V")) + + diff --git a/compiler/options.py b/compiler/options.py index f3c19283..d81a8c7e 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -197,3 +197,6 @@ class options(optparse.Values): write_driver_array = "write_driver_array" write_driver = "write_driver" write_mask_and_array = "write_mask_and_array" + + # Non-public options + experimental_power = False diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index aa1f1a70..8eff8c8f 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -71,7 +71,7 @@ class precharge(design.design): self.connect_poly() self.route_en() self.place_nwell_and_contact() - self.route_vdd() + self.route_supplies() self.route_bitlines() self.connect_to_bitlines() self.add_boundary() @@ -91,28 +91,51 @@ class precharge(design.design): mults=self.ptx_mults, tx_type="pmos") - def route_vdd(self): + def route_supplies(self): """ Adds a vdd rail at the top of the cell """ - pmos_pin = self.upper_pmos2_inst.get_pin("S") - pmos_pos = pmos_pin.center() - self.add_path(pmos_pin.layer, [pmos_pos, self.well_contact_pos]) + if OPTS.experimental_power: + pmos_pin = self.upper_pmos2_inst.get_pin("S") + pmos_pos = pmos_pin.center() + self.add_path(pmos_pin.layer, [pmos_pos, self.well_contact_pos]) - self.add_via_stack_center(from_layer=pmos_pin.layer, - to_layer=self.supply_stack[0], - offset=self.well_contact_pos, - directions=("V", "V")) - - self.add_min_area_rect_center(layer=self.en_layer, + self.add_via_stack_center(from_layer=pmos_pin.layer, + to_layer=self.supply_stack[0], offset=self.well_contact_pos, - width=self.well_contact.mod.second_layer_width) + directions=("V", "V")) - self.add_layout_pin_rect_center(text="vdd", - layer=self.supply_stack[0], - offset=self.well_contact_pos) + self.add_min_area_rect_center(layer=self.en_layer, + offset=self.well_contact_pos, + width=self.well_contact.mod.second_layer_width) + self.add_layout_pin_rect_center(text="vdd", + layer=self.supply_stack[0], + offset=self.well_contact_pos) + else: + # Adds the rail across the width of the cell + vdd_position = vector(0.5 * self.width, self.height) + layer_width = drc("minwidth_" + self.en_layer) + self.add_rect_center(layer=self.en_layer, + offset=vdd_position, + width=self.width, + height=layer_width) + + pmos_pin = self.upper_pmos2_inst.get_pin("S") + + # center of vdd rail + pmos_vdd_pos = vector(pmos_pin.cx(), vdd_position.y) + self.add_path(self.en_layer, [pmos_pin.center(), pmos_vdd_pos]) + + self.add_power_pin("vdd", + self.well_contact_pos, + directions=("V", "V")) + + self.add_via_stack_center(from_layer=pmos_pin.layer, + to_layer=self.en_layer, + offset=pmos_pin.center(), + directions=("V", "V")) def create_ptx(self): """ From 8c911f70b9024d4f9b834db3d6e893d4ce085c50 Mon Sep 17 00:00:00 2001 From: mrg Date: Sun, 6 Mar 2022 10:31:43 -0800 Subject: [PATCH 132/229] Build changes. Don't pull docker since it will be build by CI. Shuffle tests to stagger technologies and test types. --- compiler/modules/wordline_buffer_array.py | 4 ++-- compiler/tests/Makefile | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/modules/wordline_buffer_array.py b/compiler/modules/wordline_buffer_array.py index b62ea872..51fe4030 100644 --- a/compiler/modules/wordline_buffer_array.py +++ b/compiler/modules/wordline_buffer_array.py @@ -43,7 +43,7 @@ class wordline_buffer_array(design.design): self.route_layer = "m1" self.place_drivers() self.route_layout() - self.route_vdd_gnd() + self.route_supplies() self.offset_all_coordinates() self.add_boundary() self.DRC_LVS() @@ -65,7 +65,7 @@ class wordline_buffer_array(design.design): size=self.cols, height=b.height) - def route_vdd_gnd(self): + def route_supplies(self): """ Add a pin for each row of vdd/gnd which are must-connects next level up. diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 5ddcf862..c40698d9 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -86,17 +86,17 @@ getfile = $(word 2,$(subst /, ,$*)) TECH_TEST_STAMPS=$(foreach T, $(TEST_TECHS), $(addprefix $T/, $(TEST_STAMPS))) # Filter out the tests after creating the tech stamps -WORKING_TECH_TEST_STAMPS=$(filter-out $(BROKEN_STAMPS), $(TECH_TEST_STAMPS)) +WORKING_TECH_TEST_STAMPS=$(shell shuf -e -- $(filter-out $(BROKEN_STAMPS), $(TECH_TEST_STAMPS))) # Run all technologies -all: docker-pull $(WORKING_TECH_TEST_STAMPS) +all: $(WORKING_TECH_TEST_STAMPS) @ls -1 $(TOP_DIR)/compiler/tests/results/*/*.bad 1> /dev/null 2>&1 && echo "FAILING TESTS" && ls -1 $(TOP_DIR)/compiler/tests/results/*/*.bad | sed -e "s#^.*results\/##" && exit 1 || exit 0 .PHONY: all # Run a given technology # e.g. make freepdk45 -$(TECHS): docker-pull +$(TECHS): @$(MAKE) --no-print-directory $(filter-out $(BROKEN_STAMPS), $(addprefix $@/, $(TEST_STAMPS))) .PHONY: $(TECHS) From 6da3e44b6f62d9552c03f55f9af9532580942066 Mon Sep 17 00:00:00 2001 From: mrg Date: Sun, 6 Mar 2022 11:26:03 -0800 Subject: [PATCH 133/229] Split up 06_hierarchical_decoder test --- .../06_hierarchical_decoder_132row_test.py | 42 +++++++++++ .../06_hierarchical_decoder_16row_test.py | 42 +++++++++++ .../06_hierarchical_decoder_17row_test.py | 42 +++++++++++ .../06_hierarchical_decoder_32row_test.py | 42 +++++++++++ .../06_hierarchical_decoder_4096row_test.py | 42 +++++++++++ .../06_hierarchical_decoder_512row_test.py | 42 +++++++++++ .../06_hierarchical_decoder_64row_test.py | 42 +++++++++++ .../tests/06_hierarchical_decoder_test.py | 72 ------------------- 8 files changed, 294 insertions(+), 72 deletions(-) create mode 100755 compiler/tests/06_hierarchical_decoder_132row_test.py create mode 100755 compiler/tests/06_hierarchical_decoder_16row_test.py create mode 100755 compiler/tests/06_hierarchical_decoder_17row_test.py create mode 100755 compiler/tests/06_hierarchical_decoder_32row_test.py create mode 100755 compiler/tests/06_hierarchical_decoder_4096row_test.py create mode 100755 compiler/tests/06_hierarchical_decoder_512row_test.py create mode 100755 compiler/tests/06_hierarchical_decoder_64row_test.py delete mode 100755 compiler/tests/06_hierarchical_decoder_test.py diff --git a/compiler/tests/06_hierarchical_decoder_132row_test.py b/compiler/tests/06_hierarchical_decoder_132row_test.py new file mode 100755 index 00000000..3681fcbf --- /dev/null +++ b/compiler/tests/06_hierarchical_decoder_132row_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class hierarchical_decoder_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + # Checks 2x4 and 2 x 3x8 and 3-input NAND with non-power-of-two + debug.info(1, "Testing 132 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", num_outputs=132) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/06_hierarchical_decoder_16row_test.py b/compiler/tests/06_hierarchical_decoder_16row_test.py new file mode 100755 index 00000000..b3dd35aa --- /dev/null +++ b/compiler/tests/06_hierarchical_decoder_16row_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class hierarchical_decoder_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + # Checks 2x4 and 2-input NAND decoder + debug.info(1, "Testing 16 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", num_outputs=16) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/06_hierarchical_decoder_17row_test.py b/compiler/tests/06_hierarchical_decoder_17row_test.py new file mode 100755 index 00000000..f4407baa --- /dev/null +++ b/compiler/tests/06_hierarchical_decoder_17row_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class hierarchical_decoder_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + # Checks 2x4 and 2-input NAND decoder with non-power-of-two + debug.info(1, "Testing 17 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", num_outputs=17) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/06_hierarchical_decoder_32row_test.py b/compiler/tests/06_hierarchical_decoder_32row_test.py new file mode 100755 index 00000000..26bcffad --- /dev/null +++ b/compiler/tests/06_hierarchical_decoder_32row_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class hierarchical_decoder_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + # Checks 2x4 with 3x8 and 2-input NAND decoder + debug.info(1, "Testing 32 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", num_outputs=32) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/06_hierarchical_decoder_4096row_test.py b/compiler/tests/06_hierarchical_decoder_4096row_test.py new file mode 100755 index 00000000..50e9bcaa --- /dev/null +++ b/compiler/tests/06_hierarchical_decoder_4096row_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class hierarchical_decoder_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + # Checks 2x4 and 2-input NAND decoder + debug.info(1, "Testing 4096 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", num_outputs=4096) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/06_hierarchical_decoder_512row_test.py b/compiler/tests/06_hierarchical_decoder_512row_test.py new file mode 100755 index 00000000..5bcfff11 --- /dev/null +++ b/compiler/tests/06_hierarchical_decoder_512row_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class hierarchical_decoder_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + # Checks 3 x 3x8 and 3-input NAND decoder + debug.info(1, "Testing 512 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", num_outputs=512) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/06_hierarchical_decoder_64row_test.py b/compiler/tests/06_hierarchical_decoder_64row_test.py new file mode 100755 index 00000000..0ef767e9 --- /dev/null +++ b/compiler/tests/06_hierarchical_decoder_64row_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class hierarchical_decoder_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + # Checks 3 x 2x4 and 3-input NAND decoder + debug.info(1, "Testing 64 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", num_outputs=64) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/06_hierarchical_decoder_test.py b/compiler/tests/06_hierarchical_decoder_test.py deleted file mode 100755 index ae55ba3e..00000000 --- a/compiler/tests/06_hierarchical_decoder_test.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python3 -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2021 Regents of the University of California and The Board -# of Regents for the Oklahoma Agricultural and Mechanical College -# (acting for and on behalf of Oklahoma State University) -# All rights reserved. -# -import unittest -from testutils import * -import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) -import globals -from globals import OPTS -from sram_factory import factory -import debug - - -class hierarchical_decoder_test(openram_test): - - def runTest(self): - config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) - globals.init_openram(config_file) - - OPTS.num_rw_ports = 1 - OPTS.num_r_ports = 0 - OPTS.num_w_ports = 0 - globals.setup_bitcell() - - # Checks 2x4 and 2-input NAND decoder - debug.info(1, "Testing 16 row sample for hierarchical_decoder") - a = factory.create(module_type="hierarchical_decoder", num_outputs=16) - self.local_check(a) - - # Checks 2x4 and 2-input NAND decoder with non-power-of-two - debug.info(1, "Testing 17 row sample for hierarchical_decoder") - a = factory.create(module_type="hierarchical_decoder", num_outputs=17) - self.local_check(a) - - # Checks 2x4 with 3x8 and 2-input NAND decoder - debug.info(1, "Testing 32 row sample for hierarchical_decoder") - a = factory.create(module_type="hierarchical_decoder", num_outputs=32) - self.local_check(a) - - # Checks 3 x 2x4 and 3-input NAND decoder - debug.info(1, "Testing 64 row sample for hierarchical_decoder") - a = factory.create(module_type="hierarchical_decoder", num_outputs=64) - self.local_check(a) - - # Checks 2x4 and 2 x 3x8 and 3-input NAND with non-power-of-two - debug.info(1, "Testing 132 row sample for hierarchical_decoder") - a = factory.create(module_type="hierarchical_decoder", num_outputs=132) - self.local_check(a) - - # Checks 3 x 3x8 and 3-input NAND decoder - debug.info(1, "Testing 512 row sample for hierarchical_decoder") - a = factory.create(module_type="hierarchical_decoder", num_outputs=512) - self.local_check(a) - - # Checks 3 x 4x16 and 4-input NAND decoder - #debug.info(1, "Testing 4096 row sample for hierarchical_decoder") - #a = factory.create(module_type="hierarchical_decoder", num_outputs=4096) - #self.local_check(a) - - globals.end_openram() - -# run the test from the command line -if __name__ == "__main__": - (OPTS, args) = globals.parse_args() - del sys.argv[1:] - header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) From a0f1327f5eddb6ea59bc102fc196bd90dc47c06b Mon Sep 17 00:00:00 2001 From: mrg Date: Sun, 6 Mar 2022 11:26:18 -0800 Subject: [PATCH 134/229] Add odd rows to 23_lib tests --- compiler/tests/23_lib_sram_linear_regression_test.py | 11 ++++++++++- compiler/tests/23_lib_sram_model_corners_test.py | 11 ++++++++++- compiler/tests/23_lib_sram_model_test.py | 11 ++++++++++- compiler/tests/23_lib_sram_prune_test.py | 11 ++++++++++- compiler/tests/23_lib_sram_test.py | 11 ++++++++++- 5 files changed, 50 insertions(+), 5 deletions(-) diff --git a/compiler/tests/23_lib_sram_linear_regression_test.py b/compiler/tests/23_lib_sram_linear_regression_test.py index bdca8fdd..620b8f0e 100755 --- a/compiler/tests/23_lib_sram_linear_regression_test.py +++ b/compiler/tests/23_lib_sram_linear_regression_test.py @@ -24,12 +24,21 @@ class lib_sram_linear_regression_test(openram_test): OPTS.netlist_only = True OPTS.model_name = "linear_regression" + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + from characterizer import lib from sram import sram from sram_config import sram_config c = sram_config(word_size=2, num_words=16, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=1 c.recompute_sizes() debug.info(1, "Testing analytical timing for sample 2 bit, 16 words SRAM with 1 bank") diff --git a/compiler/tests/23_lib_sram_model_corners_test.py b/compiler/tests/23_lib_sram_model_corners_test.py index 3f989b61..1de09c2b 100755 --- a/compiler/tests/23_lib_sram_model_corners_test.py +++ b/compiler/tests/23_lib_sram_model_corners_test.py @@ -23,12 +23,21 @@ class lib_model_corners_lib_test(openram_test): OPTS.nominal_corner_only = False OPTS.netlist_only = True + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + from characterizer import lib from sram import sram from sram_config import sram_config c = sram_config(word_size=2, num_words=16, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=1 c.recompute_sizes() debug.info(1, "Testing analytical timing for sample 2 bit, 16 words SRAM with 1 bank") diff --git a/compiler/tests/23_lib_sram_model_test.py b/compiler/tests/23_lib_sram_model_test.py index e729a9bd..e421235e 100755 --- a/compiler/tests/23_lib_sram_model_test.py +++ b/compiler/tests/23_lib_sram_model_test.py @@ -23,12 +23,21 @@ class lib_sram_model_test(openram_test): OPTS.nominal_corner_only = False OPTS.netlist_only = True + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + from characterizer import lib from sram import sram from sram_config import sram_config c = sram_config(word_size=2, num_words=16, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=1 c.recompute_sizes() debug.info(1, "Testing analytical timing for sample 2 bit, 16 words SRAM with 1 bank") diff --git a/compiler/tests/23_lib_sram_prune_test.py b/compiler/tests/23_lib_sram_prune_test.py index b4efd1dd..ae9093f5 100755 --- a/compiler/tests/23_lib_sram_prune_test.py +++ b/compiler/tests/23_lib_sram_prune_test.py @@ -32,11 +32,20 @@ class lib_sram_prune_test(openram_test): if not OPTS.spice_exe: debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + from sram import sram from sram_config import sram_config c = sram_config(word_size=2, num_words=16, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=1 c.recompute_sizes() debug.info(1, "Testing pruned timing for sample 2 bit, 16 words SRAM with 1 bank") diff --git a/compiler/tests/23_lib_sram_test.py b/compiler/tests/23_lib_sram_test.py index a894b328..cf9cf801 100755 --- a/compiler/tests/23_lib_sram_test.py +++ b/compiler/tests/23_lib_sram_test.py @@ -30,11 +30,20 @@ class lib_test(openram_test): if not OPTS.spice_exe: debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + from sram import sram from sram_config import sram_config c = sram_config(word_size=2, num_words=16, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=1 c.recompute_sizes() debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank") From ff319908312b13873d897559c76d8a43ab306668 Mon Sep 17 00:00:00 2001 From: mrg Date: Sun, 6 Mar 2022 11:26:57 -0800 Subject: [PATCH 135/229] Add parallel build for dockerfile --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index b4d67404..80ac0ede 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -29,7 +29,7 @@ WORKDIR /root RUN git clone https://github.com/KLayout/klayout WORKDIR /root/klayout RUN git checkout ${KLAYOUT_COMMIT} -RUN ./build.sh -qt5 \ +RUN ./build.sh -qt5 -j 8 \ && cp -r bin-release /usr/local/klayout RUN rm -rf /root/klayout From 6eeb81b9fe0fc1d79936a610716f8de8b0c22790 Mon Sep 17 00:00:00 2001 From: mrg Date: Sun, 6 Mar 2022 11:27:13 -0800 Subject: [PATCH 136/229] Skip sky130 23_lib tests and 4096 row hierarchical decoder test --- compiler/tests/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index c40698d9..bf8f20ae 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -32,6 +32,7 @@ BROKEN_STAMPS = \ sky130/05_bitcell_array_test.ok \ sky130/05_bitcell_array_1rw_1r_test.ok \ sky130/05_dummy_array_test.ok \ + %/06_hierarchical_decoder_4096row_test.ok \ sky130/07_column_mux_array_pbitcell_test.ok \ sky130/19_pmulti_bank_test.ok \ sky130/19_psingle_bank_test.ok \ @@ -65,6 +66,11 @@ BROKEN_STAMPS = \ %/22_sram_1bank_nomux_sparecols_func_test.ok \ %/22_sram_1bank_wmask_1rw_1r_func_test.ok \ %/22_sram_wmask_func_test.ok \ + sky130/23_lib_sram_linear_regression_test.ok \ + sky130/23_lib_sram_model_corners_test.ok \ + sky130/23_lib_sram_model_test.ok \ + sky130/23_lib_sram_prune_test.ok \ + sky131/23_lib_sram_test.ok \ %/26_hspice_pex_pinv_test.ok \ %/50_riscv_1k_1rw1r_func_test.ok \ %/50_riscv_1k_1rw_func_test.ok \ From 5263532a95f6e4c9720b594c7c8284072b15e578 Mon Sep 17 00:00:00 2001 From: mrg Date: Sun, 6 Mar 2022 11:57:40 -0800 Subject: [PATCH 137/229] Remove setpaths csh version as it is not maintained --- setpaths.csh | 8 -------- 1 file changed, 8 deletions(-) delete mode 100755 setpaths.csh diff --git a/setpaths.csh b/setpaths.csh deleted file mode 100755 index 69f736d4..00000000 --- a/setpaths.csh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/csh -# This is a csh utility script to set the paths to the current -# directory of OpenRAM. It must be sourced in the local directory -# like this: -# source setpaths.csh - -setenv OPENRAM_HOME "`pwd`/compiler" -setenv OPENRAM_TECH "`pwd`/technology" From 67b51ff7f54179ec821533c46a4d8ffbf0227c1d Mon Sep 17 00:00:00 2001 From: mrg Date: Sun, 6 Mar 2022 12:20:54 -0800 Subject: [PATCH 138/229] Move vdd pin in freepdk45 sense amp from dout --- technology/freepdk45/gds_lib/sense_amp.gds | Bin 14318 -> 14318 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/technology/freepdk45/gds_lib/sense_amp.gds b/technology/freepdk45/gds_lib/sense_amp.gds index da3fcc4aadc12da6270362f04d48fcb65610ad1d..f0bfebfd210fedacdcc5a82b7f040a3b13e89b58 100644 GIT binary patch delta 92 zcmaEt|1MvNfsKKQDS| Date: Sun, 6 Mar 2022 12:21:09 -0800 Subject: [PATCH 139/229] Add even columns for sky130 to ring test --- compiler/tests/20_sram_1bank_ring_test.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/compiler/tests/20_sram_1bank_ring_test.py b/compiler/tests/20_sram_1bank_ring_test.py index e34920c2..db2b5297 100755 --- a/compiler/tests/20_sram_1bank_ring_test.py +++ b/compiler/tests/20_sram_1bank_ring_test.py @@ -23,9 +23,19 @@ class sram_1bank_nomux_test(openram_test): globals.init_openram(config_file) OPTS.supply_pin_type = "ring" from sram_config import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=4, num_words=16, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=1 c.recompute_sizes() From 038acd1568705afdc021023f7af8034291e0ddfc Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Mon, 7 Mar 2022 01:20:59 -0800 Subject: [PATCH 140/229] single port rba lvs progress --- .../sky130/modules/sky130_bitcell_array.py | 6 ++- .../modules/sky130_bitcell_base_array.py | 37 +++++++++++++++++-- .../sky130/modules/sky130_dummy_array.py | 22 ++++++++--- .../modules/sky130_replica_bitcell_array.py | 5 +++ .../sky130/modules/sky130_replica_column.py | 4 +- 5 files changed, 61 insertions(+), 13 deletions(-) diff --git a/technology/sky130/modules/sky130_bitcell_array.py b/technology/sky130/modules/sky130_bitcell_array.py index d0d69c74..b589e321 100644 --- a/technology/sky130/modules/sky130_bitcell_array.py +++ b/technology/sky130/modules/sky130_bitcell_array.py @@ -63,8 +63,10 @@ class sky130_bitcell_array(bitcell_array, sky130_bitcell_base_array): row_layout.append(self.cell2) self.cell_inst[row, col]=self.add_inst(name="row_{}_col_{}_bitcell".format(row, col), mod=self.cell2) - - self.connect_inst(self.get_bitcell_pins(row, col)) + if col % 2 == 1: + self.connect_inst(self.get_bitcell_pins(row, col, swap=True)) + else: + self.connect_inst(self.get_bitcell_pins(row, col, swap=False)) if col != self.column_size - 1: if alternate_strap: if row % 2: diff --git a/technology/sky130/modules/sky130_bitcell_base_array.py b/technology/sky130/modules/sky130_bitcell_base_array.py index d472b264..9c6c947d 100644 --- a/technology/sky130/modules/sky130_bitcell_base_array.py +++ b/technology/sky130/modules/sky130_bitcell_base_array.py @@ -61,7 +61,7 @@ class sky130_bitcell_base_array(bitcell_base_array): self.width = max([x.rx() for x in self.insts]) self.height = max([x.uy() for x in self.insts]) - def get_bitcell_pins(self, row, col): + def get_bitcell_pins(self, row, col, swap = False): """ Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array @@ -69,6 +69,14 @@ class sky130_bitcell_base_array(bitcell_base_array): bitcell_pins = [] for port in self.all_ports: bitcell_pins.extend([x for x in self.get_bitline_names(port) if x.endswith("_{0}".format(col))]) + if swap: + swap_pins = [] + for pin in bitcell_pins: + if "bl" in pin: + swap_pins.append(pin.replace("bl", "br")) + elif "br" in pin: + swap_pins.append(pin.replace("br", "bl")) + bitcell_pins = swap_pins bitcell_pins.append("gnd") # gnd bitcell_pins.append("vdd") # vdd bitcell_pins.append("vdd") # vpb @@ -104,9 +112,9 @@ class sky130_bitcell_base_array(bitcell_base_array): for port in self.all_ports: strap_pins.extend([x for x in self.get_bitline_names(port) if "br" in x and x.endswith("_{0}".format(col))]) if row == 0: - strap_pins.extend(["gate_top"]) + strap_pins.extend(["top_gate"]) else: - strap_pins.extend(["gate_bottom"]) + strap_pins.extend(["bot_gate"]) return strap_pins def get_row_cap_pins(self, row, col): @@ -152,3 +160,26 @@ class sky130_bitcell_base_array(bitcell_base_array): except: pin = inst.get_pin("vnb") self.add_label("vdd", pin.layer, pin.center()) + + def add_bitline_pins(self): + bitline_names = self.cell.get_all_bitline_names() + for col in range(self.column_size): + for port in self.all_ports: + bl_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port]) + text = "bl_{0}_{1}".format(port, col) + if "Y" in self.cell_inst[0, col].mirror: + text = text.replace("bl", "br") + self.add_layout_pin(text=text, + layer=bl_pin.layer, + offset=bl_pin.ll().scale(1, 0), + width=bl_pin.width(), + height=self.height) + br_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port + 1]) + text = "br_{0}_{1}".format(port, col) + if "Y" in self.cell_inst[0, col].mirror: + text = text.replace("br", "bl") + self.add_layout_pin(text=text, + layer=br_pin.layer, + offset=br_pin.ll().scale(1, 0), + width=br_pin.width(), + height=self.height) diff --git a/technology/sky130/modules/sky130_dummy_array.py b/technology/sky130/modules/sky130_dummy_array.py index 416e9f3d..0c81b812 100644 --- a/technology/sky130/modules/sky130_dummy_array.py +++ b/technology/sky130/modules/sky130_dummy_array.py @@ -72,8 +72,11 @@ class sky130_dummy_array(sky130_bitcell_base_array): row_layout.append(self.dummy_cell2) self.cell_inst[row, col]=self.add_inst(name="row_{}_col_{}_bitcell".format(row, col), mod=self.dummy_cell2) - - self.connect_inst(self.get_bitcell_pins(row, col)) + if col % 2 == 1: + self.connect_inst(self.get_bitcell_pins(row, col, swap=True)) + else: + self.connect_inst(self.get_bitcell_pins(row, col, swap=False)) + #self.connect_inst(self.get_bitcell_pins(row, col)) if col != self.column_size - 1: if alternate_strap: if col % 2: @@ -99,6 +102,7 @@ class sky130_dummy_array(sky130_bitcell_base_array): self.add_inst(name=name, mod=self.strap3) alternate_strap = 1 + self.connect_inst(self.get_strap_pins(row, col, name)) if alternate_bitcell == 0: alternate_bitcell = 1 @@ -108,11 +112,11 @@ class sky130_dummy_array(sky130_bitcell_base_array): def add_pins(self): # bitline pins are not added because they are floating - for wl_name in self.get_wordline_names(): - self.add_pin(wl_name, "INPUT") for bl in range(self.column_size): self.add_pin("bl_0_{}".format(bl)) self.add_pin("br_0_{}".format(bl)) + for wl_name in self.get_wordline_names(): + self.add_pin(wl_name, "INPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") #self.add_pin("vpb", "BIAS") @@ -124,13 +128,19 @@ class sky130_dummy_array(sky130_bitcell_base_array): for col in range(self.column_size): for port in self.all_ports: bl_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port]) - self.add_layout_pin(text="bl_{0}_{1}".format(port, col), + text = "bl_{0}_{1}".format(port, col) + if "Y" in self.cell_inst[0, col].mirror: + text = text.replace("bl", "br") + self.add_layout_pin(text=text, layer=bl_pin.layer, offset=bl_pin.ll().scale(1, 0), width=bl_pin.width(), height=self.height) br_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port + 1]) - self.add_layout_pin(text="br_{0}_{1}".format(port, col), + text = "br_{0}_{1}".format(port, col) + if "Y" in self.cell_inst[0, col].mirror: + text = text.replace("br", "bl") + self.add_layout_pin(text=text, layer=br_pin.layer, offset=br_pin.ll().scale(1, 0), width=br_pin.width(), diff --git a/technology/sky130/modules/sky130_replica_bitcell_array.py b/technology/sky130/modules/sky130_replica_bitcell_array.py index 0bc402ed..6f0a1188 100644 --- a/technology/sky130/modules/sky130_replica_bitcell_array.py +++ b/technology/sky130/modules/sky130_replica_bitcell_array.py @@ -321,15 +321,20 @@ class sky130_replica_bitcell_array(replica_bitcell_array, sky130_bitcell_base_ar if len(self.rbls) > 0: for (names, inst) in zip(self.rbl_bitline_names, self.replica_col_insts): pin_names = self.replica_columns[self.rbls[0]].all_bitline_names + mirror = self.replica_col_insts[0].mirror for (bl_name, pin_name) in zip(names, pin_names): pin = inst.get_pin(pin_name) if 'rbl_bl' in bl_name: + if mirror != "MY": + bl_name = bl_name.replace("rbl_bl","rbl_br") self.add_layout_pin(text=bl_name, layer=pin.layer, offset=pin.ll().scale(1, 0), width=pin.width(), height=self.height) elif 'rbl_br' in bl_name: + if mirror != "MY": + bl_name = bl_name.replace("rbl_br","rbl_bl") self.add_layout_pin(text=bl_name, layer=pin.layer, offset=pin.ll().scale(1, 0) + vector(0,(pin_height + drc_width*2)), diff --git a/technology/sky130/modules/sky130_replica_column.py b/technology/sky130/modules/sky130_replica_column.py index f3d1801b..90c24222 100644 --- a/technology/sky130/modules/sky130_replica_column.py +++ b/technology/sky130/modules/sky130_replica_column.py @@ -90,8 +90,8 @@ class sky130_replica_column(sky130_bitcell_base_array): self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") - self.add_pin("gate_top", "BIAS") - self.add_pin("gate_bottom", "BIAS") + self.add_pin("top_gate", "INPUT") + self.add_pin("bot_gate", "INPUT") def add_modules(self): self.replica_cell = factory.create(module_type="replica_bitcell_1port", version="opt1") From 134d7cde7a43e19253b0b817664c588ee5762d83 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 7 Mar 2022 07:58:00 -0800 Subject: [PATCH 141/229] Add FREEPDK45 to paths --- docker/Dockerfile | 2 +- docker/set-paths.sh | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 80ac0ede..e1045107 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -149,8 +149,8 @@ RUN rm -rf /var/lib/apt/lists/* # ### SET UP A GENERIC USER ### -RUN mkdir /home/cad-user RUN useradd cad-user +RUN mkdir /home/cad-user RUN chown -R cad-user /home/cad-user RUN chgrp -R cad-user /home/cad-user ADD set-paths.sh /home/cad-user/.bashrc diff --git a/docker/set-paths.sh b/docker/set-paths.sh index 386872b5..bbe2023d 100644 --- a/docker/set-paths.sh +++ b/docker/set-paths.sh @@ -17,3 +17,6 @@ export XYCE_NO_TRACKING="anything at all" # OpenRAM export OPENRAM_HOME=/openram/compiler export OPENRAM_TECH=/openram/technology + +# FreePDK45 +export FREEPDK45=/freepdk45 From ce2b125762c7acf8f4cc1ac638605f7a9a0771b4 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 7 Mar 2022 07:58:26 -0800 Subject: [PATCH 142/229] Clean up git action flow --- .github/workflows/ci.yml | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index be5b1d1f..57facdb8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,37 +35,3 @@ jobs: with: name: Regress Archives path: ${{ github.workspace }}/compiler/tests/results/* -# freepdk45: -# runs-on: self-hosted -# steps: -# - name: Checkout code -# uses: actions/checkout@v1 -# - name: FreePDK45 test -# run: | -# . /home/github-runner/setup-paths.sh -# export OPENRAM_HOME="${{ github.workspace }}/compiler" -# export OPENRAM_TECH="${{ github.workspace }}/technology:/software/PDKs/skywater-tech" -# export OPENRAM_TMP="${{ github.workspace }}/freepdk45_temp" -# #python3-coverage run -p $OPENRAM_HOME/tests/regress.py -j 12 -t freepdk45 -# $OPENRAM_HOME/tests/regress.py -j 24 -t freepdk45 -# - name: Archive -# if: ${{ failure() }} -# uses: actions/upload-artifact@v2 -# with: -# name: FreePDK45 Archives -# path: ${{ github.workspace }}/*.zip - # coverage_stats: - # if: ${{ always() }} - # needs: [scn4me_subm, freepdk45] - # runs-on: self-hosted - # steps: - # - name: Coverage stats - # run: | - # python3-coverage combine - # python3-coverage report - # python3-coverage html -d ${{ github.workspace }}/coverage_html - # - name: Archive coverage - # uses: actions/upload-artifact@v2 - # with: - # name: code-coverage-report - # path: ${{ github.workspace }}/coverage_html/ From f17d661e3ac6c1b19bef84f5a61116f7e6745ecd Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 7 Mar 2022 07:58:41 -0800 Subject: [PATCH 143/229] Add spare column option to tests for sky130 --- compiler/tests/21_hspice_delay_test.py | 11 ++++++++++- compiler/tests/21_model_delay_test.py | 11 ++++++++++- compiler/tests/21_ngspice_delay_global_test.py | 11 ++++++++++- compiler/tests/21_ngspice_delay_test.py | 11 ++++++++++- compiler/tests/21_regression_delay_test.py | 11 ++++++++++- compiler/tests/21_xyce_delay_test.py | 11 ++++++++++- compiler/tests/22_sram_1bank_2mux_func_test.py | 11 ++++++++++- .../tests/22_sram_1bank_2mux_global_func_test.py | 11 ++++++++++- .../tests/22_sram_1bank_2mux_sparecols_func_test.py | 12 ++++++++++-- compiler/tests/22_sram_1bank_4mux_func_test.py | 11 ++++++++++- compiler/tests/22_sram_1bank_8mux_func_test.py | 11 ++++++++++- compiler/tests/22_sram_1bank_nomux_func_test.py | 11 ++++++++++- .../tests/22_sram_1bank_nomux_sparecols_func_test.py | 12 ++++++++++-- .../tests/22_sram_1bank_wmask_1rw_1r_func_test.py | 11 ++++++++++- compiler/tests/22_sram_wmask_func_test.py | 11 ++++++++++- compiler/tests/Makefile | 9 +++++---- 16 files changed, 155 insertions(+), 21 deletions(-) diff --git a/compiler/tests/21_hspice_delay_test.py b/compiler/tests/21_hspice_delay_test.py index 4f8ba8ec..987fffa8 100755 --- a/compiler/tests/21_hspice_delay_test.py +++ b/compiler/tests/21_hspice_delay_test.py @@ -31,9 +31,18 @@ class timing_sram_test(openram_test): reload(characterizer) from characterizer import delay from sram_config import sram_config + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=4, num_words=16, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=1 c.recompute_sizes() debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") diff --git a/compiler/tests/21_model_delay_test.py b/compiler/tests/21_model_delay_test.py index cf320208..71b002e1 100755 --- a/compiler/tests/21_model_delay_test.py +++ b/compiler/tests/21_model_delay_test.py @@ -33,9 +33,18 @@ class model_delay_test(openram_test): from characterizer import elmore from sram import sram from sram_config import sram_config + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=1, num_words=16, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=1 c.recompute_sizes() debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") diff --git a/compiler/tests/21_ngspice_delay_global_test.py b/compiler/tests/21_ngspice_delay_global_test.py index b71313f8..f826880c 100755 --- a/compiler/tests/21_ngspice_delay_global_test.py +++ b/compiler/tests/21_ngspice_delay_global_test.py @@ -33,9 +33,18 @@ class timing_sram_test(openram_test): from characterizer import delay from sram_config import sram_config OPTS.local_array_size = 2 + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=4, num_words=16, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=1 c.recompute_sizes() # c = sram_config(word_size=8, diff --git a/compiler/tests/21_ngspice_delay_test.py b/compiler/tests/21_ngspice_delay_test.py index 15fdaca3..e13eada8 100755 --- a/compiler/tests/21_ngspice_delay_test.py +++ b/compiler/tests/21_ngspice_delay_test.py @@ -30,9 +30,18 @@ class timing_sram_test(openram_test): reload(characterizer) from characterizer import delay from sram_config import sram_config + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=4, num_words=16, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=1 c.recompute_sizes() debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") diff --git a/compiler/tests/21_regression_delay_test.py b/compiler/tests/21_regression_delay_test.py index 9d0c50c8..c79f0218 100755 --- a/compiler/tests/21_regression_delay_test.py +++ b/compiler/tests/21_regression_delay_test.py @@ -33,9 +33,18 @@ class regression_model_test(openram_test): from characterizer import neural_network from sram import sram from sram_config import sram_config + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=1, num_words=16, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=1 c.recompute_sizes() debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") diff --git a/compiler/tests/21_xyce_delay_test.py b/compiler/tests/21_xyce_delay_test.py index 16fdc2f6..6592b50e 100755 --- a/compiler/tests/21_xyce_delay_test.py +++ b/compiler/tests/21_xyce_delay_test.py @@ -31,9 +31,18 @@ class timing_sram_test(openram_test): reload(characterizer) from characterizer import delay from sram_config import sram_config + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=4, num_words=16, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=1 c.recompute_sizes() debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") diff --git a/compiler/tests/22_sram_1bank_2mux_func_test.py b/compiler/tests/22_sram_1bank_2mux_func_test.py index cca6aeeb..dedbba0c 100755 --- a/compiler/tests/22_sram_1bank_2mux_func_test.py +++ b/compiler/tests/22_sram_1bank_2mux_func_test.py @@ -32,9 +32,18 @@ class sram_1bank_2mux_func_test(openram_test): reload(characterizer) from characterizer import functional from sram_config import sram_config + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=4, num_words=32, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=2 c.recompute_sizes() debug.info(1, "Functional test for sram with " diff --git a/compiler/tests/22_sram_1bank_2mux_global_func_test.py b/compiler/tests/22_sram_1bank_2mux_global_func_test.py index 14de7ba8..664815e7 100755 --- a/compiler/tests/22_sram_1bank_2mux_global_func_test.py +++ b/compiler/tests/22_sram_1bank_2mux_global_func_test.py @@ -33,9 +33,18 @@ class sram_1bank_2mux_func_test(openram_test): from characterizer import functional from sram_config import sram_config OPTS.local_array_size = 8 + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=8, num_words=32, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=2 c.recompute_sizes() debug.info(1, "Functional test for sram with " diff --git a/compiler/tests/22_sram_1bank_2mux_sparecols_func_test.py b/compiler/tests/22_sram_1bank_2mux_sparecols_func_test.py index 0e3a0f27..0466af79 100755 --- a/compiler/tests/22_sram_1bank_2mux_sparecols_func_test.py +++ b/compiler/tests/22_sram_1bank_2mux_sparecols_func_test.py @@ -32,10 +32,18 @@ class sram_1bank_2mux_sparecols_func_test(openram_test): reload(characterizer) from characterizer import functional from sram_config import sram_config + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=4, num_words=32, - num_spare_cols=3, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols+2, + num_spare_rows=num_spare_rows) c.words_per_row=2 c.recompute_sizes() debug.info(1, "Functional test for sram with " diff --git a/compiler/tests/22_sram_1bank_4mux_func_test.py b/compiler/tests/22_sram_1bank_4mux_func_test.py index 4f7035cc..c08a4fef 100755 --- a/compiler/tests/22_sram_1bank_4mux_func_test.py +++ b/compiler/tests/22_sram_1bank_4mux_func_test.py @@ -32,9 +32,18 @@ class sram_1bank_4mux_func_test(openram_test): reload(characterizer) from characterizer import functional from sram_config import sram_config + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=4, num_words=128, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=4 c.recompute_sizes() debug.info(1, "Functional test for sram with " diff --git a/compiler/tests/22_sram_1bank_8mux_func_test.py b/compiler/tests/22_sram_1bank_8mux_func_test.py index cc6456cf..6e6190e4 100755 --- a/compiler/tests/22_sram_1bank_8mux_func_test.py +++ b/compiler/tests/22_sram_1bank_8mux_func_test.py @@ -35,9 +35,18 @@ class sram_1bank_8mux_func_test(openram_test): debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) from sram_config import sram_config + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=4, num_words=128, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=8 c.recompute_sizes() debug.info(1, "Functional test for sram with " diff --git a/compiler/tests/22_sram_1bank_nomux_func_test.py b/compiler/tests/22_sram_1bank_nomux_func_test.py index ff33ead5..c0e4e19a 100755 --- a/compiler/tests/22_sram_1bank_nomux_func_test.py +++ b/compiler/tests/22_sram_1bank_nomux_func_test.py @@ -32,9 +32,18 @@ class sram_1bank_nomux_func_test(openram_test): reload(characterizer) from characterizer import functional from sram_config import sram_config + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=4, num_words=16, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=1 c.recompute_sizes() debug.info(1, "Functional test for sram with " diff --git a/compiler/tests/22_sram_1bank_nomux_sparecols_func_test.py b/compiler/tests/22_sram_1bank_nomux_sparecols_func_test.py index a2fa6d88..0116f444 100755 --- a/compiler/tests/22_sram_1bank_nomux_sparecols_func_test.py +++ b/compiler/tests/22_sram_1bank_nomux_sparecols_func_test.py @@ -32,10 +32,18 @@ class sram_1bank_nomux_sparecols_func_test(openram_test): reload(characterizer) from characterizer import functional from sram_config import sram_config + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=4, num_words=16, - num_spare_cols=3, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols+2, + num_spare_rows=num_spare_rows) c.words_per_row=1 c.recompute_sizes() debug.info(1, "Functional test for sram with " diff --git a/compiler/tests/22_sram_1bank_wmask_1rw_1r_func_test.py b/compiler/tests/22_sram_1bank_wmask_1rw_1r_func_test.py index 6808462e..d2b62470 100755 --- a/compiler/tests/22_sram_1bank_wmask_1rw_1r_func_test.py +++ b/compiler/tests/22_sram_1bank_wmask_1rw_1r_func_test.py @@ -36,10 +36,19 @@ class sram_wmask_1w_1r_func_test(openram_test): reload(characterizer) from characterizer import functional from sram_config import sram_config + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=8, num_words=16, write_size=2, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row = 1 c.recompute_sizes() debug.info(1, diff --git a/compiler/tests/22_sram_wmask_func_test.py b/compiler/tests/22_sram_wmask_func_test.py index f41b3d98..de10d9f6 100755 --- a/compiler/tests/22_sram_wmask_func_test.py +++ b/compiler/tests/22_sram_wmask_func_test.py @@ -32,10 +32,19 @@ class sram_wmask_func_test(openram_test): reload(characterizer) from characterizer import functional from sram_config import sram_config + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=8, num_words=16, write_size=4, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=1 c.recompute_sizes() debug.info(1, "Functional test for sram with " diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index bf8f20ae..54cc13c5 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -96,7 +96,7 @@ WORKING_TECH_TEST_STAMPS=$(shell shuf -e -- $(filter-out $(BROKEN_STAMPS), $(TEC # Run all technologies -all: $(WORKING_TECH_TEST_STAMPS) +all: clean $(WORKING_TECH_TEST_STAMPS) @ls -1 $(TOP_DIR)/compiler/tests/results/*/*.bad 1> /dev/null 2>&1 && echo "FAILING TESTS" && ls -1 $(TOP_DIR)/compiler/tests/results/*/*.bad | sed -e "s#^.*results\/##" && exit 1 || exit 0 .PHONY: all @@ -120,8 +120,8 @@ $(TEST_BASES): @mkdir -p results/$*/tmp @docker run \ -v $(TOP_DIR):/openram \ - -v $(FREEPDK45):/pdk/freepdk45\ - -e FREEPDK45=/pdk/freepdk45\ + -v $(FREEPDK45):/freepdk45\ + -e FREEPDK45=/freepdk45\ -v $(PDK_ROOT):/pdk \ -e PDK_ROOT=/pdk \ -e PDKPATH=/pdk/sky130A \ @@ -144,7 +144,8 @@ docker-pull: mount: docker run -it \ -v $(TOP_DIR):/openram \ - -v $(FREEPDK45):/pdk/freepdk45 \ + -v $(FREEPDK45):/freepdk45 \ + -e FREEPDK45=/freepdk45\ -v $(PDK_ROOT):/pdk \ -e PDK_ROOT=/pdk \ -e PDKPATH=/pdk/sky130A \ From 0667a93d5361e5135704c060ecedb1ac71c91b51 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Mon, 7 Mar 2022 13:45:50 -0800 Subject: [PATCH 144/229] single port rba passing lvs --- .../sky130/modules/sky130_col_cap_array.py | 46 ++++++++++++++++++- .../sky130/modules/sky130_replica_column.py | 2 +- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/technology/sky130/modules/sky130_col_cap_array.py b/technology/sky130/modules/sky130_col_cap_array.py index a363dda2..fa70ed27 100644 --- a/technology/sky130/modules/sky130_col_cap_array.py +++ b/technology/sky130/modules/sky130_col_cap_array.py @@ -89,10 +89,10 @@ class sky130_col_cap_array(sky130_bitcell_base_array): elif col % 4 == 2: row_layout.append(self.colend1) self.cell_inst[col]=self.add_inst(name=name, mod=self.colend1) - pins.append("fake_bl_{}".format(bitline)) + pins.append("fake_br_{}".format(bitline)) pins.append("vdd") pins.append("gnd") - pins.append("fake_br_{}".format(bitline)) + pins.append("fake_bl_{}".format(bitline)) pins.append("gate") bitline += 1 elif col % 4 ==3: @@ -170,6 +170,48 @@ class sky130_col_cap_array(sky130_bitcell_base_array): offset=inst.lr(), width=pin.width(), height=pin.height()) + + + for col in range(len(self.insts)): + + inst = self.insts[col] + if col % 4 == 0: + pin = self.cell_inst[col].get_pin("bl") + text = "fake_bl_{}".format(int(col/2)) + self.add_layout_pin(text=text, + layer=pin.layer, + offset=pin.ll().scale(1, 0), + width=pin.width(), + height=pin.height()) + + pin = self.cell_inst[col].get_pin("br") + text = "fake_br_{}".format(int(col/2)) + self.add_layout_pin(text=text, + layer=pin.layer, + offset=pin.ll().scale(1, 0), + width=pin.width(), + height=pin.height()) + + elif col % 4 == 2: + pin = self.cell_inst[col].get_pin("bl") + text = "fake_br_{}".format(int(col/2)) + self.add_layout_pin(text=text, + layer=pin.layer, + offset=pin.ll().scale(1, 0), + width=pin.width(), + height=pin.height()) + + pin = self.cell_inst[col].get_pin("br") + text = "fake_bl_{}".format(int(col/2)) + self.add_layout_pin(text=text, + layer=pin.layer, + offset=pin.ll().scale(1, 0), + width=pin.width(), + height=pin.height()) + + + + return def add_supply_pins(self): diff --git a/technology/sky130/modules/sky130_replica_column.py b/technology/sky130/modules/sky130_replica_column.py index 90c24222..d0eb9979 100644 --- a/technology/sky130/modules/sky130_replica_column.py +++ b/technology/sky130/modules/sky130_replica_column.py @@ -214,7 +214,7 @@ class sky130_replica_column(sky130_bitcell_base_array): for port in self.all_ports: for row in range(row_range_min, row_range_max): wl_pin = self.cell_inst[row].get_pin(self.cell.get_wl_name(port)) - self.add_layout_pin(text="wl_{0}_{1}".format(port, row), + self.add_layout_pin(text="wl_{0}_{1}".format(port, row_range_max-row), layer=wl_pin.layer, offset=wl_pin.ll().scale(0, 1), width=self.width, From 772fbd6f9650f77f5b5c163ac05ad3bdea1c4afc Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 7 Mar 2022 15:38:25 -0800 Subject: [PATCH 145/229] Remove extra well tap to save area. --- compiler/pgates/pand2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/pgates/pand2.py b/compiler/pgates/pand2.py index b8d1feed..ab601096 100644 --- a/compiler/pgates/pand2.py +++ b/compiler/pgates/pand2.py @@ -32,7 +32,7 @@ class pand2(pgate.pgate): def create_modules(self): self.nand = factory.create(module_type="pnand2", height=self.height, - add_wells=self.add_wells) + add_wells=False) self.inv = factory.create(module_type="pdriver", size_list=[self.size], From 27968008983aaf0ddf7469f9e32cc8fa7e1a19ae Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 7 Mar 2022 16:12:20 -0800 Subject: [PATCH 146/229] Fix bug with incorrect pitch while adding channel route trunks. --- compiler/base/channel_route.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/base/channel_route.py b/compiler/base/channel_route.py index abbb267b..9b240a72 100644 --- a/compiler/base/channel_route.py +++ b/compiler/base/channel_route.py @@ -99,6 +99,8 @@ class channel_route(design.design): channel_route.unique_id += 1 super().__init__(name) + if self.name == "cr_7": + breakpoint() self.netlist = netlist self.offset = offset self.layer_stack = layer_stack @@ -242,12 +244,12 @@ class channel_route(design.design): if self.vertical: self.add_vertical_trunk_route(net.pins, current_offset, - self.vertical_nonpref_pitch) + self.horizontal_pitch) current_offset = vector(current_offset.x, net.max_value + self.horizontal_nonpref_pitch) else: self.add_horizontal_trunk_route(net.pins, current_offset, - self.horizontal_nonpref_pitch) + self.vertical_pitch) current_offset = vector(net.max_value + self.vertical_nonpref_pitch, current_offset.y) # Remove the net from other constriants in the VCG From 08c2e21724a657f0f380ac06326fae58818fe62b Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 7 Mar 2022 16:13:37 -0800 Subject: [PATCH 147/229] Fix tab spacing in Makefile --- macros/Makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/macros/Makefile b/macros/Makefile index 5da8d7ef..31943ad9 100644 --- a/macros/Makefile +++ b/macros/Makefile @@ -55,21 +55,21 @@ all: | configs docker run -v $(TOP_DIR):/openram \ -v $(SKY130_PDK):$(SKY130_PDK) \ -e PDK_ROOT=$(PDK_ROOT) \ - -e OPENRAM_HOME=/openram/compiler \ - -e OPENRAM_TECH=/openram/technology \ + -e OPENRAM_HOME=/openram/compiler \ + -e OPENRAM_TECH=/openram/technology \ -e OPENRAM_TMP=/openram/macros/$*/tmp \ --user $(UID):$(GID) \ - vlsida/openram-ubuntu:latest \ + vlsida/openram-ubuntu:latest \ python3 -u /openram/compiler/openram.py $(OPENRAM_OPTS) -o $* -p /openram/macros/$* /openram/macros/$< && touch $@ mount: docker run -it -v $(TOP_DIR):/openram \ -v $(SKY130_PDK):$(SKY130_PDK) \ -e PDK_ROOT=$(PDK_ROOT) \ - -e OPENRAM_HOME=/openram/compiler \ - -e OPENRAM_TECH=/openram/technology \ + -e OPENRAM_HOME=/openram/compiler \ + -e OPENRAM_TECH=/openram/technology \ --user $(UID):$(GID) \ - vlsida/openram-ubuntu:latest + vlsida/openram-ubuntu:latest .PHONY: mount From b841e18abdead42fe45ce108fee30bc10d1ca137 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 7 Mar 2022 16:59:55 -0800 Subject: [PATCH 148/229] Remove breakpoint --- compiler/base/channel_route.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/base/channel_route.py b/compiler/base/channel_route.py index 9b240a72..d64b7e3c 100644 --- a/compiler/base/channel_route.py +++ b/compiler/base/channel_route.py @@ -99,8 +99,6 @@ class channel_route(design.design): channel_route.unique_id += 1 super().__init__(name) - if self.name == "cr_7": - breakpoint() self.netlist = netlist self.offset = offset self.layer_stack = layer_stack From e16defdae4a6c7dae082a4ee3c7093d0e2c05d11 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 9 Mar 2022 10:24:50 -0800 Subject: [PATCH 149/229] Add a sleep to see if problem is async one --- compiler/tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 54cc13c5..c5d508c4 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -129,7 +129,7 @@ $(TEST_BASES): --user $(UID):$(GID) \ -e OPENRAM_TMP=$(OPENRAM_DIR)/results/$*/tmp \ vlsida/openram-ubuntu:latest \ - sh -c ". /home/cad-user/.bashrc && python3 -u $(OPENRAM_DIR)/$(getfile).py \ + sh -c ". /home/cad-user/.bashrc && sleep 1 && python3 -u $(OPENRAM_DIR)/$(getfile).py \ -t $(gettech) -k -v $(ARGS) -p $(OPENRAM_DIR)/results/$* > $(OPENRAM_DIR)/results/$*.out 2>&1 && touch $(OPENRAM_DIR)/results/$*.ok || touch $(OPENRAM_DIR)/results/$*.bad" @test -f $(TOP_DIR)/compiler/tests/results/$*.ok && echo "$* ... PASS!" && \ rm -rf $(TOP_DIR)/compiler/tests/results/$* || echo "$* ... FAIL!" From 4567c2ebcddfea945bb1b89f649d2891bca2374e Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 10 Mar 2022 08:37:48 -0800 Subject: [PATCH 150/229] Add space after docker command. Regress to klayout v0.27.4 --- compiler/tests/Makefile | 4 ++-- docker/Dockerfile | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index c5d508c4..2cd5c17d 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -120,8 +120,8 @@ $(TEST_BASES): @mkdir -p results/$*/tmp @docker run \ -v $(TOP_DIR):/openram \ - -v $(FREEPDK45):/freepdk45\ - -e FREEPDK45=/freepdk45\ + -v $(FREEPDK45):/freepdk45 \ + -e FREEPDK45=/freepdk45 \ -v $(PDK_ROOT):/pdk \ -e PDK_ROOT=/pdk \ -e PDKPATH=/pdk/sky130A \ diff --git a/docker/Dockerfile b/docker/Dockerfile index e1045107..0913cfba 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -24,7 +24,8 @@ RUN apt-get install --no-install-recommends -y libx11-dev libcairo2-dev RUN apt-get install --no-install-recommends -y qt5-default qtcreator ruby-full ruby-dev python3-dev qtmultimedia5-dev libqt5multimediawidgets5 libqt5multimedia5-plugins libqt5multimedia5 libqt5svg5-dev libqt5designer5 libqt5designercomponents5 libqt5xmlpatterns5-dev qttools5-dev ### Klayout ### -ARG KLAYOUT_COMMIT=v0.27.8 +#ARG KLAYOUT_COMMIT=v0.27.8 +ARG KLAYOUT_COMMIT=ea1bf40a1ee1c1c934e47a0020417503ab3d7e7e WORKDIR /root RUN git clone https://github.com/KLayout/klayout WORKDIR /root/klayout From c2589fbb398b07f0ef8c73a87f9bbaad58e32c39 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 10 Mar 2022 11:48:53 -0800 Subject: [PATCH 151/229] Change docker to use debug klayout --- docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 0913cfba..3922477c 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -30,8 +30,8 @@ WORKDIR /root RUN git clone https://github.com/KLayout/klayout WORKDIR /root/klayout RUN git checkout ${KLAYOUT_COMMIT} -RUN ./build.sh -qt5 -j 8 \ - && cp -r bin-release /usr/local/klayout +RUN ./build.sh -qt5 -debug -j 8 \ + && cp -r bin-debug /usr/local/klayout RUN rm -rf /root/klayout ### Trilinos ### From b981ad58149cb03e8c06c5eba1ffce30e5cf4fe0 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 11 Mar 2022 10:17:24 -0800 Subject: [PATCH 152/229] Erase duplicate macro configs --- macros/configs/riscv_sky130_1kbyte_1rw.py | 25 --------------------- macros/configs/riscv_sky130_1kbyte_1rw1r.py | 25 --------------------- macros/configs/riscv_sky130_2kbyte_1rw.py | 25 --------------------- macros/configs/riscv_sky130_2kbyte_1rw1r.py | 25 --------------------- macros/configs/riscv_sky130_4kbyte_1rw.py | 25 --------------------- macros/configs/riscv_sky130_4kbyte_1rw1r.py | 25 --------------------- 6 files changed, 150 deletions(-) delete mode 100644 macros/configs/riscv_sky130_1kbyte_1rw.py delete mode 100644 macros/configs/riscv_sky130_1kbyte_1rw1r.py delete mode 100644 macros/configs/riscv_sky130_2kbyte_1rw.py delete mode 100644 macros/configs/riscv_sky130_2kbyte_1rw1r.py delete mode 100644 macros/configs/riscv_sky130_4kbyte_1rw.py delete mode 100644 macros/configs/riscv_sky130_4kbyte_1rw1r.py diff --git a/macros/configs/riscv_sky130_1kbyte_1rw.py b/macros/configs/riscv_sky130_1kbyte_1rw.py deleted file mode 100644 index 9bdf47ed..00000000 --- a/macros/configs/riscv_sky130_1kbyte_1rw.py +++ /dev/null @@ -1,25 +0,0 @@ -word_size = 32 -num_words = 256 -write_size = 8 - -local_array_size = 16 - -num_rw_ports = 1 -num_r_ports = 0 -num_w_ports = 0 - -tech_name = "sky130" -nominal_corner_only = True - -route_supplies = False -check_lvsdrc = True -perimeter_pins = False -#netlist_only = True -#analytical_delay = False -output_name = "sram_{0}rw{1}r{2}w_{3}_{4}_{5}".format(num_rw_ports, - num_r_ports, - num_w_ports, - word_size, - num_words, - tech_name) -output_path = "macro/{}".format(output_name) diff --git a/macros/configs/riscv_sky130_1kbyte_1rw1r.py b/macros/configs/riscv_sky130_1kbyte_1rw1r.py deleted file mode 100644 index d0b47857..00000000 --- a/macros/configs/riscv_sky130_1kbyte_1rw1r.py +++ /dev/null @@ -1,25 +0,0 @@ -word_size = 32 -num_words = 256 -write_size = 8 - -#local_array_size = 16 - -num_rw_ports = 1 -num_r_ports = 1 -num_w_ports = 0 - -tech_name = "sky130" -nominal_corner_only = True - -#route_supplies = False -check_lvsdrc = True -#perimeter_pins = False -#netlist_only = True -#analytical_delay = False -output_name = "sram_{0}rw{1}r{2}w_{3}_{4}_{5}".format(num_rw_ports, - num_r_ports, - num_w_ports, - word_size, - num_words, - tech_name) -output_path = "macro/{}".format(output_name) diff --git a/macros/configs/riscv_sky130_2kbyte_1rw.py b/macros/configs/riscv_sky130_2kbyte_1rw.py deleted file mode 100644 index b85df3f9..00000000 --- a/macros/configs/riscv_sky130_2kbyte_1rw.py +++ /dev/null @@ -1,25 +0,0 @@ -word_size = 32 -num_words = 512 -write_size = 8 - -local_array_size = 16 - -num_rw_ports = 1 -num_r_ports = 0 -num_w_ports = 0 - -tech_name = "sky130" -nominal_corner_only = True - -route_supplies = False -check_lvsdrc = True -perimeter_pins = False -#netlist_only = True -#analytical_delay = False -output_name = "sram_{0}rw{1}r{2}w_{3}_{4}_{5}".format(num_rw_ports, - num_r_ports, - num_w_ports, - word_size, - num_words, - tech_name) -output_path = "macro/{}".format(output_name) diff --git a/macros/configs/riscv_sky130_2kbyte_1rw1r.py b/macros/configs/riscv_sky130_2kbyte_1rw1r.py deleted file mode 100644 index e94882e9..00000000 --- a/macros/configs/riscv_sky130_2kbyte_1rw1r.py +++ /dev/null @@ -1,25 +0,0 @@ -word_size = 32 -num_words = 512 -write_size = 8 - -local_array_size = 16 - -num_rw_ports = 1 -num_r_ports = 1 -num_w_ports = 0 - -tech_name = "sky130" -nominal_corner_only = True - -route_supplies = False -check_lvsdrc = True -perimeter_pins = False -#netlist_only = True -#analytical_delay = False -output_name = "sram_{0}rw{1}r{2}w_{3}_{4}_{5}".format(num_rw_ports, - num_r_ports, - num_w_ports, - word_size, - num_words, - tech_name) -output_path = "macro/{}".format(output_name) diff --git a/macros/configs/riscv_sky130_4kbyte_1rw.py b/macros/configs/riscv_sky130_4kbyte_1rw.py deleted file mode 100644 index 1b6cdc07..00000000 --- a/macros/configs/riscv_sky130_4kbyte_1rw.py +++ /dev/null @@ -1,25 +0,0 @@ -word_size = 32 -num_words = 1024 -write_size = 8 - -local_array_size = 16 - -num_rw_ports = 1 -num_r_ports = 0 -num_w_ports = 0 - -tech_name = "sky130" -nominal_corner_only = True - -route_supplies = False -check_lvsdrc = True -perimeter_pins = False -#netlist_only = True -#analytical_delay = False -output_name = "sram_{0}rw{1}r{2}w_{3}_{4}_{5}".format(num_rw_ports, - num_r_ports, - num_w_ports, - word_size, - num_words, - tech_name) -output_path = "macro/{}".format(output_name) diff --git a/macros/configs/riscv_sky130_4kbyte_1rw1r.py b/macros/configs/riscv_sky130_4kbyte_1rw1r.py deleted file mode 100644 index 2d53df31..00000000 --- a/macros/configs/riscv_sky130_4kbyte_1rw1r.py +++ /dev/null @@ -1,25 +0,0 @@ -word_size = 32 -num_words = 1024 -write_size = 8 - -local_array_size = 16 - -num_rw_ports = 1 -num_r_ports = 1 -num_w_ports = 0 - -tech_name = "sky130" -nominal_corner_only = True - -route_supplies = False -check_lvsdrc = True -perimeter_pins = False -#netlist_only = True -#analytical_delay = False -output_name = "sram_{0}rw{1}r{2}w_{3}_{4}_{5}".format(num_rw_ports, - num_r_ports, - num_w_ports, - word_size, - num_words, - tech_name) -output_path = "macro/{}".format(output_name) From 229a3b5b3d0375f075a9aaf7b48fa4bf1206d0e7 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 11 Mar 2022 18:01:45 -0800 Subject: [PATCH 153/229] By default uniquify instances based on macro name. --- compiler/base/hierarchy_design.py | 10 ++++++++++ compiler/base/hierarchy_layout.py | 7 +------ compiler/globals.py | 1 - compiler/openram.py | 5 +++-- compiler/options.py | 4 ---- compiler/sram/sram.py | 20 -------------------- compiler/tests/configs/config.py | 1 + compiler/tests/configs/config_back_end.py | 1 + compiler/tests/configs/config_front_end.py | 2 ++ technology/freepdk45/tech/freepdk45.lylvs | 2 +- 10 files changed, 19 insertions(+), 34 deletions(-) diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py index fe295273..00edc558 100644 --- a/compiler/base/hierarchy_design.py +++ b/compiler/base/hierarchy_design.py @@ -8,6 +8,7 @@ import hierarchy_layout import hierarchy_spice import debug +import os from globals import OPTS @@ -22,6 +23,15 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): self.drc_errors = "skipped" self.lvs_errors = "skipped" + # Flag for library cells which is recomputed in hierachy_layout + gds_file = OPTS.openram_tech + "gds_lib/" + cell_name + ".gds" + is_library_cell = os.path.isfile(gds_file) + # Uniquify names to address the flat GDS namespace + # except for the top/output name + if not is_library_cell and name != OPTS.output_name: + name = OPTS.output_name + "_" + name + cell_name = name + hierarchy_spice.spice.__init__(self, name, cell_name) hierarchy_layout.layout.__init__(self, name, cell_name) self.init_graph_params() diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index b3eff27d..bb17f81d 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -42,6 +42,7 @@ class layout(): self.cell_name = cell_name self.gds_file = OPTS.openram_tech + "gds_lib/" + cell_name + ".gds" + self.is_library_cell = os.path.isfile(self.gds_file) self.width = None self.height = None @@ -60,8 +61,6 @@ class layout(): self.pin_map = {} # List of modules we have already visited self.visited = [] - # Flag for library cells - self.is_library_cell = False self.gds_read() @@ -903,10 +902,6 @@ class layout(): """Reads a GDSII file in the library and checks if it exists Otherwise, start a new layout for dynamic generation.""" - # This must be done for netlist only mode too - if os.path.isfile(self.gds_file): - self.is_library_cell = True - if OPTS.netlist_only: self.gds = None return diff --git a/compiler/globals.py b/compiler/globals.py index 15bb4fe9..d0c0d673 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -377,7 +377,6 @@ def read_config(config_file, is_unit_test=True): ports, OPTS.tech_name) - def end_openram(): """ Clean up openram for a proper exit """ cleanup_paths() diff --git a/compiler/openram.py b/compiler/openram.py index 089c0f3a..3a509f3b 100755 --- a/compiler/openram.py +++ b/compiler/openram.py @@ -74,8 +74,9 @@ for path in output_files: from sram import sram -s = sram(sram_config=c, - name=OPTS.output_name) +s = sram(name=OPTS.output_name, + sram_config=c) + # Output the files for the resulting SRAM s.save() diff --git a/compiler/options.py b/compiler/options.py index d81a8c7e..ebf716b0 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -166,10 +166,6 @@ class options(optparse.Values): keep_temp = False - # Add a prefix of the root cell before every structure in the GDS - # after outputting the GDS2 - uniquify = False - # These are the default modules that can be over-riden bank_select = "bank_select" bitcell_array = "bitcell_array" diff --git a/compiler/sram/sram.py b/compiler/sram/sram.py index 90855d8e..b656f547 100644 --- a/compiler/sram/sram.py +++ b/compiler/sram/sram.py @@ -61,26 +61,6 @@ class sram(): def gds_write(self, name): self.s.gds_write(name) - # This addresses problems with flat GDS namespaces when we - # want to merge this SRAM with other SRAMs. - if OPTS.uniquify: - import gdsMill - gds = gdsMill.VlsiLayout() - reader = gdsMill.Gds2reader(gds) - reader.loadFromFile(name) - - # Uniquify but skip the library cells since they are hard coded - try: - from tech import library_prefix_name - except ImportError: - library_prefix_name = None - gds.uniquify(library_prefix_name) - - writer = gdsMill.Gds2writer(gds) - unique_name = name.replace(".gds", "_unique.gds") - writer.writeToFile(unique_name) - shutil.move(unique_name, name) - def verilog_write(self, name): self.s.verilog_write(name) diff --git a/compiler/tests/configs/config.py b/compiler/tests/configs/config.py index dc3739ab..9e35f558 100644 --- a/compiler/tests/configs/config.py +++ b/compiler/tests/configs/config.py @@ -14,3 +14,4 @@ tech_name = OPTS.tech_name nominal_corner_only = True check_lvsdrc = True +output_name = "sram" diff --git a/compiler/tests/configs/config_back_end.py b/compiler/tests/configs/config_back_end.py index 3294e979..4bf0aa8b 100644 --- a/compiler/tests/configs/config_back_end.py +++ b/compiler/tests/configs/config_back_end.py @@ -15,4 +15,5 @@ nominal_corner_only = True check_lvsdrc = True spice_name = "ngspice" +output_name = "sram" diff --git a/compiler/tests/configs/config_front_end.py b/compiler/tests/configs/config_front_end.py index 4486b077..2b42a914 100644 --- a/compiler/tests/configs/config_front_end.py +++ b/compiler/tests/configs/config_front_end.py @@ -11,3 +11,5 @@ num_words = 16 tech_name = OPTS.tech_name +output_name = "sram" + diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index 934a981c..5500d9e3 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -214,7 +214,7 @@ connect_global(pwell, "PWELL") connect_global(nwell, "NWELL") connect_global(bulk, "BULK") -for pat in %w(pinv* pnor* pnand* and?_dec* write_driver* port_address* replica_bitcell_array*) +for pat in %w(*pinv* *pnor* *pnand* *and?_dec* *write_driver* *port_address* *replica_bitcell_array*) connect_explicit(pat, [ "NWELL", "vdd" ]) connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) end From 8979612ccaaca2ecd1d666761119c738be14dc46 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 14 Mar 2022 10:14:31 -0700 Subject: [PATCH 154/229] Rework macro Makefile to take technology target --- macros/Makefile | 24 ++++++++++++++----- ...bm.py => example_config_big_scn4m_subm.py} | 0 ....py => example_config_giant_scn4m_subm.py} | 0 ...py => example_config_medium_scn4m_subm.py} | 0 ...e.py => freepdk45_sram_1rw1r_32x2048_8.py} | 0 ...cn4m_subm_sram_16kbyte_1rw1r_32x4096_8.py} | 0 ... scn4m_subm_sram_1kbyte_1rw1r_32x256_8.py} | 0 ... scn4m_subm_sram_2kbyte_1rw1r_32x512_8.py} | 0 ...4m_subm_sram_32kbyte_1rw1r_2x32x4096_8.py} | 1 + ...scn4m_subm_sram_4kbyte_1rw1r_32x1024_8.py} | 0 ...scn4m_subm_sram_8kbyte_1rw1r_32x2048_8.py} | 0 11 files changed, 19 insertions(+), 6 deletions(-) rename macros/configs/{big_config_scn4m_subm.py => example_config_big_scn4m_subm.py} (100%) rename macros/configs/{giant_config_scn4m_subm.py => example_config_giant_scn4m_subm.py} (100%) rename macros/configs/{medium_config_scn4m_subm.py => example_config_medium_scn4m_subm.py} (100%) rename macros/configs/{riscv_freepdk45_8kbyte.py => freepdk45_sram_1rw1r_32x2048_8.py} (100%) rename macros/configs/{riscv_scn4m_subm_16kbyte_1rw1r.py => scn4m_subm_sram_16kbyte_1rw1r_32x4096_8.py} (100%) rename macros/configs/{riscv_scn4m_subm_1kbyte_1rw1r.py => scn4m_subm_sram_1kbyte_1rw1r_32x256_8.py} (100%) rename macros/configs/{riscv_scn4m_subm_2kbyte_1rw1r.py => scn4m_subm_sram_2kbyte_1rw1r_32x512_8.py} (100%) rename macros/configs/{riscv_scn4m_subm_32kbyte_1rw1r.py => scn4m_subm_sram_32kbyte_1rw1r_2x32x4096_8.py} (98%) rename macros/configs/{riscv_scn4m_subm_4kbyte_1rw1r.py => scn4m_subm_sram_4kbyte_1rw1r_32x1024_8.py} (100%) rename macros/configs/{riscv_scn4m_subm_8kbyte_1rw1r.py => scn4m_subm_sram_8kbyte_1rw1r_32x2048_8.py} (100%) diff --git a/macros/Makefile b/macros/Makefile index 31943ad9..ca7bcdc7 100644 --- a/macros/Makefile +++ b/macros/Makefile @@ -33,15 +33,15 @@ configs: .PHONY: configs -BROKEN := \ - sky130_sram_1kbyte_1r1w_8x1024_8 \ - sky130_sram_1kbyte_1rw_32x256_8 \ - sky130_sram_2kbyte_1rw_32x512_8 \ - sky130_sram_4kbyte_1rw_32x1024_8 \ +BROKEN := WORKING_STAMPS=$(filter-out $(addsuffix .ok, $(BROKEN)), $(STAMPS)) +EXAMPLE_STAMPS=$(filter example%, $(WORKING_STAMPS)) +SKY130_STAMPS=$(filter sky130%, $(WORKING_STAMPS)) +FREEPDK45_STAMPS=$(filter freepdk45%, $(WORKING_STAMPS)) +SCN4M_SUBM_STAMPS=$(filter scn4m_subm%, $(WORKING_STAMPS)) -all: | configs +all: | configs @echo @echo "Building following working configs" @for S in $(WORKING_STAMPS); do echo " - $$S"; done @@ -49,6 +49,18 @@ all: | configs $(MAKE) $(WORKING_STAMPS) @echo "Built all macros." +example: $(EXAMPLE_STAMPS) +.PHONY: example + +sky130: $(SKY130_STAMPS) +.PHONY: sky130 + +freepdk45: $(FREEPDK45_STAMPS) +.PHONY: freepdk45 + +scn4m_subm: $(SCN4M_SUBM_STAMPS) +.PHONY: scn4m_subm + %.ok: configs/%.py @echo "Building $*" @mkdir -p $* diff --git a/macros/configs/big_config_scn4m_subm.py b/macros/configs/example_config_big_scn4m_subm.py similarity index 100% rename from macros/configs/big_config_scn4m_subm.py rename to macros/configs/example_config_big_scn4m_subm.py diff --git a/macros/configs/giant_config_scn4m_subm.py b/macros/configs/example_config_giant_scn4m_subm.py similarity index 100% rename from macros/configs/giant_config_scn4m_subm.py rename to macros/configs/example_config_giant_scn4m_subm.py diff --git a/macros/configs/medium_config_scn4m_subm.py b/macros/configs/example_config_medium_scn4m_subm.py similarity index 100% rename from macros/configs/medium_config_scn4m_subm.py rename to macros/configs/example_config_medium_scn4m_subm.py diff --git a/macros/configs/riscv_freepdk45_8kbyte.py b/macros/configs/freepdk45_sram_1rw1r_32x2048_8.py similarity index 100% rename from macros/configs/riscv_freepdk45_8kbyte.py rename to macros/configs/freepdk45_sram_1rw1r_32x2048_8.py diff --git a/macros/configs/riscv_scn4m_subm_16kbyte_1rw1r.py b/macros/configs/scn4m_subm_sram_16kbyte_1rw1r_32x4096_8.py similarity index 100% rename from macros/configs/riscv_scn4m_subm_16kbyte_1rw1r.py rename to macros/configs/scn4m_subm_sram_16kbyte_1rw1r_32x4096_8.py diff --git a/macros/configs/riscv_scn4m_subm_1kbyte_1rw1r.py b/macros/configs/scn4m_subm_sram_1kbyte_1rw1r_32x256_8.py similarity index 100% rename from macros/configs/riscv_scn4m_subm_1kbyte_1rw1r.py rename to macros/configs/scn4m_subm_sram_1kbyte_1rw1r_32x256_8.py diff --git a/macros/configs/riscv_scn4m_subm_2kbyte_1rw1r.py b/macros/configs/scn4m_subm_sram_2kbyte_1rw1r_32x512_8.py similarity index 100% rename from macros/configs/riscv_scn4m_subm_2kbyte_1rw1r.py rename to macros/configs/scn4m_subm_sram_2kbyte_1rw1r_32x512_8.py diff --git a/macros/configs/riscv_scn4m_subm_32kbyte_1rw1r.py b/macros/configs/scn4m_subm_sram_32kbyte_1rw1r_2x32x4096_8.py similarity index 98% rename from macros/configs/riscv_scn4m_subm_32kbyte_1rw1r.py rename to macros/configs/scn4m_subm_sram_32kbyte_1rw1r_2x32x4096_8.py index 87ddb5eb..285b1dbf 100644 --- a/macros/configs/riscv_scn4m_subm_32kbyte_1rw1r.py +++ b/macros/configs/scn4m_subm_sram_32kbyte_1rw1r_2x32x4096_8.py @@ -1,3 +1,4 @@ +num_banks=2 word_size = 32 num_words = 8192 write_size = 8 diff --git a/macros/configs/riscv_scn4m_subm_4kbyte_1rw1r.py b/macros/configs/scn4m_subm_sram_4kbyte_1rw1r_32x1024_8.py similarity index 100% rename from macros/configs/riscv_scn4m_subm_4kbyte_1rw1r.py rename to macros/configs/scn4m_subm_sram_4kbyte_1rw1r_32x1024_8.py diff --git a/macros/configs/riscv_scn4m_subm_8kbyte_1rw1r.py b/macros/configs/scn4m_subm_sram_8kbyte_1rw1r_32x2048_8.py similarity index 100% rename from macros/configs/riscv_scn4m_subm_8kbyte_1rw1r.py rename to macros/configs/scn4m_subm_sram_8kbyte_1rw1r_32x2048_8.py From 7e7670581c11fb4f579acc81e9516de5610facdf Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 16 Mar 2022 07:58:29 -0700 Subject: [PATCH 155/229] Add some vertical/horizontal pins for sky130 only --- compiler/base/hierarchy_layout.py | 76 +++++++++++++++-------- compiler/modules/hierarchical_decoder.py | 2 +- compiler/modules/precharge_array.py | 2 +- compiler/modules/replica_bitcell_array.py | 27 +++----- 4 files changed, 59 insertions(+), 48 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index bb17f81d..3ebc4ac3 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -449,12 +449,19 @@ class layout(): bins[x] = [(inst,pin)] for x, v in bins.items(): - # Not enough to route a pin + # Not enough to route a pin, so just copy them if len(v) < 2: + debug.warning("Copying pins instead of connecting with pin.") + for inst,pin in v: + self.add_layout_pin(pin.name, + pin.layer, + pin.ll(), + pin.width(), + pin.height()) continue - bot_y = min([inst.by() for (inst,pin) in v]) - top_y = max([inst.uy() for (inst,pin) in v]) + bot_y = min([pin.by() for (inst,pin) in v]) + top_y = max([pin.uy() for (inst,pin) in v]) last_via = None for inst,pin in v: @@ -477,16 +484,21 @@ class layout(): top_pos = vector(x, top_y) bot_pos = vector(x, bot_y) - rect = self.add_layout_pin_rect_center(text=name, - layer=pin_layer, - offset=top_pos) -# self.add_layout_pin_rect_center(text=name, -# layer=pin_layer, -# offset=bot_pos) - self.add_segment_center(layer=pin_layer, - start=vector(rect.cx(), bot_pos.y), - end=rect.bc(), - width=via_width) +# top_rect = self.add_layout_pin_rect_center(text=name, +# layer=pin_layer, +# offset=top_pos) + #bot_rect = self.add_layout_pin_rect_center(text=name, + # layer=pin_layer, + # offset=bot_pos) +# self.add_segment_center(layer=pin_layer, +# start=vector(top_rect.cx(), bot_pos.y), +# end=top_rect.bc(), +# width=via_width) + self.add_layout_pin_segment_center(text=name, + layer=pin_layer, + start=top_pos, + end=bot_pos, + width=via_width) @@ -514,12 +526,18 @@ class layout(): # Filter the small bins for y, v in bins.items(): - # Not enough to route a pin if len(v) < 2: + debug.warning("Copying pins instead of connecting with pin.") + for inst,pin in v: + self.add_layout_pin(pin.name, + pin.layer, + pin.ll(), + pin.width(), + pin.height()) continue - left_x = min([inst.lx() for (inst,pin) in v]) - right_x = max([inst.rx() for (inst,pin) in v]) + left_x = min([pin.lx() for (inst,pin) in v]) + right_x = max([pin.rx() for (inst,pin) in v]) last_via = None for inst,pin in v: @@ -543,19 +561,25 @@ class layout(): left_pos = vector(left_x, y) right_pos = vector(right_x, y) - rect = self.add_layout_pin_rect_center(text=name, - layer=pin_layer, - offset=left_pos) -# self.add_layout_pin_rect_center(text=name, -# layer=pin_layer, -# offset=right_pos) +# left_rect = self.add_layout_pin_rect_center(text=name, +# layer=pin_layer, +# offset=left_pos) + #right_rect = self.add_layout_pin_rect_center(text=name, + # layer=pin_layer, + # offset=right_pos) # This is made to not overlap with the pin above # so that the power router will only select a small pin. # Otherwise it adds big blockages over the rails. - self.add_segment_center(layer=pin_layer, - start=rect.rc(), - end=vector(right_pos.x, rect.cy()), - width=via_height) +# self.add_segment_center(layer=pin_layer, +# start=left_rect.rc(), +# end=vector(right_pos.x, left_rect.cy()), +# width=via_height) + + self.add_layout_pin_segment_center(text=name, + layer=pin_layer, + start=left_pos, + end=right_pos, + width=via_height) def add_layout_pin_segment_center(self, text, layer, start, end, width=None): diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index 0db5acbb..f9987bb8 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -596,7 +596,7 @@ class hierarchical_decoder(design.design): """ # This is an experiment with power rails - if OPTS.experimental_power: + if OPTS.tech_name=="sky130" or OPTS.experimental_power: if layer_props.hierarchical_decoder.vertical_supply: pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst self.route_vertical_pins("vdd", insts=pre_insts, yside="by") diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index 0215d76a..cfd2015b 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -95,7 +95,7 @@ class precharge_array(design.design): self.copy_layout_pin(inst, "br", "br_{0}".format(i)) def route_supplies(self): - if OPTS.experimental_power: + if OPTS.tech_name=="sky130" or OPTS.experimental_power: self.route_horizontal_pins("vdd") else: for inst in self.local_insts: diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 57a58d79..be6d1ef5 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -458,27 +458,14 @@ class replica_bitcell_array(bitcell_base_array): width=pin.width(), height=self.height) - # vdd/gnd are only connected in the perimeter cells - # replica column should only have a vdd/gnd in the dummy cell on top/bottom - supply_insts = self.dummy_col_insts + self.dummy_row_insts - - - if OPTS.experimental_power: - for pin_name in self.supplies: - #self.route_vertical_pins(name=pin_name, insts=supply_insts) - self.route_horizontal_pins(name=pin_name, insts=supply_insts) - - #self.route_vertical_pins(name=pin_name, insts=self.replica_col_insts) - #self.route_horizontal_pins(name=pin_name, insts=self.replica_col_insts) - for inst in supply_insts: - pin_list = inst.get_pins(pin_name) - for pin in pin_list: - self.copy_power_pin(pin) - - for inst in self.replica_col_insts: - if inst: - self.copy_layout_pin(inst, pin_name) + if OPTS.tech_name=="sky130" or OPTS.experimental_power: + self.route_vertical_pins(name="gnd", insts=self.replica_col_insts) + self.route_horizontal_pins(name="vdd", insts=self.dummy_row_insts) else: + # vdd/gnd are only connected in the perimeter cells + # replica column should only have a vdd/gnd in the dummy cell on top/bottom + supply_insts = self.dummy_col_insts + self.dummy_row_insts + for pin_name in self.supplies: for inst in supply_insts: pin_list = inst.get_pins(pin_name) From 01a73b31e18702357b7ee6c7da7d6f1e0533f576 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 18 Mar 2022 10:32:25 -0700 Subject: [PATCH 156/229] Fix power ring routing boundary bug. --- compiler/base/hierarchy_layout.py | 23 ++++-------- compiler/modules/delay_chain.py | 19 ++++++---- compiler/modules/wordline_driver_array.py | 2 +- compiler/router/grid.py | 12 +++++- compiler/router/router.py | 46 ++++++++++++++++------- compiler/router/signal_escape_router.py | 2 +- compiler/router/signal_grid.py | 5 ++- compiler/router/supply_tree_router.py | 22 ++++++----- compiler/sram/sram_1bank.py | 34 ++++++++--------- compiler/sram/sram_base.py | 4 ++ 10 files changed, 98 insertions(+), 71 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 3ebc4ac3..403920c6 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -1322,7 +1322,7 @@ class layout(): self.bbox = [self.bounding_box.ll(), self.bounding_box.ur()] - def get_bbox(self, side="all", big_margin=0, little_margin=0): + def get_bbox(self, side="all", margin=0): """ Get the bounding box from the GDS """ @@ -1349,27 +1349,18 @@ class layout(): ll_offset = vector(0, 0) ur_offset = vector(0, 0) if side in ["ring", "top", "all"]: - ur_offset += vector(0, big_margin) - else: - ur_offset += vector(0, little_margin) + ur_offset += vector(0, margin) if side in ["ring", "bottom", "all"]: - ll_offset += vector(0, big_margin) - else: - ll_offset += vector(0, little_margin) + ll_offset += vector(0, margin) if side in ["ring", "left", "all"]: - ll_offset += vector(big_margin, 0) - else: - ll_offset += vector(little_margin, 0) + ll_offset += vector(margin, 0) if side in ["ring", "right", "all"]: - ur_offset += vector(big_margin, 0) - else: - ur_offset += vector(little_margin, 0) + ur_offset += vector(margin, 0) bbox = (ll - ll_offset, ur + ur_offset) size = ur - ll - debug.info(1, "Size: {0} x {1} with perimeter big margin {2} little margin {3}".format(size.x, + debug.info(1, "Size: {0} x {1} with perimeter margin {2}".format(size.x, size.y, - big_margin, - little_margin)) + margin)) return bbox diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index e044aaa3..a5bcea27 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -177,15 +177,18 @@ class delay_chain(design.design): # The routing to connect the loads is over the first and last cells # We have an even number of drivers and must only do every other # supply rail + if OPTS.experimental_power: + self.route_horizontal_pins("vdd") + self.route_horizontal_pins("gnd") + else: + for inst in self.driver_inst_list: + load_list = self.load_inst_map[inst] + for pin_name in ["vdd", "gnd"]: + pin = load_list[0].get_pin(pin_name) + self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0)) - for inst in self.driver_inst_list: - load_list = self.load_inst_map[inst] - for pin_name in ["vdd", "gnd"]: - pin = load_list[0].get_pin(pin_name) - self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0)) - - pin = load_list[-2].get_pin(pin_name) - self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0)) + pin = load_list[-2].get_pin(pin_name) + self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0)) def add_layout_pins(self): diff --git a/compiler/modules/wordline_driver_array.py b/compiler/modules/wordline_driver_array.py index a13f4bcd..b4c2c54f 100644 --- a/compiler/modules/wordline_driver_array.py +++ b/compiler/modules/wordline_driver_array.py @@ -78,7 +78,7 @@ class wordline_driver_array(design.design): """ # Experiment with power straps - if OPTS.experimental_power: + if OPTS.tech_name=="sky130" or OPTS.experimental_power: if layer_props.wordline_driver.vertical_supply: self.route_vertical_pins("vdd", insts=self.wld_inst) self.route_vertical_pins("gnd", insts=self.wld_inst) diff --git a/compiler/router/grid.py b/compiler/router/grid.py index 843fb3ed..a366ebe0 100644 --- a/compiler/router/grid.py +++ b/compiler/router/grid.py @@ -68,6 +68,16 @@ class grid: self.add_map(n) return self.map[n].blocked + def is_inside(self, n): + if not isinstance(n, vector3d): + for item in n: + if self.is_inside(item): + return True + else: + return False + else: + return n.x >= self.ll.x and n.x <= self.ur.x and n.y >= self.ll.y and n.y <= self.ur.y + def set_path(self, n, value=True): if isinstance(n, (list, tuple, set, frozenset)): for item in n: @@ -128,7 +138,7 @@ class grid: """ Side specifies which side. Layer specifies horizontal (0) or vertical (1) - Width specifies how wide the perimter "stripe" should be. + Width specifies how wide the perimeter "stripe" should be. Works from the inside out from the bbox (ll, ur) """ if "ring" in side: diff --git a/compiler/router/router.py b/compiler/router/router.py index f82a6128..2502d322 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -92,12 +92,19 @@ class router(router_tech): def get_bbox(self): return self.bbox - def create_routing_grid(self, router_type): + def create_routing_grid(self, router_type=None): """ - Create a sprase routing grid with A* expansion functions. + Create (or recreate) a sprase routing grid with A* expansion functions. """ + debug.check(router_type or hasattr(self, "router_type"), "Must specify a routing grid type.") + self.init_bbox(self.bbox, self.margin) - self.rg = router_type(self.ll, self.ur, self.track_width) + + if router_type: + self.router_type = router_type + self.rg = router_type(self.ll, self.ur, self.track_width) + else: + self.rg = self.router_type(self.ll, self.ur, self.track_width) def clear_pins(self): """ @@ -927,40 +934,34 @@ class router(router_tech): def add_ring_supply_pin(self, name, width=3, space=2): """ - Adds a ring supply pin that goes inside the given bbox. + Adds a ring supply pin that goes outside the given bbox. """ pg = pin_group(name, [], self) - # Offset two spaces inside and one between the rings - # Units are in routing grids - if name == "gnd": - offset = width + 2 * space - else: - offset = space # LEFT left_grids = set(self.rg.get_perimeter_list(side="left_ring", width=width, margin=self.margin, - offset=offset, + offset=space, layers=[1])) # RIGHT right_grids = set(self.rg.get_perimeter_list(side="right_ring", width=width, margin=self.margin, - offset=offset, + offset=space, layers=[1])) # TOP top_grids = set(self.rg.get_perimeter_list(side="top_ring", width=width, margin=self.margin, - offset=offset, + offset=space, layers=[0])) # BOTTOM bottom_grids = set(self.rg.get_perimeter_list(side="bottom_ring", width=width, margin=self.margin, - offset=offset, + offset=space, layers=[0])) horizontal_layer_grids = left_grids | right_grids @@ -972,6 +973,7 @@ class router(router_tech): # Add vias in the overlap points horizontal_corner_grids = vertical_layer_grids & horizontal_layer_grids + corners = [] for g in horizontal_corner_grids: self.add_via(g) @@ -984,6 +986,15 @@ class router(router_tech): self.pin_groups[name].append(pg) self.new_pins[name] = pg.pins + # Update the bbox so that it now includes the new pins + for p in pg.pins: + if p.lx() < self.ll.x or p.by() < self.ll.y: + self.ll = p.ll() + if p.rx() > self.ur.x or p.uy() > self.ur.y: + self.ur = p.ur() + self.bbox = (self.ll, self.ur) + self.create_routing_grid() + def get_new_pins(self, name): return self.new_pins[name] @@ -1274,11 +1285,18 @@ class router(router_tech): """ debug.info(2, "Adding router info") + show_bbox = False show_blockages = False show_blockage_grids = False show_enclosures = False show_all_grids = True + if show_bbox: + self.cell.add_rect(layer="text", + offset=vector(self.ll.x, self.ll.y), + width=self.ur.x - self.ll.x, + height=self.ur.y - self.ll.y) + if show_all_grids: for g in self.rg.map: self.annotate_grid(g) diff --git a/compiler/router/signal_escape_router.py b/compiler/router/signal_escape_router.py index 7cc41d97..d727e900 100644 --- a/compiler/router/signal_escape_router.py +++ b/compiler/router/signal_escape_router.py @@ -63,7 +63,7 @@ class signal_escape_router(router): print_time("Maze routing pins",datetime.now(), start_time, 3) - # self.write_debug_gds("final_escape_router.gds",False) + #self.write_debug_gds("final_escape_router.gds",False) return True diff --git a/compiler/router/signal_grid.py b/compiler/router/signal_grid.py index 340db093..3d8c69eb 100644 --- a/compiler/router/signal_grid.py +++ b/compiler/router/signal_grid.py @@ -119,10 +119,11 @@ class signal_grid(grid): # Expand all directions. neighbors = curpath.expand_dirs() + # Filter the out of region ones # Filter the blocked ones - unblocked_neighbors = [x for x in neighbors if not self.is_blocked(x)] + valid_neighbors = [x for x in neighbors if self.is_inside(x) and not self.is_blocked(x)] - return unblocked_neighbors + return valid_neighbors def hpwl(self, src, dest): """ diff --git a/compiler/router/supply_tree_router.py b/compiler/router/supply_tree_router.py index 88d02f2e..bb21813f 100644 --- a/compiler/router/supply_tree_router.py +++ b/compiler/router/supply_tree_router.py @@ -43,6 +43,7 @@ class supply_tree_router(router): bbox=bbox, route_track_width=self.route_track_width) + def route(self, vdd_name="vdd", gnd_name="gnd"): """ Route the two nets in a single layer. @@ -75,6 +76,9 @@ class supply_tree_router(router): self.add_ring_supply_pin(self.vdd_name) self.add_ring_supply_pin(self.gnd_name) + #self.write_debug_gds("initial_tree_router.gds",False) + #breakpoint() + # Route the supply pins to the supply rails # Route vdd first since we want it to be shorter start_time = datetime.now() @@ -82,8 +86,6 @@ class supply_tree_router(router): self.route_pins(gnd_name) print_time("Maze routing supplies", datetime.now(), start_time, 3) - # self.write_debug_gds("final_tree_router.gds",False) - # Did we route everything?? if not self.check_all_routed(vdd_name): return False @@ -144,15 +146,15 @@ class supply_tree_router(router): # Route MST components for index, (src, dest) in enumerate(connections): - if not (index % 100): + if not (index % 25): debug.info(1, "{0} supply segments routed, {1} remaining.".format(index, len(connections) - index)) self.route_signal(pin_name, src, dest) - # if pin_name == "gnd": - # print("\nSRC {}: ".format(src) + str(self.pin_groups[pin_name][src].grids) + str(self.pin_groups[pin_name][src].blockages)) - # print("DST {}: ".format(dest) + str(self.pin_groups[pin_name][dest].grids) + str(self.pin_groups[pin_name][dest].blockages)) - # self.write_debug_gds("post_{0}_{1}.gds".format(src, dest), False) + if False and pin_name == "gnd": + print("\nSRC {}: ".format(src) + str(self.pin_groups[pin_name][src].grids) + str(self.pin_groups[pin_name][src].blockages)) + print("DST {}: ".format(dest) + str(self.pin_groups[pin_name][dest].grids) + str(self.pin_groups[pin_name][dest].blockages)) + self.write_debug_gds("post_{0}_{1}.gds".format(src, dest), False) - #self.write_debug_gds("final.gds", True) + #self.write_debug_gds("final_tree_router_{}.gds".format(pin_name), False) #return def route_signal(self, pin_name, src_idx, dest_idx): @@ -161,7 +163,7 @@ class supply_tree_router(router): # Second pass, clear prior pin blockages so that you can route over other metal # of the same supply. Otherwise, this can create a lot of circular routes due to accidental overlaps. for unblock_routes in [False, True]: - for detour_scale in [5 * pow(2, x) for x in range(5)]: + for detour_scale in [2 * pow(2, x) for x in range(5)]: debug.info(2, "Routing {0} to {1} with scale {2}".format(src_idx, dest_idx, detour_scale)) # Clear everything in the routing grid. @@ -187,6 +189,8 @@ class supply_tree_router(router): # Actually run the A* router if self.run_router(detour_scale=detour_scale): return + if detour_scale > 2: + self.write_debug_gds("route_{0}_{1}_d{2}.gds".format(src_idx, dest_idx, detour_scale), False) self.write_debug_gds("debug_route.gds", True) diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index ce10eb4f..110b8330 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -336,31 +336,27 @@ class sram_1bank(sram_base): # Some technologies have an isolation self.add_dnwell(inflate=2.5) + # Route the supplies together and/or to the ring/stripes. + # This is done with the original bbox since the escape routes need to + # be outside of the ring for OpenLane + rt = router_tech(self.supply_stack, 1) + init_bbox = self.get_bbox(side="ring", + margin=rt.track_width) + # We need the initial bbox for the supply rings later # because the perimeter pins will change the bbox # Route the pins to the perimeter - pre_bbox = None if OPTS.perimeter_pins: - rt = router_tech(self.supply_stack, 1) - - if OPTS.supply_pin_type in ["ring", "left", "right", "top", "bottom"]: - big_margin = 12 * rt.track_width - little_margin = 2 * rt.track_width - else: - big_margin = 6 * rt.track_width - little_margin = 0 - - pre_bbox = self.get_bbox(side="ring", - big_margin=rt.track_width) - - bbox = self.get_bbox(side=OPTS.supply_pin_type, - big_margin=big_margin, - little_margin=little_margin) + # We now route the escape routes far enough out so that they will + # reach past the power ring or stripes on the sides + # The power rings are 4 tracks wide with 2 tracks spacing, so space it + # 11 tracks out + bbox = self.get_bbox(side="ring", + margin=11*rt.track_width) self.route_escape_pins(bbox) - # Route the supplies first since the MST is not blockage aware - # and signals can route to anywhere on sides (it is flexible) - self.route_supplies(pre_bbox) + self.route_supplies(init_bbox) + def route_dffs(self, add_routes=True): diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index ec690610..f6782597 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -243,6 +243,7 @@ class sram_base(design, verilog, lef): for inst in self.insts: self.copy_power_pins(inst, pin_name, self.ext_supply[pin_name]) + # Pick the router type if not OPTS.route_supplies: # Do not route the power supply (leave as must-connect pins) return @@ -250,6 +251,7 @@ class sram_base(design, verilog, lef): from supply_grid_router import supply_grid_router as router else: from supply_tree_router import supply_tree_router as router + rtr=router(layers=self.supply_stack, design=self, bbox=bbox, @@ -257,6 +259,8 @@ class sram_base(design, verilog, lef): rtr.route() + # This removes the original pre-supply routing pins and replaces them + # with the ring or peripheral power pins if OPTS.supply_pin_type in ["left", "right", "top", "bottom", "ring"]: # Find the lowest leftest pin for vdd and gnd for pin_name in ["vdd", "gnd"]: From 2bfc94fcdd6f78a97348add91369829b51b40ca3 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 18 Mar 2022 14:44:13 -0700 Subject: [PATCH 157/229] Add unblocking of source and destination pins to router. --- compiler/router/grid_cell.py | 3 +-- compiler/router/router.py | 13 ++++++++++--- compiler/router/signal_router.py | 2 +- compiler/router/supply_tree_router.py | 6 +++--- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/compiler/router/grid_cell.py b/compiler/router/grid_cell.py index 42be2761..f201a094 100644 --- a/compiler/router/grid_cell.py +++ b/compiler/router/grid_cell.py @@ -20,8 +20,7 @@ class grid_cell: def reset(self): """ - Reset the dynamic info about routing. The pins/blockages are not reset so - that they can be reused. + Reset the dynamic info about routing. """ self.min_cost=-1 self.min_path=None diff --git a/compiler/router/router.py b/compiler/router/router.py index 2502d322..39a9ea0c 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -375,9 +375,10 @@ class router(router_tech): # This is just a virtual function pass - def prepare_blockages(self): + def prepare_blockages(self, src=None, dest=None): """ Reset and add all of the blockages in the design. + Skip adding blockages from src and dest component if specified as a tuple of name,component. """ debug.info(3, "Preparing blockages.") @@ -400,8 +401,14 @@ class router(router_tech): # Now go and block all of the blockages due to pin shapes. # Some of these will get unblocked later if they are the source/target. for name in self.pin_groups: - # This should be a superset of the grids... - blockage_grids = {y for x in self.pin_groups[name] for y in x.blockages} + blockage_grids = [] + for component_idx, component in enumerate(self.pin_groups[name]): + # Skip adding source or dest blockages + if src and src[0] == name and src[1] == component_idx: + continue + if dest and dest[0] == name and dest[1] == component_idx: + continue + blockage_grids.extend(component.blockages) self.set_blockages(blockage_grids, True) # If we have paths that were recently routed, add them as blockages as well. diff --git a/compiler/router/signal_router.py b/compiler/router/signal_router.py index 9fbf871f..11e40a91 100644 --- a/compiler/router/signal_router.py +++ b/compiler/router/signal_router.py @@ -59,7 +59,7 @@ class signal_router(router): self.write_debug_gds(stop_program=False) return False - self.write_debug_gds(stop_program=False) + #self.write_debug_gds(stop_program=False) return True diff --git a/compiler/router/supply_tree_router.py b/compiler/router/supply_tree_router.py index bb21813f..9450243d 100644 --- a/compiler/router/supply_tree_router.py +++ b/compiler/router/supply_tree_router.py @@ -171,7 +171,7 @@ class supply_tree_router(router): # This is inefficient since it is non-incremental, but it was # easier to debug. - self.prepare_blockages() + self.prepare_blockages(src=(pin_name, src_idx), dest=(pin_name, dest_idx)) if unblock_routes: msg = "Unblocking supply self blockages to improve access (may cause DRC errors):\n{0}\n{1})" debug.warning(msg.format(pin_name, @@ -189,8 +189,8 @@ class supply_tree_router(router): # Actually run the A* router if self.run_router(detour_scale=detour_scale): return - if detour_scale > 2: - self.write_debug_gds("route_{0}_{1}_d{2}.gds".format(src_idx, dest_idx, detour_scale), False) + #if detour_scale > 2: + # self.write_debug_gds("route_{0}_{1}_d{2}.gds".format(src_idx, dest_idx, detour_scale), False) self.write_debug_gds("debug_route.gds", True) From a8f50f212e2c760e81d1e54aaad0eff8048d6f32 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 18 Mar 2022 16:01:57 -0700 Subject: [PATCH 158/229] Change track spacing for freepdk45 --- compiler/router/router.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/router/router.py b/compiler/router/router.py index 39a9ea0c..fd00d98d 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -939,7 +939,7 @@ class router(router_tech): self.new_pins[name] = pg.pins - def add_ring_supply_pin(self, name, width=3, space=2): + def add_ring_supply_pin(self, name, width=3, space=3): """ Adds a ring supply pin that goes outside the given bbox. """ From e31bec131c3f510f7b440b9f4a5b2fa6b377699d Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 22 Mar 2022 11:59:04 -0700 Subject: [PATCH 159/229] Remove 1rw1r combined test and add separate tests. --- ...hierarchical_decoder_132row_1rw_1r_test.py | 42 ++++++++++++ ..._hierarchical_decoder_16row_1rw_1r_test.py | 42 ++++++++++++ ..._hierarchical_decoder_17row_1rw_1r_test.py | 42 ++++++++++++ .../06_hierarchical_decoder_1rw_1r_test.py | 68 ------------------- ..._hierarchical_decoder_32row_1rw_1r_test.py | 42 ++++++++++++ ...ierarchical_decoder_4096row_1rw_1r_test.py | 42 ++++++++++++ ...hierarchical_decoder_512row_1rw_1r_test.py | 42 ++++++++++++ ..._hierarchical_decoder_64row_1rw_1r_test.py | 42 ++++++++++++ 8 files changed, 294 insertions(+), 68 deletions(-) create mode 100755 compiler/tests/06_hierarchical_decoder_132row_1rw_1r_test.py create mode 100755 compiler/tests/06_hierarchical_decoder_16row_1rw_1r_test.py create mode 100755 compiler/tests/06_hierarchical_decoder_17row_1rw_1r_test.py delete mode 100755 compiler/tests/06_hierarchical_decoder_1rw_1r_test.py create mode 100755 compiler/tests/06_hierarchical_decoder_32row_1rw_1r_test.py create mode 100755 compiler/tests/06_hierarchical_decoder_4096row_1rw_1r_test.py create mode 100755 compiler/tests/06_hierarchical_decoder_512row_1rw_1r_test.py create mode 100755 compiler/tests/06_hierarchical_decoder_64row_1rw_1r_test.py diff --git a/compiler/tests/06_hierarchical_decoder_132row_1rw_1r_test.py b/compiler/tests/06_hierarchical_decoder_132row_1rw_1r_test.py new file mode 100755 index 00000000..3c4ee7ee --- /dev/null +++ b/compiler/tests/06_hierarchical_decoder_132row_1rw_1r_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class hierarchical_decoder_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + # Checks 2x4 and 2 x 3x8 and 3-input NAND with non-power-of-two + debug.info(1, "Testing 132 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", num_outputs=132) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/06_hierarchical_decoder_16row_1rw_1r_test.py b/compiler/tests/06_hierarchical_decoder_16row_1rw_1r_test.py new file mode 100755 index 00000000..ea50b36c --- /dev/null +++ b/compiler/tests/06_hierarchical_decoder_16row_1rw_1r_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class hierarchical_decoder_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + # Checks 2x4 and 2-input NAND decoder + debug.info(1, "Testing 16 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", num_outputs=16) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/06_hierarchical_decoder_17row_1rw_1r_test.py b/compiler/tests/06_hierarchical_decoder_17row_1rw_1r_test.py new file mode 100755 index 00000000..549ce54f --- /dev/null +++ b/compiler/tests/06_hierarchical_decoder_17row_1rw_1r_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class hierarchical_decoder_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + # Checks 2x4 and 2-input NAND decoder with non-power-of-two + debug.info(1, "Testing 17 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", num_outputs=17) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/06_hierarchical_decoder_1rw_1r_test.py b/compiler/tests/06_hierarchical_decoder_1rw_1r_test.py deleted file mode 100755 index 867cdaff..00000000 --- a/compiler/tests/06_hierarchical_decoder_1rw_1r_test.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python3 -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2021 Regents of the University of California and The Board -# of Regents for the Oklahoma Agricultural and Mechanical College -# (acting for and on behalf of Oklahoma State University) -# All rights reserved. -# -import unittest -from testutils import * -import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) -import globals -from globals import OPTS -from sram_factory import factory -import debug - - -class hierarchical_decoder_1rw_1r_test(openram_test): - - def runTest(self): - config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) - globals.init_openram(config_file) - - # Use the 2 port cell since it is usually bigger/easier - OPTS.num_rw_ports = 1 - OPTS.num_r_ports = 1 - OPTS.num_w_ports = 0 - globals.setup_bitcell() - - # Checks 2x4 and 2-input NAND decoder - debug.info(1, "Testing 16 row sample for hierarchical_decoder") - a = factory.create(module_type="hierarchical_decoder", num_outputs=16) - self.local_check(a) - - # Checks 2x4 and 2-input NAND decoder with non-power-of-two - debug.info(1, "Testing 17 row sample for hierarchical_decoder") - a = factory.create(module_type="hierarchical_decoder", num_outputs=17) - self.local_check(a) - - # Checks 2x4 with 3x8 and 2-input NAND decoder - debug.info(1, "Testing 32 row sample for hierarchical_decoder") - a = factory.create(module_type="hierarchical_decoder", num_outputs=32) - self.local_check(a) - - # Checks 3 x 2x4 and 3-input NAND decoder - debug.info(1, "Testing 64 row sample for hierarchical_decoder") - a = factory.create(module_type="hierarchical_decoder", num_outputs=64) - self.local_check(a) - - # Checks 2x4 and 2 x 3x8 and 3-input NAND with non-power-of-two - debug.info(1, "Testing 132 row sample for hierarchical_decoder") - a = factory.create(module_type="hierarchical_decoder", num_outputs=132) - self.local_check(a) - - # Checks 3 x 3x8 and 3-input NAND decoder - debug.info(1, "Testing 512 row sample for hierarchical_decoder") - a = factory.create(module_type="hierarchical_decoder", num_outputs=512) - self.local_check(a) - - globals.end_openram() - -# run the test from the command line -if __name__ == "__main__": - (OPTS, args) = globals.parse_args() - del sys.argv[1:] - header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/06_hierarchical_decoder_32row_1rw_1r_test.py b/compiler/tests/06_hierarchical_decoder_32row_1rw_1r_test.py new file mode 100755 index 00000000..6c2f6bd6 --- /dev/null +++ b/compiler/tests/06_hierarchical_decoder_32row_1rw_1r_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class hierarchical_decoder_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + # Checks 2x4 with 3x8 and 2-input NAND decoder + debug.info(1, "Testing 32 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", num_outputs=32) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/06_hierarchical_decoder_4096row_1rw_1r_test.py b/compiler/tests/06_hierarchical_decoder_4096row_1rw_1r_test.py new file mode 100755 index 00000000..201fc399 --- /dev/null +++ b/compiler/tests/06_hierarchical_decoder_4096row_1rw_1r_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class hierarchical_decoder_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + # Checks 2x4 and 2-input NAND decoder + debug.info(1, "Testing 4096 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", num_outputs=4096) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/06_hierarchical_decoder_512row_1rw_1r_test.py b/compiler/tests/06_hierarchical_decoder_512row_1rw_1r_test.py new file mode 100755 index 00000000..f53f4838 --- /dev/null +++ b/compiler/tests/06_hierarchical_decoder_512row_1rw_1r_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class hierarchical_decoder_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + # Checks 3 x 3x8 and 3-input NAND decoder + debug.info(1, "Testing 512 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", num_outputs=512) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/06_hierarchical_decoder_64row_1rw_1r_test.py b/compiler/tests/06_hierarchical_decoder_64row_1rw_1r_test.py new file mode 100755 index 00000000..af9fb4f4 --- /dev/null +++ b/compiler/tests/06_hierarchical_decoder_64row_1rw_1r_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class hierarchical_decoder_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + # Checks 3 x 2x4 and 3-input NAND decoder + debug.info(1, "Testing 64 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", num_outputs=64) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From 9f7426052de24cef34ace79ddf8887f44cd8a4b4 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 23 Mar 2022 14:46:41 -0700 Subject: [PATCH 160/229] Split port_address tests --- .../18_port_address_16rows_1rw_1r_test.py | 40 +++++++++++++++++++ compiler/tests/18_port_address_16rows_test.py | 34 ++++++++++++++++ ...=> 18_port_address_256rows_1rw_1r_test.py} | 4 -- ...est.py => 18_port_address_512rows_test.py} | 4 -- 4 files changed, 74 insertions(+), 8 deletions(-) create mode 100755 compiler/tests/18_port_address_16rows_1rw_1r_test.py create mode 100755 compiler/tests/18_port_address_16rows_test.py rename compiler/tests/{18_port_address_1rw_1r_test.py => 18_port_address_256rows_1rw_1r_test.py} (88%) rename compiler/tests/{18_port_address_test.py => 18_port_address_512rows_test.py} (86%) diff --git a/compiler/tests/18_port_address_16rows_1rw_1r_test.py b/compiler/tests/18_port_address_16rows_1rw_1r_test.py new file mode 100755 index 00000000..ff39eeed --- /dev/null +++ b/compiler/tests/18_port_address_16rows_1rw_1r_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class port_address_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + # Use the 2 port cell since it is usually bigger/easier + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + debug.info(1, "Port address 16 rows") + a = factory.create("port_address", cols=16, rows=16, port=0) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/18_port_address_16rows_test.py b/compiler/tests/18_port_address_16rows_test.py new file mode 100755 index 00000000..a60508de --- /dev/null +++ b/compiler/tests/18_port_address_16rows_test.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class port_address_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + debug.info(1, "Port address 16 rows") + a = factory.create("port_address", cols=16, rows=16, port=0) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/18_port_address_1rw_1r_test.py b/compiler/tests/18_port_address_256rows_1rw_1r_test.py similarity index 88% rename from compiler/tests/18_port_address_1rw_1r_test.py rename to compiler/tests/18_port_address_256rows_1rw_1r_test.py index f81196e8..e9c11bd7 100755 --- a/compiler/tests/18_port_address_1rw_1r_test.py +++ b/compiler/tests/18_port_address_256rows_1rw_1r_test.py @@ -26,10 +26,6 @@ class port_address_1rw_1r_test(openram_test): OPTS.num_w_ports = 0 globals.setup_bitcell() - debug.info(1, "Port address 16 rows") - a = factory.create("port_address", cols=16, rows=16, port=0) - self.local_check(a) - debug.info(1, "Port address 256 rows") a = factory.create("port_address", cols=256, rows=256, port=1) self.local_check(a) diff --git a/compiler/tests/18_port_address_test.py b/compiler/tests/18_port_address_512rows_test.py similarity index 86% rename from compiler/tests/18_port_address_test.py rename to compiler/tests/18_port_address_512rows_test.py index 7ecf3288..120ec9be 100755 --- a/compiler/tests/18_port_address_test.py +++ b/compiler/tests/18_port_address_512rows_test.py @@ -20,10 +20,6 @@ class port_address_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - debug.info(1, "Port address 16 rows") - a = factory.create("port_address", cols=16, rows=16, port=0) - self.local_check(a) - debug.info(1, "Port address 512 rows") a = factory.create("port_address", cols=256, rows=512, port=0) self.local_check(a) From 23b5655cabadc15fcfbcb730209f80a0434dba63 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 23 Mar 2022 15:59:29 -0700 Subject: [PATCH 161/229] Split replica_bitcell_array test --- ...lica_bitcell_array_bothrbl_1rw_1r_test.py} | 26 ----------- ...plica_bitcell_array_leftrbl_1rw_1r_test.py | 43 +++++++++++++++++++ ...replica_bitcell_array_norbl_1rw_1r_test.py | 42 ++++++++++++++++++ 3 files changed, 85 insertions(+), 26 deletions(-) rename compiler/tests/{14_replica_bitcell_array_1rw_1r_test.py => 14_replica_bitcell_array_bothrbl_1rw_1r_test.py} (55%) create mode 100755 compiler/tests/14_replica_bitcell_array_leftrbl_1rw_1r_test.py create mode 100755 compiler/tests/14_replica_bitcell_array_norbl_1rw_1r_test.py diff --git a/compiler/tests/14_replica_bitcell_array_1rw_1r_test.py b/compiler/tests/14_replica_bitcell_array_bothrbl_1rw_1r_test.py similarity index 55% rename from compiler/tests/14_replica_bitcell_array_1rw_1r_test.py rename to compiler/tests/14_replica_bitcell_array_bothrbl_1rw_1r_test.py index 0523b471..8dad9f9b 100755 --- a/compiler/tests/14_replica_bitcell_array_1rw_1r_test.py +++ b/compiler/tests/14_replica_bitcell_array_bothrbl_1rw_1r_test.py @@ -25,21 +25,6 @@ class replica_bitcell_array_1rw_1r_test(openram_test): OPTS.num_w_ports = 0 globals.setup_bitcell() - debug.info(2, "Testing 4x4 non-replica array for dp cell") - a = factory.create(module_type="replica_bitcell_array", - cols=4, - rows=4, - rbl=[1, 1]) - self.local_check(a) - - debug.info(2, "Testing 4x4 left replica array for dp cell") - a = factory.create(module_type="replica_bitcell_array", - cols=4, - rows=4, - rbl=[1, 1], - left_rbl=[0]) - self.local_check(a) - debug.info(2, "Testing 4x4 array left and right replica for dp cell") a = factory.create(module_type="replica_bitcell_array", cols=4, @@ -49,17 +34,6 @@ class replica_bitcell_array_1rw_1r_test(openram_test): right_rbl=[1]) self.local_check(a) - - # Sky 130 has restrictions on the symmetries - if OPTS.tech_name != "sky130": - debug.info(2, "Testing 4x4 array right only replica for dp cell") - a = factory.create(module_type="replica_bitcell_array", - cols=4, - rows=4, - rbl=[1, 1], - right_rbl=[1]) - self.local_check(a) - globals.end_openram() # run the test from the command line diff --git a/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_1r_test.py b/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_1r_test.py new file mode 100755 index 00000000..3137802b --- /dev/null +++ b/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_1r_test.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class replica_bitcell_array_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + debug.info(2, "Testing 4x4 left replica array for dp cell") + a = factory.create(module_type="replica_bitcell_array", + cols=4, + rows=4, + rbl=[1, 1], + left_rbl=[0]) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/14_replica_bitcell_array_norbl_1rw_1r_test.py b/compiler/tests/14_replica_bitcell_array_norbl_1rw_1r_test.py new file mode 100755 index 00000000..7f7ee74c --- /dev/null +++ b/compiler/tests/14_replica_bitcell_array_norbl_1rw_1r_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class replica_bitcell_array_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + debug.info(2, "Testing 4x4 non-replica array for dp cell") + a = factory.create(module_type="replica_bitcell_array", + cols=4, + rows=4, + rbl=[1, 1]) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From 83e5848728fa95fc231aadb80d5f3888154773d7 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 30 Mar 2022 13:48:53 -0700 Subject: [PATCH 162/229] Change FreePDK and SCMOS 2rw cell to share gnd power rail. --- technology/freepdk45/gds_lib/cell_2rw.gds | Bin 15930 -> 15226 bytes .../freepdk45/gds_lib/dummy_cell_2rw.gds | Bin 15672 -> 14976 bytes .../freepdk45/gds_lib/replica_cell_2rw.gds | Bin 16002 -> 15234 bytes technology/scn4m_subm/gds_lib/cell_2rw.gds | Bin 6326 -> 6262 bytes .../scn4m_subm/gds_lib/dummy_cell_2rw.gds | Bin 6082 -> 6012 bytes .../scn4m_subm/gds_lib/replica_cell_2rw.gds | Bin 6278 -> 6270 bytes 6 files changed, 0 insertions(+), 0 deletions(-) diff --git a/technology/freepdk45/gds_lib/cell_2rw.gds b/technology/freepdk45/gds_lib/cell_2rw.gds index 3ceea6170128341e277a067442310aada3fe3664..ca7468cf7a094b00bd96065d213ecce73753e642 100644 GIT binary patch literal 15226 zcmchdZ^&g;6~^~D_uO;to%fy5@lTV^P>mBpS(1gC7>Q4)vheJxlKjcJmUuLWp1r|x!c_R+Z|Wd@7VLcy*qE%b=kR>?6_vv zRUf*}9XA-h`4ta-@vcMf{QFraU9sV@OZLCoZ5pQUv0T?z@7le4$Lsg(bJfVXdTr^( zu3lF<=U#L4z`61m{Pk_m;!^M)=S11TYQ3ATub;zBp))@1T=OyfEy{jrM*nf|zXs{I z+0>H$Y0vo|9EN7UbL8kP2=ca;vV+O^i?90ljflHE$H#9(JfS_QukOV4H^DF1Y;bOP zW=q+@q<(NWG`ApraP)oLXQ`#^U{*i4*6RoV^!f>9zc#HOZt?y}`lnBke~0#@f3^=U z^ViX@#VpExS=xX7UF7d1d`Q;K<_={)DXlNpdcBd)?|QE{LLb`m@jv9_ug~`Ji-TYX zv-;srrt4(~vwHcd-r)U(^!2;u1Yf`6DA>Vd{9XMBbAXK>aZdgC-s%2j2b2D7+`tdXxLN-q;}7j~=^4L` zKXFbyjo9*f*yAm#6sn zNycB^-jeZ$_GJ8BJ>#Z+!a4PfbDIB&Jrh6cmvNGepYRo^ej| zKe5k49QUjfl67P2Z=meC=ik+{Zm6Fy+;^6qbu!KW#2(krQg{DZ zUxfYL0n`l0c$;l4We2;3F+%2b210JK{eTA8`04@Tr!vgGv4HYd(J@^H<;BlKBhmNqxE3>q+Vd zA8ko}Xiw_h#fTaCCz*eTS{7x`<-fQZ{tn^;GJnO>EoIN;kG0C@MDqESr?-?n_xupC zTf#oy__%XpJc}h!_W1itRDY|Df7SJ~6*d1IJOgn2F!)4E*}>%V<9x~f8`19}_Au$KBoD08OMA?mL{VqKJTcHOV%;m!m zwv-)A>RGp{Q`T+qL);@!_FVlo*LgijU4Q-w?P>qc_tOdx{b&6#593p1pV5EJ8yqt> zk9-}({80tU4krDVcy`qb7&jp6XMkrY$_}RWzw!AmLFS*|zeVPs_FVq$doyFW)7MSC zuO;gzv?u)!|K{T-88`JJ;}7jgJ@dW>HDJWt#r&@kWxqJxe_KBe!Y|g3HQz+vZ){ly zJDBuu^B1losptG9QXkrrdiQJR+%x!q1-|bVm$#H1OzVFHe>sLE} zaF1ip39QHXV9pU`&(&Xl{55~{U{D|B?*uSuUTSjPj z|A_VTB_-_jhQbY9ePV&Xmp2a2dDQ+r=9c+hvRDV}5jQ%a-naWSgt#7`73p7!I{vWN zzb@#*`_HxA{b$AX=K);6_2&ZQV2dcbu{(ZxdgT6OuP^WO`Uzz}IT}Bao<5mp^Nsbx z{nS4PQubc{BYkr|a&-`O4s!q0Jl0ZnFdhH9z3&RNe*Ctj#pc_S`r=COpS1nkvn}aA zv?uj8e_-!#{5kr50`?!G>=$L?e|s2zAjeJhi3t#Zj<>$^MT%f}A~s4>(=|f7w!YFsW~@hvrG-4ICd0-q%ugFsUzY zf*#L|9G?h2+ER8fsdqb|M?cB&D?zN`qU`GbvY-DjerL~rqr2_CnE$TYqxowk`sQ}% z4|D#zYR_qSEbH-EiN5#(`mtpC{`@;v{O(h&Uh#+dx9rZpgC|j6Z**>eXUILs@ETEe zV>kbi9*czOp|bZ*Tz~lf$@b5W`$Z#{OTFz4!ho@;^KP?N-DMQpfiY zqU>PO|L`u<9M(;e?{AtHTgnb5^#vX-uOq4Neq_(-%l%$Y+WVtnOX@>=(tnBXJ}%}r$dp}iabpj&^e5Wc79zvXSLo0hWo zet(GcgCAp`fx0EBAHJuh>|oMA^F}|U{ceEo9HQ(w|EybHM^eZ76=m<~>u&!SsQ*a6 zK>bJh1^OT9SKI#u#$V)rf$pN532Jp ze}4t_dmaWL#!mITD7&#cej5=qi5di-48fC3V$PiqU>Nce!gR1 z{DY0){Vin&llo>aG|-dOGj37#oW8;uy>tfRCZ7fW)S>KWr2X^x*zY|czeDr+iL!&q z_-m}2{Jn;xuK8f!I_86a zld^+JJ;x36M6&J@njNeGV!1#^ywtqnVk*u5k_zmsd`uVTw z`}4_y0DZw{hS+`HSL*&in_?)qkv4b{)vPaomcsgUS4HeDOMxy8iwzwExfa zoF5eDH2P6Xm`^Px{z5OTWUFu2dIY0eB z_5Jwg@y~Ud*D3A^Wj`~W|Nj2Dc--HIOzfYd{H<1BUhn;ojJtfXCH;r?Wc~F0_w`fu z|LOR#Zd?BY=jng{`$P5nQ2(IS|5jr%{?+P-w|GA!$I4_LJ+`&y#$VrmUmx1D@t2$N z4AD{(Z|CnG#u~O0b#pOzsHL3+f*tI} zANjZQH_(&R+xf9T>O*@{-&}}zPsVyf-UB|;q3rSRuaSQ{cZTbX(A)VlQTB|Uc^?-( z|Kpp%C-8q!_9ESX>h1g$`MB3lc&WcH+LQgSw&VLD#wnj4&kgbUdCG3=>YwXAe_TEJ zxAbYmj`!c7~z-acj(_Jd&d6)^%v!Df%=Q|)xC)KRy-WAS&K3B z+Lp3|$^0)+Ke2z*xSi7i?c5(~UzELf{x8;VN9;G?Lq3lW>UTofZ^*>I^6?Y-=bAUf zxG}PhFy^@DH_Co)+P|GI!aPNC{<8B&ftp{ zM0)m{^Oq5R*>Czc%AWDhxS2oW0UtN>$M`4qO#V1lnJ1F@v-6jMvV+O|EwFwa)t$ep zPhh^g6)}+b?o)lKL)qi;6YE!gekj&2!5`k?t>FAitiKKOJJx)jyL88a4~ViGEq~$n zf9PkQKdA16?gjq-f87W0ll;o{pGChuNB!Pwqz~)Ix+woEU%z7g3dVnfepK$?9mohF literal 15930 zcmcheYpfkr6~|}h%$d2pk7{{X>#Yge_`&xhDM|?7lcufZVM9WN+5oMMp)pdWB@#45 zq#7WIUyRlws05YpK{QHK{8A%eYiz9$5edOUd?qz9KKM}M|G)PBpP4|Hd&Pw#iiNmyr`eeX0o|#DjQ~N+ka=L71c$%KeXqHkL`HhJ2q|G zzT?VkcV?#zhUcE~ll}J`-~6w$UU~V-Bb)AjO}2U%|BTtHx@yO+UEAKWdv8`wWmz>> zWXrN@d68w=>s~y_vf>oH*Lyw&dBW@%N`2$_~c$H#`3o ziO;E5w+R1cPxv4FGs~8plV!$Z2=X@kTa^8rxc~f{E`E~n7w0u({JuRJe|a~qXL87U zvuya*7G+-%_dkH9UWxd@>5K3=GYw@2qyDKY|Kaq*Tb*8%9gOOSYn*?Q{)hV-(!Xy{ z>dW7`>*$wyQFbt@uO5Q`2Qbc{)z2#$$__^L#hlZVHh$MMq~5nj_3Yp95*L4c$i*+p z4kq>W*75q0eQR1j@^jGnABsM%lz--J_>9XRtAI2zC9X$ zThI7y{)s*HjB}j-kv$QA^%cyK$1r~25dP{xL)pP-{B8Zzv&u5PyOD2jeGYPpzMA zJ=aa@#J+m=bDaN?J+Xdr-gBHu){WhNJ!MbTPg~ErpkIkD&pp!{Ad5We21B;kR7=jL2X0 zpv#{T`Sa~jeX+;sjnEHna(W~5zCEhXHo_9%OAsLBc1a#}>)430UzpJEK)uXEPac5&qbzAkOVA4Owk1viJ z{f;PmV*HBl!yo*Utlz;|4P^(T{`t&;<8Q?H^Z5hoz$klS{Q2B~^=m}!R(tVpQT9ar z4*%}rCmBEWBIEb%(fFCSnJ4*Q%)_lNf1>PQRB!h^th40oyHP{eH=OczFsiq8m+Lgv zU+TI3iq!k|s6P8G0^g1|c^9rn4n~xHd)$Ba2>O2l8gLfA^W6<)2c!O%x_%8g*EvpL z{YCtZniXYF)n9l1)_-*KnB@FlX#TQpxlWT-|5$@X*^}${64!tBn|?^ETl8O)J>{Qq zGfyP*HbDHM?5X_a?{Rq|x&C$6Pv0IN|I6UB#{30&58?VH$_|=-7OwF875m?p@cC=C zGRHID>Sa0po}C|_ci3J>vROWt&6mS^LpHUl+Pmw`_{bG_FG~MXeCU+Zzsc+U^WVAl z{@d<**h3q!2j}+z?!}F=ZwTr?(A&P_eB__|kY6GfH?=7H`Eh-QYwSJ++WrrpA<7Q6 z^B?%Hv1Zsl8MJ-#k%qE&_RoRd_O}%5e`A2fzmA`Jt`RCiC`l-v^ z_>s1M_(MaEpKp)qZQp~jH)8B<-y_PNsGs4VQEyl~NE|j*Sy5)py=>!slZBzjC+M z@5Sir+o9j*^qu=hFaPY1ds{zf*B@(yztiwFcZRDUQTER7 zPl0~$Gwicax8xkw{^9!@$__^TGjH@m+V4gi8_J&Y&${JxB=xLcQTC3$YWIJF`VaII z)PJC#p#On>sr{c|{ssOgn16wOg83KfQ8$`rns=h?o%t8&CzyYMeuDXj?>x=OM{ssE-3rD;p%Xa+v z2F(2fh#BNF(EQ&GWe21B8aGE?M^cXyKqJbY(lc+|`;z=EmiZH92c!Nie(ZTI{`-#!r+T zjOr`gH~Gwkq^|y3L)pQ&9^Y};Pkz_2{$t-I%AV?fjxpnPBz1%NhO(#hyq?!d$2{hHg*SDmZwhijaFlKy>rd;SOh zyZUbY3+d^Ddp1)27G(#c{=4g!ox@@tAHv(OYn}NQ#BaWE9ck~*`sdrD{+Fun#@}Q8 zjmBR+hdv{qOD{`2BdTqU#|1}4^aCS(e@v%J(~Ze>bvpx*gwVl z|8keN8P7iX3*v{){CoE5Kkid@9mu?K-ioq=(fo1V@j8;a?*7lW|IhSX9~9>}|GvGS zf8@>L_f)@9{nveVbl>&+5bhy)|Ml%r|2!|q>qzZ;MA=jK@2-D7w`%Jb^55M*@f;rY zB>nsLX#DN-e$;6nrG1rekLtVryZVLv%g;!6uZy4O-Wb1ckNW3xe_ls2e%6a9I~dh> z{de_!{Bw@bKko(9i?V}J|6G4~9Z8)%|M8Ul|EcfB@8e6x&-?Va_+?Mszq|YA{HV(V z$@{l&kNRJ#zI|Si`7cg7|0MnU_TK)x`o+Z0`?mF4?9u=3_lNTLzWzb0fA{?&8vj!D z!+p*V$$2+gNB#E~-`?AQSMTHNr5`+j7}#%->%t5BKimHPRQw1JJ~v{VNj!rcoZF)8 z;rX3FKm04Sn=yw;%;9Qxi?WC3Hv_$$zr>#3_#}87pCQV=C0IWKJ>#Z-Bm6Ud#$l8_ z;h%lyJ<|xk%mMuyWl#98*TdKMFlRu17pf06lpSo3Ul6~Y|AU^S-p((2Qt#WNdXDe( z9d4XwP6dx)ALA)InAF=jJA97)ZU?<6d*}RJ5I@JAxid0%7=OzhDSM)R?EDwzx$!9Y zlv@LgvWL%KPPFS6UPdoHw--kZ_}CSA``@3Y+xlX)uOAY1Q{36&X8i5iqk5iC;#nIz zr*t*0UyB;{lpT!ftIt6LKSubkPjUW@vWN8>#Bb-1;or_-!LOY^_OvrV&s%&^{}a@2 z;D3Vp4fI?y?ffKp0Cn{G7UwZ&u00z61oad8&+(hjI`|m`9eFc| z`W;dBGNH%3(>&9>6J_trzaV})KZbc@=f_wtm@~C!zonmp4E&fd$|4u z{_XtO9jMu--MYi`S6qKcu0Os#>VJauEAVgU$Kc1#kHIhdPyZzS`}U}R#>YI7%$uDb z^OQZ6KRX|WJQ`zBVTJ;ls!EE73ybDzc@Fui1SCG{xy}`aWT7TTqM4za*cyeVxv0A?kp{czTKGqZ zm4%5FL{O3Vhpi723(q`%+x8t- zT({F5F&Mt(mG^(?&L`jX_tTEO^r%P9-}f4~ahSfx;dQwWS-o`jFB&_u9h-&XtGbukUyk7l3y;C&~_1>)dpG{Tyxzo$)E>nvdgeQT7Wm z`cHWOHAuhB#+LL?d(Qvh1!(p;M~>c#Aa89cJD7~W_?nO3h`7r$eEdel6WWvd>JD6g zBm9ERQO*rdZ7DmL)DQMTb2H)xM?b)QmRiaVX7z)syngUcub)u%tJ3=6X78V*fBF>p zcW6)gXZzqne;xf=%%bcUrv2C7L;jA%hh*Js>QMG$)B19)*Bkl#c6q%K`p}+_{{bI= zeY%fd90WU<)enC|iqfuDiRx#!dZ% z;l8u*IKjeq=CjE=D=lpYh;5=#T1md@K zBT)9-{MXfU-lTrQaNk*a_H&wl*>nBpxM!V^tQ%W@17*)W|E`{OL;Zx|zO(eKlWG1Z z_PBnQy8F-iJnZlGqh>(H+g#LAcCb5sBmL-dWKj3>kJ|Nf5 z=7yHCgGqgJF5*1^4OspKe5j@DU{YUQg7{Cw2OPc`e4?f7U{XK)y3ZfU{MGliWd1^X zQeW=zdXoCV$68V!+LL;>1u-N4B=hf3%cAVL{1;ck-vN9;=C63FrR=%Tk92ueyG=qUOJgX8?{L1RrZDJD7ZaoG;mb zBl_X}Aw!5M>9`{*OF(@F3>R>PS3+GvRl$D7!JO-+||U z3-n-vxqSGcma>CMJ?mC=%DOFngnI|>|k2|Tc7_DWd8a6TV(!e&*k5~ zH#3GieBIR7w`Bc<_N4#e-+cTe|4_PxAo%y{9^rB z^DXrKhL&}(gGv83f8jckdd^=W^`SkfcfWDYJ&g}o;QMZIaZB03wEoBNw+(voPH1;` zDEqdwezo%l_c->PzT>bUOU-OI~ha|`EtntVCWzWrjs2tnB5xfV-kI4Ol z{R{iIWrT+Jk61rnR>EE%Rk)$6k16o?@`m9V58J;-+%n%w7Kgxk(2b6+ufO^vgt!i$ z73p7&I{vWNzdq>0`_HxA{b$AX=RRD(_2(SqV6!N@u{(ZxdgT5%uP^WM`Uzz}E*d|P zo<5mp^Nsbx{mefHQubc{BYkr=a&-W84s!q0JknBjFdhGUyzdIMe*CVb#pc_S`r3t#Zj<>$^MT%ikv-w4>(=|f7McUFsW~LLGw8B296H{ z?`bJJnA8_HLXT%gj*kH!ZYevM)Vpoaqo3sXRUp=IQFirz+0TC%zq9AR(O$bR=D#a; zYyMh^zPSzh7dZc2vHK)EmUZ~7L|=Rn{a7-6fBu~-e)s8CulU3KTXyH)!Q-f}H#s-J zGvpp*xLuUp*v)^W$0A{RsO-HH*B`!rvi&pe8`_il>Uj7@{gKqw*#C>N_ud~x{)hXa z-HNzD>i8Z)lpRd^AKryOWDDszQDufbtLuOkL)>pxzFoKdw(=+NquNf z`Y-Xlhj}8|?;-S}?795$eF5`CQaAWOOWAYz8$9XbCmBC~a}ybVXz#{9=++-AgzxG3 zZ}}qDO-tE(zduC!!B4QyK;4qm58vBTb};Fmd7~fFemB5(4pH`;f7UIpBdKHkin90g zb+`Wu)PJO3p#CHM0{xHltL^^+<1g~R!1#;w3yi;5kGjz~)3_65?~T7mzrgs5^b3qX z?D^aC2h~}azrTw5JqrU6W2bsvl-<}JKasxtIqLrfj31D{ck%s)C_9+cS6}dYlDZn- zpGE3Jdskm|<1esB<-2?155a%o|Dx<`Bma@U!Qx205xVC0UT>5=qi5di-48fC6n`Us zqU>Nce!gR1{DTePy)9)2llo>4G|-dOGj37#oW8;uy>trVCZ7fW)S>LBr2X^x*zY|c zzeDr+iL!&q_-m}2{Jn;xuK8usD^BI;Ezevw<%lxfi{6_i(#&4uwVEjgU+drWGNY+h% z{D$^!{rp$;{rO|K*~dY${zH4xe_!8^f0o|*ed_f7^DJ3tPx|lAUp$9nc?1*lSCqfz zef~OZ`Yh{RgOh zi)i}~-=6IMYW4m2=h#1``+uv?+cOa;iyAEXDIBrGR!DRk8zIYu; zU4Q=<+W%*I&JT)nn*Y!~pMT`d;ty26a{bpjJ6U(bKE%#-VOyFJpJ!~f2jTt>L0ZF-)c<8zgqq9X77jOSeeYD>sxzn{Pq3! z^`Si*f4K?I5dE~X9O(CivTus&Z@K&ZiSGzFR~q+$PvHNe>?dUO@H;NN|M5-WWB9)) zdy&`M`6JxNem8=C!VCO;(cbNUFMfPKLY*>xo||F(p0XRe`scd+$JLX6OP@jPc>gO- z8gScn_=Mjt)^zpdMqGux18MKeztU26FsWyaa?LjW8uvLF{}*MyIIXV{GyRbC-|#oQ zK-qKt?feS-7~z-aSLoj;d&YlrE@D0o*OPaF4|OPe{QGy5KRfq_>x|Ib`9D$ijJ~=X z@!o=m12$_hcfGEq?7j0xk^kxv)d})AU;V^-)VQ5f0`1%zYG0JScm6HbUxL`L#fN+z zAJp%JvR|8i{v7u!96ynN&iO<1+sHb?nB$(;DEpad|8~CSLF8a3bX&k@TJkJlXiwI^ zox4HqjL03&t#JM@${x=jQT*)x3g@3l&wf*HgkScX{*AI{{4;Lm&$!>m&HOR`i9M4) zj#cJ~Wd7{@VW8|_GJgxq--mYRuj-SipIZ?%jKN|DY{ut*xeN{9sfB6A(fG;~$z*3pNdjwbZ8eE&b49Y_$|6 zXox5pAfjK4A_yu$G<*<^8Wq3Ph}bq#D@Me|XeA;TYhu*!0ps(WnP+!ry))hSzNt64 z{NA3~=bkfXX3os+y<}BZ6z|Sf=f&tx*=#nSjk7A7ZU3Fk71hGdYqsy-^Pwzz(O`JV znxEWx--%6syYN+4uXt?3gRjU|598Y9Rkg7H+G{_&ZO6_%d$zr4-+`?{-O254jY^0n}J6)pg& zs~%}6I~dgu4?_P3yg};6+Z)Ob#`X81zmG!?4p&0^d_&p6s6Ic}=}GDbpKeIKZ;$GW z2c4dzemHDMy>E}}cj0>EuK?M9>P6X8`OA(#gZz=y4R$w_J(a(~2^T-f_^X>5GJfCQ zj(^aef1D#T(D60D#?2p5b}*_R{5;F%FmK8Er{ViO4P^(TdghIO$k_*=U*Aynlz+}! zUPn^T`76ra(O2#MPci=k{S@;*&`;6-K)=-fbKP;CEMoly{-;=ffqshh7wR!@w9d5d zMAo0H5zx;Bnox4z{z;Yw_pN6u7?e!DrN9Q;_Nj>(jn$-LDsJ?tF z^7kw>VD)A2UkzmklluI8r_Y~p`kJzzAJ<#|-{$-OP4N5p49|hLgHivZ>(GB(M^b0~ z_mn-QFE2p-`YE*F{71mQHk2KV`nUCe5IMwqv=zDA+_2Sl+Vth;oo|x*7+ytw>;jE{(XDY|5Ekc_`Cjn zd(?lRf4R?}XP^89@k3|+J$v;Z>(;IVnLn;yQFbsIKi3_vBdO#16=gr2de#T}A>~(; zy|;hl&Eof@-uExs|LQDP|4G(=+rvCr|9yK@KN|S`1GN3)GYxJ3aP3ij*Z-)aKb8L+ zdoKNu^k2NLq3mGPe*u5Ij--CDs-f&Deb;|i@7tsPc|HBqy8FFkK(f)Vi@9KSfFa6*N#DMi z-T!**KY_lxe<+V+Wd8{CQ`E0OKgIeTw$~r$|03`I13mlCa~{caV~_KDpl6k2Biw7t7&$9p2>c@&0;?vagHltCQGopd-io@%JYh$__^TSD%DG_%Y&hMys8F zqwER)gMZ_h?Zv2>U^~>OwydQJ+%`M8l zEbe~*&1ePU2WQ@e&%rrNlpT!vr;g98$l+~HFUk%^_4d33{z>}fekanuZ%^vWKf3Ga zmwHilFsiQ}M*kne_=7foUfED~Fsd)+ou0Ju+uM+O-yYSoe|%1A{XFF2A9>2&d43wK zAJc7}tmk>mxA*eTdT03)eOxL3%p1Qau{pvw4s2FGzlG!TB%p`wQP5&0kw@^$z-)J@u@Yll<5Ai{kNfd>JRnxH*2J?49pl zg8aAjjN8_q=s)*Vdd4})e{E01&*uf)dq{qN#^(W|>|iwiZ9UKH?dJ)7^>*%_;9qty z>YvXG=!az7d=4PWo{GP%XZ-Ew34Qg9bCQ4AQ}J`&(GSVE?S9--_Eh|Bz1=Ti{)>I} zjB}EI*-sTe>m>D~LoR+%_Eh~c9qPvWkB&dvYd;5l{zM;F%0Kr9);ZfJ5Wn3= zd&-`wpKX2Xe%n5$ub%y!L=Gd$C>2(vHinS_SF1o>p5?z7yIftPbT@79c+)^ zZ2SC~{~Gac!a0jXKMH(*S5x*)aeamF4XHOmKf-tM)Ei|_==pmM-m}~9Hn8`NPeAJ_ zI~a|>dJflr6`ui)zlFbVXec`v)sNO8-yeVuEI$fz4SC8AM)l!&R^j_c=Ff=y`Sz&3!1s>KzY)5@%}#HWJ(2%xJ$xbmB=c^+1M!qSmH&K) z%OA|j*y!t;IW3XgVFwTzhjls%Qd z!4Hx1wdgPTC_V@8nzFA=_|oSCpP6v{ zjTnDEf8abY%AOd1J~!a}HDc~o2k>uE_Qd=h{?o-zGJfhs#_!vs@iT9;Px8N5hg)6# zMA^Zp-u6AzS#s{}m@hXp9D6$$)mzd) zKYwF7dlDLO4!-k!4P^(T{+C+6hFt3$Cvfxy{Eay)%AT5k-Ss>A3-qW1WS{lRdCNLY z+Wbci7G+P??n=52uZMcGsN%irPhL{6%ozCAwvTi|nq z^$T(jVf_+i2TeZ*SNQ!i_K%kom~qvLJj1ixm*x0-Zq@M8!}hu(o8#}I^D|++F&nR} z4(vG>AGr+gMd@FP4;?%GIbJ_@{^#50Z`=29hBo31&T~A^;zrpo59WWMw{yp3$Un~^ zzeFx>Zc+Bj;`$8N*ggd^|NIP5cCelQ!2bv}!_LVd&rPGp8p;kv^>)6!0{!JV__v6K z=U-9wE8_b6z0N;r=eB1W+WF13NBuKz1^gJ{*UrtN>pRPeaR^t5RIp^(Q z)PMO-xBf`3yYe>;x&C~6R6oAjjUUNz8$aEUdOP=E?2QJ6pVyJp@!nUIJ*8*=_#)@O;`%Sj4o3ZR{_;gq$N4MD4o3A{KlTEt z(&=emhQT-x4p!=ehRw{0sH7*e4fPKSTZP@Qa$m z^M3v{@CPl*j{ohUi>hdjK7`M+)f(|GavdlAR2)bDz~^gjPH?fl#GhwtLr z9dL31_*BDzw}b8c1^Qw&>g6W9$;a`&yG7Z<=Rbj-=X;)2?VP_G+VfBYJY@%?{;NBn zfgdCMkCr?CM%feo?fD(g%Fj8!_WTb1NjpQsp7L+cPmm{jeuwAxzS ze}0E=_wSx3Ifwg?*|Ttd*xqo)+rg-R_Mg|;^E2q}`I)EeDZSl4L2vg@(6RrF zgQVWKNB!IV(@_^c^Je!?p3I+bkLvCI2zfFhZ}!|tls%C@&fCETH-84daPz08>>Gmo z&9&=S@gwZH>k%h;1fO+Di?WB$p91~x@6e*ZM%0gLAO0=M9@dXQPrp|GNa*OlCiK3& zoxeao#rXe^UhAai`U&*xH}hvi{@8!!(I|T&e^z%e*A`KK&TNn0lJy%GT|Z8?{iC<_ YYkm!C-`S`?o^=Ddw+wII=9k%j0f1|D4FCWD diff --git a/technology/freepdk45/gds_lib/replica_cell_2rw.gds b/technology/freepdk45/gds_lib/replica_cell_2rw.gds index 1b2564a4edde04c4198b1d51cfc6371b9bee9972..24b5543ad3d5a4a7c42ca3c550ed281fd1b5ae16 100644 GIT binary patch literal 15234 zcmchdZ>VKe8OGP%XP>?AoqMl3{%IO#h{lPDvLp*NF_JMebP^k*7#s64j^iK=kvE$O z{19SgVS^P!P?7k-v}7PG$c(5MrAz}&i=w2VNh_)R5NTmHJu-WzuvzEa@SK*igGv41E@*B+{NT*@ai6)CvV&Ru;99RA{L|}4l>OSYez@8DC+VL) zMgASylm6L0xZGbyzZSD7`{il>^>>lK)9@i#H=8q`^Kk4gt&3a$I;!LoE$@sha8O#ATe#B+!XYU#BUv@C*-^LC6kc^x4 zFEaknzAQcCxA7+~Q_ncZ`IkKxe|PHOsoup?!$N85%*ME+C)(OeFvGq4l_T2OD>RC6`j~MPdNzXbN z=YM36>u0XJ|Ew>;{_Zep24uX=j+U~6-SHdgXLcdqH)GEN4nG4PZ7DmL)Yt!j@00KW zxpp=;wv-)A>YIxZ?-6Lg@-N`SEoBFj`f4ZQKLa0d_$Khlma>CM{qSo(eza>IWZfNquNf>fJWPjQo?#ze6pHvgh(&?1sN1_<+n`@l;FMbNOSf@;Q-w ze&ty$WzRi7MC|6U&o@5i+$^5OoG5$z{Uxfu)yBW-`q_?}{|=r3IQtOzcuU#AnF4){SW`<<0lz6^&;aB?MXfJz6Ld5#N5UFuMuV6mhQi;A4lL9 z>&KdJqVG4htb-j)`nUND*OAn7{t~GV?Mc1+wR7%ie82+VcZ(}p$_}RWKZ3tS=*c^w zUFuNw#k794^9T1h_ME_a79Y$xqU^c)>yN+YkA57I9KVysAM2CzBx!ZOtEKGO`E$G1 zPd)!)zNR0|+w8y9FDQG?KjUVeY@8u~1H{k#k+SFV$2FgMA~o-cvghVMRF3W62;PI^ zN96v&{)PS9JVL|!N35SODPgbI6>jM2Qw#h(zhQX(Blho6H_!Ky#c{A6b2IDf1N+WI zh->j#k^ZHq;}3iN>w-SK|6J(qKP#?3_u~StKNlefn?>1;-SN}YBllapzP#7#N0fa_ zG=3sIeKODH8|#PrsecZn?7jR)`sPC9>Imu_C7w59A|I{tTi-xX;6_-#vz&9^7@ z#Z}%vY5TWlTGD@LPwH*{z~0~ZbM$>Z_8+3`mt^99dl)Am$4&K%mNtHTd(!{Rl|Ij; zt>1rW$^3`*j2`vzfWL13L=bvU*^NnkbD_VE&yPAjKTp~7dUuh(j?aoZ){Up^d3|w} zzmCs|x&qJ7Q}(>RVt)UO9D>|8GXJ9NV6y)+AA$Zse8AZ`@Ru!R2b22ddT5?N-oV)t zzOzPbt^yoi1`w9?ixG1~&Kkw&1jNi%g-^^WhU(A13 zFKPZ-iN3iF`sX?SUA=TB9?M#MR-!MyfPT!GzCZsiD}MK>R zhITvR2C3tF2vK%0>3?`9Y7Xlr$@e$Si!EgblllS=m)DWhcR#Y{^yMM1C++>wuqE}O zJ?X#1_a5enWWR^di?ZkP$M*%y6G`3ReJy3r=H5M!r$PL$o)9Y2x2{2A*1d5j;BzjyKdhbTLk)K{PPdXl;t z-=9V5Lwi?Wb>lCvN9DVF;}5`p;s2uS3z7dw-(Yd1-UwauJFhp&p3yUJ_U;E99*@6~ zKT&ot8$aJMF#f>?@V=I^gGqg}9~$UM>KV5vdrn_rjh;Ijag)!0f9g>7v(x_heC+og zkna-s{6yKoWc)SOP5xd(QrG;orR-o@f0FM%-!)smvF{Su|L_hvsV{E#dXl>Chx*W- z)bn~?Cmr*_ze(A_q@Lr3c_QsyOvt118rqZk;yj-}lKK++7m@i3?MXe?c*aRGZsjrL z&FsDSi&c)lNI%8+i}X{Bzn)(6oaQ}I_WzjwB0a|~^S6TW8|kMQzma~5@f+!F|A6`< zSvURh8``_|^Iz4g&PnFKO+BqeLw!to{gVp#>Vx3WIrbwzmfm`{Ka!PmPar# ze?|J{z5Y6qy8iqZ+LQ6GR^N}m??1FJ&;PqZ{DJKMr1&|%X`jG#pWi=3*?aqkD1WQf zS8ogZ50HNQ`*nf;$yAEXjIDSRh z!DRd#cf5|IuD|~a?f)}9=Lf|(&VOiMo`2-c;ty26a{bpjJ6dC{-%*mT&{mxC*hy#2mOn(gGv9K zKX@HU9p_(B_W!58AAg818$Z|Saq*Arnf1HBe=Z*L{U;Oq=V<*|t-ie8`yrY4^2L_) zAKH`s@B8oT$L#;p@nhY#{s%6n|NZX|)$c?7gI53Bjmh{|s~_It{g50tqj~hC)}9-G zegA!ZXwSx9Zo)G}KkY0B`aPoTo1*bI-~Il?cLba(jfcP|@qbbF)6;r8fAHbr1=dZ}eyne*X{C&}$?0>Zr-w!cP`TTfph|kYc zc4JrnZ1?%&>e0WsPa}4`{}x9Lxb0eeW>DVv{eDeXUv9)zhmmv8elPfPOWDDso@11I z7UQpQpR@3PQT8j+`Wi9Q4@v(Gf5QxvJ?G!f@4$}{etCX}{*AI{{7+GTQU0c=zer!* zgLrSn!vUKGjG@=IlpRdwe~S8v{iDY1oEB*3{!sg(?7j1Uv3@6FzX2ceIebvRBg%e5 zCjOO=pU6MgydlPok#&SI$34GM_N{6EcD@Mn6v_F^&L0JG{tE5M{M)%BBEYM)!ZD{T%$^9o`Dgzr^~3nBTGH^W3F7 z8N6SV-Dvp>zyCu&`TRk32Xrs+_y4``$4~Mr*MAoM`W*H9uaQ2iAIC-cU-|kK>sK)T J8}y@c{{|qX3zq-@ literal 16002 zcmchdZLA$d8OL|`?Ag8a-dim~Yi&)c{Up9bO+*O+e5Gk?d9fj(mfDoIHiX7Nm6q6` zX;i8a0{F#ft$+qm2_FQbB#K{Z1Z<716(XV`Scsw~H8H+@sPX@QX8vb))-!YWo-3Z@ z^mqHr{?GHwvop`ko-L&dCnTE21QGNa`rzfc|E@?=;Z;$E+|H!hlF3K|FNp$jd{9ly)qPYL^ zUif2j$osQw`1TfMUlP|3psAO^Ke*@$e9m-3*}-`H(3O98`r&O(FUk%^^~2T9KS}?? zgAM85w z{Pj^6zbHGH)Yn_a>qqu2Y5mC05$As>`nXd5nYZC{E`N->M*c+E!D#$#eRa9hi+%O% zr`^Yn|B*e>e;fD9-T0lx9On2J7kN7vjlZp5gt2GyN9?JezHq$%k^REBf15Y(Lo#lT zf06O~_GtWVJ>$3eC-&4c&T;-n_C);E-Iya!;{Jg{_^SsEWe212xAlYfIK9|cUp_G2 zzwBVtfAM-3KgsxuI~vlzZ||jN+|-MG^^9|zf7w&bMcKh<{B1qsre5r; zXPo2w%RX29tY6gEN1cCB_Eh~c9qPw8J?n>WPxgQ0=ZMdr=;KQH=lZ}pXX^ywFR*?v zep2>S{cP)5H>nf*>eZ2k3=JvDyXdX5|F#lCuskFow`2ix~= zy1oCb)*=3l$Qg-#)K|AC`^LDw*o&R)dT7X>A@)zVDEs=jp4#da?lZV{@-sx)!Fc@t z!u4OrXMj`R!QcBE$__^L^;*Py19V{d3Giq`*}2xjwMJ z8X~g)v?u$2C7u`7<2rD96L_+r>|iv1`NMAhkeolo+ZtltWWGJBAN&CKYz^{7J^}xD zk0|?^xc@2ine&|Fyq`MNQ1;aPFE=A+KZ0MdItKo>q3mEZe$EfpAR}rI=M8I+QT9as zn0Muw`RCdr%AU%9xBlgix&D*vzi*GmU+;3)k>m2`+oO7TFds(roAZzTH=_UcO7$Ok z&p+?;|4yHOPuanwf7VaFSU2f+MA;Mdv-m#x5C0_dKDeNv>|oSCziVOrFrt3&`v=w$ zqwI)js@Rlsz&2hktYNlQwRk7a6~AkH*iuO+UkbQ75*z{E4!IQN693 zsPp8^dohOgH=OczFsiq@!F2-lgL>8vk$T@A)n~s!;5+ap@4@xBha<|qBkn(Y9Q{8H z4LAee`JRTdgHiv!zFM7C-4*-P-yv%S?-N*m34deEin6E1Uw8i2FS>b5a{kXXe>rYh zXGk0WsH39nsru8cU-Ml**l+qFZQP>&qUoE$j=yJC3@;3n~v+e!6?K`n|H)1cz=Lzl^jk2!`#($u< zb?;JK&voz@=oHsKQT9vYdfWHoIwN$p{}*LX=rden>l|qNerQG6!S?+N;;&J2Y@ZI= z{{47E**p99K+k>`m%08Izjpl}QTEH?{__tx|D^4o|Jcy>&#pZhzwJBW#|Zzn?-XTE z__z9n>uvw|Vf14;_K%)3-VR3nPhI2kPul+B4-J`r-yYQu|Ag^^xldZ&uzrcMgHb)# zZC*!G$7f$r_LQFS@kP#l4MhB+>|oSC#}8j5bv4G1C_5O{bNt#1q>gh(lpT!fId1qO zsmn2bMA^ZpzI;FG?=83hCw z0Uv5n_Hg|U^!Wi?e>3_`VlL*#T9p0fc>LK`T#x=6zYF5MNR&O%f6E`%FOusP^Cxos z^6i$t8B7(_f5bm`{pW8{hzs@q+C8e@^U>FLK!4EbJL^X;|M{1pKV9)E!z>d}key>S08jv8d42-ueD9@Nd8MJcrLX;&k>Liq9eW{h@D<`XAnh{yvH8K-S*+Ohehhs6NNd<#iaTJ*6)mbb6Bd;jkg~zCG%{*oEtnKa%;QUX(qRKh|jGiKK3DeM8y7sQapJjOuGFj=YYf9w&)L zls%VJ-V#_LGx1}hrMp3?JrUMC&%z|SFNPw6>tm?x6`R~|{(Q~Ap|XOKUV`r=GO z*;D!Bm}i_M<5nI?**o#)?fEys_z(0pz7M-`-gEv2`U&Q5ptriGI@hoM1^Nl*Z=j!G z{s#I9=5L_q7}J~MhxJ#Ky)*v)r+STZjr-wh=bxm1-`<}8f&Z?)8~p z!KnXk{jzgh%;TeY`?}Vde?k1_3)hkM?$kfu9`(OaeK-Cd^*0)S^#b~U_($~pO7*|H zf8g^6_W@*N{}A|JsJ>j|_aC74Eu!r|TzfSC3)Oey@3DW1_y5%{Z_}QA@)yJpo%#3d z)qkv0b{)vPao&ougVFqP-tjt;y6*nZx4&e1)(6Eo&cAQ(=O1~q_&wFHRR6Wkj@Dhj z58)n?>#uK*`saB=UPo%*Bg&pyzq|hVy;WO3m;dhmiRbvJC+Xj}N8@jw7o<-6DDA6! zdsN@`-__6MUw%fq`(6AzH^=yWd(=O_x94>vqzSC`yWr)|DXD9{64;9{9LEU#V>nm{qF9c^Aj!)B-d}>9`(Oaefzv4^Ix2C z{z>}x?Y;eX_4A3J>$dePjhWJB3I=MMw_yl;%($lT%nS?);L!}w3P z$1koLz4X1kIBGz*mf-Dw|5?=57c2e!CvpFaueQkh@7kk!o_n&hHsI9t__{{-_t(6i>+`Calb#?c#FT!DPJ_GtWe?z6;on{f|r1yTP-l)a4S&+4Y?XwaJQTDKY1^(^)*j*Se&${}- z^H;1RBN(<+d-#9lj zkMlpF{_6p>m#F{% diff --git a/technology/scn4m_subm/gds_lib/cell_2rw.gds b/technology/scn4m_subm/gds_lib/cell_2rw.gds index 0a0e0f8dd79ae21d52569758fc389a38f91532f5..cc0c08738cc802cdb9dd225f758eacb0e136f6aa 100644 GIT binary patch literal 6262 zcmbW5J!~9R6os$<)=t=jH8I8plNb_X$1(BRNl0iQNEDIMq@b{9h#&|T7P4I6lv|nt z$z>!Ocer%vk_x#@nUX3>=`s?C<$m+#FmKnsBjJ_oZ*|^1d++<1_h!Z#HaNIuGXsO8 zFKx&!ThrP$o`1L2VB@>*H#WXm+1mC$vx%XR&%XHi?!!NRJO1>`!{xnSzy8W*Mq+=n zk^HM$+crFA*0?Zei`KX}Xl6^TA^-26+2@IOpPDVU%|z+W;c@%Vf4$e=?f&&L`H9D$ zD7|3r|2X%Lzcy=cn!!&F%%<*DlCW80l=q*!bDfm`#_uV=DBT(Q$6t55fB%`rZ)i4+U!wGax&KC< z|I&`xs+qw%?w{PRDBT(QFFY{2zHSDYd-^U)cZPoQ5(n{-UzA?wpFT={h;QaqMf_!Z zn4h}mTd98H@r%-(p?`EN)eOmXb)h1CDceIo`RO|(p8TS8XXxkm&o87r7hk0OqI75I zzqHfs{CVtU`rPcDO|RcM?d$N| zPn2FTum5I#{fxKGuH5(i+sVHF zmj8*;ouQw#a_um!8GNikQMxnqbLM^U%#tc$#vr|#JGxW1Y$PJ0d zFG_cYe#VV>jU%2b_tS4mcZPoU8`d0T?8z@mcZPoI=A4Jb;}@m(o&P81pE&h{+|&)F z*ZG-$;vn?5LdXKjA^ zsoxH^iywZJ=M)UID5V*-5L7HMI6LOK2ds~e>ER}`m6hd+iPhaMCpC^ z4=4QdFaFp5-{be^uj1N)TsuRrDsoMg?Ro!u{2x6?eu$r1MEqrY=%@cWXLat1()-Te zp8RJx|9kvrIKO-RXE^^>^7;26E1o~#o!NBnF0LZ_$C;1c3IEbgid)`Keo?wJ^ylXn z@$BOw`&ii?`k5;|C+N9Hl-~FJ&{IG6_{2dy_lVN#{5*3IciQuh^g2KFbKa{T?49_a zbZ2e<*>m(eJip_E(w((_YR6AJc}3~Y(9eAvdwp>q=XJB^Q9qRK4E^j?%rhijJ}BK8 z`U{WyA?t=SL&RUUhkoj&pOARvh0^Q#pFgt^&wegW?wghEVSdJ)IEaruTa@k${pY;D z%o*gY;=3r_8T#|*S8AYsk?&=D=;yj24pKKYi_)E;U$KxsjXTVKEA(^T5eM-vc>hJ| z&d|@iGft3k>%adg+e1Hj=_h2|c>f?uuj{}0hck~4W6j51}scX>a1D?c9xc2hs- z6X)XafhfJ|-)a6)?;r1X7)$)DiA3r3{``Ex$C?(|XUq0{etPQ9-!IW;{D~=l*&h05 z%lcX0D!HV?|k;easRKl uzV*=)$JtiKZPmpwwu)0;9|G3L=lS|DJ|o3{)>Co)iqf4$|3O2mlwXwY4E@xN+>pK)yC~h6``^p+GuF+eH0G^4X7dMTqI75I zKYP~~lJ^0xe`+>-R8zV$^pl@Bh@bqT^pbz^S@J`Cqm!EWtM)KI<7TaD9{BM=>CVtU z-A_3no=aD2lDldT{p4lNka+qKr8`4E{o{qK0rHE|ouQw)*u`J zeDlN~OwL=6%`W&F7Nt8w|MaohYfpR(&XKRfnFlqcJ465MF!>?=bNe;%SM8yn7@hd@ zQ@S(sFC8a8#QXMxn)s{s&`;eKE!B^B>L*HfhJNbC93gY3exh_|=qLZ|?}6GZ=%+sTR7b|kIH2@Wey$ZY*EJ(A z*APl~hWQyE`z<71J}BK8`WZKIng@L_ZYaIv=eiRIxn5j9QF_V$#$n0_sat+Bj;cKz zKkZy6^@B&JbZ61eT=7$Po+F}kXVK3*@e{AwLFujeujcn3xi0UeoL7daj-qsDp1Areqwau%TMVgKjYQj&pkuUMCs0O{Jbv{2l0_p zl-}}h8CU2`HA8;l$ty~ChJNmG_DsmQ@rcr$p`ULxt}`Sa zzbM@q`iarWy1^?-FZmfaIU(`nBQghWYu%B{w8D;}@knLqGS8_E5$>e~`uxr8`4EbJU4HKc$!E&wfiB#LI6+ zqV$rV>rS1Z-n&HUrTUSVIzj5j?+>E%QvJ*iYR^HvxOYV9&ai&?SbH3khsiHWcaHso z^!ukj|K|DqbHMMP!@vC9?OW?F_P+VD!pQ3bU=)b&2RQg81$NeQrcaHtl zy7Btg>&ve(zt8%5__Doj8gYC-C{F9)Mg8%9U&ZZ|;`oM9+*)&fALZ+dIq2|pJHG!! M>CW-|rk#`a51+?*QUCw| diff --git a/technology/scn4m_subm/gds_lib/dummy_cell_2rw.gds b/technology/scn4m_subm/gds_lib/dummy_cell_2rw.gds index 00bba7f7276252e9e35d1d689b1b40c36b8389bf..f8fd67606fa2e1b71f0ed72c5f981459974f2711 100644 GIT binary patch literal 6012 zcmb7|J#1V>6os$<)=qH3Ix!{&lNb`qPGaJpBqTHtBnl*&6ciRsA~3>*gRDr9(77}P zlFLXm>2R6SB^7d+G9^`%(q$wN%l+Pchn-#LKEYb+Z*}ILy)$>_&6|DJvcbVMn;94! zeQrZ`)=v1})$+5o2U}l%v$=U^<^BVIn@tXleDujrH$MOU*TWA#-CuhA%a>o+%t-D( z)oQJOfA8LpcdBn$z5l?5$IMzM2JMoyP7a#cVtdH{`)l@T@Ww;4OUq`Wbm#Dd{p-Kj z>+f{_d>(${@du?>EdB47{)v}n%UfpfgC}NZZgwf%nfgb(&u^SDgKw{yUD)qZx-<2^ z=JD+fGf4c|hh0i{rhf8{J&OFqlV6nXEd7h+_{lrB9r-W+7WqZ#&eT8gveWtNkEq|! zY}79(y<+LVT;@N$W43B$@Vfh__PUhrO#LT5GrPE92AO-tE=qT%e)19r@sVGY-sGP? z2tUL(^P)@qb$gnhe$Tg~|HR`Lr8`sq=ved_lI#3JmyD%uPyOU)?2vf!i_)E`pYK1u z5P42Mi~OQ=XX-z_)9L)Z6@3`kjod-$6-)nexqc>Z`}#TX?a6s<&95C_i=uRA>K}b- z_U4xN-#P8;@Yvlhr8`sq$#(c5{?{LOiN9`7{cr7tAL5^x?Gk_8p8DDAh=cgwyW6F7 zXX>YJ)C>~OXHmK{^;5Uwhf%-r?Wmt9-I@By%N_(-gX9#YJ5xX7CJ!Vp;}@kjHEo5cz}BE0+DgQeHn3 z%Vy_p`Tp%>-#_JVQMxnrvsNzb$C|;%8Wg2FQ$P2-cOQAboy6l8r8`qU>yMg2`a8be zrF3WNXN`~>5|3Y$?o9pEjd;}&&$(Oiozk7DpZ$h42dO>zMd{AePrtd(L*ns^();fJ zN9Lb6jf33u8%l5TGylXv=8O3gr8oKCc@p^`b>sRK=||n3j-PgFuJ6H%4@z&EKYY{+ zGG_J>QM$7+KjYN*kQX16-Z%cG^7>=HV9fCRVboES?kw~7_{qUN8*+B!o-0asrv7Ta z-4F4xkBRu}_S8Q+7WpAQ=3c~Kx2Jyk+un$Na|UP67o|H>Ke>p5_{b+p@AI#g^=G^~ zCtO>Lc@U-doga?)=b!zr{r`wx_c`77MCpC^zdpbAd9(kx|F4wecUN`(hSz7~>?*Dz z`pa3?|A>EaC*qd&!Y@j9rv7sOCZ2svCVRSbIs{{`2C6xN_RH;={tVn$ty~Crhd*X>~+;S z#{11RPyeBGXX@u#Wu77N@>YCen7ovFY4{YD??zsTphJ@s?l5C`cueHNuV zQ@>&%Z`Bx>7kvDpbZ6>k-l-F$ZvFTFx;^!imvKVs#_w-YdeivLUqdhW zAGK!hq2^G!GtF-nzmxH^*6;!T-*ds`iMzbTH|Do%O51gwvb%k^QrMymg;r|S9> Nr8}$fje7rw?H`G^uDbvL literal 6082 zcmaKwJ!~CC6os$(4rS&)k{2vpe%PIx#$aKNg0D$N!Fz z7>cRr#CZLG%no-pe|Y@(rw3nuv$geLb$dr=#D$TuyC45@`?EiOJHGSD;quPaCFn zG4<0vUPwIoP3vOqzg~}@m}`5bjhla!{HAp=^;0);L)xP6rggFQzhCF4uj`AY&l~q5 zX7?jZ>tgCZ`>7_9+JHAckLW(?)4G`Y$xj@_Pkz&Sn}7a!@k4wIFZ#saTu<}UZ|17U zfgc~VE~ftRiIM~2xpb{hayQpgKY1B5B%U@*>tgDseY}u4Kz`G@nEI(ZUU)`ca+=n~ z+P_lIp9`w_`U}0D#M@6IE@}>&*2UC6eiZTgQ}sby&^(-c*r#>}C;s}hE~fs)qvD5n-+kC8{^ok>r*896>PI~FGp&oMpSm$d$k?f$XSui9f#hZUruDY`#4KsvLY_OkrgbsRPydO7_^6+0z0FUpiG%pKho<#5 zKY6J=oYdIKZ(0}Y{@<*hpP7|XGst`Y{O^5I%jSCOf9?B-tGa&>KXb;kE~fsAb7jqf z#N#(FA8I`1dg^D4Z{I65pubbQWjxTjnEKBgmo*C#Zy#hWYp$n$>Vwa9q`&k7T5rqG zy`tv6XXND`LhE9hpZ>AlLgMX%*2UCMzlrlWXoG%3>urASJ8_Wv#r-p_xB1^ZDET0D zt55pTTu=MYb?%ef!Q<1q*y?Aj_^CVZ5!1TZ>SvtziFfUw^?~s(*UulhuI!eaSG%Q- zrggE-f5JcUOnsh+fbZyJ?KG{6sh>U*2l4S9F|D`xiSdcAKCQR;>95y*o*8OpS{Kv) zvtK3-;v=VNeZap~*ProvpWuCiX?uvpi z<9_i&eC*#${LS^cey8&5_h2voh`i)Ct&6Fj_KAb|$ZuL7@UPbO4;|}^{4M)__Pp%> zp>?s&f6BkS-?PWs^WrnDi>bd}KZxf&YVr&>*Hb_D&HMDh-yhb+)XzO44*GY8X}!(Q zUY$5N`1`|po1gx(-g+G8_DXxux|sGKAMbm&Gq+KE(7M>_XU@1C^5TQm#njKfi8Z6Q zk5V1*Fm7mFO#S>;;XXs+?St0E)K830<_&F_*4zB_n_Q51=Y`hAH2;u%+Az`RO#M7JUPI{j?0)G#v@WK8 z#^@7&eOhlDKkE%~5HH_MOzUla?mKmY-glVR+v-PN>IA79zrRiEZS@Ns)SiQS@$8t^ z#k79-n0p+f2gPq%7kmDx^8HWm?^(Y8P4WG&`;Yc6cVl9{^X+$=YJ%^4FNjdjr-t$xF0v$+GC9zSuE|XHtnele4o5kuTRw&dg~HnV|{`g&GouIC;U|ndp>H5 zA96I;Q-8fa_`8_Ny=tzf{;A#4N9gC$r0>o3)X%&m&hyjzWN2MX{me@aNWYn%rgbs( zU)d$9?2+;De3{n8p1+wls(*ie=^pcaQuE=f!Fh8cj{URaJRe@x9{bxSZo4gxJ-p*q aPLA)RdVVnmADXwl=g+h*_Qp3Zj>dm))MWAi diff --git a/technology/scn4m_subm/gds_lib/replica_cell_2rw.gds b/technology/scn4m_subm/gds_lib/replica_cell_2rw.gds index c91147fdfd1589ddd5f8706e1fced468c73e866c..df0f9e2802dea06430f41223efae3fff9867b4ef 100644 GIT binary patch literal 6270 zcmbW5KX4UQ6vhwv^Aa%Ni$nyB5CtUs5kdgLMsdc185;_Vj14F-#+i(hNnt2c#=@DD z%-GPGl9JNOp`@g=Vkjw@(eZhHd-ikhzIb+o$AsUT@1F0Sd(XXl@9tX9Mn;xwcGt+n zGaI!dw%7k1F27rUq<8!7%F4|PYwP}JHZwZ@>E}OP`SSN)Uwrb#qw^1b`T8rH9nbwU zz24g0)s^pWe{-|?oyE0v8=Exi?H#ex*4sB?W@r1O{=a|bo&>MlGdsOtCQ5gXP20cz zQ*HlX@aMDe6OTVAy<+MAsPs?2G+S6TgC9RMJ9xFBbZ6=x_ddUU&fL+Q@c z|Axo+m(3vYNA5M0?o9pUoxC6Ui6_4(-C6q2mg6VyiH*pA=C{Z%N_VFI>6e4SUw=gX zM(3h_LFpAs|CuuX{!Oz*GlQ4ie_*?zbZ6?{d)@5RvKeIV8M`Rmnfl2~9K=U{QF@pE z(Btq!e6!CR;;-A&{Pg=|Kl)EReo?wJ^-oMjpCP%9%{OE$b$jY3KVyf)lV6nXO#S@+ zp83eL?`h;0r8`sq{>{PQ@73tTuC2%&lwPs)FO=(N=7z7I$G$;1FD?1C<7-ir?o9m? zPt4v~_5M2#`8wQvtD$sf>fhH7Kg9p$gNFF)_SAoPEBp}u>|8_qb$jY(uOklP|KL_b z>CV(o-KZHPp6{Y`XX>YJdtOBSrZ%E}qI75KCog*tWDSy2l|Jxyi^6@iF%z{<=N&)8GDb^qYHd_Iy#gGxd{;IEasYqVysEVp)I2 ztNVmYOEC|k^r8EQ9sZL~Uupku`TaSpx^^Jf&gk=oTvK&>IsTUa!|UOP`00y?zivh{#nTRDyu6g|M|M=-Y z=e@?k-iZ%NcXp1SJx9O8^E*B$-P!5qxd}h<pS_BC zhQ!MUr8`r9<#9h`-Ed}z`0Mu6Prn%_Bwl%;^se!j&uqlApNj{!&Fc0vKXoS#;$zPi zr8`sqZXYjm205$vE=qT%{_^>iKG1)W?{$0X=ei*d(r@}KN_VDy#X|m6cUb&Z>gT*8 z4&tBp@r%-(sh@eLPLR3{-~ZI@sh_-z6H+(cKZw%1#&7=N%;Q6?**iq(&NRPSyeGiV zTEicdzT^EtYyV?>!5ul!T-{?qdx;Qi+m??0y}{rT)? zn>^I}?uR?|IrCp}{bhg0H$&X|%7uTG%s-%w}|`kj`DhUc|UuxJRf&$ zMIEUr=i->xB`AGIeOvwsA0O{`s0BXOL{NISzdWDtv8Ki3d}-w`-!Cy{{K3dyx0mzV z^3T=%XMK~G^&Jd<-JbeSY((6Njqq`O;-7yYy<#~}p1)Ziyi4_aK%b{?SBB=Z703O* v;)d2oD~_|Rj$7-Bqqd4uUM~UbAs`-nezNy8rW6 zU)W$GZfCaBY-eL<*T%bMowF@lvCeeM%r5ua{@0JC)5MRSnysvviPD|pGxo3ly-|O1 zr*`n;gV~Y$ujKxjzs#;ZF@rab&E~giN_U3-iO0zU-}H0&s3vVy*F*nH9{+)_+)2x-;~XpE!u0{G#-df8km3Lwtjin)s{hVSf6} zTGcr4{4&hJM<|3t0o?7o|HxKXu0o&$ySI zqI75OU(46etk-<=#2--3>yORO`x+LdJ465EvDs@+ybsQSufwUkHKjX4|8zh3A^vmw zHSt&1Lq9P(@#m*>XXsx%PJW2@ox3&hSJy*7bz87hKjNvMDBT(QsT*U2jGg+4(w(87 z{L{au{QZY1zbM@q`WYX2AbAdYwHt08$Uh*^V#6jkZ`4gp={BInl ze2}{3C;h0dhyCX|^Q3n0=#=g(`WY*J>dtdSlUuu@hX38$$q(`K>=f}=*F!(=Xw(T(H}+gndZ~V|d%uZ;_;`O5rI-9Xzu9}? zx&8n2{?Hiz|JeTCVuf@1Ml8kBB_Os_UVjy6HP*^!rQt$oEU5|Ev+>;OO_0^pcm#azf(yUzF|)^N+cY?@dTN`++Fk8TzR^aS$Kh4x;puf6B+p z-Ur!>nLkmwGtAF7D!C!K>Axu58TwiG+5_qL+(GI;l$d5HG*^ zh|)`b=AAl0y*G){OZ6i!b%NB5-w#CTrTUp4)SiQSaqo!Ionig(vGzE|50hV%?i~7i z>Gw;2e$DawWsl!4`+xhp*9X>J=zRPAeQ$!_DPI)FzOueW-0rq_u^9K^A#p$4FSW-W z+g?oVtyk@N8TftmTE4$zV;Jr$jE(&Ta#Yvz`ZWAm4TnBziyv}S*F%5)e8r<5O4E-1Oh)VDH__)7B>CU0Q zS~p(*dVTpE^ZTl=hi^vLO(Tx?f5mA%yr@0i&#SndQXJnPid$=r?~{CeF$NvJZin}u NDBU?6-=uTg{sGWqc#;4B From 111533f0b0c0f3bb95cc8961a4bcbe99ace4eae8 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 31 Mar 2022 16:36:19 -0700 Subject: [PATCH 163/229] Move power pins to horizontal or vertical layer in all cells. --- technology/freepdk45/gds_lib/cell_1rw.gds | Bin 19192 -> 18132 bytes technology/freepdk45/gds_lib/cell_2rw.gds | Bin 15226 -> 14614 bytes .../freepdk45/gds_lib/dummy_cell_1rw.gds | Bin 18930 -> 18510 bytes .../freepdk45/gds_lib/dummy_cell_2rw.gds | Bin 14976 -> 14364 bytes .../freepdk45/gds_lib/replica_cell_1rw.gds | Bin 19060 -> 18512 bytes .../freepdk45/gds_lib/replica_cell_2rw.gds | Bin 15234 -> 14622 bytes technology/scn4m_subm/gds_lib/cell_1rw.gds | Bin 5868 -> 5746 bytes .../scn4m_subm/gds_lib/dummy_cell_1rw.gds | Bin 5544 -> 5422 bytes .../scn4m_subm/gds_lib/replica_cell_1rw.gds | Bin 5906 -> 5784 bytes 9 files changed, 0 insertions(+), 0 deletions(-) diff --git a/technology/freepdk45/gds_lib/cell_1rw.gds b/technology/freepdk45/gds_lib/cell_1rw.gds index 3a67e40b4ceeba52e0663ae9a61c1e918a35b8f5..905175076a286367b1dcee649395e8746ad5a589 100644 GIT binary patch delta 169 zcmew{mGMe1qY?uf0~1pOgA5}R`!fb+26+Yn1`!5jWcEZQRdF0r8{;0xZ?02lV%+SY z?7+53tDZ%KgMmkYnSp_669WivNV28prA+>)CxtA*)dZ3#O94r!P43p)zqw1_j%hQ8 bQ4`~0FB8_yrz~GEZZ@*H#Io7NaSJB^lQbqA delta 913 zcmcc8%lKm|qY?uf0~1pOgA5}R`%?x^1_1_s5JYBAR8kekA+<5?fxO25|Nkq2ct40{ zU|?_r;&vDf69>_o)f8qi*0cNuu^AXxenZr-al&YrIGAP;1S;WRU|{2AV&G4T|*>4VWQalHELDK&tB$qHf-lNH2bW)Bz*6UXNO4F)0&*t|?JijBh10y>1K zm|?&b+MEBYH?T~;t#ew9sgQwz6BuP6nj08pOn(tHOq}!g<{sS$CRl>l1+pF(Hf}%+ zN)TWgC(VNfc&tg;qN9ZnSf&i)kCkQYNQUi_fU6XrsrKqoTvyY(^E3w9&(Un#O z1t(#D`Is>=O}=EVB>+^t5a@F`1`bKK^t=>?$!E-s_?R9rFmO!+36-U!Fl_d)xWTgd Ifz20A03t>v5dZ)H diff --git a/technology/freepdk45/gds_lib/cell_2rw.gds b/technology/freepdk45/gds_lib/cell_2rw.gds index ca7468cf7a094b00bd96065d213ecce73753e642..cd57876817e87c14a13e9c9f7cf0dfa11d556cbe 100644 GIT binary patch delta 141 zcmexWHmyjBfsKKQDS|g8+jp13NN%qLQI77U7L)N_>+~@HuYwR@32 E0EQ_eh4wPYy6*cjRYa<6{Dvts}q;w5Fby_~2WD25h>8r$LZHNN w1`bKK^t=?HK9FUo3MK(vH5H_wECr?j>KeYuH;nBW`6kaWwqRoi>SJL507no|SO5S3 diff --git a/technology/freepdk45/gds_lib/dummy_cell_1rw.gds b/technology/freepdk45/gds_lib/dummy_cell_1rw.gds index cbfcb06421b33ab8ed54140940c31b6e25d1928a..031ded2ba10f04b29c143651edf438f2d99b0470 100644 GIT binary patch delta 154 zcmew~nep5NMkNL|1}3Hm1{p>s_Gb*t4Dt*D3?dAi$n1$qs^U1LHpVTJ+w3Cmz`6N| z#z9t54h9|pW(EePO$;EwA<34Wm%=bPM^6%2hN}rAQd;`6h4nv%f$`I1MkNL|1}3Hm1{p>s_NNS-3<3=N3}Ord$n1$qs^U1LHpVTJ)A;}YeAbRr~xd=|8RZq^5k>2dCv5$3gqTXIcn6_O|OWdHAfN7u@SR6!e zW;2+pt(8%%nS@ng$xXwzaca?Cy@TjzyPCR;+(%H zAG0)KV|u{Az%^~MgP!Q*%a+OlKvygTnj*)*A<34Wm%_05n58G*uBf!kSz%qvc1UMww((_V)TtOh_VPIh6Wn$oFU=w2k%CU(vGQd<%VqoB& W08(9+lESe0i%6R?8#_=33j+XVP!>%9 delta 433 zcmbPJ&`_$xz{bGD6u}_F$i)7Pftf*$ftNv(K^2)jQOQski}1!Y4L&6nZUzQ!e+C9H zeUX8IRT9XD(O~h(8+hd=_whL@ivIuqe?L&AC<6n7BT%I>jE0F%-oP)v`8;1eGm)ll z_7nQgxOt^WuCfOQ0|Of`69Yd38y^$USRDaophX=(r*uQ<`9OLOkPo9_;@u1^fgHp_Kf_K=ZV=nqMFqUbmViO!d{^1B0zck diff --git a/technology/freepdk45/gds_lib/replica_cell_1rw.gds b/technology/freepdk45/gds_lib/replica_cell_1rw.gds index cef0722d49c6456cabf4a9c5df43f82b86c40383..706f0220c82b4785b5e1382a90b47a858b280e58 100644 GIT binary patch delta 160 zcmew|h4I1!MkNL|1}3Hm1{p>s_Gb*t4Dt*D3?dAc$n1$qs^U1LHpab>-`u9)#I)H% zxsGi!n^q$WF9!pU05byv(s_NNS-3<3=N3_=XX$n1$qs^U1LHpab>*ZBYceAbPW&LKKr4lNE@~z`$e$QN!#3qhaD8dUBqIv?4*3o3oVWu#sZ_ zEXK_pTK}0QKi0KZV=81|;QS4A2$1IH1k!&IG)$cH_ht^g2qu^nyMRsudC?7sL0$yY zKryg5h~DgBFoRtMqzWbqQw5`8;+v0{voTHfv(yp*iYx@m$}wuBf!kSz%qvc1UMww((_V)TtOh_VPIh6Wn$oFU=w2k%CU(vGQd<%VqoB& W08(9+lESe0n@F1q8#_=33j+XZdKOp! delta 433 zcmbPN)Ksp-z{bGD6u}_F$i)7Pftf*$ftNv%K^>VrQOQski}1!YEj~3CZUzQ!e+C9H zeUX8IRT9XD(J*oU$z^=es-pk@|KAT(DaydW;0RQy45MM~^vv{CxnY=(mMTTV|P~tZOha_8iUJ6hj n$TCy~lYp+83Q|y(0#g8W4d3Jk#`cVSlNT6Uu(1R6u`mDt@6b%V diff --git a/technology/scn4m_subm/gds_lib/cell_1rw.gds b/technology/scn4m_subm/gds_lib/cell_1rw.gds index 92523dc1bf8eb78f321678c9b2b1d2bce034067a..6f4d7b268a63b17752ed5d9a96f7dbf7f0e3d8c3 100644 GIT binary patch delta 117 zcmaE(`$g8+jlgCR0|qLQjO4ylcC3A~&C@$O}nU=wF# r;9%epU}j+8O=DotSiry`$ySzg8+jV11BYm>C#&c^DWp7BFx~vX!NzFibWQJ}}uxa!^G7ECLa@i#l!2t Wz@V{!fkTq5EM;?6(FJj diff --git a/technology/scn4m_subm/gds_lib/replica_cell_1rw.gds b/technology/scn4m_subm/gds_lib/replica_cell_1rw.gds index 53525453da5d3e71b9bc506b7936044fb6beeffb..a5b5e3d26b206d8059c634ecd31cbd13232cd8f4 100644 GIT binary patch delta 108 zcmbQFH$zv6fsKKQDS|g8+jVgDf(8qLRKSR*8*i8N8eM`2Mo;vWYV? ja4_%)Ff%alR!z delta 183 zcmbQCJ4sK8fsKKQDS| Date: Mon, 4 Apr 2022 16:02:47 -0700 Subject: [PATCH 164/229] Fix WL to gnd spacing for grounded wordlines. --- technology/freepdk45/gds_lib/cell_2rw.gds | Bin 14614 -> 14422 bytes .../freepdk45/gds_lib/dummy_cell_2rw.gds | Bin 14364 -> 14172 bytes .../freepdk45/gds_lib/replica_cell_2rw.gds | Bin 14622 -> 14430 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/technology/freepdk45/gds_lib/cell_2rw.gds b/technology/freepdk45/gds_lib/cell_2rw.gds index cd57876817e87c14a13e9c9f7cf0dfa11d556cbe..728b20a795535b32a4885490014edacd3cc39a39 100644 GIT binary patch literal 14422 zcmcheU925d8HQ(O&(A*XDWT9K0yU_;FjzI#glJ=8g;Y$b1VK@>m6Jl7(pbb6ZDY7F z#-GMSgW*CGHIiN+Gz3k+M57^GXhbZUR=}SNC3p~2Oq%%51=jcd)_P}VP4-%6pM8vn z>^|)~^Un9JZ~e?VvxltCisFWBV_r1RWhMSQH_Nhh{l8}$iu&D$4;!ESMR>y)YT8XHrrUmuQ6ZOH}5-maPdutk7ngK%j$JS zHkZ}s6o~e^b4OWLoQJ>t$}ztcyf4c{>0r4&o9wU8;G*!64X)RGwxe_~?*E*NUxSR> zZ0yMR)Kl?C|AOaamXYHU;lCSk!RE3otKQsE zIvDkj?uF+b>1tN1t*2@*?LKrGrs_waLXN8NWK#k@5ZUq<{2LcOK)? zFG>fa{`z6m@9p@2Hhx~!Q92m)7wep#wEjEPk$!(X>Sy~#OD_NV11^72I+*lVFHH7J z2a|rqDX;bQ^OT;7&$^Yjx%x5h2K5uAgVFeXfB9SIZ|SeQoS*HqejLP?o@&31dyIW@ z4dxEVzc}_f7|p-$pIdN#aa#Y}W0T`c2cz*T&Ku-OGH;H5QFzMpy1FHY-co|EEB zPvy@wD!&>12eOu&L!xvr+Wx*jKkfW2{dJe~kG4*Z-|AcA@r%taf0B6@cXnj{{&+P1 zzMpy1-*QSn^PCjF)f4$MXXZ)r!|^XlPt~vQXWsO;^w(X^&pao^Z}nyJA1ygQ*B!GcMN&Qa(}oa_fiUaQ$R_QF-)KGnosoCUCz&T zPKqx*)&6Re8$YDg@>oZXAAdYr|GuB&hU-tuDg7KLlj65}IDXdl_n-Au*xx;anuE-@ zxuK(Uu%Cb6w>=;BUS#!caH%8rWd3;6U%!ahTkruJ?)~oQC>@OYn;ppaKk$H~dGKUM z>0s1f?!q{G7d~M1K@ej{lnzGy`7d4lNY<}-wj=B3k4OF4PQ*l=NY*d=Sx4z$)X$h~ zC&~8bf9NPZ)&Be;SAUZAFR+IeS$}^#8Xp;FYj5SB;2GRI-_WD<@b`~k{H!+rRrmk3 z7^A;IAAobugHLpn4o2HQ`T^?o6lxBR-w!|b0-|&<>M!@9{wLrAo6YF^+dE1JqyFLe z$scv&hn!~oH2d9oE3Q zQu={-`)&Qi{3qA^0&TgYW9@Y?8sFwO*AL8p`Z@na`u*{!zv6nuc7pY5@VTa=^i=;1 z$6xa&TnpqP{8#jA8N>9yS&U>CW>-=ZC=_jq<(SA{SDn9dOoot+< zek0`1I+D^;^~>Mk>O`_`!};%zN9$(;4`Y`pO|?aO!&{9J^P6BXO}y_qjaPB zaeLzPFRcGBq0|m!1EOalf*?3-`Eh@$4gem92lax30gpDi_eN+i^Ma6#8dV zkJ7gXwGI5)mGB-%dqLY9V1A0y2XiCvH;BPK0BL(8$L~8z z2m50q@aH$W_@wPk{@juA{qd-uze}vW1@XzhqwSa{Ev4TQkI(&^&25l#vix;N>4Ui$ z_7S%^q-^jv_HGjoyYM* zUxxAHC_U}ZZ*=FepXkfce~!}Ae%5~ueMfR{$oh-Y!D#!(pG3`;@B!y81+mVG(!r>| zIRwvNQ8$q5TJvB>>0s2Ke+uWid1v z4eN)k0a!mAr5i2(dAGJ={I+XrbhYGjE#!su>!!o#))o7kJKzy{-VGBW*O?kH4Hy|rol1bDBala|G-~j%#ASqNc!qWJ4y$m{_2PD z-i9>;q@TYFi_!MpS9gO-%KgI3$Im8F)<8uj7IvDk{?u&lsAgnzy3#!TiNNulL>hQV$a-C`sN`2 zz~A8JNWT&O=2_=AN>BKiclimIfAxBozbG9{=AWN-`SZC>{ymH*Pw8OP-(bz-c_e+z zTa=#imsq>kz886e^VlGif9WV4jK*jG+IJZsz5{UgE>G!T)L-Mi%P~jN-~6qkbTIBe z-?hI6t=-sniEKahRQvP0ou8y{ba6-e{qbmgp3n2-V?B5sQhF*r=N;=rvi9n=(RU>K-R?b}>{EZd-~azp|8V|Sn_M0w$_(T6N|K@Kxb=(oeg6K@QhK<52riT>mKvv+|=?fXRd{qbo1SL?UDm8as0(x=TIb+dh| zI7R-tPqz0>zmKqYj!sY9e+1*7?=s~$&)#Xm{fEzucpoCAgVFj8;}8A*c+@}K|JXZ1 zh;Msp z#`as^VJ)7p{|(0PYW@9psTj9-$;BtR7W?DT_7CF^{VU2J_ibyxC*v>Y=NPeCfi~`+ z?)qVyd>{J?MTjv;4zx9kA8gz@KDdL8VyKk#Qe5fkT;^x3;rp3+nPW(V@d zcW=fYgUG!QrH9|&2J!ifihd(}d^d}Jqx6KI{Wf@Mx_~X(1`K*`o-*_DNkUehx8>NTyKgi$K4V-6$e~R@Z@Y_30@EhT0 z`?(Gor6=Mu?`qNI&-&RrO``Nf{p{T()XCm$Lf!1$CQsJSACJ~=hWk&@{*|nM4a!?) F{{=a|r)vNJ literal 14614 zcmchdZ>(HZ6~)iJbLZZfzE^B1SW9cPt!bht5e-y=krWXFm0&TNVv(k$r7<=pt+h4b zgCVHIAVK|NqDI1pT9h;~Xd-HinnD!8q!lz8B{o)2iOL5f)hO1r_BreRW6qh^dFo3h zzj^!IHG7|Z_W3h+t}9)hZ*^<3yn4nB+$-EN_i|UY-@Ehj@}2wNe{jcv-8XEyZu_p? zJ3qX~oi`Z1<&_VA;qa+<{r$3aH?2H=-O<;$HN*I4%$MaYyZ7$h{)YXBTrqO4T$;PF zE6>TDbFW=Ca4tU=@4n@kT@T*xoG3e3EO(Rj<#YH@=!{Q0SA87sMcJ=U=s)58mmvLC zYZ}r&?J56*)6g7sjvT!eLEha^b}$-$_7xw$5pm~N`1p;8C$vZP#eKN`cK8LWmCg+} zHk2KV>IX-lxfAh&qwnK$<{HWlCiR0`y?*d7udgZlt#SQuz4uSjKYfaPAKIh-**>_z zUq`c6cozUTEd!{<)Zv!9dv%bx1L z)%_=Z{VrMM>sK5FI~a|>tsh|xu=yh{P(OZPvVYmZsDGO`@Ix|g*1yR3L;HgCjNj&; zxIjJQoaA5jRQ%<=SmWM?@dF3&R}C7<4o2f|>$9(Wea-N>)AWPYll|BB)p7s%g+6|g z@#pt6Wc;B$8h=~QxT&wXKt1D}(PEpVGhyF#`Q|lLXTqh>!WuLZw$Pd>|`WIzS`RD$?b<*|;#BcjXpzNvjudV00 zNqx=mxzqIQ=Oq8Kr~1!%&pIJlH@5!<%AOkkww`rEea-N>)AX#9N&ahlw|?f@=g;z5 zobQgIWW5$T`6HRX@}Y*zUuci&^MhVbQa|`u zL+V3&RPQz;X5^n_{vB#rls%RI>=yVti5JNHWluMhJ(WM!D#wZB_~n;0lsz?mh}g~H zoNqkg+!$jqC(7Ra{?e(x#m2wr`q_e-{|?3g96t&^(NK0UI(`Fat8Zf5!O>;V<1<9r z!Kl92jr`vQ9av#49e${x>|j*Sx>235Zn7Wx`XOac)lap@Uq?=w|DiqZ-<>&g2J5!{ zZSv#qjItY}dd^$cELnUFFU((2b}*{Xk^ADGs9TWZH^3N(vV(E`Z+!l9koo8LUy=Ez zJ(Yj^-pUy6^W$C~YRK^q?NR^3zxnt{#!bD*_(OYC&%7@|4H&U@aQ-b3W#1g{zpdXV z;TP-ol5e2zw>2z-9gO<7^#j+D)N}n1sSoW@z5BIu?iswm4Bt1i8ym_F#`QmfzwOYI zhoRlyqU_t_dY%z1&tN&m3u~4rd#Zl=^QZcwpGPF;-?aI|`r?aJ>{QqGfy^8kiP-qXZ}dpQ~Beb$vlyh*00bWAAbxz_gVh&TGqcP zJ81fOgogWf*neJ{?sPkY7rSWUl;3(kkXtC6wwqU^?Ywt9Mu z)CRB5AN2Z~vTx|jmX4l2ZC9ah>^APF4P^(T{;R7nIwvtJK%Q2r;|*m8qx#}KzQ3gP zg>@$-~Dt#?=Z>o``_ zv3@*dPwTUr{dF8C>N1R41BPm>|j)%-3~p*j2vG8KHgAvFsgUkp-2D8@vA`W*rM#}|GZx3dB2T!6J--NvoBhK^55XthC-Pj(jjviZz>7lZFLfqSUZ)kjx z>}h@RYWPOAlGK&>P9VzOySLNvKg7Pua|KBq?-7WygVFehhf$%}lS$rNsa|L(I~dhx z7+hXQQr~{bp3>(>y`HptJHv+5hxVxd9N&qUCzAahLNCgm${)YWGfyOSgAX*6J(a(~ zDIY({`1yO7$oNBhJN`kt{#ZA>ht9wGt*o1dviE))=;#MO#;F8#OHx04Z$sI^sDI{- zen`8gkMAR*>?!}OTV6*}$NCjz@9E2S|7WQGj(&#v@91afe@DOA{?9P~I{s&ve;xe{ z^RKH%-DsX^-ifmJ=3hrY!~E;$XPAH3Gn!`uiYu``e;M_AB_<%|PVu}byRkigI{N%) zsQ=TLKOldL;=K`3b}*_hKIio$btS%Ai`0kqw!Ub`pW#Hy`|8FYfd9t-qU=jM{yX{# znZ^m$Ku=Q7xJB7h z`T~3Z+@*+{d=~sui?UxD_s{XM-(o<1Kj-*~vV+n1OYEEcErq16`fEek!MJ{f??3MY zTfcGc650Q7e>keo?)7?-y7r6u&>q$EdR`|T^TGF|>|j*SdBZ%B>_2s)?5X@^m;3yY z)a5w8h|FJTkNW2x&p1iOtvrUjnY|Z(w#fO{(a$jdI{F#rUr(=fPV1g1`-|4Uj-K?ga=5I%D=Lggu$-3#!-_YK!pZ}`9zkUqY`#4C}e`t^T@9X>VPt#k! zH%{(9pYsasQUCq*i_ged9>K`^)yZG=K7SoaU4Q)x?NR@W)%WA?`w#64^Z)J;e<1rm zE&l%bf!{y4|C5pPLnnWW)faCM=MPZl7SYZhzCGIi#p?U*%v-ktmuT=lF z&(`~HIEUCXSJ+oVd(=Ol<>LNh&vaq`=6xsbe}1xOq~PD4xk6kM z&QIO?4RP8tUC`+qMKb>ItX8!DegA#^H2?Bb>yCsNK>82uQUAQl&g)2C%X$%I2c!D% z`E|eh`i1zneG>k;e^4*V-a9{b^WQsva^0n#q@L^3|5M+Oe*$Kco|=Ds|9yREPsX3G#TcTW_M8X$T~qe8o%)+^e}CdV z0BaJ(~kPNxePW6-a$(kLs&y z5bp-;H{|``V=cbw=pz*)UP|gr0dHXFmVqJHRLKzbJba??3f?Hq3a! z>+RPzd`@leJ{#7Fzu1QFhnS}vKR#2$@$;13*v{W`?eWLe^&ft(visj+-GGl>j@Jm~ zjb{UvwDtKKTy+dN2krNQFEx~1&lXJ5bB^-NV*C|8=Mwxc%6?)F#C`xT@_D>azcpn)kcj{6=TFB!_q-wIjgfVPxyUoWQT9!7 z|Mu(>)+v(fmp$7Q$n`6Dc<0hBdk-8~dh_9< zSvAVCW^IwpWz8!J_BSrdeT4bDgWg^p*fjl*eRUlAd*K&s zFU_+0EuON2QGIzoH1{EXaP(We&l*qJ!KA+Yl+{-kSiLAa7}eLCtbdaJ>tmku@7k04 z@}u@T`lVi!9gOOmhmpT`;02ocd5x#+U{qhMwR+Nw-yu)xU3*l|{*}u%{^kQVeo=NX zsjpugua_N6>gA`p-sR6x_LP6-t-8(Tk8!uipC~&R_21W5zp?s`?tLfe*-tZ$1OKw8 z`futUwNK7t?y&yFk+Xx*`1|^~MXML5)z3XP-oNZ%)PK!+gE&dX&H5K*PsQKYGj8g| zY4wbAoPXI<@pFyJZ^8J1%q8cLC_5PKe_x-Uw)&3leJAP5t>gW7_N{UM#bz5n$+(NV zJsH1ikH+8EGj8fTPN`>{{SG2d~af5o$&%%5wI>a(li6L}(;zw8N5 z*}5oc=-@?Y=_?wxPyQTFijM^Hbj zjephSe?4mS*BAqE?s@P@Puam}|H~gBUr!_F;OPC(V=o}e4o3CWUgZA-bYQy~V}HA+ z>|j(ste^Z*TR-G9_0#UN*OBAquWOI{&(5Ab`-mO?>@qw4ma-d0^_+J_i5S4@XLw=$ ziL!%HeeqqyeLmg;{rPV}rT|qy9O*oadyeo86wWr{+J` z4PH0v`oVrvPnvN@|3%qT{uwv(Wa{*ALeo&7Y|})GmK= z)-LK#%$yxGdfcA){0r;LYt*^)~-S>+KTf%{|*&+uvJNi&*=< zj|&zN^OeZ&CQ)|7er^YPjO%u*FHTu~N7=UrwH@f`lXJlM#@J?Yme&rS!B(v@K62? zeaAfMDEqB(|J?tXxeanoR=@I;eK0qJ{*QJ+gZz``-ug#R*;Dx+?LvJZXVfpC&_>W( z%5E6#f4kjY$MK`C#rRpup4Mkq+Ur<9)UkdnWl!t#o9uNQC+c#HpQY?+J@Y?@u_L*+ zWd23j!D#A2C>eHvV&25dkC7pAa5Yowf5VdvV&25{s~;)px@+M!N+@) zy@~6yC0vjG8(t262Y-vQyZ$fOwH5W(t*z13lFzm9zF7ZmK8#^8@vlVR-VObt)elzN zsr=_(hW=usAFkF@>9fyyz2YC){ullAw|olqg}j$fA$LE)+}k6{ZrC5cK%a4M%QXx? zd?vygu$0{}s;^LUCF+l)u6fi`b}*{1e+cbuh#RDypQT0F2hTQw`1$<-KVRv4jP_;3 zgRv)N2c!OT3@)!DsVhJ0DSJv^JZSZ#c{WmeQt#TM{)>IMei_$+>~{^lD0?b@{4C8p zk<^tR_LM!9Kl)&tB;#)|k44!B{V)6V$GYKMT@XR&uTd<=R#o8WgkhO#dP{SWljm#p3pI_8dgL+D+5-+$GQKfemT zHzNlmKId`I+fnw-f&W0?;^s)bA@uFDR&OYKLeIQacj5)sZv>G)QFbsHe}3A=&*w7v z_fSucvV&25i#3nek<>A6QTCL+!o7dZdl5IdfDJq_Ug$}^YmfTp^}J3x=7aA; z%AWGidBZ%B>_2s)?5X_aZ?pL$sVlH=5t%>N9*v(q7$?cNl}DF1V;{tyuX6qc`Wfb5 zpr2v>4fI;)wC;(r|JV8#=(+ANerc@CW{aJFq{-jIo{{w{(6=A5 zdXoC#`sdoC{a>wq82`|}YoE^l?Jj;t_J30R!~Fw4fAIcqxM@TAJSF5ky>GmI_ z_AMg(yY{I6)#``wGiO~KEA9USE^p!#`XGMjjDK;O{^Ned{U7HUNaey%^f zj--z3t|@Ic~9BFX#A_y*T-DUApLji=(*m$68}TJ zi!T{J&*SqtQ>*BIN7=Up{a@&Rellk}c0j)qx|43qMcH>G^zb`(k@Y`!9DEXgi?Uyo z*7Ix<<2TgO`W*gv4+G7avQK)-J~&$x>QT4V zJ$Qlj1`zct$__@y&&(UmlQYmyoS^GvM(HZ6~)iJbLZZfzE`9zSWBB|Thl~QA{wX!BPk*VD#6xhibY;pS{h?9X)UdW z4~C!;g9P=9i5dwXYEja}poyq4YJez$Nh@eHN@%R05S0%`s!^*RMQw&C%DoHU0Q!EHBGlx7>X5M;C6~y?5`z8}}b_ z#lX38Y3_!uJS%t3z3%LubNO<-`?hCxEqI@EqU>O?%#GKVFW^I=Gd|;7^$ENeWxqC| z|D^X{g7jOhsY(B|r~LO$L37kOa_}|;c~?!@!D#&1SAG0O#GPN}<2NFn&>qzn_u~57 z;1{e`I@jM=Q+6<_?;U~W4#W=*et^%Jt0_B})c0=k`rbdieni=CitGF9y?>Ja=~LwU z&>r>A_TE;19sOF&qU>Aa{>$$nf9vofSvPANlzm-XpD*=#Bgb!_*BhY^?dkX*@$r|J z`uN3Ou!Bi`|EJ^ivV%#z{1k8U{zchS{+YL83;N9bA%4qWpzL7Oe^Xz4-|I&VpF2s< zevb1md#e9d_n-3hyJVHGUvUuZU^M=wetF;)Q=cG zcaolQj`KgVPl%uE6!lzx=wFmQwSG~@bz+=e_DSo9{BYf*e^K_7f9?-lCvBfV{I+id z%AQ*PntHCA)Q=cGcaom{9Oqy5RR1~eStlgx#`fPp*;C`+)U$4=A2EFHBt7e7od1!% zT|aZp^JjTA&UX)?Wib{w`6HRX^1+(SUuci& z^MhVbQs4V{P3l8?RPQz;X5^n_{vB#rls%RI>_+%Iffva9WzW=I(|K9t8Zc4 z!NDca<1<9r!Kl92jr`vU9av#4?SHtY>|j*Sx>235Zn7Ww`XOac)lap@Uq_Cc|DiqZ z-<>{v8tb z$o%vBugLtucIRBQ2 zvTu&}-`4LF@Qd|($v4sWTWglV4o3ak`hn|6>bZW1)Q9${-u=co_bgsuhVPr%bv0!N zylO`1QfFRnAB)$NX& zvZvM`u3Nlr*7b}1r=GOBL;pqDQ~nt@^JMb``RgHm=8u#;l|Sy8%o90o{R-{z@yF0} zpXDE~W&Mk?gQlNHXt;le{paO5E-zPRZs6v57q9q|eZXK@b5Cb5?6l?d)#Ln zu0FUcadqF7=VkcZ`PKc)9=E?^-dlDStf#3zwD-cex48ZlsPT_@{TqTl+?!n5JR270 zV(tA7E;twdu0(#vHA9>KD)vDC+%$Yd`b2Zu|xM zz6$?~vR|Eu|D9oOgPfDaFKgPI_w7;tgX?|%N!#21P?Px&?Fl{V<6(c@{BjU_PuY!8 zeRYMuj^jri$InytwBB9muj5!z$NKSZp0cO)1@rqS^A5zX5{cZ@bQ|mgHgR( zfFAuPhpz^)zl*Y~|MPxr#rz+wt)+1(TEEUjU)>G;DXxDz_g{!%S%%k{ z=(8`NA9JSfuD?^o?>=4Y6@OTN^XB^7dlL2aX6%I+L!M9iyF}TI&HT6Y*d$C3mE9BK z-o|@F!wY0j>x~|k}QT9~+_+6fPBB|?r zu%_&({Pj-y_({gk-@`=4AKIJo_nP&`y5T)^{>^V=-PDx5^V>j6-}?#98K_&5`u_WB z$__^TGjH@m+C6=I9}#6w`DfkoI+8lpuPA#*UpD(cL;bh(Gt_@eKSTdp`o;EthWXd> zKg0ZM>1UXKZ9VEn^Gx$jl)W?mTKXC0UrRs3{KKACKO0b7j`jH~sNc&m0Wo)q7e(2P z&H2;P=RZgNpThhB`CAn4jfk>?QGM}wuP3Q1@!eXaKD0OWMKk^kXH?!-H~tX(7ycJz zU)u8D(pT6VsW(Db{m$!+vM2P+o81=z`!B|j)19fSsY zl6uB1%AV2}*!$-$M%?7{;2#^5{o=TPj*tBo1M>Sh$4`_UjK*JL-{fy8Bz4taYRV4A z^(%b;c^}yNjdPdC{)hX+QGIrg*OSyWU(|>8sGisJI_a1Xz9(e|qk7I8=80tgsS{;S z_e9zM zWBqICId7T2Gnl_E{S5QBrJrH`w)A#>K>d-do9_G#?ali6uj;$&M}NJKgJk`O_Nf1^ zz8n7}z4d$J`2O=buh1U#-(A1>jEvx z1E%Xg?kMr z>>K0x@1CEtZ=nubF+x=g0)PRp&hFAFgVo6h?!~DYzzDt;g`?0(7#dkg#YR) z#JmC5llOs-H7I-g_wQEz?3p}VXN2CK%@bu$=!^Ri@0}PNuv&_>>-9Bd?>w8-@?UIM zogk0X)lXZG8n3W-{y_x$#G~W&!3im zuK9iR+sHb?XYtHylzmg&zdgJ2C~~j|y3OEoHTj%hXphgIr~Ue2&-Ng9d?tqLhY>k7 zdwcz8#n1kq;ri3kv)|Mk;g|iUf1~UP|BR3MGd|?wX8sue$ezd_=PL6=GJp1LVxa6` OG=FEZephf+xPJpow3254 diff --git a/technology/freepdk45/gds_lib/replica_cell_2rw.gds b/technology/freepdk45/gds_lib/replica_cell_2rw.gds index ef71ca9d4f1d02a07c9c858b3ebab6784de539ba..f7bec774581137999370dbc670b05c9c77bbaec5 100644 GIT binary patch literal 14430 zcmcheU94S270379XMdb~drK%#`Km$fgTbn?CPW((E2LsdC5Vcmt=yEhDUC&F(Kdz$ zWBh1LG#DNz za`=@s`@h$kHEU+i*=NY=tSD~GHsnR~Y*yl*bF)0VsQ>ruf}(!M;R8o@e|XLCGJtzhxgrn@W7tki+lDRJh=G! z!$-4noMrXeBAd(VbBZj>UVZK;%Zl^xw_iBsw}SU)nJ7D0uFEFt>od41bYz43HJ|Dz zI~do0+WD_R`fWCJq<`8|{zw0W=46(U z{G#k&QeQnkSuZ=7)XPtKz0aSg>?!}uTX~zyALDM2KT&ot>c6iqf9>=w{e73yv!6DO z1OKw8`fqiQ+9&5RcUb@8*xSKq{C)l0dZ!ns)z3XP*}v>y)PKc!gE&dX&H5K*PsQKY zGj8g|Y4wbAl7HD#@pFyJ_h9@$=8|(rlpT!rzpu|vJAF%k-{th9EtCDX_APP$#U>X& z$+(NVIx>FW9*w`RXWZ1coKnv?C;4yfiTD{a<0ScE{fn}v^4HfhZt7e5`!1(voRj>w z_GRK9Ejc~c9r_n#2c!9?U#=6RbfWCbtsnBk^^^WZ*;D@ceBe51&k4j|9CC4xvZvO+ zzMku*=|q3u<@D_5B>%Ff`d@8y^+Q@Nk9B1I`1WZ2`+C+5*PoVC>RBg~{I~Y7e%AE& zpY=7^-#v|-gN(Piv7_u@KmI^(dp_*F$m$#5Qb+E|e0x-1zX0Ex@c|p|{qF22I~dhB z+Y#@-p#et=;K`1%gHe6C6Lt1>e8B4cAZkaH9gOPppS%2#%wO?LN9NDBNA=kb_(Yya z<}dq6N7=!so<7-6lKszr-%<8d|MQ1j{z>M)z#dv;{(XDYKO)Z7+{%B0XYlNNZI7~t z-#>!-S#A8Q9{=l6qrbu!fOF4*Pjr+WjP`%@J>=^t2`Ln17<|U{qgx8*yKZdw?82u6d&DU|j!Om;VA}{`vh?Wd3PS<)1m`IFlUr`e;Yl zQ{!L#-NjEbZt6wG@7tsCGxPHYT>j^uhZgg%rR)dd{kQcO>jydiGxX)ojJd_BX}NA@PJuCn@)9QR$gwA%W({W;~l<>w&Amr{T9;O4luxc(y4_!pf1bzbk^ z?XB(at;+RS`@V|{)+36mk>8D??8bg>2YQU_Hm5I6Iekmnw*|Ew=;@Plz1z;DdVz()Lz}L6m*4w+Qs*d*E{(zCi28?>fp3M*E-N^rxdr~ozoGA#CoN^aCGMa5KbwOf=VbZIjKcrnqwHyYcD1{X^+O%&$5HmQKEKIb$8n-A$M`wQ zp4Kz}a~M04drRhDlpT!rfBZ4zYzZH5?s5?8v?x0m)i;Nr`3v#}a$Re_*->^ds?R@; z>udCzd?WaHkFwWseYS|}(SPGr;J5JKqU^r^3vO*i{k3arbp7IcE!-FD-_3_HEEfMt z^vzw+uXp;v`Z<;V{7cYZZu;T+JC#2BY^PWJW7q$pzy6M%M13LeqbHHOA7Sq86=gT} z$1l)l+}m;u!ympAVGTISZj9359gMZ|-#CuIkt{&Ng2uOq1&eWs)ADSh#v)06gYr0Ph$Z;$#f_T%~`TnDn> z74)L)sr>P~H1kAKH~L^l*;DzW55`F{{u=XGlzq_uQNR9JH=Jwyvv9=Kk0?9X?|+~l z{TPqWXWz3D%)U$p?*$4W%-~SovKhV!m|ABsn z{s;Qi_J4-?7x2<4wU$__^TbA0T# z3=qEoxMz>2>|j)1!f2ocpp;slz+|}=80tgsS{;StCSfy2JdD%-8e*^st^Ec4j{sCi8 zvTp3z<;j}x?fv@spX!I}N43$#LDIi(kNO|#hw(3`w|?I+x&M{yHw5cX(Eoa~n}4L` z@8OP-^()XfA8>k-`r-QL+oSzot$rB)(7$h=&i@@geoyv)x%h|s2Y&zH^WV7Mt&7-S zME$Q;U%t)nKS=FcMELjZQU9ye594Rf+BjC){|9{D#3}Sa{Lq+3+dg;wKE%!}op#UT zJly|<>&M7Ff9y;Yo3R>4*M@dfy)H|8W0gXN=(A_T=zCVgD4w-#^R5 zxV4YczRI^x?SH6W&cFP$y8B%IMj-R&+oS&Z-kjHwjGy%)%AU&q(Em_BjemPi!atuM z)Qhr%(fGOk@H&z@uDhb_|4;oeeji^lemnPbNO+t^_(p0Ixo>UXvJ z{#h*gEnal~Nv_4dJ=*`F|Dk?G@#DE|{r9B*<@Br(%N1yK|6E7e!D#%e)mO)S%pm=@ z>*)ENeI@>fdLLghexAqYbylnBe@of72K`^?e}A&G9owPb3EfFQ=A!J|<9a(g2A_7e z>;Slg`tdBi9qh*+_|JC0C$1x@v$Iv6vZwUTcEpX}&Wt|<5qlxZ9{&Cs_~$z+>W$Fx zY!>xK*%Nx^eeN>!fjkaA(WC5_#rsbk&t@6VIKBOThWoVk@N8BPf4LLi4+tcv-^};*#RgpUG;#)74!_z__QBc2KyPPH zjzaSg=FSVa&lNq&j{h$w=D+^D^H0)$b6!XK_w8{#eDXYxow32+dA5dsH_D#yKSTY6 z{a<z@ta}(1pe)8(;|H0_os^Wa$S$IFUI}b*(R)Cb~X>|mYr?#x|G(vHk>l_M85V(A(K2QTBv?#$7GC_?bUD(?96-yY51N}gX0(o<&t0jcw<@c;k- literal 14622 zcmchdZ>(HJ8OG?=7|ztfh_G)-+L+hz5{gBt^tPCDsrVvFiX$6f&iH#LhqVmB=HH!6l-kIn8b7$`DUiBuM z-`;o5v+q0ayfbt5?6}h9`Bt|k%d2PIz`epPb1!$J_Ir0;UcPhg)`L3^?AfyM`t7^- z?ELUvciv$5mRCOVg~O-b^|#B{-L&%f^+#Xh)(jJ$QI>OiKDh7JT|2h#+Ou!p_BYHO za>dBGa%t|yt~@7q&b@Zoz`6Wfy!)nSb_4i;bE52EvD{78m(Sxvp))??T=j9h7iGU8 zq5p*UUxM^ot!YUAw5R+JPD69lIdb$?1bKHu*}-W1*_VC%M#P<8>Ekydp3olE7x&@% z+u;|iRysGltfA~+R6jTZ&7FuJ9DNU;Gt*FZFsUEh;`M`ndVNjVZ;9)N>%D)H{^?WX z`_LZs&-TF8{2_kJU!d$@)PGxFeAnx1hR>Z( z&wftwFMF#0R`;Lu^}A%1uU~N#>|iwhwtj>)z~+y*K>hf^$^K;rqyBB)zz@l|S^pyA z5A6%mGk%+Y;sW)IbCQ4AQ}LJgVvTzn#t$68Uo~hbI~a|>t$A2(fHeX#!Y?A1?m~+B>%NN5kKpfagvOm^()Gr%3oX0xT&uh zK6gGnlm127Q~tR>aGkV$0`c3v z5h#0V{cG#FZc<+}eC~XD_H&Yd*;D=Jyl0(|tQ*^Z17%N*e_PMGp}uDL-1+pZlS%$- zd$)dO+V`L3b-2GfhMEBxZ?(0d>|lHTcJ!ki$oCz%X90(w0Z%oQ9gOPBzr*(myg=@q z)ol%B2c!DxTEu%28ZiGe_;^Fv!Kl92hWIbS3mm=~e7d3RU{pW+iq9X({FM(kWd1^X zRG%O8dXoCV#~M-}+M{~62{9x8B=hf3%cAV5{Aau1?<8Iz^Orr-Q1(>*SgRZ-lH-?O z(opu)_#t99gZq5r3FpQbiy2Y&?)R5Y{Vg{BMc2<})cm(G2H^NH@X3a9KQj^K$IPf>woR@ zpM%UlzyFHNKkcdf+xJ$+aGxLd@=!yLe`t^TAO6+HPcm-mMaCc6qk86j32MNIwS)6- zi75M~c>itvJ_)~Azn6R+eZQ??8SG%xzpWp*j-;OJhe&;BkLum8oO93O1!nlZncdh> zb}+90A^dHJo;(cgT#K@AkL!7lV0i}1F#>@;5;I%pWOxDu3KFnJ046`W4#a zc6@gV|fyD2;{v@b-bbMU{qhc$M=`Ce*C7P#pc_i`s`-!pR{|c=Ni&~XpidoU1|pR z<;I_(@2l{?DEoDZ_}>xcAjmmc{Jf#fP2V2%Kf1~1pR~RG_YIl<(4NqvJ|6Mc&7KQF z?R3OXvZwXg&Hg%$6LlHJ&r|lazF>a;gdBpr zr)B;{*}-W4M<0d$QM|x0YGL$?hO&cEeYGE&r;s;rybOG(q3mE(pWO~U#*7?a06x)B zb}*`U+o4DQ$?>Z|?C+xN>i?`?TQUFZwKckajgHvoV*T4Wr}gV>^wmAkpXU0vbM9gc z%W}NVMxT8i{g^R*fBjuh{O(hYUh#+ZH*c@MgQrkmZ^B-PG35QpaJMMCv7P^p9-D;e zp|WQ}+}rqUXnc|EX?^i(_(uJa)Rp*7Aj;l*w$t%H#JO#tUX(qRKYo{I zo=EBj?{6r3Du07hK7Nw%^Y<{3@rU+y{DXG=v2OSboqw}iSvL)3@BKE=(GPxv`wY}A zN&WD>4P^(T{+T!WA?=wyzK@8qr~I>Sc^yd|>sOS$r!U+6pQ8Rd`YGzaqo1Px9sOea zKgIm(_@83_b@Wrrzpfs2qj{!zC(7QNe;xf4^RJ_yV*X*zYt9A~S7Cj=AN6|`CLrcc z@q#G3u|0n}`uwM;|I?U1Ab*SEvk_5tFsd&;=k+9YCB9pW)Q9%AzG%mv;U1OG)s5c= z|AqfW*_U?wck~rDN9v8xRloImqwEPi^JdS5z~M{q9{Cex2b1yh`2*u0tOg%$C_5O{ zR|lbio}`{}i?XNm1@``#OA$Bu9Qel;Wxq7;pW|b{#ejTH!SNGi2cz+q*f;rG3Q1k{ zmxi)~as3M4e?AAce&fDNWdFnS;ix{l*Xv2@+Ar!udsNTsd7X632j7#jgHb)_4f90W zbDoe#W^gI^yhDAZ`aR%Rj)cH>3_Js zVPyU2`0wlc@rU+g{5;P!ssFY8vd;YN`0uY@JR@Uy1S9KLM_;|qUq@2cU;jdTH2%fv z`|F?9zl8Q^{}-$8 z$KUrK+N1tE`nyB^0vD3MPW;fB|3K>J?LX$NT?aCMoWG*%U^ITtJ6=ap*T4S@?f)}9 z*9XNp$$w~Hn1AHW;ty26QvKIHTkpH!KE%#kVP6UDQU5&4#r?<5bYcJIb0_ZOr0l8v zyYIiRpU;2){>jcr!M~lk;=YLfr2MzfV(A`AWc;B$+W)?PX-Vqm^RMe_-4UO^0Z4sl zkNW3xb6!XCTGopwI~di6&o_;9;zIq~J_-NaKj>eS9gObU-jvj0Ez{rE$C z$@sZXPl~^`C-(3D{d0E0_n(a1KX>+@#p?6@-Ve#V=Px#-|Ii-of8T#!KjHpA9zXVN z>wn-v`rrTlQ2Z{`KWO#8*%*y~vHIbi-Ve!nQ?H{d8hdK~_5Jttp*6v7Nu?+vAU`>p%Qn zZ_mHQx&a@%9Ip||8)pNSwDtKKTy+dN2krNQFEx~1XA36jIY)WVV*DjO=Mwxc%6?zFPX4B-zmC3m5b@rH!2zqKm_x5? zC_5M(zbWdc>mN04XShH+(}&s@W$&Hs>*}{5_5*m4FW`mxtttC~MEqwze>(oT=M6D$ zjI1NfMc(rpW#1V0Z)caVPLW){>}*pY*RRkX&A**#Lhg*n9nS=D{V>YjT|YYUPqF@V z^z1j+FC+Zg*(Oo;gn!1({27n=xS2o3U)vM;<6LE)NaoMZW(LX*M)P+z`&R{5h5I)* CRjNJ! From 5e546ee97445f3707168c8b34dd24f781b5d8bae Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 5 Apr 2022 13:51:55 -0700 Subject: [PATCH 165/229] New power strapping mostly working. Each module uses M3/M4 power straps with pins on the ends. Works in all technologies for a single no mux, dual port SRAM. --- compiler/base/hierarchy_layout.py | 347 +++++++++++++++++---- compiler/modules/bitcell_array.py | 2 + compiler/modules/bitcell_base_array.py | 11 +- compiler/modules/control_logic.py | 60 +++- compiler/modules/delay_chain.py | 8 +- compiler/modules/dff_array.py | 29 +- compiler/modules/dff_buf_array.py | 31 +- compiler/modules/dummy_array.py | 4 + compiler/modules/hierarchical_decoder.py | 66 +--- compiler/modules/hierarchical_predecode.py | 6 +- compiler/modules/port_address.py | 24 +- compiler/modules/precharge_array.py | 8 +- compiler/modules/replica_bitcell_array.py | 132 +++++--- compiler/modules/replica_column.py | 14 +- compiler/modules/wordline_driver_array.py | 52 +-- compiler/options.py | 2 +- compiler/sram/sram_1bank.py | 2 - 17 files changed, 512 insertions(+), 286 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 403920c6..6fca63c7 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -407,8 +407,8 @@ class layout(): """ pins = instance.get_pins(pin_name) - debug.check(len(pins) > 0, - "Could not find pin {}".format(pin_name)) + if len(pins) == 0: + debug.warning("Could not find pin {0} on {1}".format(pin_name, instance.mod.name)) for pin in pins: if new_name == "": @@ -427,11 +427,194 @@ class layout(): for pin_name in self.pin_map.keys(): self.copy_layout_pin(instance, pin_name, prefix + pin_name) - def route_vertical_pins(self, name, insts=None, layer=None, xside="cx", yside="cy"): + def connect_row_locs(self, from_layer, to_layer, locs, name=None, full=False): + """ + Connects left/right rows that are aligned on the given layer. + """ + bins = {} + for loc in locs: + y = pin.y + try: + bins[y].append(loc) + except KeyError: + bins[y] = [loc] + + for y, v in bins.items(): + # Not enough to route a pin, so just copy them + if len(v) < 2: + continue + + if full: + left_x = 0 + right_x = self.width + else: + left_x = min([loc.x for loc in v]) + right_x = max([loc.x for loc in v]) + + left_pos = vector(left_x, y) + right_pos = vector(right_x, y) + + # Make sure to add vias to the new route + for loc in v: + self.add_via_stack_center(from_layer=from_layer, + to_layer=to_layer, + offset=loc, + min_area=True) + + if name: + self.add_layout_pin_segment_center(text=name, + layer=to_layer, + start=left_pos, + end=right_pos) + else: + self.add_segment_center(layer=to_layer, + start=left_pos, + end=right_pos) + + def connect_row_pins(self, layer, pins, name=None, full=False): + """ + Connects left/right rows that are aligned. + """ + bins = {} + for pin in pins: + y = pin.cy() + try: + bins[y].append(pin) + except KeyError: + bins[y] = [pin] + + for y, v in bins.items(): + # Not enough to route a pin, so just copy them + if len(v) < 2: + continue + + if full: + left_x = 0 + right_x = self.width + else: + left_x = min([pin.lx() for pin in v]) + right_x = max([pin.rx() for pin in v]) + + left_pos = vector(left_x, y) + right_pos = vector(right_x, y) + + # Make sure to add vias to the new route + for pin in v: + self.add_via_stack_center(from_layer=pin.layer, + to_layer=layer, + offset=pin.center(), + min_area=True) + + if name: + self.add_layout_pin_segment_center(text=name, + layer=layer, + start=left_pos, + end=right_pos) + else: + self.add_segment_center(layer=layer, + start=left_pos, + end=right_pos) + + def connect_col_locs(self, from_layer, to_layer, locs, name=None, full=False): + """ + Connects top/bot columns that are aligned. + """ + bins = {} + for loc in locs: + x = loc.x + try: + bins[x].append(loc) + except KeyError: + bins[x] = [loc] + + for x, v in bins.items(): + # Not enough to route a pin, so just copy them + if len(v) < 2: + continue + + if full: + bot_y = 0 + top_y = self.height + else: + bot_y = min([loc.y for loc in v]) + top_y = max([loc.y for loc in v]) + + top_pos = vector(x, top_y) + bot_pos = vector(x, bot_y) + + # Make sure to add vias to the new route + for loc in v: + self.add_via_stack_center(from_layer=from_layer, + to_layer=to_layer, + offset=loc, + min_area=True) + + if name: + self.add_layout_pin_segment_center(text=name, + layer=to_layer, + start=top_pos, + end=bot_pos) + else: + self.add_segment_center(layer=to_layer, + start=top_pos, + end=bot_pos) + + + def connect_col_pins(self, layer, pins, name=None, full=False): + """ + Connects top/bot columns that are aligned. + """ + bins = {} + for pin in pins: + x = pin.cx() + try: + bins[x].append(pin) + except KeyError: + bins[x] = [pin] + + for x, v in bins.items(): + # Not enough to route a pin, so just copy them + if len(v) < 2: + continue + + if full: + bot_y = 0 + top_y = self.height + else: + bot_y = min([pin.by() for pin in v]) + top_y = max([pin.uy() for pin in v]) + + top_pos = vector(x, top_y) + bot_pos = vector(x, bot_y) + + # Make sure to add vias to the new route + for pin in v: + self.add_via_stack_center(from_layer=pin.layer, + to_layer=layer, + offset=pin.center(), + min_area=True) + + if name: + self.add_layout_pin_segment_center(text=name, + layer=layer, + start=top_pos, + end=bot_pos) + else: + self.add_segment_center(layer=layer, + start=top_pos, + end=bot_pos) + + + + + + def route_vertical_pins(self, name, insts=None, layer=None, xside="cx", yside="cy", num_pins=2, full_width=True): """ Route together all of the pins of a given name that vertically align. Uses local_insts if insts not specified. Uses center of pin by default, or right or left if specified. + num_pins specifies whether to add a single pin or multiple pins (equally spaced) + TODO: Add equally spaced option for IR drop min, right now just 2 """ @@ -451,7 +634,7 @@ class layout(): for x, v in bins.items(): # Not enough to route a pin, so just copy them if len(v) < 2: - debug.warning("Copying pins instead of connecting with pin.") + debug.warning("Pins don't align well so copying pins instead of connecting with pin.") for inst,pin in v: self.add_layout_pin(pin.name, pin.layer, @@ -460,10 +643,8 @@ class layout(): pin.height()) continue - bot_y = min([pin.by() for (inst,pin) in v]) - top_y = max([pin.uy() for (inst,pin) in v]) - last_via = None + pin_layer = None for inst,pin in v: if layer: pin_layer = layer @@ -482,31 +663,57 @@ class layout(): else: via_width=None + if full_width: + bot_y = 0 + top_y = self.height + else: + bot_y = min([pin.by() for (inst,pin) in v]) + top_y = max([pin.uy() for (inst,pin) in v]) top_pos = vector(x, top_y) bot_pos = vector(x, bot_y) -# top_rect = self.add_layout_pin_rect_center(text=name, -# layer=pin_layer, -# offset=top_pos) - #bot_rect = self.add_layout_pin_rect_center(text=name, - # layer=pin_layer, - # offset=bot_pos) -# self.add_segment_center(layer=pin_layer, -# start=vector(top_rect.cx(), bot_pos.y), -# end=top_rect.bc(), -# width=via_width) - self.add_layout_pin_segment_center(text=name, - layer=pin_layer, - start=top_pos, - end=bot_pos, - width=via_width) + + if num_pins==2: + self.add_layout_pin_rect_ends(name=name, + layer=pin_layer, + start=top_pos, + end=bot_pos, + width=via_width) + else: + self.add_layout_pin_segment_center(text=name, + layer=pin_layer, + start=top_pos, + end=bot_pos, + width=via_width) + def add_layout_pin_rect_ends(self, name, layer, start, end, width=None): - def route_horizontal_pins(self, name, insts=None, layer=None, xside="cx", yside="cy"): + # This adds pins on the end connected by a segment + top_rect = self.add_layout_pin_rect_center(text=name, + layer=layer, + offset=start) + bot_rect = self.add_layout_pin_rect_center(text=name, + layer=layer, + offset=end) + # This is made to not overlap with the pin above + # so that the power router will only select a small pin. + # Otherwise it adds big blockages over the rails. + if start.y != end.y: + self.add_segment_center(layer=layer, + start=bot_rect.uc(), + end=top_rect.bc()) + else: + self.add_segment_center(layer=layer, + start=bot_rect.rc(), + end=top_rect.lc()) + + def route_horizontal_pins(self, name, insts=None, layer=None, xside="cx", yside="cy", num_pins=2, full_width=True): """ Route together all of the pins of a given name that horizontally align. Uses local_insts if insts not specified. Uses center of pin by default, or top or botom if specified. + num_pins specifies whether to add a single pin or multiple pins (equally spaced) + TODO: Add equally spaced option for IR drop min, right now just 2 """ @@ -527,7 +734,7 @@ class layout(): for y, v in bins.items(): if len(v) < 2: - debug.warning("Copying pins instead of connecting with pin.") + debug.warning("Pins don't align well so copying pins instead of connecting with pin.") for inst,pin in v: self.add_layout_pin(pin.name, pin.layer, @@ -536,10 +743,8 @@ class layout(): pin.height()) continue - left_x = min([pin.lx() for (inst,pin) in v]) - right_x = max([pin.rx() for (inst,pin) in v]) - last_via = None + pin_layer = None for inst,pin in v: if layer: pin_layer = layer @@ -550,7 +755,7 @@ class layout(): last_via = self.add_via_stack_center(from_layer=pin.layer, to_layer=pin_layer, - offset=vector(pin.cx(), y), + offset=vector(x, y), min_area=True) if last_via: @@ -558,29 +763,56 @@ class layout(): else: via_height=None + if full_width: + left_x = 0 + right_x = self.width + else: + left_x = min([pin.lx() for (inst,pin) in v]) + right_x = max([pin.rx() for (inst,pin) in v]) left_pos = vector(left_x, y) right_pos = vector(right_x, y) -# left_rect = self.add_layout_pin_rect_center(text=name, -# layer=pin_layer, -# offset=left_pos) - #right_rect = self.add_layout_pin_rect_center(text=name, - # layer=pin_layer, - # offset=right_pos) - # This is made to not overlap with the pin above - # so that the power router will only select a small pin. - # Otherwise it adds big blockages over the rails. -# self.add_segment_center(layer=pin_layer, -# start=left_rect.rc(), -# end=vector(right_pos.x, left_rect.cy()), -# width=via_height) + if num_pins==2: + self.add_layout_pin_rect_ends(name=name, + layer=pin_layer, + start=left_pos, + end=right_pos, + width=via_height) + else: + # This adds a single big pin + self.add_layout_pin_segment_center(text=name, + layer=pin_layer, + start=left_pos, + end=right_pos, + width=via_height) - self.add_layout_pin_segment_center(text=name, - layer=pin_layer, - start=left_pos, - end=right_pos, - width=via_height) + def add_layout_end_pin_segment_center(self, text, layer, start, end): + """ + Creates a path with two pins on the end that don't overlap. + """ + start_pin = self.add_layout_pin_rect_center(text=text, + layer=layer, + offset=start) + end_pin = self.add_layout_pin_rect_center(text=text, + layer=layer, + offset=end) + + if start.x != end.x and start.y != end.y: + file_name = "non_rectilinear.gds" + self.gds_write(file_name) + debug.error("Cannot have a non-manhatten layout pin: {}".format(file_name), -1) + elif start.x != end.x: + self.add_segment_center(layer=layer, + start=start_pin.rc(), + end=end_pin.lc()) + elif start.y != end.y: + self.add_segment_center(layer=layer, + start=start_pin.uc(), + end=end_pin.bc()) + else: + debug.error("Cannot have a point pin.", -1) + def add_layout_pin_segment_center(self, text, layer, start, end, width=None): """ @@ -1447,12 +1679,13 @@ class layout(): width = None height = None + pin = None if start_layer in self.pwr_grid_layers: - self.add_layout_pin_rect_center(text=name, - layer=start_layer, - offset=loc, - width=width, - height=height) + pin = self.add_layout_pin_rect_center(text=name, + layer=start_layer, + offset=loc, + width=width, + height=height) else: via = self.add_via_stack_center(from_layer=start_layer, to_layer=self.pwr_grid_layers[0], @@ -1463,11 +1696,13 @@ class layout(): width = via.width if not height: height = via.height - self.add_layout_pin_rect_center(text=name, - layer=self.pwr_grid_layers[0], - offset=loc, - width=width, - height=height) + pin = self.add_layout_pin_rect_center(text=name, + layer=self.pwr_grid_layers[0], + offset=loc, + width=width, + height=height) + + return pin def copy_power_pin(self, pin, loc=None, directions=None, new_name=""): """ diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index d08e3f48..0432dec2 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -46,6 +46,8 @@ class bitcell_array(bitcell_base_array): self.add_layout_pins() + self.route_supplies() + self.add_boundary() self.DRC_LVS() diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index 5bff2448..45285267 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -156,18 +156,15 @@ class bitcell_base_array(design.design): width=self.width, height=wl_pin.height()) - def add_supply_pins(self): - for row in range(self.row_size): - for col in range(self.column_size): - inst = self.cell_inst[row, col] - for pin_name in ["vdd", "gnd"]: - self.copy_layout_pin(inst, pin_name) + def route_supplies(self): + for inst in self.cell_inst.values(): + for pin_name in ["vdd", "gnd"]: + self.copy_layout_pin(inst, pin_name) def add_layout_pins(self): """ Add the layout pins """ self.add_bitline_pins() self.add_wl_pins() - self.add_supply_pins() def _adjust_x_offset(self, xoffset, col, col_offset): tempx = xoffset diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 01810323..df7a8241 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -280,7 +280,8 @@ class control_logic(design.design): def route_rails(self): """ Add the input signal inverted tracks """ height = self.control_logic_center.y - self.m2_pitch - offset = vector(self.ctrl_dff_array.width, 0) + # DFF spacing plus the power routing + offset = vector(self.ctrl_dff_array.width + self.m4_pitch, 0) self.input_bus = self.create_vertical_bus("m2", offset, @@ -312,7 +313,8 @@ class control_logic(design.design): self.place_dffs() # All of the control logic is placed to the right of the DFFs and bus - self.control_x_offset = self.ctrl_dff_array.width + self.internal_bus_width + # as well as the power supply stripe + self.control_x_offset = self.ctrl_dff_array.width + self.internal_bus_width + self.m4_pitch row = 0 # Add the logic on the right of the bus @@ -368,7 +370,7 @@ class control_logic(design.design): self.route_clk_buf() self.route_gated_clk_bar() self.route_gated_clk_buf() - self.route_supply() + self.route_supplies() def create_delay(self): """ Create the replica bitline """ @@ -707,28 +709,60 @@ class control_logic(design.design): start=out_pos, end=right_pos) - def route_supply(self): + def route_supplies(self): """ Add vdd and gnd to the instance cells """ - supply_layer = self.dff.get_pin("vdd").layer + pin_layer = self.dff.get_pin("vdd").layer + supply_layer = self.supply_stack[2] max_row_x_loc = max([inst.rx() for inst in self.row_end_inst]) + min_row_x_loc = self.control_x_offset + + vdd_pin_locs = [] + gnd_pin_locs = [] + for inst in self.row_end_inst: pins = inst.get_pins("vdd") for pin in pins: - if pin.layer == supply_layer: + if pin.layer == pin_layer: row_loc = pin.rc() pin_loc = vector(max_row_x_loc, pin.rc().y) - self.add_power_pin("vdd", pin_loc, start_layer=pin.layer) - self.add_path(supply_layer, [row_loc, pin_loc]) + vdd_pin_locs.append(pin_loc) + self.add_via_stack_center(from_layer=pin_layer, + to_layer=supply_layer, + offset=pin_loc, + min_area=True) + self.add_path(pin_layer, [row_loc, pin_loc]) pins = inst.get_pins("gnd") for pin in pins: - if pin.layer == supply_layer: + if pin.layer == pin_layer: row_loc = pin.rc() - pin_loc = vector(max_row_x_loc, pin.rc().y) - self.add_power_pin("gnd", pin_loc, start_layer=pin.layer) - self.add_path(supply_layer, [row_loc, pin_loc]) + pin_loc = vector(min_row_x_loc, pin.rc().y) + gnd_pin_locs.append(pin_loc) + self.add_via_stack_center(from_layer=pin_layer, + to_layer=supply_layer, + offset=pin_loc, + min_area=True) + self.add_path(pin_layer, [row_loc, pin_loc]) + + min_y = min([x.y for x in vdd_pin_locs]) + max_y = max([x.y for x in vdd_pin_locs]) + bot_pos = vector(max_row_x_loc, min_y) + top_pos = vector(max_row_x_loc, max_y) + self.add_layout_pin_segment_center(text="vdd", + layer=supply_layer, + start=bot_pos, + end=top_pos) + + min_y = min([x.y for x in gnd_pin_locs]) + max_y = max([x.y for x in gnd_pin_locs]) + bot_pos = vector(min_row_x_loc, min_y) + top_pos = vector(min_row_x_loc, max_y) + self.add_layout_pin_segment_center(text="gnd", + layer=supply_layer, + start=bot_pos, + end=top_pos) self.copy_layout_pin(self.delay_inst, "gnd") self.copy_layout_pin(self.delay_inst, "vdd") @@ -781,7 +815,7 @@ class control_logic(design.design): # Connect this at the bottom of the buffer out_pin = inst.get_pin("Z") out_pos = out_pin.center() - mid1 = vector(out_pos.x, out_pos.y - 0.4 * inst.mod.height) + mid1 = vector(out_pos.x, out_pos.y - 0.3 * inst.mod.height) mid2 = vector(self.input_bus[name].cx(), mid1.y) bus_pos = self.input_bus[name].center() self.add_wire(self.m2_stack[::-1], [out_pos, mid1, mid2, bus_pos]) diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index a5bcea27..af446bbd 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -177,9 +177,11 @@ class delay_chain(design.design): # The routing to connect the loads is over the first and last cells # We have an even number of drivers and must only do every other # supply rail - if OPTS.experimental_power: - self.route_horizontal_pins("vdd") - self.route_horizontal_pins("gnd") + if True or OPTS.experimental_power: + left_load_insts = [self.load_inst_map[x][0] for x in self.driver_inst_list] + right_load_insts = [self.load_inst_map[x][-1] for x in self.driver_inst_list] + self.route_vertical_pins("vdd", left_load_insts, xside="lx") + self.route_vertical_pins("gnd", right_load_insts, xside="rx") else: for inst in self.driver_inst_list: load_list = self.load_inst_map[inst] diff --git a/compiler/modules/dff_array.py b/compiler/modules/dff_array.py index 27f6f5bf..99b59064 100644 --- a/compiler/modules/dff_array.py +++ b/compiler/modules/dff_array.py @@ -42,6 +42,7 @@ class dff_array(design.design): self.height = self.rows * self.dff.height self.place_dff_array() + self.route_supplies() self.add_layout_pins() self.add_boundary() self.DRC_LVS() @@ -106,17 +107,25 @@ class dff_array(design.design): return dout_name + def route_supplies(self): + if OPTS.experimental_power and self.rows > 1: + # Vertical straps on ends if multiple rows + left_dff_insts = [self.dff_insts[x, 0] for x in range(self.rows)] + right_dff_insts = [self.dff_insts[x, self.columns-1] for x in range(self.rows)] + self.route_vertical_pins("vdd", left_dff_insts, xside="lx", yside="cy") + self.route_vertical_pins("gnd", right_dff_insts, xside="rx", yside="cy") + else: + for row in range(self.rows): + for col in range(self.columns): + # Continous vdd rail along with label. + vdd_pin=self.dff_insts[row, col].get_pin("vdd") + self.copy_power_pin(vdd_pin) + + # Continous gnd rail along with label. + gnd_pin=self.dff_insts[row, col].get_pin("gnd") + self.copy_power_pin(gnd_pin) + def add_layout_pins(self): - for row in range(self.rows): - for col in range(self.columns): - # Continous vdd rail along with label. - vdd_pin=self.dff_insts[row, col].get_pin("vdd") - self.copy_power_pin(vdd_pin) - - # Continous gnd rail along with label. - gnd_pin=self.dff_insts[row, col].get_pin("gnd") - self.copy_power_pin(gnd_pin) - for row in range(self.rows): for col in range(self.columns): din_pin = self.dff_insts[row, col].get_pin("D") diff --git a/compiler/modules/dff_buf_array.py b/compiler/modules/dff_buf_array.py index 6f8b54aa..62a7cfb6 100644 --- a/compiler/modules/dff_buf_array.py +++ b/compiler/modules/dff_buf_array.py @@ -145,24 +145,23 @@ class dff_buf_array(design.design): return dout_bar_name def route_supplies(self): - for row in range(self.rows): - vdd0_pin=self.dff_insts[row, 0].get_pin("vdd") - vddn_pin=self.dff_insts[row, self.columns - 1].get_pin("vdd") - self.add_path(vdd0_pin.layer, [vdd0_pin.lc(), vddn_pin.rc()], width=vdd0_pin.height()) + if OPTS.experimental_power and self.rows > 1: + # Vertical straps on ends if multiple rows + left_dff_insts = [self.dff_insts[x, 0] for x in range(self.rows)] + right_dff_insts = [self.dff_insts[x, self.columns-1] for x in range(self.rows)] + self.route_vertical_pins("vdd", left_dff_insts, xside="lx", yside="cy") + self.route_vertical_pins("gnd", right_dff_insts, xside="rx", yside="cy") + else: + for row in range(self.rows): + for col in range(self.columns): + # Continous vdd rail along with label. + vdd_pin=self.dff_insts[row, col].get_pin("vdd") + self.copy_power_pin(vdd_pin) - gnd0_pin=self.dff_insts[row, 0].get_pin("gnd") - gndn_pin=self.dff_insts[row, self.columns - 1].get_pin("gnd") - self.add_path(gnd0_pin.layer, [gnd0_pin.lc(), gndn_pin.rc()], width=gnd0_pin.height()) + # Continous gnd rail along with label. + gnd_pin=self.dff_insts[row, col].get_pin("gnd") + self.copy_power_pin(gnd_pin) - for row in range(self.rows): - for col in range(self.columns): - # Continous vdd rail along with label. - vdd_pin=self.dff_insts[row, col].get_pin("vdd") - self.copy_power_pin(vdd_pin, loc=vdd_pin.lc()) - - # Continous gnd rail along with label. - gnd_pin=self.dff_insts[row, col].get_pin("gnd") - self.copy_power_pin(gnd_pin, loc=gnd_pin.lc()) def add_layout_pins(self): diff --git a/compiler/modules/dummy_array.py b/compiler/modules/dummy_array.py index 0786142f..83449a70 100644 --- a/compiler/modules/dummy_array.py +++ b/compiler/modules/dummy_array.py @@ -36,6 +36,8 @@ class dummy_array(bitcell_base_array): self.add_layout_pins() + self.route_supplies() + self.add_boundary() self.DRC_LVS() @@ -98,6 +100,8 @@ class dummy_array(bitcell_base_array): width=self.width, height=wl_pin.height()) + def route_supplies(self): + # Copy a vdd/gnd layout pin from every cell for row in range(self.row_size): for col in range(self.column_size): diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index f9987bb8..2b173969 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -28,7 +28,6 @@ class hierarchical_decoder(design.design): self.pre2x4_inst = [] self.pre3x8_inst = [] self.pre4x16_inst = [] - self.local_insts = [] b = factory.create(module_type=OPTS.bitcell) self.cell_height = b.height @@ -591,65 +590,20 @@ class hierarchical_decoder(design.design): def route_supplies(self): """ - Add a pin for each row of vdd/gnd which are - must-connects next level up. """ - # This is an experiment with power rails - if OPTS.tech_name=="sky130" or OPTS.experimental_power: - if layer_props.hierarchical_decoder.vertical_supply: - pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst - self.route_vertical_pins("vdd", insts=pre_insts, yside="by") - self.route_vertical_pins("gnd", insts=pre_insts, yside="by") - self.route_vertical_pins("vdd", insts=self.and_inst, yside="by") - self.route_vertical_pins("gnd", insts=self.and_inst, yside="by") - else: - pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst - self.route_vertical_pins("vdd", insts=pre_insts) - self.route_vertical_pins("gnd", insts=pre_insts) - self.route_vertical_pins("vdd", insts=self.and_inst, xside="rx") - self.route_vertical_pins("gnd", insts=self.and_inst, xside="lx") + # Leave these to route in the port_address + all_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst + for inst in all_insts: + self.copy_layout_pin(inst, "vdd") + self.copy_layout_pin(inst, "gnd") - # Widen the rails to cover any gap - for inst in self.and_inst: - for name in ["vdd", "gnd"]: - supply_pin = inst.get_pin(name) - self.add_segment_center(layer=supply_pin.layer, - start=vector(0, supply_pin.cy()), - end=vector(self.width, supply_pin.cy())) - else: - if layer_props.hierarchical_decoder.vertical_supply: - for n in ["vdd", "gnd"]: - pins = self.and_inst[0].get_pins(n) - for pin in pins: - self.add_rect(layer=pin.layer, - offset=pin.ll() + vector(0, self.bus_space), - width=pin.width(), - height=self.height - 2 * self.bus_space) + for inst in self.and_inst: + for pin in inst.get_pins("vdd"): + self.add_power_pin("vdd", pin.rc()) + for pin in inst.get_pins("gnd"): + self.add_power_pin("gnd", pin.lc()) - # This adds power vias at the top of each cell - # (except the last to keep them inside the boundary) - for i in self.and_inst[:-1]: - pins = i.get_pins(n) - for pin in pins: - self.copy_power_pin(pin, loc=pin.uc()) - - for i in self.pre2x4_inst + self.pre3x8_inst: - self.copy_layout_pin(i, n) - else: - # The vias will be placed at the right of the cells. - xoffset = max(x.rx() for x in self.and_inst) + 0.5 * self.m1_space - for row in range(0, self.num_outputs): - for pin_name in ["vdd", "gnd"]: - # The nand and inv are the same height rows... - supply_pin = self.and_inst[row].get_pin(pin_name) - pin_pos = vector(xoffset, supply_pin.cy()) - self.copy_power_pin(supply_pin, loc=pin_pos) - - # Copy the pins from the predecoders - for pre in self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst: - for pin_name in ["vdd", "gnd"]: - self.copy_layout_pin(pre, pin_name) def route_predecode_bus_outputs(self, rail_name, pin, row): """ diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index 706fc58e..0d7f31a3 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -381,7 +381,7 @@ class hierarchical_predecode(design.design): def route_supplies(self): """ Add a pin for each row of vdd/gnd which are must-connects next level up. """ - # We may ahve vertical power supply rails + # We may have vertical power supply rails if layer_props.hierarchical_predecode.vertical_supply and not self.column_decoder: for n in ["vdd", "gnd"]: # This makes a wire from top to bottom for both inv and and gates @@ -403,8 +403,6 @@ class hierarchical_predecode(design.design): # In other techs, we are using standard cell decoder cells with horizontal power else: for num in range(0, self.number_of_outputs): - - # Route both supplies for n in ["vdd", "gnd"]: and_pins = self.and_inst[num].get_pins(n) for and_pin in and_pins: @@ -418,4 +416,4 @@ class hierarchical_predecode(design.design): else: xoffset = self.inv_inst[0].lx() - self.bus_space pin_pos = vector(xoffset, and_pin.cy()) - self.copy_power_pin(and_pin, loc=pin_pos) + self.add_power_pin(n, pin_pos) diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index 7c3af51c..2757a86f 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -76,15 +76,21 @@ class port_address(design.design): def route_supplies(self): """ Propagate all vdd/gnd pins up to this level for all modules """ - for inst in [self.wordline_driver_array_inst, self.row_decoder_inst]: - self.copy_layout_pin(inst, "vdd") - self.copy_layout_pin(inst, "gnd") - - for rbl_vdd_pin in self.rbl_driver_inst.get_pins("vdd"): - if layer_props.port_address.supply_offset: - self.copy_power_pin(rbl_vdd_pin) - else: - self.copy_power_pin(rbl_vdd_pin, loc=rbl_vdd_pin.lc()) + self.route_vertical_pins("vdd", [self.row_decoder_inst]) + self.route_vertical_pins("gnd", [self.row_decoder_inst]) + self.route_vertical_pins("vdd", [self.wordline_driver_array_inst]) + if layer_props.wordline_driver.vertical_supply: + self.route_vertical_pins("gnd", [self.wordline_driver_array_inst]) + self.copy_layout_pin(self.rbl_driver_inst, "vdd") + else: + rbl_pos = self.rbl_driver_inst.get_pin("vdd").rc() + self.add_power_pin("vdd", rbl_pos) + self.add_path("m4", [rbl_pos, self.wordline_driver_array_inst.get_pins("vdd")[0].rc()]) + + vdd_pins = self.row_decoder_inst.get_pins("vdd") + self.wordline_driver_array_inst.get_pins("vdd") + self.connect_row_pins(self.route_layer, vdd_pins) + gnd_pins = self.row_decoder_inst.get_pins("gnd") + self.wordline_driver_array_inst.get_pins("gnd") + self.connect_row_pins(self.route_layer, gnd_pins) # Also connect the B input of the RBL and_dec to vdd if OPTS.local_array_size == 0: diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index cfd2015b..c820dfc1 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -83,7 +83,7 @@ class precharge_array(design.design): def add_layout_pins(self): en_pin = self.pc_cell.get_pin("en_bar") - self.route_horizontal_pins("en_bar", layer=self.en_bar_layer) + self.route_horizontal_pins("en_bar", layer=self.en_bar_layer, num_pins=1) for inst in self.local_insts: self.add_via_stack_center(from_layer=en_pin.layer, to_layer=self.en_bar_layer, @@ -95,11 +95,7 @@ class precharge_array(design.design): self.copy_layout_pin(inst, "br", "br_{0}".format(i)) def route_supplies(self): - if OPTS.tech_name=="sky130" or OPTS.experimental_power: - self.route_horizontal_pins("vdd") - else: - for inst in self.local_insts: - self.copy_layout_pin(inst, "vdd") + self.route_horizontal_pins("vdd") def create_insts(self): """Creates a precharge array by horizontally tiling the precharge cell""" diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index be6d1ef5..5a7a046f 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -305,19 +305,18 @@ class replica_bitcell_array(bitcell_base_array): def create_layout(self): - # We will need unused wordlines grounded, so we need to know their layer - # and create a space on the left and right for the vias to connect to ground - pin = self.cell.get_pin(self.cell.get_all_wl_names()[0]) - pin_layer = pin.layer - self.unused_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer)) - self.unused_offset = vector(self.unused_pitch, 0) + # This creates space for the unused wordline connections as well as the + # row-based or column based power and ground lines. + self.vertical_pitch = getattr(self, "{}_pitch".format(self.supply_stack[0])) + self.horizontal_pitch = getattr(self, "{}_pitch".format(self.supply_stack[2])) + self.unused_offset = vector(2 * self.horizontal_pitch, 2 * self.vertical_pitch) # This is a bitcell x bitcell offset to scale self.bitcell_offset = vector(self.cell.width, self.cell.height) self.col_end_offset = vector(self.cell.width, self.cell.height) self.row_end_offset = vector(self.cell.width, self.cell.height) - # Everything is computed with the main array at (self.unused_pitch, 0) to start + # Everything is computed with the main array self.bitcell_array_inst.place(offset=self.unused_offset) self.add_replica_columns() @@ -336,6 +335,8 @@ class replica_bitcell_array(bitcell_base_array): self.add_layout_pins() + self.route_supplies() + self.route_unused_wordlines() self.add_boundary() @@ -458,23 +459,82 @@ class replica_bitcell_array(bitcell_base_array): width=pin.width(), height=self.height) - if OPTS.tech_name=="sky130" or OPTS.experimental_power: - self.route_vertical_pins(name="gnd", insts=self.replica_col_insts) - self.route_horizontal_pins(name="vdd", insts=self.dummy_row_insts) - else: - # vdd/gnd are only connected in the perimeter cells - # replica column should only have a vdd/gnd in the dummy cell on top/bottom - supply_insts = self.dummy_col_insts + self.dummy_row_insts + def route_supplies(self): - for pin_name in self.supplies: - for inst in supply_insts: - pin_list = inst.get_pins(pin_name) - for pin in pin_list: - self.copy_power_pin(pin) + # vdd/gnd are only connected in the perimeter cells + # replica column should only have a vdd/gnd in the dummy cell on top/bottom + supply_insts = self.dummy_col_insts + self.dummy_row_insts + + vdd_leftx = 0 + vdd_rightx = 0 + gnd_leftx = 0 + gnd_rightx = 0 + + for inst in supply_insts: + for pin in inst.get_pins("vdd"): + (vdd_leftx, vdd_rightx) = self.connect_pin(pin, 2.5) + for pin in inst.get_pins("gnd"): + (gnd_leftx, gnd_rightx) = self.connect_pin(pin) + + + self.add_layout_end_pin_segment_center(text="vdd", + layer=self.supply_stack[2], + start=vector(vdd_leftx, 0), + end=vector(vdd_leftx, self.height)) + self.add_layout_end_pin_segment_center(text="vdd", + layer=self.supply_stack[2], + start=vector(vdd_rightx, 0), + end=vector(vdd_rightx, self.height)) + self.add_layout_end_pin_segment_center(text="gnd", + layer=self.supply_stack[2], + start=vector(gnd_leftx, 0), + end=vector(gnd_leftx, self.height)) + self.add_layout_end_pin_segment_center(text="gnd", + layer=self.supply_stack[2], + start=vector(gnd_rightx, 0), + end=vector(gnd_rightx, self.height)) + + + def route_unused_wordlines(self): + """ Connect the unused RBL and dummy wordlines to gnd """ + # This grounds all the dummy row word lines + for inst in self.dummy_row_insts: + for wl_name in self.col_cap_top.get_wordline_names(): + pin = inst.get_pin(wl_name) + self.connect_pin(pin) + + # Ground the unused replica wordlines + for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts): + for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()): + if wl_name in self.gnd_wordline_names: + pin = inst.get_pin(pin_name) + self.connect_pin(pin) + + + def connect_pin(self, pin, offset_multiple=1): + + pin_layer = pin.layer + + left_pin_loc = vector(self.dummy_col_insts[0].lx(), pin.cy()) + right_pin_loc = vector(self.dummy_col_insts[1].rx(), pin.cy()) + + # Place the pins a track outside of the array + left_loc = left_pin_loc - vector(offset_multiple * self.horizontal_pitch, 0) + right_loc = right_pin_loc + vector(offset_multiple * self.horizontal_pitch, 0) + self.add_via_stack_center(offset=left_loc, + from_layer=pin_layer, + to_layer=self.supply_stack[2], + directions=("H", "H")) + self.add_via_stack_center(offset=right_loc, + from_layer=pin_layer, + to_layer=self.supply_stack[2], + directions=("H", "H")) + + # Add a path to connect to the array + self.add_path(pin_layer, [left_loc, right_loc]) + + return (left_loc.x, right_loc.x) - for inst in self.replica_col_insts: - if inst: - self.copy_layout_pin(inst, pin_name) def analytical_power(self, corner, load): @@ -494,34 +554,6 @@ class replica_bitcell_array(bitcell_base_array): cell_power.leakage * self.column_size * self.row_size) return total_power - def route_unused_wordlines(self): - """ Connect the unused RBL and dummy wordlines to gnd """ - # This grounds all the dummy row word lines - for inst in self.dummy_row_insts: - for wl_name in self.col_cap_top.get_wordline_names(): - self.ground_pin(inst, wl_name) - - # Ground the unused replica wordlines - for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts): - for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()): - if wl_name in self.gnd_wordline_names: - self.ground_pin(inst, pin_name) - - def ground_pin(self, inst, name): - pin = inst.get_pin(name) - pin_layer = pin.layer - - left_pin_loc = vector(self.dummy_col_insts[0].lx(), pin.cy()) - right_pin_loc = vector(self.dummy_col_insts[1].rx(), pin.cy()) - - # Place the pins a track outside of the array - left_loc = left_pin_loc - vector(self.unused_pitch, 0) - right_loc = right_pin_loc + vector(self.unused_pitch, 0) - self.add_power_pin("gnd", left_loc, directions=("H", "H")) - self.add_power_pin("gnd", right_loc, directions=("H", "H")) - - # Add a path to connect to the array - self.add_path(pin_layer, [left_loc, right_loc], width=pin.height()) def gen_bl_wire(self): if OPTS.netlist_only: diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index a3de3a38..43a3cda3 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -69,6 +69,8 @@ class replica_column(bitcell_base_array): self.add_layout_pins() + self.route_supplies() + self.add_boundary() self.DRC_LVS() @@ -185,15 +187,11 @@ class replica_column(bitcell_base_array): width=self.width, height=wl_pin.height()) - # Supplies are only connected in the ends - for (index, inst) in enumerate(self.cell_inst): + def route_supplies(self): + + for inst in self.cell_inst: for pin_name in ["vdd", "gnd"]: - if inst in [self.cell_inst[0], self.cell_inst[self.total_size - 1]]: - #for pin in inst.get_pins(pin_name): - # self.copy_power_pin(pin) - self.copy_power_pins(inst, pin_name) - else: - self.copy_layout_pin(inst, pin_name) + self.copy_layout_pin(inst, pin_name) def get_bitline_names(self, port=None): if port == None: diff --git a/compiler/modules/wordline_driver_array.py b/compiler/modules/wordline_driver_array.py index b4c2c54f..276194ee 100644 --- a/compiler/modules/wordline_driver_array.py +++ b/compiler/modules/wordline_driver_array.py @@ -53,7 +53,7 @@ class wordline_driver_array(design.design): self.height = self.wld_inst[-1].uy() self.add_boundary() - self.route_vdd_gnd() + self.route_supplies() self.DRC_LVS() def add_pins(self): @@ -72,54 +72,16 @@ class wordline_driver_array(design.design): self.wl_driver = factory.create(module_type="wordline_driver", cols=self.cols) - def route_vdd_gnd(self): + def route_supplies(self): """ Add vertical power rails. """ - # Experiment with power straps - if OPTS.tech_name=="sky130" or OPTS.experimental_power: - if layer_props.wordline_driver.vertical_supply: - self.route_vertical_pins("vdd", insts=self.wld_inst) - self.route_vertical_pins("gnd", insts=self.wld_inst) - else: - self.route_vertical_pins("vdd", insts=self.wld_inst, xside="lx") - self.route_vertical_pins("gnd", insts=self.wld_inst, xside="rx") - - # Widen the rails to cover any gap - for num in range(self.rows): - for name in ["vdd", "gnd"]: - supply_pin = self.wld_inst[num].get_pin(name) - self.add_segment_center(layer=supply_pin.layer, - start=vector(0, supply_pin.cy()), - end=vector(self.width, supply_pin.cy())) - else: - if layer_props.wordline_driver.vertical_supply: - for name in ["vdd", "gnd"]: - supply_pins = self.wld_inst[0].get_pins(name) - for pin in supply_pins: - self.add_layout_pin_segment_center(text=name, - layer=pin.layer, - start=pin.bc(), - end=vector(pin.cx(), self.height)) - else: - # Find the x offsets for where the vias/pins should be placed - xoffset_list = [self.wld_inst[0].rx()] - for num in range(self.rows): - # this will result in duplicate polygons for rails, but who cares - - # use the inverter offset even though it will be the and's too - (gate_offset, y_dir) = self.get_gate_offset(0, - self.wl_driver.height, - num) - # Route both supplies - for name in ["vdd", "gnd"]: - supply_pin = self.wld_inst[num].get_pin(name) - - # Add pins in two locations - for xoffset in xoffset_list: - pin_pos = vector(xoffset, supply_pin.cy()) - self.copy_power_pin(supply_pin, loc=pin_pos) + for inst in self.wld_inst: + for pin in inst.get_pins("vdd"): + self.add_power_pin("vdd", pin.rc()) + #self.copy_layout_pin(inst, "vdd") + self.copy_layout_pin(inst, "gnd") def create_drivers(self): diff --git a/compiler/options.py b/compiler/options.py index ebf716b0..c7c062ba 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -195,4 +195,4 @@ class options(optparse.Values): write_mask_and_array = "write_mask_and_array" # Non-public options - experimental_power = False + experimental_power = True diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index 110b8330..a410e04a 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -349,8 +349,6 @@ class sram_1bank(sram_base): if OPTS.perimeter_pins: # We now route the escape routes far enough out so that they will # reach past the power ring or stripes on the sides - # The power rings are 4 tracks wide with 2 tracks spacing, so space it - # 11 tracks out bbox = self.get_bbox(side="ring", margin=11*rt.track_width) self.route_escape_pins(bbox) From 64f2f9066417f281cbad33d2f522c86bfab11b52 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 19 Apr 2022 08:50:11 -0700 Subject: [PATCH 166/229] Rework replica_bitcell_array supplies Uses layer and direction preferences in tech file. Places straps on left/right or top/bottom. --- compiler/base/custom_cell_properties.py | 10 ++ compiler/base/hierarchy_layout.py | 17 +- compiler/modules/col_cap_array.py | 2 +- compiler/modules/dff_buf_array.py | 9 + compiler/modules/replica_bitcell_array.py | 201 +++++++++++++++++----- compiler/modules/row_cap_array.py | 7 +- compiler/openram.py | 3 +- compiler/tests/configs/config.py | 2 + technology/freepdk45/tech/tech.py | 1 - technology/scn4m_subm/tech/tech.py | 2 + technology/sky130/tech/tech.py | 17 ++ 11 files changed, 210 insertions(+), 61 deletions(-) diff --git a/compiler/base/custom_cell_properties.py b/compiler/base/custom_cell_properties.py index b2697472..0102bf24 100644 --- a/compiler/base/custom_cell_properties.py +++ b/compiler/base/custom_cell_properties.py @@ -156,6 +156,16 @@ class bitcell(cell): self.storage_nets = storage_nets + self.wl_layer = "m1" + self.wl_dir = "H" + self.bl_layer = "m2" + self.bl_dir = "V" + + self.vdd_layer = "m1" + self.vdd_dir = "H" + self.gnd_layer = "m1" + self.gnd_dir = "H" + class cell_properties(): """ diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 6fca63c7..a37ccb2b 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -673,9 +673,9 @@ class layout(): bot_pos = vector(x, bot_y) if num_pins==2: - self.add_layout_pin_rect_ends(name=name, - layer=pin_layer, - start=top_pos, + self.add_layout_pin_rect_ends(name=name, + layer=pin_layer, + start=top_pos, end=bot_pos, width=via_width) else: @@ -689,10 +689,10 @@ class layout(): def add_layout_pin_rect_ends(self, name, layer, start, end, width=None): # This adds pins on the end connected by a segment - top_rect = self.add_layout_pin_rect_center(text=name, + top_rect = self.add_layout_pin_rect_center(text=name, layer=layer, offset=start) - bot_rect = self.add_layout_pin_rect_center(text=name, + bot_rect = self.add_layout_pin_rect_center(text=name, layer=layer, offset=end) # This is made to not overlap with the pin above @@ -773,9 +773,9 @@ class layout(): right_pos = vector(right_x, y) if num_pins==2: - self.add_layout_pin_rect_ends(name=name, - layer=pin_layer, - start=left_pos, + self.add_layout_pin_rect_ends(name=name, + layer=pin_layer, + start=left_pos, end=right_pos, width=via_height) else: @@ -812,7 +812,6 @@ class layout(): end=end_pin.bc()) else: debug.error("Cannot have a point pin.", -1) - def add_layout_pin_segment_center(self, text, layer, start, end, width=None): """ diff --git a/compiler/modules/col_cap_array.py b/compiler/modules/col_cap_array.py index 438fd34a..27194a89 100644 --- a/compiler/modules/col_cap_array.py +++ b/compiler/modules/col_cap_array.py @@ -99,4 +99,4 @@ class col_cap_array(bitcell_base_array): inst = self.cell_inst[row, col] for pin_name in ["vdd", "gnd"]: for pin in inst.get_pins(pin_name): - self.copy_power_pin(pin) + self.copy_layout_pin(inst, pin_name) diff --git a/compiler/modules/dff_buf_array.py b/compiler/modules/dff_buf_array.py index 62a7cfb6..70209767 100644 --- a/compiler/modules/dff_buf_array.py +++ b/compiler/modules/dff_buf_array.py @@ -145,6 +145,15 @@ class dff_buf_array(design.design): return dout_bar_name def route_supplies(self): + for row in range(self.rows): + vdd0_pin=self.dff_insts[row, 0].get_pin("vdd") + vddn_pin=self.dff_insts[row, self.columns - 1].get_pin("vdd") + self.add_path(vdd0_pin.layer, [vdd0_pin.lc(), vddn_pin.rc()], width=vdd0_pin.height()) + + gnd0_pin=self.dff_insts[row, 0].get_pin("gnd") + gndn_pin=self.dff_insts[row, self.columns - 1].get_pin("gnd") + self.add_path(gnd0_pin.layer, [gnd0_pin.lc(), gndn_pin.rc()], width=gnd0_pin.height()) + if OPTS.experimental_power and self.rows > 1: # Vertical straps on ends if multiple rows left_dff_insts = [self.dff_insts[x, 0] for x in range(self.rows)] diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 5a7a046f..e1a3cbb8 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -6,7 +6,8 @@ import debug from bitcell_base_array import bitcell_base_array -from tech import drc, spice, cell_properties +from tech import drc, spice, preferred_directions +from tech import cell_properties as props from vector import vector from globals import OPTS from sram_factory import factory @@ -309,7 +310,7 @@ class replica_bitcell_array(bitcell_base_array): # row-based or column based power and ground lines. self.vertical_pitch = getattr(self, "{}_pitch".format(self.supply_stack[0])) self.horizontal_pitch = getattr(self, "{}_pitch".format(self.supply_stack[2])) - self.unused_offset = vector(2 * self.horizontal_pitch, 2 * self.vertical_pitch) + self.unused_offset = vector(0.25, 0.25) # This is a bitcell x bitcell offset to scale self.bitcell_offset = vector(self.cell.width, self.cell.height) @@ -461,38 +462,67 @@ class replica_bitcell_array(bitcell_base_array): def route_supplies(self): + bitcell = getattr(props, "bitcell_{}port".format(OPTS.num_ports)) + + wl_layer = bitcell.wl_layer + wl_dir = bitcell.wl_dir + + bl_layer = bitcell.bl_layer + bl_dir = bitcell.bl_dir + + vdd_layer = bitcell.vdd_layer + vdd_dir = bitcell.vdd_dir + + gnd_layer = bitcell.gnd_layer + gnd_dir = bitcell.gnd_dir + # vdd/gnd are only connected in the perimeter cells - # replica column should only have a vdd/gnd in the dummy cell on top/bottom supply_insts = self.dummy_col_insts + self.dummy_row_insts - vdd_leftx = 0 - vdd_rightx = 0 - gnd_leftx = 0 - gnd_rightx = 0 + # For the wordlines + top_bot_mult = 1 + left_right_mult = 1 + + vdd_locs = [] + gnd_locs = [] + # There are always vertical pins for the WLs on the left/right if we have unused wordlines + self.left_gnd_locs = self.route_side_pin("gnd", "left", left_right_mult) + self.right_gnd_locs = self.route_side_pin("gnd","right", left_right_mult) + left_right_mult = 3 + + if gnd_dir == "V": + self.top_gnd_locs = self.route_side_pin("gnd", "top", top_bot_mult) + self.bot_gnd_locs = self.route_side_pin("gnd", "bot", top_bot_mult) + top_bot_mult = 3 + + if vdd_dir == "V": + self.top_vdd_locs = self.route_side_pin("vdd", "top", top_bot_mult) + self.bot_vdd_locs = self.route_side_pin("vdd", "bot", top_bot_mult) + elif vdd_dir == "H": + self.left_vdd_locs = self.route_side_pin("vdd", "left", left_right_mult) + self.right_vdd_locs = self.route_side_pin("vdd", "right", left_right_mult) + else: + debug.error("Invalid vdd direction {}".format(vdd_dir), -1) + for inst in supply_insts: for pin in inst.get_pins("vdd"): - (vdd_leftx, vdd_rightx) = self.connect_pin(pin, 2.5) + if vdd_dir == "V": + self.connect_side_pin(pin, "top", self.top_vdd_locs[0].y) + self.connect_side_pin(pin, "bot", self.bot_vdd_locs[0].y) + elif vdd_dir == "H": + self.connect_side_pin(pin, "left", self.left_vdd_locs[0].x) + self.connect_side_pin(pin, "right", self.right_vdd_locs[0].x) + + + for inst in supply_insts: for pin in inst.get_pins("gnd"): - (gnd_leftx, gnd_rightx) = self.connect_pin(pin) - - - self.add_layout_end_pin_segment_center(text="vdd", - layer=self.supply_stack[2], - start=vector(vdd_leftx, 0), - end=vector(vdd_leftx, self.height)) - self.add_layout_end_pin_segment_center(text="vdd", - layer=self.supply_stack[2], - start=vector(vdd_rightx, 0), - end=vector(vdd_rightx, self.height)) - self.add_layout_end_pin_segment_center(text="gnd", - layer=self.supply_stack[2], - start=vector(gnd_leftx, 0), - end=vector(gnd_leftx, self.height)) - self.add_layout_end_pin_segment_center(text="gnd", - layer=self.supply_stack[2], - start=vector(gnd_rightx, 0), - end=vector(gnd_rightx, self.height)) + if gnd_dir == "V": + self.connect_side_pin(pin, "top", self.top_gnd_locs[0].y) + self.connect_side_pin(pin, "bot", self.bot_gnd_locs[0].y) + elif gnd_dir == "H": + self.connect_side_pin(pin, "left", self.left_gnd_locs[0].x) + self.connect_side_pin(pin, "right", self.right_gnd_locs[0].x) def route_unused_wordlines(self): @@ -501,41 +531,120 @@ class replica_bitcell_array(bitcell_base_array): for inst in self.dummy_row_insts: for wl_name in self.col_cap_top.get_wordline_names(): pin = inst.get_pin(wl_name) - self.connect_pin(pin) + self.connect_side_pin(pin, "left", self.left_gnd_locs[0].x) + self.connect_side_pin(pin, "right", self.right_gnd_locs[0].x) # Ground the unused replica wordlines for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts): for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()): if wl_name in self.gnd_wordline_names: pin = inst.get_pin(pin_name) - self.connect_pin(pin) + self.connect_side_pin(pin, "left", self.left_gnd_locs[0].x) + self.connect_side_pin(pin, "right", self.right_gnd_locs[0].x) + def route_side_pin(self, name, side, offset_multiple=1): + """ + Routes a vertical or horizontal pin on the side of the bbox. + The multiple specifies how many track offsets to be away from the side assuming + (0,0) (self.width, self.height) + """ + if side in ["left", "right"]: + return self.route_vertical_side_pin(name, side, offset_multiple) + elif side in ["top", "bottom", "bot"]: + return self.route_horizontal_side_pin(name, side, offset_multiple) + else: + debug.error("Invalid side {}".format(side), -1) - def connect_pin(self, pin, offset_multiple=1): + def route_vertical_side_pin(self, name, side, offset_multiple=1): + """ + Routes a vertical pin on the side of the bbox. + """ + if side == "left": + bot_loc = vector(-offset_multiple * self.vertical_pitch, 0) + top_loc = vector(-offset_multiple * self.vertical_pitch, self.height) + elif side == "right": + bot_loc = vector(self.width + offset_multiple * self.vertical_pitch, 0) + top_loc = vector(self.width + offset_multiple * self.vertical_pitch, self.height) - pin_layer = pin.layer + layer = self.supply_stack[2] + self.add_path(layer, [bot_loc, top_loc]) - left_pin_loc = vector(self.dummy_col_insts[0].lx(), pin.cy()) - right_pin_loc = vector(self.dummy_col_insts[1].rx(), pin.cy()) + self.add_layout_pin_rect_center(text=name, + layer=layer, + offset=top_loc) + self.add_layout_pin_rect_center(text=name, + layer=layer, + offset=bot_loc) + + return (bot_loc, top_loc) + + def route_horizontal_side_pin(self, name, side, offset_multiple=1): + """ + Routes a horizontal pin on the side of the bbox. + """ + if side in ["bottom", "bot"]: + left_loc = vector(0, -offset_multiple * self.horizontal_pitch) + right_loc = vector(self.width, -offset_multiple * self.horizontal_pitch) + elif side == "top": + left_loc = vector(0, self.height + offset_multiple * self.horizontal_pitch) + right_loc = vector(self.width, self.height + offset_multiple * self.horizontal_pitch) + + layer = self.supply_stack[0] + self.add_path(layer, [left_loc, right_loc]) + + self.add_layout_pin_rect_center(text=name, + layer=layer, + offset=left_loc) + self.add_layout_pin_rect_center(text=name, + layer=layer, + offset=right_loc) + + return (left_loc, right_loc) + + def connect_side_pin(self, pin, side, offset): + """ + Used to connect horizontal layers of pins to the left/right straps + locs provides the offsets of the pin strip end points. + """ + if side in ["left", "right"]: + self.connect_vertical_side_pin(pin, side, offset) + elif side in ["top", "bottom", "bot"]: + self.connect_horizontal_side_pin(pin, side, offset) + else: + debug.error("Invalid side {}".format(side), -1) + + def connect_horizontal_side_pin(self, pin, side, yoffset): + """ + Used to connect vertical layers of pins to the top/bottom horizontal straps + """ + cell_loc = pin.center() + pin_loc = vector(cell_loc.x, yoffset) # Place the pins a track outside of the array - left_loc = left_pin_loc - vector(offset_multiple * self.horizontal_pitch, 0) - right_loc = right_pin_loc + vector(offset_multiple * self.horizontal_pitch, 0) - self.add_via_stack_center(offset=left_loc, - from_layer=pin_layer, - to_layer=self.supply_stack[2], - directions=("H", "H")) - self.add_via_stack_center(offset=right_loc, - from_layer=pin_layer, + self.add_via_stack_center(offset=pin_loc, + from_layer=pin.layer, + to_layer=self.supply_stack[0], + directions=("V", "V")) + + # Add a path to connect to the array + self.add_path(pin.layer, [cell_loc, pin_loc]) + + + def connect_vertical_side_pin(self, pin, side, xoffset): + """ + Used to connect vertical layers of pins to the top/bottom vertical straps + """ + cell_loc = pin.center() + pin_loc = vector(xoffset, cell_loc.y) + + # Place the pins a track outside of the array + self.add_via_stack_center(offset=pin_loc, + from_layer=pin.layer, to_layer=self.supply_stack[2], directions=("H", "H")) # Add a path to connect to the array - self.add_path(pin_layer, [left_loc, right_loc]) - - return (left_loc.x, right_loc.x) - - + self.add_path(pin.layer, [cell_loc, pin_loc]) def analytical_power(self, corner, load): """Power of Bitcell array and bitline in nW.""" diff --git a/compiler/modules/row_cap_array.py b/compiler/modules/row_cap_array.py index e7dc9816..8f092dc4 100644 --- a/compiler/modules/row_cap_array.py +++ b/compiler/modules/row_cap_array.py @@ -106,10 +106,13 @@ class row_cap_array(bitcell_base_array): width=self.width, height=wl_pin.height()) - # Add vdd/gnd via stacks for row in range(1, self.row_size - 1): for col in range(self.column_size): inst = self.cell_inst[row, col] for pin_name in ["vdd", "gnd"]: for pin in inst.get_pins(pin_name): - self.copy_power_pin(pin) + self.add_layout_pin(text=pin_name, + layer=pin.layer, + offset=pin.ll(), + width=pin.width(), + height=pin.height()) diff --git a/compiler/openram.py b/compiler/openram.py index 3a509f3b..8ce6ae1e 100755 --- a/compiler/openram.py +++ b/compiler/openram.py @@ -74,9 +74,8 @@ for path in output_files: from sram import sram -s = sram(name=OPTS.output_name, +s = sram(name=OPTS.output_name, sram_config=c) - # Output the files for the resulting SRAM s.save() diff --git a/compiler/tests/configs/config.py b/compiler/tests/configs/config.py index 9e35f558..b56c63db 100644 --- a/compiler/tests/configs/config.py +++ b/compiler/tests/configs/config.py @@ -14,4 +14,6 @@ tech_name = OPTS.tech_name nominal_corner_only = True check_lvsdrc = True +route_supplies = False + output_name = "sram" diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index d351ae36..7c1ac84b 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -31,7 +31,6 @@ tech_modules = module_type() # Custom cell properties ################################################### cell_properties = cell_properties() -cell_properties.bitcell_power_pin_directions = ("V", "V") ################################################### # Custom cell properties diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index a8c44996..525736a8 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -30,6 +30,8 @@ tech_modules = module_type() # Custom cell properties ################################################### cell_properties = cell_properties() +cell_properties.bitcell_1port.gnd_layer = "m2" +cell_properties.bitcell_1port.gnd_dir = "V" ################################################### # Custom cell properties diff --git a/technology/sky130/tech/tech.py b/technology/sky130/tech/tech.py index e81fe476..72250afc 100644 --- a/technology/sky130/tech/tech.py +++ b/technology/sky130/tech/tech.py @@ -86,6 +86,13 @@ cell_properties.bitcell_1port.port_map = {'bl': 'BL', 'vpb': 'VPB', 'gnd': 'VGND'} +cell_properties.bitcell_1port.wl_layer = "m2" +cell_properties.bitcell_1port.bl_layer = "m1" +cell_properties.bitcell_1port.vdd_layer = "m1" +cell_properties.bitcell_1port.vdd_dir = "V" +cell_properties.bitcell_1port.gnd_layer = "m2" +cell_properties.bitcell_1port.gnd_dir = "H" + cell_properties.bitcell_2port.mirror.x = True cell_properties.bitcell_2port.mirror.y = True cell_properties.bitcell_2port.end_caps = True @@ -98,6 +105,16 @@ cell_properties.bitcell_2port.port_map = {'bl0': 'BL0', 'wl1': 'WL1', 'vdd': 'VDD', 'gnd': 'GND'} +cell_properties.bitcell_1port.wl_layer = "m2" +cell_properties.bitcell_1port.vdd_layer = "m2" +cell_properties.bitcell_1port.vdd_dir = "H" +cell_properties.bitcell_1port.gnd_layer = "m2" +cell_properties.bitcell_1port.gnd_dir = "H" +cell_properties.bitcell_2port.wl_layer = "m2" +cell_properties.bitcell_2port.vdd_layer = "m1" +cell_properties.bitcell_2port.vdd_dir = "H" +cell_properties.bitcell_2port.gnd_layer = "m2" +cell_properties.bitcell_2port.gnd_dir = "H" cell_properties.col_cap_1port_bitcell = cell(['br', 'vdd', 'gnd', 'bl', 'gate'], ['INPUT', 'POWER', 'GROUND', 'INPUT', 'INPUT'], From 7195d81736f37e55e5332f261788d69f028aa72c Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 19 Apr 2022 10:32:37 -0700 Subject: [PATCH 167/229] Adjust WL and GND for contacted via2 spacing. --- technology/freepdk45/gds_lib/cell_1rw.gds | Bin 18132 -> 18132 bytes .../freepdk45/gds_lib/dummy_cell_1rw.gds | Bin 18510 -> 18510 bytes .../freepdk45/gds_lib/replica_cell_1rw.gds | Bin 18512 -> 18512 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/technology/freepdk45/gds_lib/cell_1rw.gds b/technology/freepdk45/gds_lib/cell_1rw.gds index 905175076a286367b1dcee649395e8746ad5a589..e8116b9e86ed1433d85e8715f7c62abf9905b873 100644 GIT binary patch literal 18132 zcmeI4U#MkO9mm(+`|N%1xpR%Nnuf_iEf7rSA$v$g(Z)(>n4(EglR{@28HOe&uQc=0 z5C%QfLj*<8K=fcz8H7-XU`kF{GQ`kBG*5wo5l$FI;Y-}U-`{V2&;E1ITK8PformxU zhmZc&`tILazx7*x_S!RsCY0sqV5cch? z*4NkX!tWLmg{SfRh$uT5MpuSu`VfjYQ2r2!C;lUZ>T9Cx#=QQPsQ+Em8_lmjKj|NJ zE*PR6hNpvRAteN?3VSD#@$ z_yjHfA8sl8KwtI8FNEbM;UD9-V+~r2pD6qClRf_(y~ln0ijz8ypC~)n9lveVd)%y@ zh~vu59zRj`T>BX}lw16$YY;zC_JO|X#qS{6!2E~*e*9%8d;K5iWBj4FxWm7gXn$XS zY0LTB(R}1^0XhnHm?Wy+tIs!#Yy8X%AOuS_pfo*xQnt6 z^hG=Vh~MXtFQ0bq7~y$X=tSAUZvGGS=);d)A0BYMQ+DHJ)X&#`w$;{du>7yD-J<5&HvCF2*%FPnb!9rsVte|>#R`j6#F|MTjH{U7?DrT>icwD?WznenrJLqDzm z)W`Bf|FJeai#jKr%@}!vwMdkGbTXAc^Xf5n`{>_Ezr}CdKPh|K|Gav%{}-|U;70!{ z&-cH6YPaWgqOV?X|0H#z zds|W;%ai`MTVMY%_8*+ZKjXtVPm7=Ix%jjFtT(Oyvgh>7|M4y#|MBlZ^dHZ+@)`U8vlu^d)A;H6kfgfoujilV2A#8}oqu9^cm3_?k>7*;zrX*gyf^r_x5$yum1X}^0fb6{%PKb)AMiKZGZR{_8Z*0kbK|c9h4|L z*zNyD{d2Bgx(D(6dkA6^?O;-0d>8fqh8zHwad$HMPfOXsq@L$Pwv%MLO&=-yrtP1j z|J&g|{M+MKeAC-6$_^&`U)_iPBhIAaF3O&Z|GfI)_?0*M_>r@W-@N(~ImbAWj9bZE zij+MUKb~KB|3mWrr}%bD*$4NRz5J(+>((^A>|k>Iy8i8b9sVbb?aKMD{)zgiN3#9g ze?-|g)3cq^^s?vL-}P_rtMETzY*)@d*B#z}P1Yf-Kb*H*hh!hzfA!*Ty76>9&-1Z7 z8UL<-p0~}f7~7Te&-u@GPSydeU$*XmvTvrh_YOQqx(U&Kd+s=$KVAQ9Ki9trW4m(x z*?(K_LEihZ|Dx<*Hh!wd^Ah!cv_0 zZ09upvJcw7qqqMa#oWW5891=Xc+?wNG>2F7|KabBu%Hl3Ty#%|E{PaGfK${)N|C%AQ;Qia)uYwDt4;mej}c za?)x+K_0_H?sgLCeJ@(IY(D3~cSeFTETfLM>`vM9`kL+h1Nx12^MuYUbINW^^dIBH8#Tz~K$J-&hB{a%z%;+)QMy|Kr4f!L= zKG@|t`Qtj(lTMUW;X}g0{_dME#o+gP{kZ4zYOas3iy zPv_r4KVSTOy|>dO)_vw}`LUL=gNyu~n!k(nllzwT3GExA?CJTth~HM?7thUDKPRW` z?%B0-`oz5cD%Mi`eV9GXk$C#tih8tjqF(FG{gvL?73a0_H5fzkN8pPc%6?5+Z*L~3 zXN2C~P(<02daV7=(|;s%JU6l(M%j~k#0YO_Y`+mY`@$v4p3$@2^%-w}z3%OwQ1&zF z{xfdW8=+_Xs5i=<(X-vu8=+(SsW-}=)O+0OGm+5Qxm%PysYid$V!wDa5;ui*Ga$FU`o5O34{lhuRbL&(67dq^4)TV%dbOqOgB#|a|9SQ0 zDbKy~6ymra@q1I0-Pk>Q^!!uDFQP`gGf~fXD5LECFYK%B`o(AK=YH7+|H)4F^0%W$ zzN3C~Ao4tj`P+!HA6V$G#1awD{@WZs8y_17Te}c{r|g@JpXx~`%6@tE_5~N~j1lVq zzwp}nN6Ow`f3`V(|IhjBW7Hgo#JuC!bN(4+PtL!E-oEfEPKui-doq65x1RGnH6nlc zg_rqjME=I|?)tsR-^u?WW3hkK`+W{_AKm);O|5>e=QI2#JGt0@FW>&V<^AK0_WXsh a;y>3r@YN^OU&r|^Qg+bRk0qQTM&W-I1dW0K literal 18132 zcmeI4U#MM26~<@pefGZR-rm{>#Sj~78&PV_gZiMAmc~?RsY%gTQd?0<(v-f$TJn%0 z2m!@61rZd%KoP7UR4_hBDb&9yN^DCIG!_D)g@T$=@j?3*zi+Mi&i<1#lXJUI9;D~O z;aAtpx7W;?HGlS;6GIcq^8T>1DA!&IRd{FE7OoBN>i&1wESoPr_VA;}4t*hnYpeS9 z8%}@k$(Qea{Uf_RxBcurKfXEatTWoCdFbJzM<4vavB$$?8bWh*8OqSSr3@kL-d0__ zc<~N=ZXr?lNqjyk%1(yKTf;nk2*qnw4&sTw3!yq8%6=vFc=iRf;Q?p$u@K6$XhWpz z#RKW~mp`Q*I*_{hJ1u2T>*04l>c8Y<{L1%x{7BiWm(u>LPqQ9ApvC_~EoC3*tN!?f zFg*eP7{9AN0WHQ)lzn=l=f9)p_=T|kjFUQ!pC~)n9secjJ#N-c#Bt*qkDn-euKkP~ z$}N7>HHe=m`#|6H;z)@-o+BlxeDvV+O?kJT5? zyML1Y%fl_{Kb9x`kJS&`KlC5Vlm0Dkd*;WllzmS+e%5c)o7aEpV|mhlb%V!`Wc;e1 zwPgHa`4!VozUBT&`mZ@>BI!StC;gAr5Bop#zexWX=Xvp)*)!v3{f2&C|EZ7ViT-14 zz}`E#%US;wdGsm7FjDr(U8(#TtH;>wrhg~>7Qc4?r0i+`WA$kNPh$VUOZ}@n-~W2w z{P@l6`%?PY?|t+8U(24+*B|sak!*jBGqA|`#qz}X&&sWybmAiV>X+`Hq;7IwOX_2J z(*Lsc^&i|nxrl#@8{#}KevE%C&$gfS=JkJO&x{}QfBLGA|N8eq|6nDjqR?|D0Y z)k(jc|Dx<^|4Yzg-kBdz{T5|U`}ephPU~Nd@r#r_tw;O2{-Lw}M=s)@<4!*$+s*tJ zWl#Heo$5&^%AV6RKUt5Yj`LrX{YvVG{pY+h{~-Ox@?`$@^oYB~FLDumum8}Q|HwrD zCnL|_OVz)D^Iy+D&kZ_f>D(jA4tC?;(fj<>KF{^LzyGQ{rT6jGI;(v{lpXB)ulwXT&Dj!KA)GowZ+~-{AB!m_Pq%DLa_d^L)s5l5Dr>BV`AZ`mz0AhX3$_$FF$E z+b_xvCfi>jW{fkbxQnvq;y+eD9KRAdz;PrO8Nadm@?OLa@go_x^6xEW&&7}D58nTf zy#Fb_*;4kw{beuzspEPzPcJ)|9KWuAu6Oi5V{BK>fAw$FM?I45=l&zgemOncIZrQp zuKivAY&ZSS7~7Te&-urDuGu`q`eW-3DEr|4s~3OjxL(iG%MK>v-}TS+p6j2uh=0z1 z)|;&ZSifxD0cFp%pE|a4o?iA``@8M`?3F`>|i#2vwB$jZT}Ft zpZN2$dhUCyC%>ZXU{cTi(?3Za`!C9#YkybI^Oo%&Vtnr9^laxm|FRF-e^qb)J%T)W z4*dr?ZpG6rWe28X?+{%%A3 zPdTaM`CXL#a{3zM#^*HeaJ?uym~Q`mwD}y`4|2WZ_ZOn<;aopbN(4O)ss$?J*ThEc>a+buL)!w||3ul-^ACPT=1({N znz!O&@n>K0;XJ_nWBxm3C)52On?K9YYn{-#A<7OW@(=m?XO6Rz^S(w5MA>uW&-yj= zWb+S@IUFfFnDoEWkBcAAs$3^Yes^d&A1Qlw{d`l8pUrLLuakLeb3an{bpEdN+$R*L zt;Y{*&9k1rB=gt4^NM8t#`4wrfhBs1r4_%Q>YZP!>tK8Wu>;p`M5Xt(lpRdQZ>*ks z#oF(E&zRnW@p}a4pGeukr2nz{H~aokZpWH+4siz=%j(@NWlx{qec#qTt$kaRJ-z;| z^kegn?>$`SNUne3m6o#S_V40Pt|x8%yuYQbpI)Avf7Q*dC++<3R7>h(c~akff2O{^ z-t{E)u{@#2{&^Z2zCVI|@4Dpu(aJOH2hQt!PviRs^?d&jWzW68U2^{Zx$A3?`dFT5 zKl*yc>yh-!_dk*PSf13g-8`q;`xD>2`2G|rd;0wDakF~{#ECk_Pn12a_x8~b+esbU zFUp?NGd`?GQpdQ7vP-{-(D?rKwh}FEwijUaTtzq9N)#_uG?{5@1Zezce6S9fo@>f2EB7LPK2-N{=br|iaV zmUZ+fdxqtt>zF0fhdX5_)BcOyR&KZS)G-Jx(G4Gle`L8+c4Jas+-lDc#jUO@ek96nOz2T|S|8U1%oh3& z9M`riq35`x9%mPHydAPzLZj@)j2@cvuD9JC`6J3c*yTI<<2u!oPLzG6PtTv~_PEP} zw##B3h_=gm`D*+yHRD@OC;yP!yd~sYI>@}UQ$nQd>HJ&i$HmXrdpk{H-DlpGA8#o; zxXRzT`MX*_?G(M*e{BEOz9}wy|BUBmte>+}cK7VsIelVYe;I2j{yof&=5RcHZbd!W zHd7z#&Hatu*%jxt>3=Z?!1XVIIJbzhgWa{Gr{|fG_3RA=dV52Ols&Dta}o4T`sKM% zls&CSjQEBI|MrFky}hAD%AV7+-St6le|^r|Kcnmi)BU#_2Glb`&-hVqls%(oyXoHu z9otX6QTC+X<5nMxgwD?0qU=dM`g;=l#odv(DYTmbQTDsj{kIzk)H6a?J%#6qvS;*m zLxOrn=dMvqqiFx)H6cQ8yfmI%AV2lUwGL~9LO8G@-HoAAKcLO^1pZ@-mrpp zvwCAoyJ7Y6+Wgpxy_u4;JUmo||D~}_NdlA3aMcIwX{!_-u@psC8x$#py=|tJDtlqxi#X4i;x`$s|*!oAx-d}%~9KZkP{Pi(vc12>| zaqKz&jIt-^-%8JWr#Buy>~+t2o*KFT?(zIJB7b9fcl}=F@9h5}W3_+O{1qH>ko)M? v*Kca|aXp{mAKA&({(I&2-!1PSueIkdj8*3k-};0aAF)$p>&F_-5R>pfec5^0 diff --git a/technology/freepdk45/gds_lib/dummy_cell_1rw.gds b/technology/freepdk45/gds_lib/dummy_cell_1rw.gds index 031ded2ba10f04b29c143651edf438f2d99b0470..92d2b130fb69c0fc2845042ee9df2bbf23a9fee7 100644 GIT binary patch literal 18510 zcmeI3U8o&b7036?oHO^Hn_H>XHpEs_1)*vl)Q8l5(E3?4L=g+s7E3=&4Z+mV)HDbU z5?}Q}1btBuAGCh-K?;f#tfCQ{5~TQ0>{G!)MN}$^A{4p)|7-34%$~V-&pEl{ZKyfI z_1CUF|5%-T*>65#k{_vyU3s+6^+RN(t(24u+|NLE_y6@=GyWVm9WSFdmP+wAp zGSsgsLkRmWtwN|i7Q&=()+cene*8ts4o+T;%QovbHZ~4Y@1(ALyX#5W^LkwWSO~>w zXZ4v7re8-ak+Oq%|9_z#{z2->r(4RN*F*avw0D!p$lsv-f+)K&<3H-(74=U>y%9RI z8#8*ey_fA|%=^1V*~w1-tN!?{J_5fO$F*yr#rTP`gQ@>Sk9%YMRv&Rv$8i&7&+EP4 zvp+a@9ryl=vV$4_WA%s|d9ye{`mK>aQTAT^^~n4s`fcSe(fhb*o@w5RviIgsqIdtA zXA921M8B>1m+0aD{O4a+pVXg?8|qig)L&1J7&w1$ALY#{JK3qfA|3zfJ42XVj&+Cp zA&9x#Q1;97`sx?1H$p$T&Gkm;V|!Zv9seEu+2~(fK;Ma9I&p#cH|c+e_^Brs(D&oF zenY?A{-2*7WBWMcj70v!M?L>W*$2k2*ysH;LSOvS^+xnRwr9q#=O6txojBM3X1&D? z{bKP$|D)J{QaX|Ttvz4Ao&GCsac=*c{CJ+E6Bp34ex?ulJgH}1H=^udCjZc4-tsz< zI?i8F_8~p}PmZxX$Jsbl?% zvgh;f^*?>kNgeB6lzpCla;(*-{$(HPKjUUUw~Al(ozr{Vic|d-WzYME9`oC-1EmvX z&+DQ6D)s<}BmaZ3yaxX+%6@pD{;zg@MM78oBq8)>pQGpATl&<$>|l2OF@9cW{ZQPI zvhSpxanq0DPx~+XkpHpz;+*H-h<=y%dj5^be{9d@FWljJBlJ82aU6}%$M!)z`zd|u zU-qH?Gd^CoRs6E=q@HopkK#}JFZ+=HvHJ2(oVT#%k-H|SBOJ6v*}-i7%R8|KeAo4i zg?gv##vRn3cl?ud|J{FnF7W(K^ynM*e_AKG?k%wXCwiZ^9B0kn1=gRAzCZp8)PG06 zjqx9=pZ4?5eLly*_WeBnob`QFWAE;t6TRoZ*?&W~!2UPUvu;(Vs#{TZV_LtnG=8r8 zjF;qli^;!Q$_@_d`JTk?gFH~rev`8I-XCo8uj~5$WgpUqFMIqX^;~~M#vj|W@w1(N z>^j6vJ>w^3pXXoK$*(B;ke+$tdkW(*&l~qm%wJ>gzCYZQKh9g~d2Xk!q3pBa@spoM z7w;oGIG8_P$NVvF=B=UZbM&^~f}Z}VZ;1GLU$igeztP3}G;t01ul|lXhxeyOtYbWX za6L21emd`;I@`B_e1A%vC_9*qKlLx2*u*v9pZjiJXGGk^S3G{B>~r*tlY084PLzEp z{?xy8ViVVZ|MFIh@jsD6u=o=Ar3t@#Ca24;K%eS?Z9o#W}^>Nha&yX{4 z1%0Ug+ER8f>wm1C^MiRJnLo~dQTCzyHR}e}53X0ux~+8tcFe16{5C&1-{9ZYJIr6v z<|FJw`mz4|<8Se!4#-8u-{Qykkz0*lZ2w>Oe^>hao!*FiJ&XMUIQt{`L`&Jh)PF}` zJ>`0m`pLnT)W`O$zS!@2lKSGOEvb*~Sv~JRz1IEIA8`Mo>|j>Ue)Bq#I`&_beMryv zcpXU{;}>Pm>#;XFL%ox_aEt3n+4Fkz_nW@vkkxh2yrCu6qS&78fAv<^lhjv_wxm9` zXZ6K1t|zI-7tw~)$M&o~9CAHLeR!cI^|3vxpS}nA!nuoFxeWYOOWDDt9;L8~RN?z^ zXa0`O-{d9K?$2@amoQcw3+|bWvKzDcFL&em4b%W=`;9lZlpW0K$HxCk*B7^=-v5D| zfvYEw$HOgU2ebJbtFNxanEwWI7F_ud>fkLcWe2nV$Le3{<2N?`0(%ErXSoOD`g?Or z*}+WyeU8=>C)ZETT~YS@`nl9|?NgqVH&OO{{`|S6=M;4p+w-e>pVu#G`;T9@Wc|kW zO#MQ8z1LuQz1ME_K~Z+&j_Jof|1PwC?E16RbN+9C|2g?Rp54$JPy2ni4`N;$`_TRs z=N6sQ){a1j_rId-V7C4@oqwRW^AE`LOKjgEJ?7>?&QH?kEr0)J`^WvVlll00{^L6j zlJEWa{$G?G%*2m-zBaweb4$zM^QT8MG{-^n8z481nvj4F?lmDi^+Vl6zT7RfD zoIClPA)EKcs3X1ymVI#lG^&0)?*ZUAaNaZjqU?j`AIyJ^v&LPNJwN`Qf2|W*H$>UN z%=jU0^ndkPCv|*pAW?cJS3q0Ic(Q*#RxR||>bNr(W&eNHS2ub6l6JD^ zP962j9U<#CwrAJBvFqoB){lLDEcKj!+kgH}Z^Rmg9Ub$?6OEmWjj|gv^@p}I`or3Z zlW@R&oU)Vo{ZnxR+JB4n`v%t)-xp;!X8dD*a954fV1-i^{qkhxl--!sPj9jNhbh*5 zo~Zd{(*js(vtK<3E?CdkUZ{*=p#DM>XX-|Fcarb^c>f+%>-QByd zrF-}CAwNYKQM2X0y@riAWySV1_dPxOhT7qE9CPZNvKzDd>K=5FUv)r!)v2CuDSPj$ zPRIXPeeo^$<5w-vzG}U(rR=@0S{?sm_54+*eSHLZ8ZVz~DSPi!-to^b{73z($59ql^q234`*Iw$4 zvJdF(ZQx#yfA(#UzoG1VbN%`oGjCXTNdzW8LV_Yld~>f3lN9`L}i(f9g2yPTA+_ zm*ao&*1y+CeIOF^pS8pJZ uW3NB2AJ&ln$xe2jpD(8SA6y;6HTM4jUwXpyi#WeU$`0E3YX#f0N%$`kiU|1t literal 18510 zcmeI3U#MqQ7035E=XcKi-RrfckcLSs8z`*ip?a9i1}7^tn-L`$vq(f8^JVNoQV|59 zUJD|qmjnqa3Vg^OB82{rWTS=zH3b79f>0zz4;lC{eZOn%?>YONd-u7&dr!BE%Ze%VKx1CSTCECcYooI`%ir-giEUW z>dQ}m`+G0m{P2elet!S+H$47>a9N$#zPV{m-hc1C58Zy(-KS37{(<`*46}I%&BbLX zL-U3*gm7qI6+-oCeE#BWZo~zL@rjfjoV_V*rayoF{Bi1?)RpgdJt=!$kL!ONLh)H= z_3;quZ$TF+JDB(X59;9`q^^9vqwIM-w68#WC5enY4ecYM?8c1$sd{|($N2qZ%=<@0 z*~wo2tKs;~5i`ee?Tyf4{6yKoH2y@7@5cDeA8}I0aT8_F>pgF)PdYF9l;=;B9nAQj zsz=<&o5cyzZ-e}avJc{KCgv~E?L$zJ^x>G;3Wj7*)1KZkL`=;zZ3mOE~4+nzllD!XZ>%`{{ivyd%$h?A3E!Qa@Z2yZx-cOSH;@2G+e{9d_2mTSi=_9xHzfo`TL%&%3(Elj*6XdvU z&|CY0{ofG(R{d|=El>2{?|<8#$)C@U`dH)(UO%-c`>}ldtY7Ml&~g4!Z$*1X7{Bbhsb|0GXS4pxKIVUe9`oMv2QH%L{9yi#=r_lodZX;w{CoY^ z$0DI){Zem~eGC2Ux=x?^mwl}NjGO)3EPmN{Pw#On&bHsN|FY-(Ly!4w*MXbrtvz4A zvu|Jza1`G`{t@4CMMBw+=JnO(t~Wwo{lxV~=wo|+{y<;+HeNUIFFTmkGj3kDS^To^ zrk?$ypUwI&`@AUi|k^k79&0qMO>y6Ndf4bfXeQY1qv!BwZ{$(HQ zKjY(do5e5tZt58~{V4vl|FVzypQ{sOLzq}1=!1rCxSg3c( zZp@C~bp5vDpQZcn9o&BtJ^F_IpVrCtz7y|1vJckJMDO#KBorp zsb~B~*|+d7z5I%@gIWK~8=q5<+%GYIqU?j`7aQ`&c}qRd?bM61gA4hWPF%!4^Tz8) z#?8EmvX8}29pfbFmwHk5vG`N}(us@sul|Mm7oMLQv5xWl&2`Htd;j@qFaOkW-$(NK zDRrXkU^f4$f9b?Ft`Yy-ck?T2E4rcXJ{SU|A;>TE!i;Ta; zkMSclZX(AowrAttLH{pG@4xjCZh_Pic@r_cBtQuTtvzaX8T{g*YzZI)#DwhkL_7~@h8`l)Z>k4OX_2L zRv%8fo}@m!)RFqwp4HdapwH*<0h_;rzv(DDxYVOW=12|RANS_()cnm}L+x_jzlO2m z7_5r28?*T@_v8Arr~%OS8}I5UJDAl^jsNwoXU!;1(NZIr2 z=TgtLPkGvY{`|hB`_zSa|KeHA_8Fk!+?iOFiem&*PoU-`Ss0uh5gc7c-xt>|nNj)AQRJw0!?9E^>a`aQ=bb&Oac}FR^{p zzpj%`ls$ib!Q4E~`ANom56)3`4>~M6neRW(eHGUXkk9@2{9lwE%*2oH#`_05XMvlZ zzpOo{$5n7_{=e2Aa-W<(_1swG{b&6AIkkQ~@8PVI^Pc$^ zWgk8N9AW)>9yRWw?D_F`oz@Ah8=~xBX8gSW^Cz6t@wtU4dtQ%vdDQR!q~@*2{Kxi; ze;*OMn_&OcH1(fN0p^@{jGK7V5TqU?%)9mC`2=eLx&ve{pRd06MKu=y)!{LK$E z_k59o;6cW0{OYwY^Xdmqj$DoRY;P^_t?QT8N1x^2@1CYN#EM)M?+(p@=D}0Fk-2#I zWY6wQs1Um|ab{s>Z@-W_=OaJZ*)R3UFYE2j7xSdNiOTC({%mK5yN5j)K~>q45u?wR z*q&DQGXMX>{7)Ufz1DLj;|fUH$^H`^Wd}3$<27a{Q|@edqG#-wAOzq;D%m$Z}pnU1XA*q*6huA5pXW9{wap?8J?*5X45JA7XHtm{Yv=3yygGs;V(;^ zvKzDhi$i`Lf1yDg?_*Bc$Mk4>lI^7HIQOX!?3dZeeEx0x5kJSDI*z~7bg*~&xL3#i ztKHdWcHhXuKE#0k!*rmz^FH^!9d+?=tM2dJ*V4Uv`GB9IjHuc2KVHK|jAd+3b3f3d zZ>Sw!$1$hQDZ4SNukJt>AH&##e5+Hv*irVuTb-W&srmxG?d=t4Z?h1CDEr{8R?q)b zJ%80{Zy!OP#>>BUlznh2@A|aJ(z=c8+hgTgrZYuXcNSduxvCjL`F~I`u}` zNA&jA9@iP6<6C{|jk1sE?bMCyjL`8{1=Jg5&+5I#>JyP?z4mHR_7fxh$5W8{1o}@x z$F-xS>?3-6Dvj%m(DPRT)Ei|V(R0nCeNx&R*|*X!$N$2uf3K0|U?k>0YlrjSD0_DPFZJBJ z?L2>R-PJmKL9V}EL%a{|Z2j76{c`=>yY-V}uaDOcYsf#clfC=rE9w3RSGRw7(-UfZ Q#I^z3GQKBT!Dkl!3l(?w1poj5 diff --git a/technology/freepdk45/gds_lib/replica_cell_1rw.gds b/technology/freepdk45/gds_lib/replica_cell_1rw.gds index 706f0220c82b4785b5e1382a90b47a858b280e58..076a80496d5bd062c30cf7b077ef4f833e5535ab 100644 GIT binary patch literal 18512 zcmeI3U5H&*8HU&1`|Le)CR0hZF~k;I1)_nI>htOPA zhB7p7Dnkf+cUJ4`>mS1B77~po@cE!9oeYz!!#sZo#p`H)fW$ZcBZTTJqI6^4e@pZ~ zAN@v)>))S@k856o_X%h9g%HY@@g0%Uizm|kFQ1|xK9Iip+byN1{fK)2i7A}SU-@3o zA1QrOq~lkg;&q4#TK+%KQu@GO_2(~y11#G1Aojv z{FZmb7Zd&O`(Hcn`tA6=ZdIpStly5`$E`ZuV*Pgfo_E!0KYwjq59+t$_xQ?_=3SJY zo0r112Y!s<2ksA_alcc#@gn-i^`CvU zwHqw|=WDkp9ZdFrtiL$x@kz!lA8g6^u{{}otbf@5Vf@&hjL-J+2=X>3e>43^I)659 z_~(tE{@9+3U)|vOBbmSI=PjAP*nZLclW%%_lJV;sTQYuZPsShXAC7+*e=Fl>p6BIn zrf25Q#tr|x@zWpM6XVC)@HDP@*x5``M_7wQ>63?3^)uFwx!cS5PR1>MG)&) z=>JdS_`!|w)t(=J{pkGsNv|JG`Mv*Ww>%8vOV9c1_j{g5`fKc6MdmNIC+2_FZr8~t zZpB~y+T)Y-P3~z)e{4_2-)?{X`#64ZEAg2h=6PQJr04R_{`0zdMeEz2| zfT;T!rSHnu&xQNFZl}8<5uf)z;~S+X<8Ol>_npNjH;fx8wKv*K?lhcmMgT_TK&1 z@q7Jhoz-(gln!>|*Zuq>#`(R!bo_(+7xmX)Kh>U&->W~}H{$&In|AvjzK-V&&Rs~p z@9_*uln!>sztR7U` zk<44kT8fmO%OCeIJpUni{!@ITrS!r1Wv~9}ksc+u0zrX=U=`2n{PVb z&viVuC-dKp&-LEoim_k0_`Ltw&)GVF^~=^BQ2J(m_H&+prccxL(~ZymbN!n!_A3{k zfq`O|gWFVQbb-^|bb7W<*NqI57BpW|m7l0J@Kl%9*<^|Rmfi(B=x zpY!5NAM}4m@A-QO_a2^^0pz?Dzi25P?2ftkuYoQTk^78uP~QX+G+HQ979J{{i$F-RJKQT<`e%g(y9& zXZ$!ns&Dr3GcLz3N>9i4d1Ib6f8F&%dOH6;ZjDpp7NzInGjF<1K2dtkU%lw{M{>R< z$fL;mi|yI`uN?LKul&vPKcn=csr-)}KjPkl`JP1bcg$xw|B=!s>G%ceh2tcrKLc_9 ziPF>eAL5LxpKktj--=tyKgWs>?}Ix%|4!*-di-PSXFL2_C$w&e(!oUip0mPc!apv5lQ*nB!{m)vzf)0qzJ4#YzxuF0f63}r ze16xG>wj!t)DLdaWt0m3ex|d3@i}g|PGjBX{l~RSl%Br-7JlYUc~ag)>FNAot;E>@ z>y%{umUpz2p54D(;p=C0E%N^yat1Da3`PF#meRrG{Xf=U+=qDo!u)~Dk753fw3H4e zCeA%H`c6mFM_m)XT`{-<6*KOFe$R_i>#hxqgOMTT0KZpT!^C zPulu>Z%g`Pd-DFR-s67K_8+HP(jVKC{_gn!{q@`3PtqUT6Mj5@&%nd?XOQom8{VI- zJ+uDcy^HUueE*`K?_Z+y-23Z>_m5w>zXs`#?TP+lta$I`btL2R{a2Kpi_d=ZJ;mN1 z|Kk0hMoLe=zj)s4oCSHJkNFd&r~Te<#$o?gzUuuKrRV(253eH`mw6MV%fE`$`2Ov! zC3@QIF2ZtH-C3bhp2Gjf7wu_|eDM%E!M}FST>VS*^~b#W_@T_z_?_%+1-^Cl+WL;O z{O^V584Wo*g*<;EG<%v8YrV?4s(Z3l@57Z3_{jJdr97E(N;h^ZqvJ>0(`+Z*$C;r& z+$Eh%$1nC;yZtgiA1m7_J@2nx^y@gY^zmfhDLwD6+0U0SZuFbGYR;@vx-l_+R1{AI zvAe8L9RYU;?+mAOW71#TX5Sx*+uT?DNR)0&_|bMoANPfQqI5Eyf17_+G<-afvXe<8 ze5M-{@!e-90Pu51O}{98u(R&e&%)2VD^JRsC_R@y+Zpk%`*<>d8n$0^jF>mmjmi1D z)c)%B_+$p{$&CA0v?sH-C;LA(f0wu4=h)t0G1sgc)_^EIT|Wyy?-Aumc@w3l^XJbi z+kxV_#kws&(o#COs9!8m@nmbU{?Gnp9M^5F(-*dWU*7B2<@NlJdv(ybn9dmw(5nNj-nX+QVO^c&&l-j#l% z^rRnk`z-yD@NwTvzfpS9j~wBxknxT1*{_PC^o*bVu1|XZ>viwBo3a;d%2&Bu+Q&G(wdANP7Hs>VfNw z@KvYreWLV?-%ed{oe@6#OJnmJrDyzhDunBd@bgrN@r}|me*UXEJ3Rz>s#yN1rS!q6 zV(aPxBiFgiq2YD)9z0y+p;8eU9f2_Ye?zLAQM;`A) z{{AaUH+J_fz4-L;S7;;N8R_Rcq)~eRuNqd{^^4!FkH=*n{3D(0)o;g-ddKz6{>ZZ+ z?%zg~zJKAr8cRgndu?<6Y<_GWZ0$n+ozgd(KV2uEDE;F4?N?{4Ge)cf{8if4KT>*s z{n_UHUC#CEbJXmQ#C^xP=ly4tp1l7Se*0Bgc~ag)>B;=zx%G_KsS)+dU!_^UM$~U? z@2=mA`t7`XEuJ5K4>AwuzkbuJkNf!@{*g{Dp1&9G`Fq~akJsD%7v_rp-RQtCO`*mw PW1@7>){iCZAtvGf8a(U__5DzeCEjEhmRcF*m(He#~%xmX$Z~rWhg`Q zx-x{YcSm*c;>8c(a~p}mkKpruQFby+ULWS^LnvOcauDD6ObFFUQTD5;$9KPkHaz64 zJ{Usz9NG{md+|`Z{pF9ShYqB!{$@+r(|Y(li2Bbv8Nc#f9zRm{>iM+)>SL^j4`}g! zZ%f$+`l>&EAxuxgKgRF64?~Ob6J?*C?D_BLIesCmKIx>6<0r}vcE^7U^&U5CC*rtv zgU3&lJ=cE54doU;>KepPlzpIYdht7mHZcF;zaM|u$zJ~l`WS!cE$;9yCfeWEzqIN6 z?dUykm8T2lZ%6O_R-P`Hza72DU3uD%AIf505AwI8cmIl$#$A*>J$~+AG)Z{QEy)VsgLDJ z|JBVNKa%mQe%zAri{)2MKl!@*C+WZDoQb6WSf2DhRzK|j(ElR+XPoE7Z)VSopYl<3B66deVuD=&N72 zf0DY%11+hKerBTig)mdGTZXV|ljytT(U!Gka$InE%t4ef(Fy4I=MF z*}B~;~<@^_APy62jJ?5SH0o89&_OySGo8q+kM0m-AngJ?DR{p8cjD^`G<3{DZRR{P*;TyTvbZ5q+=y z&{_W@sgLE|`7;@L{@zmk6`cQi{&{ZDIZNjrQFbuVf6ssI^IX6C`>)DVdLMVKv)VUA z*}<;=x*vb|*xdc4qaVy)jW{fkbxQnvq;y+eD9KRAdz;PrO8Nadm@_xh)@go_x^6xEW&&7}D z55E79eE%uF)>8Jt`(HEJ*>3uuF}5q`pYxCJT(fzI^~cs7Q1-$5S1_ILfW-CX~~Mf|h>w%&t$_hbJ>*}-i5X7#Z4 z+x{VPKk@I+>UrK`J^2-72a|gCpZ-be*nd&>T>HCvp0{lO5aah=PS1AE^Dq0L{nz#O z-=oNr-=O~>$F2BDOWDD0|9kq$DXc#gG$8eSzY%2z6Z&|*IOAN~k9ORR_(e{meR?LP zhrc@!|1(bNczzXSzns3txbb_MH@RMv9Za|XAliH$?FYHu@#hz!?BRSykN2bc2Jb)p zvj3v&Y5zWMjI+kCyMD-?j=%R?{Zzk2*>nCGH`S9)ls%`f&UyZk9IpxDC^G+Ic{cuQ z`#t_^zxMdgDEt0Y{Kxhmejh;WFF5Vzl|SeBqc{A2z*Whc}9ADcg0q1QU0bwiXLOynQ(^)DP}C+B^Q7>Kgx z#-H_T=*i|EAagiUb};FGsUH`=$!nIMVe(qc+f`BaeEwc*Jow<{tzD6_r{~{N&$ua0n~xvX%BMVkN#?Kp%r27o8_SpLAGVk&QWU@c z)jNMzH^TS?Vh66=f=X|1DLa^q-&j5Ox|QGgo;SS@ma^ye|KiWCCvE+Gu%)fPUY?x4 z)jM2I+WF&jOX_2JQr~?)puT>y>q+Wkc|wo<_bfELKZCq?UUGl7^33{!`wH)=ynj*8 z`p8DS(l777BK5I6sb{-+PqF(W_F}s~M#`SPzj)m2 zodt1Pg^uwPWl!t9ee}b2uHkpk*nUy=oSyMvJ(7MIH&J%!*AW`u|K3odrOmD)OvCyP zWC?%!7yqWan@2x;6pcV4O)|BAiZ*_UwND())W*-r-dNyU*Ke%%J29-I49+QT8OuN!M{?s1J9`PNw}Ad#&7l zGC&Ja#)KYaXZ3MiK!(zP;JCJB2|dRh^_bDn@kPpBCXKQiGkRz) zxZYj_kUygAgPTbwe_W?}(uuM!_38OzCnL-~dl^6uH+&f|V%*GbOpf2R)>n7Mof)*9 z8S_}Qo!QHi?YEt4+vcB-vE6Jj)|@vs_K~uu=g(4aFVlQkxuW>_eq|?6>|4y+@oxX|~fU92wac&c32fJ%ePtP+m>ygy)RwT-v)+29mZk)dA zq>kriQTDVRG2*Qd{_R!>z1<2UWzXr^?)s3ozdrBnpHcQh>HgcR2K=H5uWZrW>vDEqzX{@beu>KUP{PUHJT z*)w{3l|eltbofhS(;H>a=K1>UoDW%HIF2hV^#+;&-g8?EUp;i{tnIoWDLs z&7MfiJB~f)pHcSY{9EdIe!BAbVXu42^VG=wcc1645&0X-yX*Hde>-=t<^JJwka5`j v`c17quIG37M|N_#|6aZQchmdFEA9CUW7YYGpEQLUAF)$p>&FVt5R>p<;x6aY From b1bb9151c41d5f2704e328d212dfe95537f3f906 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 2 May 2022 15:43:14 -0700 Subject: [PATCH 168/229] Reimplement off grid pins. Long pins aren't accessed on end pins anymore. Fix problem with multiple non-enclosed space causing blockages. Add partial pin offgrid enclosure algorithm. --- compiler/base/hierarchy_layout.py | 73 +++++------ compiler/base/pin_layout.py | 7 ++ compiler/modules/bank.py | 34 ++--- compiler/modules/control_logic.py | 42 ++++--- compiler/modules/delay_chain.py | 22 +--- compiler/modules/hierarchical_decoder.py | 12 +- compiler/modules/hierarchical_predecode.py | 2 +- compiler/modules/local_bitcell_array.py | 5 +- compiler/modules/port_address.py | 15 +-- compiler/modules/precharge_array.py | 2 +- compiler/modules/replica_bitcell_array.py | 49 +++++--- compiler/modules/wordline_driver_array.py | 11 +- compiler/router/pin_group.py | 6 +- compiler/router/router.py | 139 ++++++++++++++++++--- compiler/router/supply_tree_router.py | 6 +- compiler/sram/sram_base.py | 2 +- compiler/tests/configs/config.py | 2 +- 17 files changed, 274 insertions(+), 155 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index a37ccb2b..5c986d75 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -419,13 +419,6 @@ class layout(): pin.width(), pin.height()) - def copy_layout_pins(self, instance, prefix=""): - """ - Create a copied version of the layout pin at the current level. - You can optionally rename the pin to a new name. - """ - for pin_name in self.pin_map.keys(): - self.copy_layout_pin(instance, pin_name, prefix + pin_name) def connect_row_locs(self, from_layer, to_layer, locs, name=None, full=False): """ @@ -608,12 +601,11 @@ class layout(): - def route_vertical_pins(self, name, insts=None, layer=None, xside="cx", yside="cy", num_pins=2, full_width=True): + def route_vertical_pins(self, name, insts=None, layer=None, xside="cx", yside="cy", full_width=True): """ Route together all of the pins of a given name that vertically align. Uses local_insts if insts not specified. Uses center of pin by default, or right or left if specified. - num_pins specifies whether to add a single pin or multiple pins (equally spaced) TODO: Add equally spaced option for IR drop min, right now just 2 """ @@ -660,8 +652,10 @@ class layout(): if last_via: via_width=last_via.mod.second_layer_width + via_height=last_via.mod.second_layer_height else: via_width=None + via_height=0 if full_width: bot_y = 0 @@ -669,21 +663,19 @@ class layout(): else: bot_y = min([pin.by() for (inst,pin) in v]) top_y = max([pin.uy() for (inst,pin) in v]) - top_pos = vector(x, top_y) - bot_pos = vector(x, bot_y) + top_pos = vector(x, top_y + 0.5 * via_height) + bot_pos = vector(x, bot_y - 0.5 * via_height) - if num_pins==2: - self.add_layout_pin_rect_ends(name=name, - layer=pin_layer, - start=top_pos, - end=bot_pos, - width=via_width) - else: - self.add_layout_pin_segment_center(text=name, - layer=pin_layer, - start=top_pos, - end=bot_pos, - width=via_width) +# self.add_layout_pin_rect_ends(name=name, +# layer=pin_layer, +# start=top_pos, +# end=bot_pos, +# width=via_width) + self.add_layout_pin_segment_center(text=name, + layer=pin_layer, + start=top_pos, + end=bot_pos, + width=via_width) def add_layout_pin_rect_ends(self, name, layer, start, end, width=None): @@ -707,12 +699,13 @@ class layout(): start=bot_rect.rc(), end=top_rect.lc()) - def route_horizontal_pins(self, name, insts=None, layer=None, xside="cx", yside="cy", num_pins=2, full_width=True): + return (bot_rect, top_rect) + + def route_horizontal_pins(self, name, insts=None, layer=None, xside="cx", yside="cy", full_width=True): """ Route together all of the pins of a given name that horizontally align. Uses local_insts if insts not specified. Uses center of pin by default, or top or botom if specified. - num_pins specifies whether to add a single pin or multiple pins (equally spaced) TODO: Add equally spaced option for IR drop min, right now just 2 """ @@ -760,8 +753,10 @@ class layout(): if last_via: via_height=last_via.mod.second_layer_height + via_width=last_via.mod.second_layer_width else: via_height=None + via_width=0 if full_width: left_x = 0 @@ -769,22 +764,19 @@ class layout(): else: left_x = min([pin.lx() for (inst,pin) in v]) right_x = max([pin.rx() for (inst,pin) in v]) - left_pos = vector(left_x, y) - right_pos = vector(right_x, y) + left_pos = vector(left_x + 0.5 * via_width, y) + right_pos = vector(right_x + 0.5 * via_width, y) - if num_pins==2: - self.add_layout_pin_rect_ends(name=name, - layer=pin_layer, - start=left_pos, - end=right_pos, - width=via_height) - else: - # This adds a single big pin - self.add_layout_pin_segment_center(text=name, - layer=pin_layer, - start=left_pos, - end=right_pos, - width=via_height) +# self.add_layout_pin_rect_ends(name=name, +# layer=pin_layer, +# start=left_pos, +# end=right_pos, +# width=via_height) + self.add_layout_pin_segment_center(text=name, + layer=pin_layer, + start=left_pos, + end=right_pos, + width=via_height) def add_layout_end_pin_segment_center(self, text, layer, start, end): """ @@ -1123,7 +1115,6 @@ class layout(): Add a minimum area retcangle at the given point. Either width or height should be fixed. """ - min_area = drc("minarea_{}".format(layer)) if min_area == 0: return diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index cc13e049..7ba6cdca 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -174,6 +174,10 @@ class pin_layout: def intersection(self, other): """ Check if a shape overlaps with a rectangle """ + + if not self.overlaps(other): + return None + (ll, ur) = self.rect (oll, our) = other.rect @@ -182,6 +186,9 @@ class pin_layout: min_y = max(ll.y, oll.y) max_y = min(ur.y, our.y) + if max_x - min_x == 0 or max_y - min_y == 0: + return None + return [vector(min_x, min_y), vector(max_x, max_y)] def xoverlaps(self, other): diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index bd3fc0a4..718f8f62 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -229,7 +229,7 @@ class bank(design.design): # UPPER LEFT QUADRANT # To the left of the bitcell array above the predecoders and control logic - x_offset = self.m2_gap + self.port_address[port].width + x_offset = self.decoder_gap + self.port_address[port].width self.port_address_offsets[port] = vector(-x_offset, self.main_bitcell_array_bottom) @@ -272,7 +272,7 @@ class bank(design.design): # LOWER RIGHT QUADRANT # To the right of the bitcell array - x_offset = self.bitcell_array_right + self.port_address[port].width + self.m2_gap + x_offset = self.bitcell_array_right + self.port_address[port].width + self.decoder_gap self.port_address_offsets[port] = vector(x_offset, self.main_bitcell_array_bottom) @@ -364,9 +364,9 @@ class bank(design.design): self.num_col_addr_lines = 0 self.col_addr_bus_width = self.m2_pitch * self.num_col_addr_lines - # A space for wells or jogging m2 - self.m2_gap = max(2 * drc("pwell_to_nwell") + drc("nwell_enclose_active"), - 3 * self.m2_pitch, + # Gap between decoder and array + self.decoder_gap = max(2 * drc("pwell_to_nwell") + drc("nwell_enclose_active"), + 2 * self.m2_pitch, drc("nwell_to_nwell")) def add_modules(self): @@ -400,11 +400,10 @@ class bank(design.design): self.port_data = [] self.bit_offsets = self.get_column_offsets() for port in self.all_ports: - temp_pre = factory.create(module_type="port_data", - sram_config=self.sram_config, - port=port, - bit_offsets=self.bit_offsets) - self.port_data.append(temp_pre) + self.port_data.append(factory.create(module_type="port_data", + sram_config=self.sram_config, + port=port, + bit_offsets=self.bit_offsets)) if(self.num_banks > 1): self.bank_select = factory.create(module_type="bank_select") @@ -606,15 +605,22 @@ class bank(design.design): def route_supplies(self): """ Propagate all vdd/gnd pins up to this level for all modules """ + # Copy only the power pins already on the power layer # (this won't add vias to internal bitcell pins, for example) - for inst in self.insts: - self.copy_power_pins(inst, "vdd", add_vias=False) - self.copy_power_pins(inst, "gnd", add_vias=False) + + # This avoids getting copy errors on vias and other instances + all_insts = [self.bitcell_array_inst] + self.port_address_inst + self.port_data_inst + if hasattr(self, "column_decoder_inst"): + all_insts += self.column_decoder_inst + + for inst in all_insts: + self.copy_layout_pin(inst, "vdd") + self.copy_layout_pin(inst, "gnd") if 'vpb' in self.bitcell_array_inst.mod.pins and 'vnb' in self.bitcell_array_inst.mod.pins: for pin_name, supply_name in zip(['vnb','vpb'],['gnd','vdd']): - self.copy_power_pins(self.bitcell_array_inst, pin_name, new_name=supply_name) + self.copy_layout_pin(self.bitcell_array_inst, pin_name, new_name=supply_name) # If we use the pinvbuf as the decoder, we need to add power pins. # Other decoders already have them. diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index df7a8241..79ce3e30 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -715,12 +715,17 @@ class control_logic(design.design): pin_layer = self.dff.get_pin("vdd").layer supply_layer = self.supply_stack[2] + + # FIXME: We should be able to replace this with route_vertical_pins instead + # but we may have to make the logic gates a separate module so that they + # have row pins of the same width max_row_x_loc = max([inst.rx() for inst in self.row_end_inst]) min_row_x_loc = self.control_x_offset vdd_pin_locs = [] gnd_pin_locs = [] + last_via = None for inst in self.row_end_inst: pins = inst.get_pins("vdd") for pin in pins: @@ -728,10 +733,10 @@ class control_logic(design.design): row_loc = pin.rc() pin_loc = vector(max_row_x_loc, pin.rc().y) vdd_pin_locs.append(pin_loc) - self.add_via_stack_center(from_layer=pin_layer, - to_layer=supply_layer, - offset=pin_loc, - min_area=True) + last_via = self.add_via_stack_center(from_layer=pin_layer, + to_layer=supply_layer, + offset=pin_loc, + min_area=True) self.add_path(pin_layer, [row_loc, pin_loc]) pins = inst.get_pins("gnd") @@ -740,29 +745,38 @@ class control_logic(design.design): row_loc = pin.rc() pin_loc = vector(min_row_x_loc, pin.rc().y) gnd_pin_locs.append(pin_loc) - self.add_via_stack_center(from_layer=pin_layer, - to_layer=supply_layer, - offset=pin_loc, - min_area=True) + last_via = self.add_via_stack_center(from_layer=pin_layer, + to_layer=supply_layer, + offset=pin_loc, + min_area=True) self.add_path(pin_layer, [row_loc, pin_loc]) + + if last_via: + via_height=last_via.mod.second_layer_height + via_width=last_via.mod.second_layer_width + else: + via_height=None + via_width=0 min_y = min([x.y for x in vdd_pin_locs]) max_y = max([x.y for x in vdd_pin_locs]) - bot_pos = vector(max_row_x_loc, min_y) - top_pos = vector(max_row_x_loc, max_y) + bot_pos = vector(max_row_x_loc, min_y - 0.5 * via_height) + top_pos = vector(max_row_x_loc, max_y + 0.5 * via_height) self.add_layout_pin_segment_center(text="vdd", layer=supply_layer, start=bot_pos, - end=top_pos) + end=top_pos, + width=via_width) min_y = min([x.y for x in gnd_pin_locs]) max_y = max([x.y for x in gnd_pin_locs]) - bot_pos = vector(min_row_x_loc, min_y) - top_pos = vector(min_row_x_loc, max_y) + bot_pos = vector(min_row_x_loc, min_y - 0.5 * via_height) + top_pos = vector(min_row_x_loc, max_y + 0.5 * via_height) self.add_layout_pin_segment_center(text="gnd", layer=supply_layer, start=bot_pos, - end=top_pos) + end=top_pos, + width=via_width) self.copy_layout_pin(self.delay_inst, "gnd") self.copy_layout_pin(self.delay_inst, "vdd") diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index af446bbd..fe039411 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -172,25 +172,9 @@ class delay_chain(design.design): self.add_path("m2", [z_pin.center(), mid1_point, mid2_point, next_a_pin.center()]) def route_supplies(self): - # Add power and ground to all the cells except: - # the fanout driver, the right-most load - # The routing to connect the loads is over the first and last cells - # We have an even number of drivers and must only do every other - # supply rail - if True or OPTS.experimental_power: - left_load_insts = [self.load_inst_map[x][0] for x in self.driver_inst_list] - right_load_insts = [self.load_inst_map[x][-1] for x in self.driver_inst_list] - self.route_vertical_pins("vdd", left_load_insts, xside="lx") - self.route_vertical_pins("gnd", right_load_insts, xside="rx") - else: - for inst in self.driver_inst_list: - load_list = self.load_inst_map[inst] - for pin_name in ["vdd", "gnd"]: - pin = load_list[0].get_pin(pin_name) - self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0)) - - pin = load_list[-2].get_pin(pin_name) - self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0)) + self.route_vertical_pins("vdd", self.driver_inst_list, xside="lx") + right_load_insts = [self.load_inst_map[x][-1] for x in self.driver_inst_list] + self.route_vertical_pins("gnd", right_load_insts, xside="rx") def add_layout_pins(self): diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index 2b173969..40c2a93a 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -595,14 +595,12 @@ class hierarchical_decoder(design.design): # Leave these to route in the port_address all_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst for inst in all_insts: - self.copy_layout_pin(inst, "vdd") - self.copy_layout_pin(inst, "gnd") + self.copy_layout_pin(inst, "vdd") + self.copy_layout_pin(inst, "gnd") + + self.route_vertical_pins("vdd", self.and_inst, xside="rx",) + self.route_vertical_pins("gnd", self.and_inst, xside="lx",) - for inst in self.and_inst: - for pin in inst.get_pins("vdd"): - self.add_power_pin("vdd", pin.rc()) - for pin in inst.get_pins("gnd"): - self.add_power_pin("gnd", pin.lc()) def route_predecode_bus_outputs(self, rail_name, pin, row): diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index 0d7f31a3..8ae3a08d 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -395,7 +395,7 @@ class hierarchical_predecode(design.design): height=top_pin.uy() - self.bus_pitch) # This adds power vias at the top of each cell # (except the last to keep them inside the boundary) - for i in self.inv_inst[:-1:2] + self.and_inst[:-1:2]: + for i in [self.inv_inst[0], self.inv_inst[-2], self.and_inst[0], self.and_inst[-2]]: pins = i.get_pins(n) for pin in pins: self.copy_power_pin(pin, loc=pin.uc()) diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index 49e8ed76..0d3cfd12 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -162,14 +162,15 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): # FIXME: Replace this with a tech specific paramter driver_to_array_spacing = 3 * self.m3_pitch - self.wl_insts[0].place(vector(0, self.cell.height)) + self.wl_insts[0].place(vector(0, + self.bitcell_array.get_replica_bottom() + self.cell.height)) self.bitcell_array_inst.place(vector(self.wl_insts[0].rx() + driver_to_array_spacing, 0)) if len(self.all_ports) > 1: self.wl_insts[1].place(vector(self.bitcell_array_inst.rx() + self.wl_array.width + driver_to_array_spacing, - 2 * self.cell.height + self.wl_array.height), + self.bitcell_array.get_replica_top() + self.cell.height), mirror="XY") self.height = self.bitcell_array.height diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index 2757a86f..a96a556e 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -76,22 +76,19 @@ class port_address(design.design): def route_supplies(self): """ Propagate all vdd/gnd pins up to this level for all modules """ - self.route_vertical_pins("vdd", [self.row_decoder_inst]) - self.route_vertical_pins("gnd", [self.row_decoder_inst]) - self.route_vertical_pins("vdd", [self.wordline_driver_array_inst]) if layer_props.wordline_driver.vertical_supply: - self.route_vertical_pins("gnd", [self.wordline_driver_array_inst]) self.copy_layout_pin(self.rbl_driver_inst, "vdd") else: rbl_pos = self.rbl_driver_inst.get_pin("vdd").rc() self.add_power_pin("vdd", rbl_pos) self.add_path("m4", [rbl_pos, self.wordline_driver_array_inst.get_pins("vdd")[0].rc()]) - - vdd_pins = self.row_decoder_inst.get_pins("vdd") + self.wordline_driver_array_inst.get_pins("vdd") - self.connect_row_pins(self.route_layer, vdd_pins) - gnd_pins = self.row_decoder_inst.get_pins("gnd") + self.wordline_driver_array_inst.get_pins("gnd") - self.connect_row_pins(self.route_layer, gnd_pins) + self.copy_layout_pin(self.wordline_driver_array_inst, "vdd") + self.copy_layout_pin(self.wordline_driver_array_inst, "gnd") + + self.copy_layout_pin(self.row_decoder_inst, "vdd") + self.copy_layout_pin(self.row_decoder_inst, "gnd") + # Also connect the B input of the RBL and_dec to vdd if OPTS.local_array_size == 0: rbl_b_pin = self.rbl_driver_inst.get_pin("B") diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index c820dfc1..372a5629 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -83,7 +83,7 @@ class precharge_array(design.design): def add_layout_pins(self): en_pin = self.pc_cell.get_pin("en_bar") - self.route_horizontal_pins("en_bar", layer=self.en_bar_layer, num_pins=1) + self.route_horizontal_pins("en_bar", layer=self.en_bar_layer) for inst in self.local_insts: self.add_via_stack_center(from_layer=en_pin.layer, to_layer=self.en_bar_layer, diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index e1a3cbb8..785bb62b 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -331,6 +331,7 @@ class replica_bitcell_array(bitcell_base_array): self.translate_all(array_offset.scale(-1, -1)) # Add extra width on the left and right for the unused WLs + self.width = self.dummy_col_insts[1].rx() + self.unused_offset.x self.height = self.dummy_row_insts[1].uy() @@ -340,6 +341,12 @@ class replica_bitcell_array(bitcell_base_array): self.route_unused_wordlines() + lower_left = self.find_lowest_coords() + upper_right = self.find_highest_coords() + self.width = upper_right.x - lower_left.x + self.height = upper_right.y - lower_left.y + self.translate_all(lower_left) + self.add_boundary() self.DRC_LVS() @@ -356,6 +363,18 @@ class replica_bitcell_array(bitcell_base_array): def get_main_array_right(self): return self.bitcell_array_inst.rx() + def get_replica_top(self): + return max([x.uy() for x in self.replica_col_insts if x] + [self.get_main_array_top()]) + + def get_replica_bottom(self): + return min([x.by() for x in self.replica_col_insts if x] + [self.get_main_array_bottom()]) + + def get_replica_left(self): + return min([x.lx() for x in self.replica_col_insts if x] + [self.get_main_array_left()]) + + def get_replica_right(self): + return min([x.rx() for x in self.replica_col_insts if x] + [self.get_main_array_right()]) + def get_column_offsets(self): """ Return an array of the x offsets of all the regular bits @@ -567,14 +586,15 @@ class replica_bitcell_array(bitcell_base_array): top_loc = vector(self.width + offset_multiple * self.vertical_pitch, self.height) layer = self.supply_stack[2] - self.add_path(layer, [bot_loc, top_loc]) - self.add_layout_pin_rect_center(text=name, - layer=layer, - offset=top_loc) - self.add_layout_pin_rect_center(text=name, - layer=layer, - offset=bot_loc) +# self.add_layout_pin_rect_ends(text=name, +# layer=layer, +# start=bot_loc, +# end=top_loc) + self.add_layout_pin_segment_center(text=name, + layer=layer, + start=bot_loc, + end=top_loc) return (bot_loc, top_loc) @@ -590,14 +610,15 @@ class replica_bitcell_array(bitcell_base_array): right_loc = vector(self.width, self.height + offset_multiple * self.horizontal_pitch) layer = self.supply_stack[0] - self.add_path(layer, [left_loc, right_loc]) - self.add_layout_pin_rect_center(text=name, - layer=layer, - offset=left_loc) - self.add_layout_pin_rect_center(text=name, - layer=layer, - offset=right_loc) +# self.add_layout_pin_rect_ends(text=name, +# layer=layer, +# start=left_loc, +# end=right_loc) + self.add_layout_pin_segment_center(text=name, + layer=layer, + start=left_loc, + end=right_loc) return (left_loc, right_loc) diff --git a/compiler/modules/wordline_driver_array.py b/compiler/modules/wordline_driver_array.py index 276194ee..63c39a7c 100644 --- a/compiler/modules/wordline_driver_array.py +++ b/compiler/modules/wordline_driver_array.py @@ -77,11 +77,12 @@ class wordline_driver_array(design.design): Add vertical power rails. """ - for inst in self.wld_inst: - for pin in inst.get_pins("vdd"): - self.add_power_pin("vdd", pin.rc()) - #self.copy_layout_pin(inst, "vdd") - self.copy_layout_pin(inst, "gnd") + if layer_props.wordline_driver.vertical_supply: + self.route_vertical_pins("vdd", self.wld_inst) + self.route_vertical_pins("gnd", self.wld_inst) + else: + self.route_vertical_pins("vdd", self.wld_inst, xside="rx",) + self.route_vertical_pins("gnd", self.wld_inst, xside="lx",) def create_drivers(self): diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 5e6d6f89..d67200d5 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -158,7 +158,7 @@ class pin_group: # Now add the right name for pin in new_pin_list: pin.name = self.name - + debug.check(len(new_pin_list) > 0, "Did not find any enclosures.") @@ -424,7 +424,7 @@ class pin_group: debug.check(len(self.grids) > 0, "Cannot seed an grid empty set.") common_blockages = self.router.get_blocked_grids() & self.grids - + # Start with the ll and make the widest row row = [ll] # Move in dir1 while we can @@ -641,7 +641,7 @@ class pin_group: # way than blockages. blockages = sufficient | insufficient | blockage_in_tracks self.blockages.update(blockages) - + # If we have a blockage, we must remove the grids # Remember, this excludes the pin blockages already blocked_grids = self.router.get_blocked_grids() diff --git a/compiler/router/router.py b/compiler/router/router.py index fd00d98d..94a4c432 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -229,9 +229,9 @@ class router(router_tech): # Enclose the continguous grid units in a metal # rectangle to fix some DRCs - start_time = datetime.now() - self.enclose_pins() - print_time("Enclosing pins", datetime.now(), start_time, 4) + #start_time = datetime.now() + #self.enclose_pins() + #print_time("Enclosing pins", datetime.now(), start_time, 4) # MRG: Removing this code for now. The later compute enclosure code # assumes that all pins are touching and this may produce sets of pins @@ -670,6 +670,25 @@ class router(router_tech): return set([best_coord]) + def divide_pin_to_tracks(self, pin, tracks): + """ + Return a list of pin shape parts that are in the tracks. + """ + overlap_pins = [] + for track in tracks: + track_pin = self.convert_track_to_shape_pin(track) + overlap_rect = track_pin.intersection(pin) + if not overlap_rect: + continue + else: + overlap_pin = pin_layout(pin.name, + overlap_rect, + pin.layer) + overlap_pins.append(overlap_pin) + + return overlap_pins + + def convert_pin_coord_to_tracks(self, pin, coord): """ Return all tracks that an inflated pin overlaps @@ -893,6 +912,8 @@ class router(router_tech): This will mark the grids for all pin components as a source. Marking as source or target also clears blockage status. """ + self.source_name = pin_name + self.source_components = [] for i in range(self.num_pin_components(pin_name)): self.add_pin_component_source(pin_name, i) @@ -904,6 +925,8 @@ class router(router_tech): This will mark the grids for all pin components as a target. Marking as source or target also clears blockage status. """ + self.target_name = pin_name + self.target_components = [] for i in range(self.num_pin_components(pin_name)): self.add_pin_component_target(pin_name, i) @@ -1009,6 +1032,8 @@ class router(router_tech): """ This will mark all the cells on the perimeter of the original layout as a target. """ + self.target_name = "" + self.target_components = [] self.rg.add_perimeter_target(side=side) def num_pin_components(self, pin_name): @@ -1017,6 +1042,15 @@ class router(router_tech): """ return len(self.pin_groups[pin_name]) + def set_pin_component_source(self, pin_name, index): + """ + Add the pin component but also set it as the exclusive one. + Used by supply routing with multiple components. + """ + self.source_name = pin_name + self.source_components = [] + self.add_pin_component_source(pin_name, index) + def add_pin_component_source(self, pin_name, index): """ This will mark only the pin tracks @@ -1026,6 +1060,7 @@ class router(router_tech): debug.check(index 1: + self.cell.add_route(layers=self.layers, + coordinates=abs_path, + layer_widths=self.layer_widths) else: - # convert the path back to absolute units from tracks - # This assumes 1-track wide again - abs_path = [self.convert_point_to_units(x[0]) for x in path] - # Otherwise, add the route which includes enclosures - if len(self.layers) > 1: - self.cell.add_route(layers=self.layers, - coordinates=abs_path, - layer_widths=self.layer_widths) - else: - self.cell.add_path(layer=self.layers[0], - coordinates=abs_path, - width=self.layer_widths[0]) + self.cell.add_path(layer=self.layers[0], + coordinates=abs_path, + width=self.layer_widths[0]) + + def create_route_connector(self, path_tracks, pin_name, components): + """ + Find a rectangle to connect the track and the off-grid pin of a component. + """ + + if len(path_tracks) == 0 or len(components) == 0: + return + + # Convert the off-grid pin into parts in each routing grid + offgrid_pin_parts = [] + for component in components: + pg = self.pin_groups[pin_name][component] + for pin in pg.pins: + partial_pin_parts = self.divide_pin_to_tracks(pin, pg.grids) + offgrid_pin_parts.extend(partial_pin_parts) + + # Find the track pin + track_pins = [self.convert_tracks_to_pin(x) for x in path_tracks] + + # Find closest part + closest_track_pin, closest_part_pin = self.find_closest_pin(track_pins, offgrid_pin_parts) + + # Find the bbox of the on-grid track and the off-grid pin part + closest_track_pin.bbox([closest_part_pin]) + + # Connect to off grid pin to track pin with closest shape + self.cell.add_rect(layer=closest_track_pin.layer, + offset=closest_track_pin.ll(), + width=closest_track_pin.width(), + height=closest_track_pin.height()) + + def find_closest_pin(self, first_list, second_list): + """ + Find the closest pin in the lists. Does a stupid O(n^2). + """ + min_dist = None + min_item = None + for pin1 in first_list: + for pin2 in second_list: + if pin1.layer != pin2.layer: + continue + new_dist = pin1.distance(pin2) + if not min_item or new_dist < min_dist: + min_item = (pin1, pin2) + min_dist = new_dist + + return min_item + def add_single_enclosure(self, track): """ @@ -1192,7 +1283,15 @@ class router(router_tech): self.paths.append(grid_utils.flatten_set(path)) self.add_route(path) + self.create_route_connector(path, + self.source_name, + self.source_components) + self.create_route_connector(path, + self.target_name, + self.target_components) self.path_blockages.append(self.paths[-1]) + #self.write_debug_gds("debug_route.gds", False) + #breakpoint() return True else: return False diff --git a/compiler/router/supply_tree_router.py b/compiler/router/supply_tree_router.py index 9450243d..6873999a 100644 --- a/compiler/router/supply_tree_router.py +++ b/compiler/router/supply_tree_router.py @@ -154,7 +154,7 @@ class supply_tree_router(router): print("DST {}: ".format(dest) + str(self.pin_groups[pin_name][dest].grids) + str(self.pin_groups[pin_name][dest].blockages)) self.write_debug_gds("post_{0}_{1}.gds".format(src, dest), False) - #self.write_debug_gds("final_tree_router_{}.gds".format(pin_name), False) + self.write_debug_gds("final_tree_router_{}.gds".format(pin_name), False) #return def route_signal(self, pin_name, src_idx, dest_idx): @@ -180,11 +180,11 @@ class supply_tree_router(router): # Add the single component of the pin as the source # which unmarks it as a blockage too - self.add_pin_component_source(pin_name, src_idx) + self.set_pin_component_source(pin_name, src_idx) # Marks all pin components except index as target # which unmarks it as a blockage too - self.add_pin_component_target(pin_name, dest_idx) + self.set_pin_component_target(pin_name, dest_idx) # Actually run the A* router if self.run_router(detour_scale=detour_scale): diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index f6782597..4bcc1cb3 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -213,7 +213,7 @@ class sram_base(design, verilog, lef): self.add_lvs_correspondence_points() - self.offset_all_coordinates() + #self.offset_all_coordinates() highest_coord = self.find_highest_coords() self.width = highest_coord[0] diff --git a/compiler/tests/configs/config.py b/compiler/tests/configs/config.py index b56c63db..44c3e774 100644 --- a/compiler/tests/configs/config.py +++ b/compiler/tests/configs/config.py @@ -14,6 +14,6 @@ tech_name = OPTS.tech_name nominal_corner_only = True check_lvsdrc = True -route_supplies = False +#route_supplies = False output_name = "sram" From 3e48991acb9e0e75c5e7143b6bbbb8a7890badc9 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 2 May 2022 16:07:05 -0700 Subject: [PATCH 169/229] Skip partial pins if they are too small to prevent DRC overlap errors. --- compiler/router/router.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/compiler/router/router.py b/compiler/router/router.py index 94a4c432..6e5d5b4e 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -674,16 +674,26 @@ class router(router_tech): """ Return a list of pin shape parts that are in the tracks. """ + # If pin is smaller than a track, just return it. + track_pin = self.convert_track_to_shape_pin(list(tracks)[0]) + if pin.width() < track_pin.width() and pin.height() < track_pin.height(): + return [pin] + overlap_pins = [] for track in tracks: track_pin = self.convert_track_to_shape_pin(track) overlap_rect = track_pin.intersection(pin) if not overlap_rect: continue + overlap_pin = pin_layout(pin.name, + overlap_rect, + pin.layer) + + # If pin is smaller than minwidth, in one dimension, skip it. + min_pin_width = drc("minwidth_{0}". format(pin.layer)) + if overlap_pin.width() < min_pin_width and overlap_pin.height() < min_pin_width: + continue else: - overlap_pin = pin_layout(pin.name, - overlap_rect, - pin.layer) overlap_pins.append(overlap_pin) return overlap_pins From 942ab8975440e290ae44b35731d0196c8ddf20dc Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 2 May 2022 16:42:04 -0700 Subject: [PATCH 170/229] Remove debug output. --- compiler/router/supply_tree_router.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/router/supply_tree_router.py b/compiler/router/supply_tree_router.py index 6873999a..a018a129 100644 --- a/compiler/router/supply_tree_router.py +++ b/compiler/router/supply_tree_router.py @@ -154,7 +154,7 @@ class supply_tree_router(router): print("DST {}: ".format(dest) + str(self.pin_groups[pin_name][dest].grids) + str(self.pin_groups[pin_name][dest].blockages)) self.write_debug_gds("post_{0}_{1}.gds".format(src, dest), False) - self.write_debug_gds("final_tree_router_{}.gds".format(pin_name), False) + #self.write_debug_gds("final_tree_router_{}.gds".format(pin_name), False) #return def route_signal(self, pin_name, src_idx, dest_idx): From f8f3f16b1f975c5a5d254b2e5a2c40d071fd7573 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 2 May 2022 16:42:14 -0700 Subject: [PATCH 171/229] Move delay line supply strap for pin access. --- compiler/modules/delay_chain.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index fe039411..f90191ef 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -172,9 +172,11 @@ class delay_chain(design.design): self.add_path("m2", [z_pin.center(), mid1_point, mid2_point, next_a_pin.center()]) def route_supplies(self): - self.route_vertical_pins("vdd", self.driver_inst_list, xside="lx") + # These pins get routed in one cell from the left/right + # because the input signal gets routed on M3 and can interfere with the delay input. + self.route_vertical_pins("vdd", self.driver_inst_list, xside="rx") right_load_insts = [self.load_inst_map[x][-1] for x in self.driver_inst_list] - self.route_vertical_pins("gnd", right_load_insts, xside="rx") + self.route_vertical_pins("gnd", right_load_insts, xside="lx") def add_layout_pins(self): From 50045e54e8801d61c8feaa497f3fd73bc3604d17 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 3 May 2022 11:45:51 -0700 Subject: [PATCH 172/229] Fix a couple supply routing issues. --- compiler/base/hierarchy_layout.py | 22 +++++----- compiler/modules/column_mux_array.py | 5 ++- compiler/modules/replica_bitcell_array.py | 6 ++- compiler/pgates/column_mux.py | 7 ++-- compiler/pgates/precharge.py | 49 ++++++----------------- 5 files changed, 34 insertions(+), 55 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 5c986d75..ee97a7ac 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -657,12 +657,13 @@ class layout(): via_width=None via_height=0 + bot_y = min([pin.by() for (inst,pin) in v]) + top_y = max([pin.uy() for (inst,pin) in v]) + if full_width: - bot_y = 0 - top_y = self.height - else: - bot_y = min([pin.by() for (inst,pin) in v]) - top_y = max([pin.uy() for (inst,pin) in v]) + bot_y = min(0, bot_y) + top_y = max(self.height, top_y) + top_pos = vector(x, top_y + 0.5 * via_height) bot_pos = vector(x, bot_y - 0.5 * via_height) @@ -758,12 +759,13 @@ class layout(): via_height=None via_width=0 + left_x = min([pin.lx() for (inst,pin) in v]) + right_x = max([pin.rx() for (inst,pin) in v]) + if full_width: - left_x = 0 - right_x = self.width - else: - left_x = min([pin.lx() for (inst,pin) in v]) - right_x = max([pin.rx() for (inst,pin) in v]) + left_x = min(0, left_x) + right_x = max(self.width, right_x) + left_pos = vector(left_x + 0.5 * via_width, y) right_pos = vector(right_x + 0.5 * via_width, y) diff --git a/compiler/modules/column_mux_array.py b/compiler/modules/column_mux_array.py index 0fa35af0..36d4080e 100644 --- a/compiler/modules/column_mux_array.py +++ b/compiler/modules/column_mux_array.py @@ -147,13 +147,14 @@ class column_mux_array(design.design): offset=offset, height=self.height - offset.y) - for inst in self.mux_inst: - self.copy_layout_pin(inst, "gnd") + def route_supplies(self): + self.route_horizontal_pins("gnd", self.insts) def add_routing(self): self.add_horizontal_input_rail() self.add_vertical_poly_rail() self.route_bitlines() + self.route_supplies() def add_horizontal_input_rail(self): """ Create address input rails below the mux transistors """ diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 785bb62b..cbfc6ec2 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -507,12 +507,14 @@ class replica_bitcell_array(bitcell_base_array): # There are always vertical pins for the WLs on the left/right if we have unused wordlines self.left_gnd_locs = self.route_side_pin("gnd", "left", left_right_mult) self.right_gnd_locs = self.route_side_pin("gnd","right", left_right_mult) - left_right_mult = 3 + # This needs to be big enough so that they aren't in the same supply routing grid + left_right_mult = 4 if gnd_dir == "V": self.top_gnd_locs = self.route_side_pin("gnd", "top", top_bot_mult) self.bot_gnd_locs = self.route_side_pin("gnd", "bot", top_bot_mult) - top_bot_mult = 3 + # This needs to be big enough so that they aren't in the same supply routing grid + top_bot_mult = 4 if vdd_dir == "V": self.top_vdd_locs = self.route_side_pin("vdd", "top", top_bot_mult) diff --git a/compiler/pgates/column_mux.py b/compiler/pgates/column_mux.py index a4a83dcc..bf489e87 100644 --- a/compiler/pgates/column_mux.py +++ b/compiler/pgates/column_mux.py @@ -240,10 +240,9 @@ class column_mux(pgate.pgate): self.add_via_center(layers=self.col_mux_stack, offset=active_pos) - # Add the M1->..->power_grid_layer stack - self.add_power_pin(name="gnd", - loc=active_pos, - start_layer="m1") + self.add_layout_pin_rect_center(text="gnd", + layer="m1", + offset=active_pos) # Add well enclosure over all the tx and contact if "pwell" in layer: diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index 8eff8c8f..22cef930 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -96,46 +96,21 @@ class precharge(design.design): Adds a vdd rail at the top of the cell """ - if OPTS.experimental_power: - pmos_pin = self.upper_pmos2_inst.get_pin("S") - pmos_pos = pmos_pin.center() - self.add_path(pmos_pin.layer, [pmos_pos, self.well_contact_pos]) + pmos_pin = self.upper_pmos2_inst.get_pin("S") + pmos_pos = pmos_pin.center() + self.add_path(pmos_pin.layer, [pmos_pos, self.well_contact_pos]) - self.add_via_stack_center(from_layer=pmos_pin.layer, - to_layer=self.supply_stack[0], + self.add_via_stack_center(from_layer=pmos_pin.layer, + to_layer=self.supply_stack[0], + offset=self.well_contact_pos) + + self.add_min_area_rect_center(layer=self.en_layer, offset=self.well_contact_pos, - directions=("V", "V")) + width=self.well_contact.mod.second_layer_width) - self.add_min_area_rect_center(layer=self.en_layer, - offset=self.well_contact_pos, - width=self.well_contact.mod.second_layer_width) - - self.add_layout_pin_rect_center(text="vdd", - layer=self.supply_stack[0], - offset=self.well_contact_pos) - else: - # Adds the rail across the width of the cell - vdd_position = vector(0.5 * self.width, self.height) - layer_width = drc("minwidth_" + self.en_layer) - self.add_rect_center(layer=self.en_layer, - offset=vdd_position, - width=self.width, - height=layer_width) - - pmos_pin = self.upper_pmos2_inst.get_pin("S") - - # center of vdd rail - pmos_vdd_pos = vector(pmos_pin.cx(), vdd_position.y) - self.add_path(self.en_layer, [pmos_pin.center(), pmos_vdd_pos]) - - self.add_power_pin("vdd", - self.well_contact_pos, - directions=("V", "V")) - - self.add_via_stack_center(from_layer=pmos_pin.layer, - to_layer=self.en_layer, - offset=pmos_pin.center(), - directions=("V", "V")) + self.add_layout_pin_rect_center(text="vdd", + layer=self.supply_stack[0], + offset=self.well_contact_pos) def create_ptx(self): """ From 7e89bbb9f5dcba9db9e0a8823bb74a874e070e58 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 4 May 2022 10:15:40 -0700 Subject: [PATCH 173/229] Update Slack invitation and Mastodon verification link. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 688f22da..3dc775d6 100644 --- a/README.md +++ b/README.md @@ -215,4 +215,6 @@ If I forgot to add you, please let me know! [SCMOS]: https://www.mosis.com/files/scmos/scmos.pdf [Sky130]: https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git -[Slack]: https://join.slack.com/t/openram/shared_invite/enQtNDgxMjc3NzU5NTI1LWZiYWMwNjNkZThmYTdkODc3NDE1NDhjNzUxNDhmMDQ4ZTM3NDgwNWFlNjM5NWFiZDkyMzBlNzc1NTg3ZjllNTY +[Slack]: https://join.slack.com/t/openram/shared_invite/zt-onim74ue-zlttW5XI30xvdBlJGJF6JA +[Mastodon]: @mrg@fostodon.org + From af4f94afdef8d4482eebcd0b2ed0d7808f126f7a Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 4 May 2022 10:21:12 -0700 Subject: [PATCH 174/229] Fix command formatting. Move mastodon link to getting help. --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3dc775d6..3499ca87 100644 --- a/README.md +++ b/README.md @@ -146,16 +146,18 @@ To run a specific test: ``` ce openram/compiler/tests make 05_bitcell_array_test - +``` To run a specific technology: - +``` cd openram/compiler/tests TECHS=scn4m_subm make 05_bitcell_array_test +``` To increase the verbosity of the test, add one (or more) -v options and pass it as an argument to OpenRAM: ``` ARGS="-v" make 05_bitcell_array_test +``` # Get Involved @@ -173,6 +175,7 @@ ARGS="-v" make 05_bitcell_array_test + [OpenRAM Slack Workspace][Slack] + [OpenRAM Users Group][user-group] ([subscribe here][user-group-subscribe]) + [OpenRAM Developers Group][dev-group] ([subscribe here][dev-group-subscribe]) ++ [Mastodon]: @mrg@fostodon.org # License @@ -216,5 +219,5 @@ If I forgot to add you, please let me know! [Sky130]: https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git [Slack]: https://join.slack.com/t/openram/shared_invite/zt-onim74ue-zlttW5XI30xvdBlJGJF6JA -[Mastodon]: @mrg@fostodon.org + From b3615f943de585c6901cdca2887c867e9f3fc432 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 4 May 2022 10:24:48 -0700 Subject: [PATCH 175/229] Remove word mastodon. Stupid markdown. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3499ca87..4a3ec69a 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,7 @@ ARGS="-v" make 05_bitcell_array_test + [OpenRAM Slack Workspace][Slack] + [OpenRAM Users Group][user-group] ([subscribe here][user-group-subscribe]) + [OpenRAM Developers Group][dev-group] ([subscribe here][dev-group-subscribe]) -+ [Mastodon]: @mrg@fostodon.org ++ @mrg@fostodon.org # License From b6c3580e249db400077cf982d92cd52ff55b602a Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 9 May 2022 11:44:46 -0700 Subject: [PATCH 176/229] Fix width of replica routes. Don't enclose pins if they overlap sufficiently. --- compiler/base/pin_layout.py | 2 +- compiler/modules/replica_bitcell_array.py | 12 ++++++-- compiler/router/router.py | 36 ++++++++++++++++------- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index 7ba6cdca..2058d137 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -189,7 +189,7 @@ class pin_layout: if max_x - min_x == 0 or max_y - min_y == 0: return None - return [vector(min_x, min_y), vector(max_x, max_y)] + return pin_layout("", [vector(min_x, min_y), vector(max_x, max_y)], self.layer) def xoverlaps(self, other): """ Check if shape has x overlap """ diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index cbfc6ec2..0c86f3a6 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -6,6 +6,7 @@ import debug from bitcell_base_array import bitcell_base_array +from contact import contact from tech import drc, spice, preferred_directions from tech import cell_properties as props from vector import vector @@ -588,6 +589,9 @@ class replica_bitcell_array(bitcell_base_array): top_loc = vector(self.width + offset_multiple * self.vertical_pitch, self.height) layer = self.supply_stack[2] + top_via = contact(layer_stack=self.supply_stack, + directions=("H", "H")) + # self.add_layout_pin_rect_ends(text=name, # layer=layer, @@ -596,7 +600,8 @@ class replica_bitcell_array(bitcell_base_array): self.add_layout_pin_segment_center(text=name, layer=layer, start=bot_loc, - end=top_loc) + end=top_loc, + width=top_via.second_layer_width) return (bot_loc, top_loc) @@ -612,6 +617,8 @@ class replica_bitcell_array(bitcell_base_array): right_loc = vector(self.width, self.height + offset_multiple * self.horizontal_pitch) layer = self.supply_stack[0] + side_via = contact(layer_stack=self.supply_stack, + directions=("V", "V")) # self.add_layout_pin_rect_ends(text=name, # layer=layer, @@ -620,7 +627,8 @@ class replica_bitcell_array(bitcell_base_array): self.add_layout_pin_segment_center(text=name, layer=layer, start=left_loc, - end=right_loc) + end=right_loc, + width=side_via.first_layer_height) return (left_loc, right_loc) diff --git a/compiler/router/router.py b/compiler/router/router.py index 6e5d5b4e..37db7af1 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -670,6 +670,17 @@ class router(router_tech): return set([best_coord]) + def break_on_grids(self, tracks, xvals, yvals): + track_list = [] + for x in xvals: + for y in yvals: + track_list.append(vector3d(x, y, 0)) + track_list.append(vector3d(x, y, 1)) + + for current in tracks: + if current in track_list: + breakpoint() + def divide_pin_to_tracks(self, pin, tracks): """ Return a list of pin shape parts that are in the tracks. @@ -682,16 +693,11 @@ class router(router_tech): overlap_pins = [] for track in tracks: track_pin = self.convert_track_to_shape_pin(track) - overlap_rect = track_pin.intersection(pin) - if not overlap_rect: - continue - overlap_pin = pin_layout(pin.name, - overlap_rect, - pin.layer) + overlap_pin = track_pin.intersection(pin) # If pin is smaller than minwidth, in one dimension, skip it. min_pin_width = drc("minwidth_{0}". format(pin.layer)) - if overlap_pin.width() < min_pin_width and overlap_pin.height() < min_pin_width: + if not overlap_pin or (overlap_pin.width() < min_pin_width and overlap_pin.height() < min_pin_width): continue else: overlap_pins.append(overlap_pin) @@ -1173,17 +1179,27 @@ class router(router_tech): if len(path_tracks) == 0 or len(components) == 0: return + # Find the track pin + track_pins = [self.convert_tracks_to_pin(x) for x in path_tracks] + # Convert the off-grid pin into parts in each routing grid offgrid_pin_parts = [] for component in components: pg = self.pin_groups[pin_name][component] for pin in pg.pins: + # Layer min with + min_width = drc("minwidth_{}".format(pin.layer)) + + # If we intersect, by a min_width, we are done! + for track_pin in track_pins: + intersection = pin.intersection(track_pin) + if intersection and intersection.width() > min_width and intersection.height() > min_width: + return + + #self.break_on_grids(pg.grids, xvals=[68], yvals=range(93,100)) partial_pin_parts = self.divide_pin_to_tracks(pin, pg.grids) offgrid_pin_parts.extend(partial_pin_parts) - # Find the track pin - track_pins = [self.convert_tracks_to_pin(x) for x in path_tracks] - # Find closest part closest_track_pin, closest_part_pin = self.find_closest_pin(track_pins, offgrid_pin_parts) From 8f2d787d53e329b49bb71488d1aad62133dacce9 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 11 May 2022 10:50:32 -0700 Subject: [PATCH 177/229] Add min area metal in preferred direction --- compiler/base/hierarchy_layout.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index ee97a7ac..68476a00 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -597,8 +597,14 @@ class layout(): start=top_pos, end=bot_pos) + def get_metal_layers(self, from_layer, to_layer): + from_id = layer_indices[from_layer] + to_id = layer_indices[to_layer] + layer_list = [x for x in layer_indices.keys() if layer_indices[x] >= from_id and layer_indices[x] < to_id] + + return layer_list def route_vertical_pins(self, name, insts=None, layer=None, xside="cx", yside="cy", full_width=True): @@ -647,8 +653,7 @@ class layout(): last_via = self.add_via_stack_center(from_layer=pin.layer, to_layer=pin_layer, - offset=vector(x, y), - min_area=True) + offset=vector(x, y)) if last_via: via_width=last_via.mod.second_layer_width @@ -1076,6 +1081,8 @@ class layout(): offset=offset) return None + intermediate_layers = self.get_metal_layers(from_layer, to_layer) + via = None cur_layer = from_layer while cur_layer != to_layer: @@ -1098,7 +1105,9 @@ class layout(): implant_type=implant_type, well_type=well_type) - if cur_layer != from_layer or min_area: + # Only add the enclosure if we are in an intermediate layer + # or we are forced to + if min_area or cur_layer in intermediate_layers: self.add_min_area_rect_center(cur_layer, offset, via.mod.first_layer_width, @@ -1124,14 +1133,18 @@ class layout(): min_width = drc("minwidth_{}".format(layer)) if preferred_directions[layer] == "V": - height = max(min_area / width, min_width) + new_height = max(min_area / width, min_width) + new_width = width else: - width = max(min_area / height, min_width) + new_width = max(min_area / height, min_width) + new_height = height + + debug.check(min_area <= round_to_grid(new_height*new_width), "Min area violated.") self.add_rect_center(layer=layer, offset=offset, - width=width, - height=height) + width=new_width, + height=new_height) def add_ptx(self, offset, mirror="R0", rotate=0, width=1, mults=1, tx_type="nmos"): """Adds a ptx module to the design.""" From 357f967a93e46c373eb1aa7b876c80e5d389ef50 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 11 May 2022 11:01:14 -0700 Subject: [PATCH 178/229] Leave supply routing to new helper functions. --- compiler/modules/sense_amp_array.py | 14 ++------------ compiler/pgates/precharge.py | 10 +--------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index a481679f..daabf8df 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -174,18 +174,8 @@ class sense_amp_array(design.design): height=dout_pin.height()) def route_supplies(self): - if OPTS.experimental_power: - self.route_horizontal_pins("vdd") - self.route_horizontal_pins("gnd") - else: - for i in range(len(self.local_insts)): - inst = self.local_insts[i] - - for gnd_pin in inst.get_pins("gnd"): - self.copy_power_pin(gnd_pin) - - for vdd_pin in inst.get_pins("vdd"): - self.copy_power_pin(vdd_pin) + self.route_horizontal_pins("vdd") + self.route_horizontal_pins("gnd") def route_rails(self): # Add enable across the array diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index 22cef930..1538e0a5 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -100,16 +100,8 @@ class precharge(design.design): pmos_pos = pmos_pin.center() self.add_path(pmos_pin.layer, [pmos_pos, self.well_contact_pos]) - self.add_via_stack_center(from_layer=pmos_pin.layer, - to_layer=self.supply_stack[0], - offset=self.well_contact_pos) - - self.add_min_area_rect_center(layer=self.en_layer, - offset=self.well_contact_pos, - width=self.well_contact.mod.second_layer_width) - self.add_layout_pin_rect_center(text="vdd", - layer=self.supply_stack[0], + layer=pmos_pin.layer, offset=self.well_contact_pos) def create_ptx(self): From 4345136d1a3b4ada6ab1afa14bf9db97c5299bf8 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 13 May 2022 10:46:00 -0700 Subject: [PATCH 179/229] Fix offsets for local bitcell arrays. --- compiler/modules/local_bitcell_array.py | 16 ++++++----- compiler/modules/replica_bitcell_array.py | 16 ++++++++--- compiler/modules/wordline_buffer_array.py | 33 ++++++----------------- 3 files changed, 29 insertions(+), 36 deletions(-) diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index 0d3cfd12..18b33c0f 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -159,18 +159,20 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): def place(self): """ Place the bitcelll array to the right of the wl driver. """ - # FIXME: Replace this with a tech specific paramter + + # FIXME: Replace this with a tech specific parameter driver_to_array_spacing = 3 * self.m3_pitch - self.wl_insts[0].place(vector(0, - self.bitcell_array.get_replica_bottom() + self.cell.height)) + wl_offset = vector(0, self.bitcell_array.get_replica_bottom()) + self.wl_insts[0].place(wl_offset) - self.bitcell_array_inst.place(vector(self.wl_insts[0].rx() + driver_to_array_spacing, - 0)) + bitcell_array_offset = vector(self.wl_insts[0].rx() + driver_to_array_spacing, 0) + self.bitcell_array_inst.place(bitcell_array_offset) if len(self.all_ports) > 1: - self.wl_insts[1].place(vector(self.bitcell_array_inst.rx() + self.wl_array.width + driver_to_array_spacing, - self.bitcell_array.get_replica_top() + self.cell.height), + wl_offset = vector(self.bitcell_array_inst.rx() + self.wl_array.width + driver_to_array_spacing, + self.bitcell_array.get_replica_bottom() + self.wl_array.height + self.cell.height) + self.wl_insts[1].place(wl_offset, mirror="XY") self.height = self.bitcell_array.height diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 0c86f3a6..f81926d4 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -353,28 +353,36 @@ class replica_bitcell_array(bitcell_base_array): self.DRC_LVS() def get_main_array_top(self): + """ Return the top of the main bitcell array. """ return self.bitcell_array_inst.uy() def get_main_array_bottom(self): + """ Return the bottom of the main bitcell array. """ return self.bitcell_array_inst.by() def get_main_array_left(self): + """ Return the left of the main bitcell array. """ return self.bitcell_array_inst.lx() def get_main_array_right(self): + """ Return the right of the main bitcell array. """ return self.bitcell_array_inst.rx() def get_replica_top(self): - return max([x.uy() for x in self.replica_col_insts if x] + [self.get_main_array_top()]) + """ Return the top of all replica columns. """ + return self.dummy_row_insts[0].by() def get_replica_bottom(self): - return min([x.by() for x in self.replica_col_insts if x] + [self.get_main_array_bottom()]) + """ Return the bottom of all replica columns. """ + return self.dummy_row_insts[0].uy() def get_replica_left(self): - return min([x.lx() for x in self.replica_col_insts if x] + [self.get_main_array_left()]) + """ Return the left of all replica columns. """ + return self.dummy_col_insts[0].rx() def get_replica_right(self): - return min([x.rx() for x in self.replica_col_insts if x] + [self.get_main_array_right()]) + """ Return the right of all replica columns. """ + return self.dummy_col_insts[1].rx() def get_column_offsets(self): """ diff --git a/compiler/modules/wordline_buffer_array.py b/compiler/modules/wordline_buffer_array.py index 51fe4030..9c74b79d 100644 --- a/compiler/modules/wordline_buffer_array.py +++ b/compiler/modules/wordline_buffer_array.py @@ -44,7 +44,10 @@ class wordline_buffer_array(design.design): self.place_drivers() self.route_layout() self.route_supplies() - self.offset_all_coordinates() + + # Don't offset these because some cells use standard cell style drivers + #self.offset_all_coordinates() + self.add_boundary() self.DRC_LVS() @@ -71,31 +74,11 @@ class wordline_buffer_array(design.design): are must-connects next level up. """ if layer_props.wordline_driver.vertical_supply: - for name in ["vdd", "gnd"]: - supply_pins = self.wld_inst[0].get_pins(name) - for pin in supply_pins: - self.add_layout_pin_segment_center(text=name, - layer=pin.layer, - start=pin.bc(), - end=vector(pin.cx(), self.height)) + self.route_vertical_pins("vdd", self.wld_inst) + self.route_vertical_pins("gnd", self.wld_inst) else: - # Find the x offsets for where the vias/pins should be placed - xoffset_list = [self.wld_inst[0].rx()] - for num in range(self.rows): - # this will result in duplicate polygons for rails, but who cares - - # use the inverter offset even though it will be the and's too - (gate_offset, y_dir) = self.get_gate_offset(0, - self.wl_driver.height, - num) - # Route both supplies - for name in ["vdd", "gnd"]: - supply_pin = self.wld_inst[num].get_pin(name) - - # Add pins in two locations - for xoffset in xoffset_list: - pin_pos = vector(xoffset, supply_pin.cy()) - self.copy_power_pin(supply_pin, loc=pin_pos) + self.route_vertical_pins("vdd", self.wld_inst, xside="rx",) + self.route_vertical_pins("gnd", self.wld_inst, xside="lx",) def create_drivers(self): self.wld_inst = [] From fbb2ea5fb697c1ef9fd604c2a1c9be3b871e37a8 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 13 May 2022 13:56:16 -0700 Subject: [PATCH 180/229] Intersection now returns a pin_layout fixed during LEF computation. --- compiler/base/lef.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/base/lef.py b/compiler/base/lef.py index 1d86a63e..8a54253f 100644 --- a/compiler/base/lef.py +++ b/compiler/base/lef.py @@ -119,14 +119,13 @@ class lef: old_blockages = list(self.blockages[pin.layer]) for blockage in old_blockages: if blockage.overlaps(inflated_pin): - intersection_shape = blockage.intersection(inflated_pin) + intersection_pin = blockage.intersection(inflated_pin) # If it is zero area, don't split the blockage - if intersection_shape[0][0]==intersection_shape[1][0] or intersection_shape[0][1]==intersection_shape[1][1]: + if not intersection_pin or intersection_pin.area() == 0: continue # Remove the old blockage and add the new ones self.blockages[pin.layer].remove(blockage) - intersection_pin = pin_layout("", intersection_shape, inflated_pin.layer) new_blockages = blockage.cut(intersection_pin) self.blockages[pin.layer].extend(new_blockages) # We split something so make another pass From 74c2c5ae0eaf2ecfe1aa6e999d2d2bff769620da Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 13 May 2022 14:32:52 -0700 Subject: [PATCH 181/229] Don't double prefix a name --- compiler/base/hierarchy_design.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py index 00edc558..5e9bec3f 100644 --- a/compiler/base/hierarchy_design.py +++ b/compiler/base/hierarchy_design.py @@ -28,7 +28,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): is_library_cell = os.path.isfile(gds_file) # Uniquify names to address the flat GDS namespace # except for the top/output name - if not is_library_cell and name != OPTS.output_name: + if not is_library_cell and name != OPTS.output_name and not name.startswith(OPTS.output_name): name = OPTS.output_name + "_" + name cell_name = name From 3101643964a7b4b92fa689b33ac73bcb7c0e40d0 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 13 May 2022 14:34:26 -0700 Subject: [PATCH 182/229] Check for no pins and fix closest pin return type --- compiler/router/router.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/router/router.py b/compiler/router/router.py index 37db7af1..6b2e3ab4 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -702,6 +702,8 @@ class router(router_tech): else: overlap_pins.append(overlap_pin) + debug.check(len(overlap_pins) > 0, "No pins overlapped the tracks.") + return overlap_pins @@ -1200,8 +1202,12 @@ class router(router_tech): partial_pin_parts = self.divide_pin_to_tracks(pin, pg.grids) offgrid_pin_parts.extend(partial_pin_parts) + debug.check(len(offgrid_pin_parts) > 0, "No offgrid pin parts found.") + # Find closest part closest_track_pin, closest_part_pin = self.find_closest_pin(track_pins, offgrid_pin_parts) + + debug.check(closest_track_pin and closest_part_pin, "Found no closest pins.") # Find the bbox of the on-grid track and the off-grid pin part closest_track_pin.bbox([closest_part_pin]) @@ -1217,13 +1223,13 @@ class router(router_tech): Find the closest pin in the lists. Does a stupid O(n^2). """ min_dist = None - min_item = None + min_item = (None, None) for pin1 in first_list: for pin2 in second_list: if pin1.layer != pin2.layer: continue new_dist = pin1.distance(pin2) - if not min_item or new_dist < min_dist: + if not min_dist or new_dist < min_dist: min_item = (pin1, pin2) min_dist = new_dist From 4be075e586f2f4d757f84cfb9b1b29713f4b8e1c Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 16 May 2022 14:57:32 -0700 Subject: [PATCH 183/229] Overlap length can include a rectangle overlap. --- compiler/base/pin_layout.py | 7 +++++++ compiler/router/router.py | 14 ++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index 2058d137..e6a35a0a 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -517,6 +517,13 @@ class pin_layout: if len(intersections) == 2: (p1, p2) = intersections return math.sqrt(pow(p1[0]-p2[0], 2) + pow(p1[1]-p2[1], 2)) + # If we have a rectangular overlap region + elif len(intersections) == 4: + points = intersections + ll = vector(min(p.x for p in points), min(p.y for p in points)) + ur = vector(max(p.x for p in points), max(p.y for p in points)) + new_shape = pin_layout("", [ll, ur], self.lpp) + return max(new_shape.height(), new_shape.width()) else: # This is where we had a corner intersection or none return 0 diff --git a/compiler/router/router.py b/compiler/router/router.py index 6b2e3ab4..d5f2dada 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -574,20 +574,18 @@ class router(router_tech): debug.info(3, "Converting pin [ {0} , {1} ]".format(ll, ur)) # scale the size bigger to include neaby tracks - ll = ll.scale(self.track_factor).floor() - ur = ur.scale(self.track_factor).ceil() + ll_scaled = ll.scale(self.track_factor).floor() + ur_scaled = ur.scale(self.track_factor).ceil() # Keep tabs on tracks with sufficient and insufficient overlap sufficient_list = set() insufficient_list = set() zindex = self.get_zindex(pin.lpp) - for x in range(int(ll[0]) - expansion, int(ur[0]) + 1 + expansion): - for y in range(int(ll[1] - expansion), int(ur[1]) + 1 + expansion): - (full_overlap, partial_overlap) = self.convert_pin_coord_to_tracks(pin, - vector3d(x, - y, - zindex)) + for x in range(int(ll_scaled[0]) - expansion, int(ur_scaled[0]) + 1 + expansion): + for y in range(int(ll_scaled[1] - expansion), int(ur_scaled[1]) + 1 + expansion): + cur_grid = vector3d(x, y, zindex) + (full_overlap, partial_overlap) = self.convert_pin_coord_to_tracks(pin, cur_grid) if full_overlap: sufficient_list.update([full_overlap]) if partial_overlap: From bdd334bce9bdbe4cb1594cba1ab81a89743716cf Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 16 May 2022 16:11:13 -0700 Subject: [PATCH 184/229] Add layer and directions to pbitcell --- compiler/bitcells/pbitcell.py | 12 ++++++++++++ compiler/modules/replica_bitcell_array.py | 6 +++++- technology/sky130/tech/tech.py | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/compiler/bitcells/pbitcell.py b/compiler/bitcells/pbitcell.py index fc131d0f..29355e83 100644 --- a/compiler/bitcells/pbitcell.py +++ b/compiler/bitcells/pbitcell.py @@ -33,6 +33,18 @@ class pbitcell(bitcell_base.bitcell_base): self.mirror = props.bitcell_1port.mirror self.end_caps = props.bitcell_1port.end_caps + self.wl_layer = "m1" + self.wl_dir = "H" + + self.bl_layer = "m2" + self.bl_dir = "V" + + self.vdd_layer = "m1" + self.vdd_dir = "H" + + self.gnd_layer = "m1" + self.gnd_dir = "H" + bitcell_base.bitcell_base.__init__(self, name) fmt_str = "{0} rw ports, {1} w ports and {2} r ports" info_string = fmt_str.format(self.num_rw_ports, diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index f81926d4..92a0358b 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -6,6 +6,7 @@ import debug from bitcell_base_array import bitcell_base_array +from pbitcell import pbitcell from contact import contact from tech import drc, spice, preferred_directions from tech import cell_properties as props @@ -490,7 +491,10 @@ class replica_bitcell_array(bitcell_base_array): def route_supplies(self): - bitcell = getattr(props, "bitcell_{}port".format(OPTS.num_ports)) + if OPTS.bitcell == "pbitcell": + bitcell = factory.create(module_type="pbitcell") + else: + bitcell = getattr(props, "bitcell_{}port".format(OPTS.num_ports)) wl_layer = bitcell.wl_layer wl_dir = bitcell.wl_dir diff --git a/technology/sky130/tech/tech.py b/technology/sky130/tech/tech.py index 72250afc..3cf60d70 100644 --- a/technology/sky130/tech/tech.py +++ b/technology/sky130/tech/tech.py @@ -9,7 +9,7 @@ import os from design_rules import * from module_type import * -from custom_cell_properties import cell_properties, cell +from custom_cell_properties import cell_properties from custom_layer_properties import layer_properties """ From bed12d2a9e60f2768c215cdaab4e84adebb1fd79 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 16 May 2022 17:02:53 -0700 Subject: [PATCH 185/229] pbitcell vdd/gnd are on layer m1 only. --- compiler/bitcells/pbitcell.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/compiler/bitcells/pbitcell.py b/compiler/bitcells/pbitcell.py index 29355e83..d1e7927b 100644 --- a/compiler/bitcells/pbitcell.py +++ b/compiler/bitcells/pbitcell.py @@ -99,7 +99,7 @@ class pbitcell(bitcell_base.bitcell_base): self.route_wordlines() self.route_bitlines() - self.route_supply() + self.route_supplies() if self.replica_bitcell: self.route_rbc_short() @@ -424,13 +424,14 @@ class pbitcell(bitcell_base.bitcell_base): def route_rails(self): """ Adds gnd and vdd rails and connects them to the inverters """ + # Add rails for vdd and gnd gnd_ypos = self.m1_offset - self.total_ports * self.m1_nonpref_pitch self.gnd_position = vector(0, gnd_ypos) - self.add_rect_center(layer="m1", - offset=self.gnd_position, - width=self.width) - self.add_power_pin("gnd", vector(0, gnd_ypos), directions=("H", "H")) + self.add_layout_pin_rect_center(text="gnd", + layer="m1", + offset=self.gnd_position, + width=self.width) vdd_ypos = self.inverter_nmos_ypos \ + self.inverter_nmos.active_height \ @@ -438,10 +439,10 @@ class pbitcell(bitcell_base.bitcell_base): + self.inverter_pmos.active_height \ + self.vdd_offset self.vdd_position = vector(0, vdd_ypos) - self.add_rect_center(layer="m1", - offset=self.vdd_position, - width=self.width) - self.add_power_pin("vdd", vector(0, vdd_ypos), directions=("H", "H")) + self.add_layout_pin_rect_center(text="vdd", + layer="m1", + offset=self.vdd_position, + width=self.width) def create_readwrite_ports(self): """ @@ -910,7 +911,7 @@ class pbitcell(bitcell_base.bitcell_base): self.add_path("m2", [port_contact_offest, br_offset], width=contact.m1_via.height) - def route_supply(self): + def route_supplies(self): """ Route inverter nmos and read-access nmos to gnd. Route inverter pmos to vdd. """ # route inverter nmos and read-access nmos to gnd nmos_contact_positions = [] From 9b592ab432cc9feecf94244c43bf29b8d8d40259 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 17 May 2022 13:30:41 -0700 Subject: [PATCH 186/229] Fix missing hash recompute in vector class. --- compiler/base/vector.py | 2 + compiler/modules/column_decoder.py | 111 +++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 compiler/modules/column_decoder.py diff --git a/compiler/base/vector.py b/compiler/base/vector.py index 6c4fabe2..5d011a09 100644 --- a/compiler/base/vector.py +++ b/compiler/base/vector.py @@ -51,6 +51,7 @@ class vector(): else: self.x=float(value[0]) self.y=float(value[1]) + self._hash = hash((self.x,self.y)) def __getitem__(self, index): """ @@ -104,6 +105,7 @@ class vector(): def snap_to_grid(self): self.x = self.snap_offset_to_grid(self.x) self.y = self.snap_offset_to_grid(self.y) + self._hash = hash((self.x,self.y)) return self def snap_offset_to_grid(self, offset): diff --git a/compiler/modules/column_decoder.py b/compiler/modules/column_decoder.py new file mode 100644 index 00000000..09de25fb --- /dev/null +++ b/compiler/modules/column_decoder.py @@ -0,0 +1,111 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2022 Regents of the University of California +# All rights reserved. +# +from tech import drc +import debug +import design +import math +from sram_factory import factory +from vector import vector +from globals import OPTS +from tech import cell_properties +from tech import layer_properties as layer_props + + +class column_decoder(design.design): + """ + Create the column mux decoder. + """ + + def __init__(self, name, col_addr_size): + super().__init__(name) + + self.col_addr_size = col_addr_size + self.num_inputs = col_addr_size + self.num_outputs = pow(col_addr_size, 2) + debug.info(2, + "create column decoder of {0} inputs and {1} outputs".format(self.num_inputs, + self.num_outputs)) + + self.create_netlist() + if not OPTS.netlist_only: + self.create_layout() + self.DRC_LVS() + + def create_netlist(self): + self.add_pins() + self.add_modules() + self.create_instances() + + def create_instances(self): + self.column_decoder_inst = self.add_inst(name="column_decoder", + mod=self.column_decoder) + self.connect_inst(self.pins) + + def create_layout(self): + self.column_decoder_inst.place(vector(0,0)) + + self.width = self.column_decoder_inst.width + self.height = self.column_decoder_inst.height + + self.route_layout() + + + def add_pins(self): + """ Add the module pins """ + + for i in range(self.num_inputs): + self.add_pin("in_{0}".format(i), "INPUT") + + for j in range(self.num_outputs): + self.add_pin("out_{0}".format(j), "OUTPUT") + + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def route_layout_pins(self): + """ Add the pins. """ + + for i in range(self.num_inputs): + self.copy_layout_pin(self.column_decoder_inst, "in_{0}".format(i)) + + for i in range(self.num_outputs): + self.copy_layout_pin(self.column_decoder_inst, "out_{0}".format(i)) + + def route_layout(self): + """ Create routing among the modules """ + self.route_layout_pins() + self.route_supplies() + + def route_supplies(self): + """ Propagate all vdd/gnd pins up to this level for all modules """ + + self.route_vertical_pins("vdd", self.insts, xside="rx",) + self.route_vertical_pins("gnd", self.insts, xside="lx",) + + def add_modules(self): + + self.dff =factory.create(module_type="dff") + + if self.col_addr_size == 1: + self.column_decoder = factory.create(module_type="pinvbuf", + height=self.dff.height) + elif self.col_addr_size == 2: + self.column_decoder = factory.create(module_type="hierarchical_predecode2x4", + column_decoder=True, + height=self.dff.height) + + elif self.col_addr_size == 3: + self.column_decoder = factory.create(module_type="hierarchical_predecode3x8", + column_decoder=True, + height=self.dff.height) + elif self.col_addr_size == 4: + self.column_decoder = factory.create(module_type="hierarchical_predecode4x16", + column_decoder=True, + height=self.dff.height) + else: + # No error checking before? + debug.error("Invalid column decoder?", -1) + From 8217a8416507ef0d05421897f36141388c3fcafd Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 17 May 2022 13:31:23 -0700 Subject: [PATCH 187/229] Uniquify overlap points during segment overlap computation. --- compiler/base/pin_layout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index e6a35a0a..82590ee6 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -511,7 +511,7 @@ class pin_layout: elif other.contains(self): return math.inf else: - intersections = self.compute_overlap_segment(other) + intersections = set(self.compute_overlap_segment(other)) # This is the common case where two pairs of edges overlap # at two points, so just find the distance between those two points if len(intersections) == 2: From f1f4453d14abd3da05f7aad5111ba6c097de71be Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 17 May 2022 13:32:19 -0700 Subject: [PATCH 188/229] Add column decoder module with power supply straps. --- compiler/modules/bank.py | 43 ++++--------------- compiler/modules/column_decoder.py | 24 +++++++---- compiler/options.py | 1 + .../tests/06_column_decoder_16row_test.py | 42 ++++++++++++++++++ 4 files changed, 68 insertions(+), 42 deletions(-) create mode 100755 compiler/tests/06_column_decoder_16row_test.py diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 718f8f62..1f807d63 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -523,25 +523,9 @@ class bank(design.design): if self.col_addr_size == 0: return - elif self.col_addr_size == 1: - self.column_decoder = factory.create(module_type="pinvbuf", - height=self.dff.height) - elif self.col_addr_size == 2: - self.column_decoder = factory.create(module_type="hierarchical_predecode2x4", - column_decoder=True, - height=self.dff.height) - - elif self.col_addr_size == 3: - self.column_decoder = factory.create(module_type="hierarchical_predecode3x8", - column_decoder=True, - height=self.dff.height) - elif self.col_addr_size == 4: - self.column_decoder = factory.create(module_type="hierarchical_predecode4x16", - column_decoder=True, - height=self.dff.height) else: - # No error checking before? - debug.error("Invalid column decoder?", -1) + self.column_decoder = factory.create(module_type="column_decoder", + col_addr_size=self.col_addr_size) self.column_decoder_inst = [None] * len(self.all_ports) for port in self.all_ports: @@ -927,23 +911,14 @@ class bank(design.design): stack = getattr(self, layer_props.bank.stack) pitch = getattr(self, layer_props.bank.pitch) - if self.col_addr_size == 1: + decode_names = [] + for i in range(self.num_col_addr_lines): + decode_names.append("out_{}".format(i)) - # Connect to sel[0] and sel[1] - decode_names = ["Zb", "Z"] - - # The Address LSB - self.copy_layout_pin(self.column_decoder_inst[port], "A", "addr{}_0".format(port)) - - elif self.col_addr_size > 1: - decode_names = [] - for i in range(self.num_col_addr_lines): - decode_names.append("out_{}".format(i)) - - for i in range(self.col_addr_size): - decoder_name = "in_{}".format(i) - addr_name = "addr{0}_{1}".format(port, i) - self.copy_layout_pin(self.column_decoder_inst[port], decoder_name, addr_name) + for i in range(self.col_addr_size): + decoder_name = "in_{}".format(i) + addr_name = "addr{0}_{1}".format(port, i) + self.copy_layout_pin(self.column_decoder_inst[port], decoder_name, addr_name) if port % 2: offset = self.column_decoder_inst[port].ll() - vector((self.num_col_addr_lines + 1) * pitch, 0) diff --git a/compiler/modules/column_decoder.py b/compiler/modules/column_decoder.py index 09de25fb..9cb08284 100644 --- a/compiler/modules/column_decoder.py +++ b/compiler/modules/column_decoder.py @@ -24,7 +24,7 @@ class column_decoder(design.design): self.col_addr_size = col_addr_size self.num_inputs = col_addr_size - self.num_outputs = pow(col_addr_size, 2) + self.num_outputs = pow(2, col_addr_size) debug.info(2, "create column decoder of {0} inputs and {1} outputs".format(self.num_inputs, self.num_outputs)) @@ -68,11 +68,16 @@ class column_decoder(design.design): def route_layout_pins(self): """ Add the pins. """ - for i in range(self.num_inputs): - self.copy_layout_pin(self.column_decoder_inst, "in_{0}".format(i)) + if self.col_addr_size == 1: + self.copy_layout_pin(self.column_decoder_inst, "A", "in_0") + self.copy_layout_pin(self.column_decoder_inst, "Zb", "out_0") + self.copy_layout_pin(self.column_decoder_inst, "Z", "out_1") + elif self.col_addr_size > 1: + for i in range(self.num_inputs): + self.copy_layout_pin(self.column_decoder_inst, "in_{0}".format(i)) - for i in range(self.num_outputs): - self.copy_layout_pin(self.column_decoder_inst, "out_{0}".format(i)) + for i in range(self.num_outputs): + self.copy_layout_pin(self.column_decoder_inst, "out_{0}".format(i)) def route_layout(self): """ Create routing among the modules """ @@ -81,9 +86,12 @@ class column_decoder(design.design): def route_supplies(self): """ Propagate all vdd/gnd pins up to this level for all modules """ - - self.route_vertical_pins("vdd", self.insts, xside="rx",) - self.route_vertical_pins("gnd", self.insts, xside="lx",) + if self.col_addr_size == 1: + self.copy_power_pins(self.column_decoder_inst, "vdd") + self.copy_power_pins(self.column_decoder_inst, "gnd") + else: + self.route_vertical_pins("vdd", self.insts, xside="rx",) + self.route_vertical_pins("gnd", self.insts, xside="lx",) def add_modules(self): diff --git a/compiler/options.py b/compiler/options.py index c7c062ba..26bcb099 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -171,6 +171,7 @@ class options(optparse.Values): bitcell_array = "bitcell_array" bitcell = "bitcell" buf_dec = "pbuf" + column_decoder = "column_decoder" column_mux_array = "column_mux_array" control_logic = "control_logic" decoder = "hierarchical_decoder" diff --git a/compiler/tests/06_column_decoder_16row_test.py b/compiler/tests/06_column_decoder_16row_test.py new file mode 100755 index 00000000..2823b647 --- /dev/null +++ b/compiler/tests/06_column_decoder_16row_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class column_decoder_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + # Checks 2x4 and 2-input NAND decoder + debug.info(1, "Testing 16 row sample for column_decoder") + a = factory.create(module_type="column_decoder", col_addr_size=4) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From c8905c410a83183499222ca9346d2f062f66477c Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 17 May 2022 15:49:06 -0700 Subject: [PATCH 189/229] Fix case where distance is zero length comparison --- compiler/router/router.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/router/router.py b/compiler/router/router.py index d5f2dada..2e5236ea 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -1227,7 +1227,7 @@ class router(router_tech): if pin1.layer != pin2.layer: continue new_dist = pin1.distance(pin2) - if not min_dist or new_dist < min_dist: + if min_dist == None or new_dist < min_dist: min_item = (pin1, pin2) min_dist = new_dist From 3e02a0e7dff2f2b06fc0703e48b7299d31ec3796 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 17 May 2022 15:49:50 -0700 Subject: [PATCH 190/229] Update column decoder and dff array supplies --- compiler/modules/column_decoder.py | 4 ++-- compiler/modules/dff_array.py | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/compiler/modules/column_decoder.py b/compiler/modules/column_decoder.py index 9cb08284..f94786a2 100644 --- a/compiler/modules/column_decoder.py +++ b/compiler/modules/column_decoder.py @@ -87,8 +87,8 @@ class column_decoder(design.design): def route_supplies(self): """ Propagate all vdd/gnd pins up to this level for all modules """ if self.col_addr_size == 1: - self.copy_power_pins(self.column_decoder_inst, "vdd") - self.copy_power_pins(self.column_decoder_inst, "gnd") + self.copy_layout_pin(self.column_decoder_inst, "vdd") + self.copy_layout_pin(self.column_decoder_inst, "gnd") else: self.route_vertical_pins("vdd", self.insts, xside="rx",) self.route_vertical_pins("gnd", self.insts, xside="lx",) diff --git a/compiler/modules/dff_array.py b/compiler/modules/dff_array.py index 99b59064..226db997 100644 --- a/compiler/modules/dff_array.py +++ b/compiler/modules/dff_array.py @@ -108,22 +108,23 @@ class dff_array(design.design): return dout_name def route_supplies(self): - if OPTS.experimental_power and self.rows > 1: + if self.rows > 1: # Vertical straps on ends if multiple rows left_dff_insts = [self.dff_insts[x, 0] for x in range(self.rows)] right_dff_insts = [self.dff_insts[x, self.columns-1] for x in range(self.rows)] self.route_vertical_pins("vdd", left_dff_insts, xside="lx", yside="cy") self.route_vertical_pins("gnd", right_dff_insts, xside="rx", yside="cy") else: - for row in range(self.rows): - for col in range(self.columns): - # Continous vdd rail along with label. - vdd_pin=self.dff_insts[row, col].get_pin("vdd") - self.copy_power_pin(vdd_pin) - # Continous gnd rail along with label. - gnd_pin=self.dff_insts[row, col].get_pin("gnd") - self.copy_power_pin(gnd_pin) + # Add connections every 4 cells + for col in range(1, self.columns, 4): + vdd_pin=self.dff_insts[0, col].get_pin("vdd") + self.add_power_pin("vdd", vdd_pin.lc()) + + # Add connections every 4 cells + for col in range(1, self.columns, 4): + gnd_pin=self.dff_insts[0, col].get_pin("gnd") + self.add_power_pin("gnd", gnd_pin.rc()) def add_layout_pins(self): for row in range(self.rows): From 735d66c9f176cbd530fdad07b80c77ec7ae9662e Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 17 May 2022 15:54:54 -0700 Subject: [PATCH 191/229] Start dff array supplies on first rather than second bit. --- compiler/modules/dff_array.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/modules/dff_array.py b/compiler/modules/dff_array.py index 226db997..5cca38b6 100644 --- a/compiler/modules/dff_array.py +++ b/compiler/modules/dff_array.py @@ -117,12 +117,12 @@ class dff_array(design.design): else: # Add connections every 4 cells - for col in range(1, self.columns, 4): + for col in range(0, self.columns, 4): vdd_pin=self.dff_insts[0, col].get_pin("vdd") self.add_power_pin("vdd", vdd_pin.lc()) # Add connections every 4 cells - for col in range(1, self.columns, 4): + for col in range(0, self.columns, 4): gnd_pin=self.dff_insts[0, col].get_pin("gnd") self.add_power_pin("gnd", gnd_pin.rc()) From 18c04892d1ee528ba38f9241c827caa50ad9f37d Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 18 May 2022 16:59:38 -0700 Subject: [PATCH 192/229] Set path for FREEPDK45 in ci.yml --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 57facdb8..0d4852d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,6 +22,7 @@ jobs: run: | export OPENRAM_HOME="${{ github.workspace }}/compiler" export OPENRAM_TECH="${{ github.workspace }}/technology" + export FREEPDK45="~/FreePDK45" #cd $OPENRAM_HOME/.. && make pdk && make install #export OPENRAM_TMP="${{ github.workspace }}/scn4me_subm_temp" #python3-coverage run -p $OPENRAM_HOME/tests/regress.py -j 12 -t scn4m_subm From 25fa0a8de3651ac2bb095b6c599781990976afb1 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 19 May 2022 14:53:17 -0700 Subject: [PATCH 193/229] Fix missing cell syntax error. --- technology/sky130/tech/tech.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/technology/sky130/tech/tech.py b/technology/sky130/tech/tech.py index 3cf60d70..72250afc 100644 --- a/technology/sky130/tech/tech.py +++ b/technology/sky130/tech/tech.py @@ -9,7 +9,7 @@ import os from design_rules import * from module_type import * -from custom_cell_properties import cell_properties +from custom_cell_properties import cell_properties, cell from custom_layer_properties import layer_properties """ From 172d07088049bd713c380cc1d787ee7cf961632a Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Thu, 19 May 2022 21:45:48 -0700 Subject: [PATCH 194/229] fix bl routing in rba --- technology/sky130/modules/sky130_bitcell_base_array.py | 8 ++++---- technology/sky130/modules/sky130_replica_bitcell_array.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/technology/sky130/modules/sky130_bitcell_base_array.py b/technology/sky130/modules/sky130_bitcell_base_array.py index 9c6c947d..52955f48 100644 --- a/technology/sky130/modules/sky130_bitcell_base_array.py +++ b/technology/sky130/modules/sky130_bitcell_base_array.py @@ -167,8 +167,8 @@ class sky130_bitcell_base_array(bitcell_base_array): for port in self.all_ports: bl_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port]) text = "bl_{0}_{1}".format(port, col) - if "Y" in self.cell_inst[0, col].mirror: - text = text.replace("bl", "br") + #if "Y" in self.cell_inst[0, col].mirror: + # text = text.replace("bl", "br") self.add_layout_pin(text=text, layer=bl_pin.layer, offset=bl_pin.ll().scale(1, 0), @@ -176,8 +176,8 @@ class sky130_bitcell_base_array(bitcell_base_array): height=self.height) br_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port + 1]) text = "br_{0}_{1}".format(port, col) - if "Y" in self.cell_inst[0, col].mirror: - text = text.replace("br", "bl") + #if "Y" in self.cell_inst[0, col].mirror: + # text = text.replace("br", "bl") self.add_layout_pin(text=text, layer=br_pin.layer, offset=br_pin.ll().scale(1, 0), diff --git a/technology/sky130/modules/sky130_replica_bitcell_array.py b/technology/sky130/modules/sky130_replica_bitcell_array.py index 6f0a1188..19042982 100644 --- a/technology/sky130/modules/sky130_replica_bitcell_array.py +++ b/technology/sky130/modules/sky130_replica_bitcell_array.py @@ -325,16 +325,16 @@ class sky130_replica_bitcell_array(replica_bitcell_array, sky130_bitcell_base_ar for (bl_name, pin_name) in zip(names, pin_names): pin = inst.get_pin(pin_name) if 'rbl_bl' in bl_name: - if mirror != "MY": - bl_name = bl_name.replace("rbl_bl","rbl_br") + # if mirror != "MY": + # bl_name = bl_name.replace("rbl_bl","rbl_br") self.add_layout_pin(text=bl_name, layer=pin.layer, offset=pin.ll().scale(1, 0), width=pin.width(), height=self.height) elif 'rbl_br' in bl_name: - if mirror != "MY": - bl_name = bl_name.replace("rbl_br","rbl_bl") + # if mirror != "MY": + # bl_name = bl_name.replace("rbl_br","rbl_bl") self.add_layout_pin(text=bl_name, layer=pin.layer, offset=pin.ll().scale(1, 0) + vector(0,(pin_height + drc_width*2)), From 51b0f125fba941cb60bea855cd77c26d2223bdf2 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 23 May 2022 09:59:41 -0700 Subject: [PATCH 195/229] Add offset to 0,0 that was inadvertantly removed for router debug. --- compiler/sram/sram_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index 4bcc1cb3..f6782597 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -213,7 +213,7 @@ class sram_base(design, verilog, lef): self.add_lvs_correspondence_points() - #self.offset_all_coordinates() + self.offset_all_coordinates() highest_coord = self.find_highest_coords() self.width = highest_coord[0] From 8c85230033f4911abf580a881f5b4cd42bb28408 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 23 May 2022 10:08:35 -0700 Subject: [PATCH 196/229] Remove experimental power option. --- compiler/modules/dff_buf_array.py | 2 +- compiler/modules/write_driver_array.py | 12 ++---------- compiler/options.py | 3 --- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/compiler/modules/dff_buf_array.py b/compiler/modules/dff_buf_array.py index 70209767..6c8f88de 100644 --- a/compiler/modules/dff_buf_array.py +++ b/compiler/modules/dff_buf_array.py @@ -154,7 +154,7 @@ class dff_buf_array(design.design): gndn_pin=self.dff_insts[row, self.columns - 1].get_pin("gnd") self.add_path(gnd0_pin.layer, [gnd0_pin.lc(), gndn_pin.rc()], width=gnd0_pin.height()) - if OPTS.experimental_power and self.rows > 1: + if self.rows > 1: # Vertical straps on ends if multiple rows left_dff_insts = [self.dff_insts[x, 0] for x in range(self.rows)] right_dff_insts = [self.dff_insts[x, self.columns-1] for x in range(self.rows)] diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index f232c129..3262e555 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -256,15 +256,7 @@ class write_driver_array(design.design): width=self.width) def route_supplies(self): - if OPTS.experimental_power: - self.route_horizontal_pins("vdd") - self.route_horizontal_pins("gnd") - else: - for i in range(self.word_size + self.num_spare_cols): - inst = self.local_insts[i] - for n in ["vdd", "gnd"]: - pin_list = inst.get_pins(n) - for pin in pin_list: - self.copy_power_pin(pin, directions=("V", "V")) + self.route_horizontal_pins("vdd") + self.route_horizontal_pins("gnd") diff --git a/compiler/options.py b/compiler/options.py index 26bcb099..770045b3 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -194,6 +194,3 @@ class options(optparse.Values): write_driver_array = "write_driver_array" write_driver = "write_driver" write_mask_and_array = "write_mask_and_array" - - # Non-public options - experimental_power = True From aed2ef4ecc39365270420d4d62661c0ba427ce09 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 23 May 2022 10:34:12 -0700 Subject: [PATCH 197/229] Add commit ids for PDK and open_pdks --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 5dc053d0..412544d4 100644 --- a/Makefile +++ b/Makefile @@ -10,19 +10,19 @@ PDK_ROOT ?= $(TOP_DIR) SRAM_LIB_DIR ?= $(PDK_ROOT)/sky130_fd_bd_sram SRAM_LIB_GIT_REPO ?= https://github.com/vlsida/sky130_fd_bd_sram.git #SRAM_LIB_GIT_REPO ?= https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git -SRAM_LIB_GIT_COMMIT ?= main +SRAM_LIB_GIT_COMMIT ?= 95287ef89556505b2cdf17912c025cb74d9288a7 # Open PDKs OPEN_PDKS_DIR ?= $(PDK_ROOT)/open_pdks OPEN_PDKS_GIT_REPO ?= https://github.com/RTimothyEdwards/open_pdks.git #OPEN_PDKS_GIT_COMMIT ?= 1.0.156 -OPEN_PDKS_GIT_COMMIT ?= master +OPEN_PDKS_GIT_COMMIT ?= 7ea416610339d3c29af9d0d748ceadd3fd368608 SKY130_PDK ?= $(PDK_ROOT)/sky130A # Skywater PDK SKY130_PDKS_DIR ?= $(PDK_ROOT)/skywater-pdk SKY130_PDKS_GIT_REPO ?= https://github.com/google/skywater-pdk.git -SKY130_PDKS_GIT_COMMIT ?= main +SKY130_PDKS_GIT_COMMIT ?= f70d8ca46961ff92719d8870a18a076370b85f6c # Create lists of all the files to copy/link GDS_FILES := $(sort $(wildcard $(SRAM_LIB_DIR)/cells/*/*.gds)) From b84b4dab43414f51ca21d2a39124a310a2dd6d85 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 23 May 2022 16:28:28 -0700 Subject: [PATCH 198/229] Fail on pin mismatch too. --- compiler/verify/magic.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 69429ab7..efa400c1 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -349,6 +349,14 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False, output_path= test = re.compile("match correctly.") correctly = list(filter(test.search, final_results)) + # Top level pins mismatch + test = re.compile("The top level cell failed pin matching.") + pins_incorrectly = list(filter(test.search, final_results)) + + # Fail if the pins mismatched + if len(pins_incorrectly) > 0: + total_errors += 1 + # Fail if they don't match. Something went wrong! if len(uniquely) == 0 and len(correctly) == 0: total_errors += 1 From bbfccd1e006907eecaabbb6ed95f0ab31ebc0f7a Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 23 May 2022 17:16:36 -0700 Subject: [PATCH 199/229] Remove netlist bl/br swaps on flipped cells --- technology/sky130/modules/sky130_bitcell_array.py | 5 +---- technology/sky130/modules/sky130_bitcell_base_array.py | 8 -------- technology/sky130/modules/sky130_col_cap_array.py | 8 ++++---- technology/sky130/modules/sky130_dummy_array.py | 10 +--------- 4 files changed, 6 insertions(+), 25 deletions(-) diff --git a/technology/sky130/modules/sky130_bitcell_array.py b/technology/sky130/modules/sky130_bitcell_array.py index b589e321..9910cbd5 100644 --- a/technology/sky130/modules/sky130_bitcell_array.py +++ b/technology/sky130/modules/sky130_bitcell_array.py @@ -63,10 +63,7 @@ class sky130_bitcell_array(bitcell_array, sky130_bitcell_base_array): row_layout.append(self.cell2) self.cell_inst[row, col]=self.add_inst(name="row_{}_col_{}_bitcell".format(row, col), mod=self.cell2) - if col % 2 == 1: - self.connect_inst(self.get_bitcell_pins(row, col, swap=True)) - else: - self.connect_inst(self.get_bitcell_pins(row, col, swap=False)) + self.connect_inst(self.get_bitcell_pins(row, col)) if col != self.column_size - 1: if alternate_strap: if row % 2: diff --git a/technology/sky130/modules/sky130_bitcell_base_array.py b/technology/sky130/modules/sky130_bitcell_base_array.py index 52955f48..6eae4fea 100644 --- a/technology/sky130/modules/sky130_bitcell_base_array.py +++ b/technology/sky130/modules/sky130_bitcell_base_array.py @@ -69,14 +69,6 @@ class sky130_bitcell_base_array(bitcell_base_array): bitcell_pins = [] for port in self.all_ports: bitcell_pins.extend([x for x in self.get_bitline_names(port) if x.endswith("_{0}".format(col))]) - if swap: - swap_pins = [] - for pin in bitcell_pins: - if "bl" in pin: - swap_pins.append(pin.replace("bl", "br")) - elif "br" in pin: - swap_pins.append(pin.replace("br", "bl")) - bitcell_pins = swap_pins bitcell_pins.append("gnd") # gnd bitcell_pins.append("vdd") # vdd bitcell_pins.append("vdd") # vpb diff --git a/technology/sky130/modules/sky130_col_cap_array.py b/technology/sky130/modules/sky130_col_cap_array.py index fa70ed27..909dfd21 100644 --- a/technology/sky130/modules/sky130_col_cap_array.py +++ b/technology/sky130/modules/sky130_col_cap_array.py @@ -89,10 +89,10 @@ class sky130_col_cap_array(sky130_bitcell_base_array): elif col % 4 == 2: row_layout.append(self.colend1) self.cell_inst[col]=self.add_inst(name=name, mod=self.colend1) - pins.append("fake_br_{}".format(bitline)) + pins.append("fake_bl_{}".format(bitline)) pins.append("vdd") pins.append("gnd") - pins.append("fake_bl_{}".format(bitline)) + pins.append("fake_br_{}".format(bitline)) pins.append("gate") bitline += 1 elif col % 4 ==3: @@ -194,7 +194,7 @@ class sky130_col_cap_array(sky130_bitcell_base_array): elif col % 4 == 2: pin = self.cell_inst[col].get_pin("bl") - text = "fake_br_{}".format(int(col/2)) + text = "fake_bl_{}".format(int(col/2)) self.add_layout_pin(text=text, layer=pin.layer, offset=pin.ll().scale(1, 0), @@ -202,7 +202,7 @@ class sky130_col_cap_array(sky130_bitcell_base_array): height=pin.height()) pin = self.cell_inst[col].get_pin("br") - text = "fake_bl_{}".format(int(col/2)) + text = "fake_br_{}".format(int(col/2)) self.add_layout_pin(text=text, layer=pin.layer, offset=pin.ll().scale(1, 0), diff --git a/technology/sky130/modules/sky130_dummy_array.py b/technology/sky130/modules/sky130_dummy_array.py index 0c81b812..955e640f 100644 --- a/technology/sky130/modules/sky130_dummy_array.py +++ b/technology/sky130/modules/sky130_dummy_array.py @@ -72,11 +72,7 @@ class sky130_dummy_array(sky130_bitcell_base_array): row_layout.append(self.dummy_cell2) self.cell_inst[row, col]=self.add_inst(name="row_{}_col_{}_bitcell".format(row, col), mod=self.dummy_cell2) - if col % 2 == 1: - self.connect_inst(self.get_bitcell_pins(row, col, swap=True)) - else: - self.connect_inst(self.get_bitcell_pins(row, col, swap=False)) - #self.connect_inst(self.get_bitcell_pins(row, col)) + self.connect_inst(self.get_bitcell_pins(row, col)) if col != self.column_size - 1: if alternate_strap: if col % 2: @@ -129,8 +125,6 @@ class sky130_dummy_array(sky130_bitcell_base_array): for port in self.all_ports: bl_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port]) text = "bl_{0}_{1}".format(port, col) - if "Y" in self.cell_inst[0, col].mirror: - text = text.replace("bl", "br") self.add_layout_pin(text=text, layer=bl_pin.layer, offset=bl_pin.ll().scale(1, 0), @@ -138,8 +132,6 @@ class sky130_dummy_array(sky130_bitcell_base_array): height=self.height) br_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port + 1]) text = "br_{0}_{1}".format(port, col) - if "Y" in self.cell_inst[0, col].mirror: - text = text.replace("br", "bl") self.add_layout_pin(text=text, layer=br_pin.layer, offset=br_pin.ll().scale(1, 0), From cb3d7b9d5d85ce934af4084df11e8b209394ce41 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 23 May 2022 17:27:26 -0700 Subject: [PATCH 200/229] Add spares for sky130 unit tests. --- compiler/tests/20_sram_1bank_16mux_test.py | 12 +++++++++++- compiler/tests/20_sram_1bank_2mux_global_test.py | 12 +++++++++++- compiler/tests/20_sram_1bank_2mux_test.py | 12 +++++++++++- .../20_sram_1bank_2mux_wmask_spare_cols_test.py | 13 +++++++++++-- compiler/tests/20_sram_1bank_2mux_wmask_test.py | 12 +++++++++++- compiler/tests/20_sram_1bank_32b_1024_wmask_test.py | 12 +++++++++++- compiler/tests/20_sram_1bank_4mux_test.py | 12 +++++++++++- compiler/tests/20_sram_1bank_8mux_test.py | 12 +++++++++++- .../tests/20_sram_1bank_nomux_spare_cols_test.py | 13 +++++++++++-- .../20_sram_1bank_nomux_wmask_sparecols_test.py | 13 +++++++++++-- compiler/tests/20_sram_1bank_nomux_wmask_test.py | 12 +++++++++++- 11 files changed, 121 insertions(+), 14 deletions(-) diff --git a/compiler/tests/20_sram_1bank_16mux_test.py b/compiler/tests/20_sram_1bank_16mux_test.py index 66d13869..61f469e4 100755 --- a/compiler/tests/20_sram_1bank_16mux_test.py +++ b/compiler/tests/20_sram_1bank_16mux_test.py @@ -22,9 +22,19 @@ class sram_1bank_8mux_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) from sram_config import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=2, num_words=256, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=16 c.recompute_sizes() diff --git a/compiler/tests/20_sram_1bank_2mux_global_test.py b/compiler/tests/20_sram_1bank_2mux_global_test.py index 11f084ec..ec207564 100755 --- a/compiler/tests/20_sram_1bank_2mux_global_test.py +++ b/compiler/tests/20_sram_1bank_2mux_global_test.py @@ -23,9 +23,19 @@ class sram_1bank_2mux_global_test(openram_test): globals.init_openram(config_file) from sram_config import sram_config OPTS.local_array_size = 8 + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=8, num_words=32, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=2 c.recompute_sizes() diff --git a/compiler/tests/20_sram_1bank_2mux_test.py b/compiler/tests/20_sram_1bank_2mux_test.py index d7240cac..045eccec 100755 --- a/compiler/tests/20_sram_1bank_2mux_test.py +++ b/compiler/tests/20_sram_1bank_2mux_test.py @@ -22,9 +22,19 @@ class sram_1bank_2mux_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) from sram_config import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=4, num_words=32, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=2 c.recompute_sizes() diff --git a/compiler/tests/20_sram_1bank_2mux_wmask_spare_cols_test.py b/compiler/tests/20_sram_1bank_2mux_wmask_spare_cols_test.py index 0e0b99e6..0472793c 100755 --- a/compiler/tests/20_sram_1bank_2mux_wmask_spare_cols_test.py +++ b/compiler/tests/20_sram_1bank_2mux_wmask_spare_cols_test.py @@ -22,11 +22,20 @@ class sram_1bank_2mux_wmask_spare_cols_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) from sram_config import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=8, write_size=4, - num_spare_cols=3, num_words=64, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols+2, + num_spare_rows=num_spare_rows) c.words_per_row = 2 c.recompute_sizes() diff --git a/compiler/tests/20_sram_1bank_2mux_wmask_test.py b/compiler/tests/20_sram_1bank_2mux_wmask_test.py index a1ef171d..65c0f399 100755 --- a/compiler/tests/20_sram_1bank_2mux_wmask_test.py +++ b/compiler/tests/20_sram_1bank_2mux_wmask_test.py @@ -22,10 +22,20 @@ class sram_1bank_2mux_wmask_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) from sram_config import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=8, write_size=4, num_words=64, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row = 2 c.recompute_sizes() diff --git a/compiler/tests/20_sram_1bank_32b_1024_wmask_test.py b/compiler/tests/20_sram_1bank_32b_1024_wmask_test.py index 8631ef57..4a52c385 100755 --- a/compiler/tests/20_sram_1bank_32b_1024_wmask_test.py +++ b/compiler/tests/20_sram_1bank_32b_1024_wmask_test.py @@ -23,10 +23,20 @@ class sram_1bank_32b_1024_wmask_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) from sram_config import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=32, write_size=8, num_words=1024, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.recompute_sizes() debug.info(1, "Layout test for {}rw,{}r,{}w sram " diff --git a/compiler/tests/20_sram_1bank_4mux_test.py b/compiler/tests/20_sram_1bank_4mux_test.py index 70be4900..6f87fe44 100755 --- a/compiler/tests/20_sram_1bank_4mux_test.py +++ b/compiler/tests/20_sram_1bank_4mux_test.py @@ -22,9 +22,19 @@ class sram_1bank_4mux_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) from sram_config import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=4, num_words=64, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=4 c.recompute_sizes() diff --git a/compiler/tests/20_sram_1bank_8mux_test.py b/compiler/tests/20_sram_1bank_8mux_test.py index 6910a1c8..dc4ad5ec 100755 --- a/compiler/tests/20_sram_1bank_8mux_test.py +++ b/compiler/tests/20_sram_1bank_8mux_test.py @@ -22,9 +22,19 @@ class sram_1bank_8mux_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) from sram_config import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=2, num_words=128, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row=8 c.recompute_sizes() diff --git a/compiler/tests/20_sram_1bank_nomux_spare_cols_test.py b/compiler/tests/20_sram_1bank_nomux_spare_cols_test.py index bd9645e3..d2b5da52 100755 --- a/compiler/tests/20_sram_1bank_nomux_spare_cols_test.py +++ b/compiler/tests/20_sram_1bank_nomux_spare_cols_test.py @@ -22,10 +22,19 @@ class sram_1bank_nomux_spare_cols_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) from sram_config import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=8, - num_spare_cols=3, num_words=16, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols+2, + num_spare_rows=num_spare_rows) c.words_per_row = 1 c.recompute_sizes() diff --git a/compiler/tests/20_sram_1bank_nomux_wmask_sparecols_test.py b/compiler/tests/20_sram_1bank_nomux_wmask_sparecols_test.py index ca6361b8..f115a9b0 100755 --- a/compiler/tests/20_sram_1bank_nomux_wmask_sparecols_test.py +++ b/compiler/tests/20_sram_1bank_nomux_wmask_sparecols_test.py @@ -23,11 +23,20 @@ class sram_1bank_nomux_wmask_sparecols_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) from sram_config import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=8, write_size=4, num_words=16, - num_spare_cols=3, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols+2, + num_spare_rows=num_spare_rows) c.words_per_row = 1 c.recompute_sizes() diff --git a/compiler/tests/20_sram_1bank_nomux_wmask_test.py b/compiler/tests/20_sram_1bank_nomux_wmask_test.py index 83dea577..8c012a60 100755 --- a/compiler/tests/20_sram_1bank_nomux_wmask_test.py +++ b/compiler/tests/20_sram_1bank_nomux_wmask_test.py @@ -22,10 +22,20 @@ class sram_1bank_nomux_wmask_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) from sram_config import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=8, write_size=4, num_words=16, - num_banks=1) + num_banks=1, + num_spare_cols=num_spare_cols+2, + num_spare_rows=num_spare_rows) c.words_per_row = 1 c.recompute_sizes() From fbe3032246885783caa68d7823224489583b1da8 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Thu, 26 May 2022 12:18:47 -0700 Subject: [PATCH 201/229] add case for single spare col spare_wen_dff i/o --- compiler/sram/sram_base.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index f6782597..6feda56f 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -688,7 +688,10 @@ class sram_base(design, verilog, lef): inputs = [] outputs = [] for bit in range(self.num_spare_cols): - inputs.append("spare_wen{}[{}]".format(port, bit)) + if self.num_spare_cols == 1: + inputs.append("spare_wen{0}".format(port)) + else: + inputs.append("spare_wen{0}[{1}]".format(port, bit)) outputs.append("bank_spare_wen{}_{}".format(port, bit)) self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies) From 4a400b225de01334b920a4a3058fff695faccd9f Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Mon, 6 Jun 2022 15:40:00 -0700 Subject: [PATCH 202/229] update netgen in dockerfile --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 3922477c..21f15e9e 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -112,7 +112,7 @@ RUN rm -rf /root/ngspice ### Netgen ### #ARG NETGEN_COMMIT=1.5.219 -ARG NETGEN_COMMIT=88d53fab15eb611cffc024eebf8743fae5cf8cb7 +ARG NETGEN_COMMIT=89ef83c597d799be7777cdde7af6a6fb9f96bc29 WORKDIR /root #RUN git clone https://github.com/RTimothyEdwards/netgen.git netgen RUN git clone git://opencircuitdesign.com/netgen netgen From d8ae19c0cd00b44d497f60a69938f394772efd2e Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Mon, 6 Jun 2022 16:11:53 -0700 Subject: [PATCH 203/229] update single port macros --- .../sky130_sram_1kbyte_1rw_32x256_8.py | 2 ++ .../sky130_sram_2kbyte_1rw_32x512_8.py | 2 ++ .../sky130_sram_4kbyte_1rw_32x1024_8.py | 2 ++ .../sky130_sram_4kbyte_1rw_64x512_8.py | 21 +++++++++++++++++++ 4 files changed, 27 insertions(+) create mode 100644 macros/configs/sky130_sram_4kbyte_1rw_64x512_8.py diff --git a/macros/configs/sky130_sram_1kbyte_1rw_32x256_8.py b/macros/configs/sky130_sram_1kbyte_1rw_32x256_8.py index 955d3959..88bbfd6f 100644 --- a/macros/configs/sky130_sram_1kbyte_1rw_32x256_8.py +++ b/macros/configs/sky130_sram_1kbyte_1rw_32x256_8.py @@ -13,6 +13,8 @@ write_size = 8 # Bits num_rw_ports = 1 num_r_ports = 0 num_w_ports = 0 +num_spare_rows = 1 +num_spare_cols = 1 ports_human = '1rw' import os diff --git a/macros/configs/sky130_sram_2kbyte_1rw_32x512_8.py b/macros/configs/sky130_sram_2kbyte_1rw_32x512_8.py index 7f64d18c..8e2be639 100644 --- a/macros/configs/sky130_sram_2kbyte_1rw_32x512_8.py +++ b/macros/configs/sky130_sram_2kbyte_1rw_32x512_8.py @@ -13,6 +13,8 @@ write_size = 8 # Bits num_rw_ports = 1 num_r_ports = 0 num_w_ports = 0 +num_spare_rows = 1 +num_spare_cols = 1 ports_human = '1rw' import os diff --git a/macros/configs/sky130_sram_4kbyte_1rw_32x1024_8.py b/macros/configs/sky130_sram_4kbyte_1rw_32x1024_8.py index 571ca030..50c01e92 100644 --- a/macros/configs/sky130_sram_4kbyte_1rw_32x1024_8.py +++ b/macros/configs/sky130_sram_4kbyte_1rw_32x1024_8.py @@ -14,6 +14,8 @@ write_size = 8 # Bits num_rw_ports = 1 num_r_ports = 0 num_w_ports = 0 +num_spare_rows = 1 +num_spare_cols = 1 ports_human = '1rw' import os diff --git a/macros/configs/sky130_sram_4kbyte_1rw_64x512_8.py b/macros/configs/sky130_sram_4kbyte_1rw_64x512_8.py new file mode 100644 index 00000000..34ae8537 --- /dev/null +++ b/macros/configs/sky130_sram_4kbyte_1rw_64x512_8.py @@ -0,0 +1,21 @@ +""" +Single port, 1 kbytes SRAM, with byte write, useful for RISC-V processor main +memory. +""" +word_size = 64 # Bits +num_words = 512 +human_byte_size = "{:.0f}kbytes".format((word_size * num_words)/1024/8) + +# Allow byte writes +write_size = 8 # Bits + +# Single port +num_rw_ports = 1 +num_r_ports = 0 +num_w_ports = 0 +num_spare_rows = 1 +num_spare_cols = 1 +ports_human = '1rw' + +import os +exec(open(os.path.join(os.path.dirname(__file__), 'sky130_sram_common.py')).read()) From 7b2f73d8b99c0f2ce3d7d3a0686592eef230258f Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 7 Jun 2022 12:10:16 -0700 Subject: [PATCH 204/229] Update sky130_fd_bd_sram commit --- Makefile | 2 +- docker/Dockerfile | 7 ++++--- macros/configs/sky130_sram_1kbyte_1r1w_8x1024_8.py | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 412544d4..3df8f7c8 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ PDK_ROOT ?= $(TOP_DIR) SRAM_LIB_DIR ?= $(PDK_ROOT)/sky130_fd_bd_sram SRAM_LIB_GIT_REPO ?= https://github.com/vlsida/sky130_fd_bd_sram.git #SRAM_LIB_GIT_REPO ?= https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git -SRAM_LIB_GIT_COMMIT ?= 95287ef89556505b2cdf17912c025cb74d9288a7 +SRAM_LIB_GIT_COMMIT ?= 9d452eea52cde23f0a5b03e1c5ccf1ca27dd771a # Open PDKs OPEN_PDKS_DIR ?= $(PDK_ROOT)/open_pdks diff --git a/docker/Dockerfile b/docker/Dockerfile index 3922477c..43dec418 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -112,7 +112,8 @@ RUN rm -rf /root/ngspice ### Netgen ### #ARG NETGEN_COMMIT=1.5.219 -ARG NETGEN_COMMIT=88d53fab15eb611cffc024eebf8743fae5cf8cb7 +#ARG NETGEN_COMMIT=88d53fab15eb611cffc024eebf8743fae5cf8cb7 +ARG NETGEN_COMMIT=1.5.221 WORKDIR /root #RUN git clone https://github.com/RTimothyEdwards/netgen.git netgen RUN git clone git://opencircuitdesign.com/netgen netgen @@ -128,8 +129,8 @@ RUN apt-get install --no-install-recommends -y iverilog ### Magic ### #ARG MAGIC_COMMIT=db4fa65bfc096e63954b37b188ea27b90ab31839 -#ARG MAGIC_COMMIT=8.3.274 -ARG MAGIC_COMMIT=8.3.211 +#ARG MAGIC_COMMIT=8.3.211 +ARG MAGIC_COMMIT=8.3.309 WORKDIR /root #RUN git clone https://github.com/RTimothyEdwards/magic.git magic RUN git clone git://opencircuitdesign.com/magic magic diff --git a/macros/configs/sky130_sram_1kbyte_1r1w_8x1024_8.py b/macros/configs/sky130_sram_1kbyte_1r1w_8x1024_8.py index 6462032e..5d86dff6 100644 --- a/macros/configs/sky130_sram_1kbyte_1r1w_8x1024_8.py +++ b/macros/configs/sky130_sram_1kbyte_1r1w_8x1024_8.py @@ -8,7 +8,7 @@ num_words = 1024 human_byte_size = "{:.0f}kbytes".format((word_size * num_words)/1024/8) # Allow byte writes -#write_size = 8 # Bits +write_size = 8 # Bits # Dual port num_rw_ports = 0 From ad6633ddca30431dbcae1ce58bd2299fad95c8fe Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 8 Jun 2022 13:50:25 -0700 Subject: [PATCH 205/229] Update versions of tools. Fix supply bug in predecode. --- Makefile | 7 ++----- compiler/modules/hierarchical_predecode.py | 2 +- compiler/verify/magic.py | 5 +++-- docker/Dockerfile | 6 +++--- openram.mk | 7 +++++++ 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 412544d4..c05e0804 100644 --- a/Makefile +++ b/Makefile @@ -3,9 +3,6 @@ include $(TOP_DIR)/openram.mk .DEFAULT_GOAL := install -# Keep it locally if they didn't specify -PDK_ROOT ?= $(TOP_DIR) - # Skywater PDK SRAM library SRAM_LIB_DIR ?= $(PDK_ROOT)/sky130_fd_bd_sram SRAM_LIB_GIT_REPO ?= https://github.com/vlsida/sky130_fd_bd_sram.git @@ -15,8 +12,8 @@ SRAM_LIB_GIT_COMMIT ?= 95287ef89556505b2cdf17912c025cb74d9288a7 # Open PDKs OPEN_PDKS_DIR ?= $(PDK_ROOT)/open_pdks OPEN_PDKS_GIT_REPO ?= https://github.com/RTimothyEdwards/open_pdks.git -#OPEN_PDKS_GIT_COMMIT ?= 1.0.156 -OPEN_PDKS_GIT_COMMIT ?= 7ea416610339d3c29af9d0d748ceadd3fd368608 +OPEN_PDKS_GIT_COMMIT ?= 1.0.311 +#OPEN_PDKS_GIT_COMMIT ?= 7ea416610339d3c29af9d0d748ceadd3fd368608 SKY130_PDK ?= $(PDK_ROOT)/sky130A # Skywater PDK diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index 8ae3a08d..1431d75c 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -416,4 +416,4 @@ class hierarchical_predecode(design.design): else: xoffset = self.inv_inst[0].lx() - self.bus_space pin_pos = vector(xoffset, and_pin.cy()) - self.add_power_pin(n, pin_pos) + self.add_power_pin(n, pin_pos, start_layer=and_pin.layer) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 69429ab7..50f27142 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -95,7 +95,8 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa #f.write("gds polygon subcell true\n") f.write("gds warning default\n") # Flatten the transistors - f.write("gds flatglob *_?mos_m*\n") + # Bug in Netgen 1.5.194 when using this... + #f.write("gds flatglob *_?mos_m*\n") # These two options are temporarily disabled until Tim fixes a bug in magic related # to flattening channel routes and vias (hierarchy with no devices in it). Otherwise, # they appear to be disconnected. @@ -123,7 +124,7 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa # Hack to work around unit scales in SkyWater if OPTS.tech_name=="sky130": f.write(pre + "extract style ngspice(si)\n") - f.write(pre + "extract\n") + f.write(pre + "extract all\n") f.write(pre + "select top cell\n") f.write(pre + "feedback why\n") f.write('puts "Finished extract"\n') diff --git a/docker/Dockerfile b/docker/Dockerfile index 3922477c..fb7e3897 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -111,8 +111,8 @@ RUN ./autogen.sh \ RUN rm -rf /root/ngspice ### Netgen ### -#ARG NETGEN_COMMIT=1.5.219 -ARG NETGEN_COMMIT=88d53fab15eb611cffc024eebf8743fae5cf8cb7 +#ARG NETGEN_COMMIT=1.5.195 +ARG NETGEN_COMMIT=1.5.221 WORKDIR /root #RUN git clone https://github.com/RTimothyEdwards/netgen.git netgen RUN git clone git://opencircuitdesign.com/netgen netgen @@ -129,7 +129,7 @@ RUN apt-get install --no-install-recommends -y iverilog ### Magic ### #ARG MAGIC_COMMIT=db4fa65bfc096e63954b37b188ea27b90ab31839 #ARG MAGIC_COMMIT=8.3.274 -ARG MAGIC_COMMIT=8.3.211 +ARG MAGIC_COMMIT=8.3.309 WORKDIR /root #RUN git clone https://github.com/RTimothyEdwards/magic.git magic RUN git clone git://opencircuitdesign.com/magic magic diff --git a/openram.mk b/openram.mk index 02a9ee12..d03055b1 100644 --- a/openram.mk +++ b/openram.mk @@ -1,11 +1,18 @@ OPENRAM_HOME := $(abspath $(TOP_DIR)/compiler) OPENRAM_TECH := $(abspath $(TOP_DIR)/technology) OPENRAM_COMPILER := $(OPENRAM_HOME)/openram.py + +PDK_ROOT = $(TOP_DIR) + ifeq (,$(wildcard $(OPENRAM_COMPILER))) $(error Did not find '$(OPENRAM_COMPILER)' in '$(OPENRAM_HOME)' (from $$OPENRAM_HOME)) endif export OPENRAM_HOME export OPENRAM_TECH +export PDK_ROOT +#$(info Using OPENRAM_HOME=$(OPENRAM_HOME)) +#$(info Using OPENRAM_TECH=$(OPENRAM_TECH)) +#$(info Using PDK_ROOT=$(PDK_ROOT)) UID = $(shell id -u) GID = $(shell id -g) From 910bcf9df312726a41d5a00f166216d54ac552eb Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 8 Jun 2022 14:23:28 -0700 Subject: [PATCH 206/229] Update magic to 8.3.310 --- docker/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index fb7e3897..11a7546e 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -129,7 +129,8 @@ RUN apt-get install --no-install-recommends -y iverilog ### Magic ### #ARG MAGIC_COMMIT=db4fa65bfc096e63954b37b188ea27b90ab31839 #ARG MAGIC_COMMIT=8.3.274 -ARG MAGIC_COMMIT=8.3.309 +#ARG MAGIC_COMMIT=8.3.310 +ARG MAGIC_COMMIT=d099562e85e16654ef4573f1eb26c89d1b3d1ee2 WORKDIR /root #RUN git clone https://github.com/RTimothyEdwards/magic.git magic RUN git clone git://opencircuitdesign.com/magic magic From 76bc4e1fc26c5cf35932e6eabb02bff5dfe10f37 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 8 Jun 2022 14:23:50 -0700 Subject: [PATCH 207/229] Only do one extract. Flatten transistors since bug fixed in magic. --- compiler/verify/magic.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 50f27142..4b1109ca 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -96,7 +96,7 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa f.write("gds warning default\n") # Flatten the transistors # Bug in Netgen 1.5.194 when using this... - #f.write("gds flatglob *_?mos_m*\n") + f.write("gds flatglob *_?mos_m*\n") # These two options are temporarily disabled until Tim fixes a bug in magic related # to flattening channel routes and vias (hierarchy with no devices in it). Otherwise, # they appear to be disconnected. @@ -119,12 +119,13 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa pre = "#" else: pre = "" - if final_verification and OPTS.route_supplies: - f.write(pre + "extract unique all\n") # Hack to work around unit scales in SkyWater if OPTS.tech_name=="sky130": f.write(pre + "extract style ngspice(si)\n") - f.write(pre + "extract all\n") + if final_verification and OPTS.route_supplies: + f.write(pre + "extract unique all\n") + else: + f.write(pre + "extract all\n") f.write(pre + "select top cell\n") f.write(pre + "feedback why\n") f.write('puts "Finished extract"\n') From 280582d4d624db85500a6f1604de404c0f77317f Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 8 Jun 2022 14:24:17 -0700 Subject: [PATCH 208/229] Add missing via in dff array --- compiler/modules/dff_array.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/modules/dff_array.py b/compiler/modules/dff_array.py index 5cca38b6..c1fe54b1 100644 --- a/compiler/modules/dff_array.py +++ b/compiler/modules/dff_array.py @@ -119,12 +119,12 @@ class dff_array(design.design): # Add connections every 4 cells for col in range(0, self.columns, 4): vdd_pin=self.dff_insts[0, col].get_pin("vdd") - self.add_power_pin("vdd", vdd_pin.lc()) + self.add_power_pin("vdd", vdd_pin.lc(), start_layer=vdd_pin.layer) # Add connections every 4 cells for col in range(0, self.columns, 4): gnd_pin=self.dff_insts[0, col].get_pin("gnd") - self.add_power_pin("gnd", gnd_pin.rc()) + self.add_power_pin("gnd", gnd_pin.rc(), start_layer=vdd_pin.layer) def add_layout_pins(self): for row in range(self.rows): From 00ca2d45b637603cf859f7b0c39b36b89b1c94b4 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 8 Jun 2022 15:06:06 -0700 Subject: [PATCH 209/229] Extract unique is option not command. --- compiler/verify/magic.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index e18eeb53..0b3a8c26 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -124,8 +124,7 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa f.write(pre + "extract style ngspice(si)\n") if final_verification and OPTS.route_supplies: f.write(pre + "extract unique all\n") - else: - f.write(pre + "extract all\n") + f.write(pre + "extract all\n") f.write(pre + "select top cell\n") f.write(pre + "feedback why\n") f.write('puts "Finished extract"\n') From 9e3a28237f75d55401f1920cd84823d9bb302347 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 8 Jun 2022 17:18:53 -0700 Subject: [PATCH 210/229] Update port data test for sky130 single port --- compiler/tests/18_port_data_wmask_test.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/tests/18_port_data_wmask_test.py b/compiler/tests/18_port_data_wmask_test.py index 9a4f82d5..4f08400b 100755 --- a/compiler/tests/18_port_data_wmask_test.py +++ b/compiler/tests/18_port_data_wmask_test.py @@ -22,9 +22,18 @@ class port_data_wmask_test(openram_test): globals.init_openram(config_file) from sram_config import sram_config + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + c = sram_config(word_size=16, write_size=4, - num_words=16) + num_words=16, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) c.words_per_row = 1 factory.reset() From d30f05a1ae6dd70eb3e5a13afc13d685c85c60ca Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 8 Jun 2022 17:19:26 -0700 Subject: [PATCH 211/229] Update power layer on li for sky130 --- compiler/modules/dff_array.py | 2 +- compiler/modules/dff_inv_array.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/modules/dff_array.py b/compiler/modules/dff_array.py index c1fe54b1..86805407 100644 --- a/compiler/modules/dff_array.py +++ b/compiler/modules/dff_array.py @@ -124,7 +124,7 @@ class dff_array(design.design): # Add connections every 4 cells for col in range(0, self.columns, 4): gnd_pin=self.dff_insts[0, col].get_pin("gnd") - self.add_power_pin("gnd", gnd_pin.rc(), start_layer=vdd_pin.layer) + self.add_power_pin("gnd", gnd_pin.rc(), start_layer=gnd_pin.layer) def add_layout_pins(self): for row in range(self.rows): diff --git a/compiler/modules/dff_inv_array.py b/compiler/modules/dff_inv_array.py index eb3a26d8..20d59939 100644 --- a/compiler/modules/dff_inv_array.py +++ b/compiler/modules/dff_inv_array.py @@ -128,11 +128,11 @@ class dff_inv_array(design.design): for col in range(self.columns): # Adds power pin on left of row vdd_pin=self.dff_insts[row,col].get_pin("vdd") - self.add_power_pin(vdd_pin, loc=vdd_pin.lc()) + self.add_power_pin(vdd_pin, loc=vdd_pin.lc(), start_layer=vdd_pin.layer) # Adds gnd pin on left of row gnd_pin=self.dff_insts[row,col].get_pin("gnd") - self.add_power_pin(gnd_pin, loc=gnd_pin.lc()) + self.add_power_pin(gnd_pin, loc=gnd_pin.lc(), start_layer=gnd_pin.layer) for row in range(self.rows): for col in range(self.columns): From ef7120c5cd44e01d153b976520b5f14cfec624a8 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 9 Jun 2022 06:38:33 -0700 Subject: [PATCH 212/229] Change pdk path in root directory mount command. --- Makefile | 5 +++-- openram.mk | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 8a04a599..6e5a7b13 100644 --- a/Makefile +++ b/Makefile @@ -183,8 +183,9 @@ macros: mount: @docker run -it -v $(TOP_DIR):/openram \ - -v $(SKY130_PDK):$(SKY130_PDK) \ - -e PDK_ROOT=$(PDK_ROOT) \ + -v $(PDK_ROOT):/pdk \ + -e PDK_ROOT=/pdk \ + -e PDKPATH=/pdk/sky130A \ -e OPENRAM_HOME=/openram/compiler \ -e OPENRAM_TECH=/openram/technology \ -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \ diff --git a/openram.mk b/openram.mk index d03055b1..a8776b2e 100644 --- a/openram.mk +++ b/openram.mk @@ -2,7 +2,7 @@ OPENRAM_HOME := $(abspath $(TOP_DIR)/compiler) OPENRAM_TECH := $(abspath $(TOP_DIR)/technology) OPENRAM_COMPILER := $(OPENRAM_HOME)/openram.py -PDK_ROOT = $(TOP_DIR) +PDK_ROOT ?= $(TOP_DIR) ifeq (,$(wildcard $(OPENRAM_COMPILER))) $(error Did not find '$(OPENRAM_COMPILER)' in '$(OPENRAM_HOME)' (from $$OPENRAM_HOME)) From e744ffd6ea497c6d934c33cbed723546de5a1f9e Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 9 Jun 2022 06:44:23 -0700 Subject: [PATCH 213/229] Move mount to shared target in openram.mk --- Makefile | 12 ------------ compiler/tests/Makefile | 15 --------------- openram.mk | 13 +++++++++++++ 3 files changed, 13 insertions(+), 27 deletions(-) diff --git a/Makefile b/Makefile index 6e5a7b13..29278892 100644 --- a/Makefile +++ b/Makefile @@ -181,18 +181,6 @@ macros: .PHONY: macros -mount: - @docker run -it -v $(TOP_DIR):/openram \ - -v $(PDK_ROOT):/pdk \ - -e PDK_ROOT=/pdk \ - -e PDKPATH=/pdk/sky130A \ - -e OPENRAM_HOME=/openram/compiler \ - -e OPENRAM_TECH=/openram/technology \ - -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \ - --user $(UID):$(GID) \ - vlsida/openram-ubuntu:latest -.PHONY: mount - clean: @rm -f *.zip .PHONE: clean diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 2cd5c17d..5c09d88f 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -139,21 +139,6 @@ $(TEST_BASES): docker-pull: docker pull vlsida/openram-ubuntu:latest -# Mount environment for debug -# -mount: - docker run -it \ - -v $(TOP_DIR):/openram \ - -v $(FREEPDK45):/freepdk45 \ - -e FREEPDK45=/freepdk45\ - -v $(PDK_ROOT):/pdk \ - -e PDK_ROOT=/pdk \ - -e PDKPATH=/pdk/sky130A \ - -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \ - --user $(UID):$(GID) \ - vlsida/openram-ubuntu:latest -.PHONY: mount - clean: @rm -rf $(TOP_DIR)/compiler/tests/results .PHONE: clean diff --git a/openram.mk b/openram.mk index a8776b2e..742b31d0 100644 --- a/openram.mk +++ b/openram.mk @@ -16,3 +16,16 @@ export PDK_ROOT UID = $(shell id -u) GID = $(shell id -g) + +mount: + @docker run -it -v $(TOP_DIR):/openram \ + -v $(PDK_ROOT):/pdk \ + -e PDK_ROOT=/pdk \ + -e PDKPATH=/pdk/sky130A \ + -e OPENRAM_HOME=/openram/compiler \ + -e OPENRAM_TECH=/openram/technology \ + -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \ + --user $(UID):$(GID) \ + vlsida/openram-ubuntu:latest +.PHONY: mount + From cf03454ecfb5433e86d94499f001220648f32b63 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 10 Jun 2022 09:18:40 -0700 Subject: [PATCH 214/229] Don't add wdriver_sel_n pins which aren't used. --- compiler/modules/port_data.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index aca8cd02..270cfed5 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -511,9 +511,6 @@ class port_data(design.design): wdriver_inst = self.write_driver_array_inst for bit in range(self.num_wmasks): - # Bring write mask AND array output pin to port data level - self.copy_layout_pin(wmask_inst, "wmask_out_{0}".format(bit), "wdriver_sel_{0}".format(bit)) - wmask_out_pin = wmask_inst.get_pin("wmask_out_{0}".format(bit)) wdriver_en_pin = wdriver_inst.get_pin("en_{0}".format(bit)) From f0f2c26e8d49c95d601cf37cdd761332a1149f19 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 13 Jun 2022 14:13:05 -0700 Subject: [PATCH 215/229] Add both sp and dp tiny test macro. --- ...sram_tiny.py => sky130_sram_1rw1r_tiny.py} | 0 macros/configs/sky130_sram_1rw_tiny.py | 24 +++++++++++++++++++ 2 files changed, 24 insertions(+) rename macros/configs/{sky130_sram_tiny.py => sky130_sram_1rw1r_tiny.py} (100%) create mode 100644 macros/configs/sky130_sram_1rw_tiny.py diff --git a/macros/configs/sky130_sram_tiny.py b/macros/configs/sky130_sram_1rw1r_tiny.py similarity index 100% rename from macros/configs/sky130_sram_tiny.py rename to macros/configs/sky130_sram_1rw1r_tiny.py diff --git a/macros/configs/sky130_sram_1rw_tiny.py b/macros/configs/sky130_sram_1rw_tiny.py new file mode 100644 index 00000000..85aa34f4 --- /dev/null +++ b/macros/configs/sky130_sram_1rw_tiny.py @@ -0,0 +1,24 @@ +""" +Dual port (1 read/write + 1 read only) 1 kbytes SRAM with byte write. + +FIXME: What is this useful for? +FIXME: Why would you want byte write on this? +""" +word_size = 8 # Bits +num_words = 16 +human_byte_size = "{:.0f}kbytes".format((word_size * num_words)/1024/8) + +# Allow byte writes +write_size = 2 # Bits + +# Dual port +num_rw_ports = 1 +num_r_ports = 0 +num_w_ports = 0 +ports_human = '1rw' + +num_spare_cols = 1 +num_spare_rows = 1 + +import os +exec(open(os.path.join(os.path.dirname(__file__), 'sky130_sram_common.py')).read()) From c07f6d195f96e31fec575543d09f0380fb5449ac Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 13 Jun 2022 14:13:20 -0700 Subject: [PATCH 216/229] Update docker to magic with patch for port first/next. --- docker/Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 11a7546e..8a9a9d79 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -129,13 +129,14 @@ RUN apt-get install --no-install-recommends -y iverilog ### Magic ### #ARG MAGIC_COMMIT=db4fa65bfc096e63954b37b188ea27b90ab31839 #ARG MAGIC_COMMIT=8.3.274 -#ARG MAGIC_COMMIT=8.3.310 -ARG MAGIC_COMMIT=d099562e85e16654ef4573f1eb26c89d1b3d1ee2 +ARG MAGIC_COMMIT=8.3.311 WORKDIR /root #RUN git clone https://github.com/RTimothyEdwards/magic.git magic RUN git clone git://opencircuitdesign.com/magic magic WORKDIR /root/magic RUN git checkout ${MAGIC_COMMIT} +COPY mrg.patch /root/magic +RUN git apply mrg.patch RUN ./configure \ && make \ && make install From 956fac2cecc42c6f1afad27e225bd2361e5aa790 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 13 Jun 2022 14:13:35 -0700 Subject: [PATCH 217/229] Add patch. --- docker/mrg.patch | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 docker/mrg.patch diff --git a/docker/mrg.patch b/docker/mrg.patch new file mode 100644 index 00000000..01b38f96 --- /dev/null +++ b/docker/mrg.patch @@ -0,0 +1,22 @@ +diff --git a/commands/CmdLQ.c b/commands/CmdLQ.c +index ca70086..ee3242c 100644 +--- a/commands/CmdLQ.c ++++ b/commands/CmdLQ.c +@@ -1745,7 +1745,7 @@ CmdPort(w, cmd) + if (sl->lab_flags & PORT_DIR_MASK) + { + idx = (int)sl->lab_port; +- if (idx < i) i = idx; ++ if (idx < i || i == -1) i = idx; + } + } + #ifdef MAGIC_WRAPPER +@@ -1764,7 +1764,7 @@ CmdPort(w, cmd) + { + idx = (int)sl->lab_port; + if (idx > refidx) +- if (idx < i) i = idx; ++ if (idx < i || i == -1) i = idx; + } + } + #ifdef MAGIC_WRAPPER From 69bb6826dcdb1074f7ffa8a232637e7cd10ff10e Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 14 Jun 2022 12:08:56 -0700 Subject: [PATCH 218/229] Remove duplicate mount target --- macros/Makefile | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/macros/Makefile b/macros/Makefile index ca7bcdc7..a51cd678 100644 --- a/macros/Makefile +++ b/macros/Makefile @@ -74,17 +74,6 @@ scn4m_subm: $(SCN4M_SUBM_STAMPS) vlsida/openram-ubuntu:latest \ python3 -u /openram/compiler/openram.py $(OPENRAM_OPTS) -o $* -p /openram/macros/$* /openram/macros/$< && touch $@ -mount: - docker run -it -v $(TOP_DIR):/openram \ - -v $(SKY130_PDK):$(SKY130_PDK) \ - -e PDK_ROOT=$(PDK_ROOT) \ - -e OPENRAM_HOME=/openram/compiler \ - -e OPENRAM_TECH=/openram/technology \ - --user $(UID):$(GID) \ - vlsida/openram-ubuntu:latest -.PHONY: mount - - .DELETE_ON_ERROR: $(STAMPS) $(DIRS): From 98fe4c74a41223d03e880c6561691aa267509fa8 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Wed, 15 Jun 2022 22:34:21 -0700 Subject: [PATCH 219/229] colend fixes in progress --- .../modules/sky130_bitcell_base_array.py | 5 +-- .../sky130/modules/sky130_col_cap_array.py | 34 +++++++++++-------- .../sky130/modules/sky130_dummy_array.py | 4 +-- .../sky130/modules/sky130_replica_column.py | 4 +-- technology/sky130/tech/tech.py | 16 +++++---- 5 files changed, 36 insertions(+), 27 deletions(-) diff --git a/technology/sky130/modules/sky130_bitcell_base_array.py b/technology/sky130/modules/sky130_bitcell_base_array.py index 6eae4fea..adaf1304 100644 --- a/technology/sky130/modules/sky130_bitcell_base_array.py +++ b/technology/sky130/modules/sky130_bitcell_base_array.py @@ -107,6 +107,7 @@ class sky130_bitcell_base_array(bitcell_base_array): strap_pins.extend(["top_gate"]) else: strap_pins.extend(["bot_gate"]) + strap_pins.extend(["vdd", "gnd"]) return strap_pins def get_row_cap_pins(self, row, col): @@ -131,7 +132,7 @@ class sky130_bitcell_base_array(bitcell_base_array): self.copy_layout_pin(inst, pin_name) if row == 2: #add only 1 label per col - if 'VPB' in self.cell_inst[row, col].mod.pins: + if 'VPB' or 'vpb' in self.cell_inst[row, col].mod.pins: pin = inst.get_pin("vpb") self.objs.append(geometry.rectangle(layer["nwell"], pin.ll(), @@ -139,7 +140,7 @@ class sky130_bitcell_base_array(bitcell_base_array): pin.height())) self.objs.append(geometry.label("vdd", layer["nwell"], pin.center())) - if 'VNB' in self.cell_inst[row, col].mod.pins: + if 'VNB' or 'vnb'in self.cell_inst[row, col].mod.pins: try: from tech import layer_override if layer_override['VNB']: diff --git a/technology/sky130/modules/sky130_col_cap_array.py b/technology/sky130/modules/sky130_col_cap_array.py index 909dfd21..29f0f9a5 100644 --- a/technology/sky130/modules/sky130_col_cap_array.py +++ b/technology/sky130/modules/sky130_col_cap_array.py @@ -42,7 +42,7 @@ class sky130_col_cap_array(sky130_bitcell_base_array): self.place_array("dummy_r{0}_c{1}", self.mirror) self.add_layout_pins() - #self.add_supply_pins() + self.add_supply_pins() self.add_boundary() self.DRC_LVS() @@ -79,6 +79,8 @@ class sky130_col_cap_array(sky130_bitcell_base_array): pins.append("gnd") pins.append("fake_br_{}".format(bitline)) pins.append("gate") + pins.append("vdd") + pins.append("gnd") bitline += 1 elif col % 4 == 1: row_layout.append(self.colend2) @@ -94,6 +96,8 @@ class sky130_col_cap_array(sky130_bitcell_base_array): pins.append("gnd") pins.append("fake_br_{}".format(bitline)) pins.append("gate") + pins.append("vdd") + pins.append("gnd") bitline += 1 elif col % 4 ==3: row_layout.append(self.colend2) @@ -136,6 +140,7 @@ class sky130_col_cap_array(sky130_bitcell_base_array): self.add_pin("gnd", "GROUND") self.add_pin("gate", "BIAS") + def add_layout_pins(self): """ Add the layout pins """ # Add vdd/gnd via stacks @@ -208,35 +213,36 @@ class sky130_col_cap_array(sky130_bitcell_base_array): offset=pin.ll().scale(1, 0), width=pin.width(), height=pin.height()) - - - - return def add_supply_pins(self): - for col in range(self.cols): + for col in range(len(self.insts)): inst = self.cell_inst[col] - if 'VPB' in self.cell_inst[col].mod.pins: + + if 'VPB' or 'vnb' in self.cell_inst[col].mod.pins: pin = inst.get_pin("vpb") self.objs.append(geometry.rectangle(layer["nwell"], - pin.ll(), - pin.width(), - pin.height())) + pin.ll(), + pin.width(), + pin.height())) self.objs.append(geometry.label("vdd", layer["nwell"], pin.center())) - if 'VNB' in self.cell_inst[col].mod.pins: + + if 'VNB' or 'vnb' in self.cell_inst[col].mod.pins: try: from tech import layer_override if layer_override['VNB']: pin = inst.get_pin("vnb") self.objs.append(geometry.label("gnd", layer["pwellp"], pin.center())) self.objs.append(geometry.rectangle(layer["pwellp"], - pin.ll(), - pin.width(), - pin.height())) + pin.ll(), + pin.width(), + pin.height())) except: pin = inst.get_pin("vnb") + self.add_label("vdd", pin.layer, pin.center()) + + def create_all_wordline_names(self, row_size=None): if row_size == None: diff --git a/technology/sky130/modules/sky130_dummy_array.py b/technology/sky130/modules/sky130_dummy_array.py index 955e640f..246a7f86 100644 --- a/technology/sky130/modules/sky130_dummy_array.py +++ b/technology/sky130/modules/sky130_dummy_array.py @@ -167,7 +167,7 @@ class sky130_dummy_array(sky130_bitcell_base_array): for row in range(self.row_size): for col in range(self.column_size): inst = self.cell_inst[row, col] - if 'VPB' in self.cell_inst[row, col].mod.pins: + if 'VPB' or 'vpb' in self.cell_inst[row, col].mod.pins: pin = inst.get_pin("vpb") self.objs.append(geometry.rectangle(layer["nwell"], pin.ll(), @@ -175,7 +175,7 @@ class sky130_dummy_array(sky130_bitcell_base_array): pin.height())) self.objs.append(geometry.label("vdd", layer["nwell"], pin.center())) - if 'VNB' in self.cell_inst[row, col].mod.pins: + if 'VNB' or 'vnb' in self.cell_inst[row, col].mod.pins: try: from tech import layer_override if layer_override['VNB']: diff --git a/technology/sky130/modules/sky130_replica_column.py b/technology/sky130/modules/sky130_replica_column.py index d0eb9979..1dd1ba2b 100644 --- a/technology/sky130/modules/sky130_replica_column.py +++ b/technology/sky130/modules/sky130_replica_column.py @@ -226,7 +226,7 @@ class sky130_replica_column(sky130_bitcell_base_array): for pin_name in ["vdd", "gnd"]: self.copy_layout_pin(inst, pin_name) if row == 2: - if 'VPB' in self.cell_inst[row].mod.pins: + if 'VPB' or 'vpb' in self.cell_inst[row].mod.pins: pin = inst.get_pin("vpb") self.objs.append(geometry.rectangle(layer["nwell"], pin.ll(), @@ -234,7 +234,7 @@ class sky130_replica_column(sky130_bitcell_base_array): pin.height())) self.objs.append(geometry.label("vdd", layer["nwell"], pin.center())) - if 'VNB' in self.cell_inst[row].mod.pins: + if 'VNB' or 'vnb' in self.cell_inst[row].mod.pins: try: from tech import layer_override if layer_override['VNB']: diff --git a/technology/sky130/tech/tech.py b/technology/sky130/tech/tech.py index 72250afc..9eec156b 100644 --- a/technology/sky130/tech/tech.py +++ b/technology/sky130/tech/tech.py @@ -116,13 +116,15 @@ cell_properties.bitcell_2port.vdd_dir = "H" cell_properties.bitcell_2port.gnd_layer = "m2" cell_properties.bitcell_2port.gnd_dir = "H" -cell_properties.col_cap_1port_bitcell = cell(['br', 'vdd', 'gnd', 'bl', 'gate'], - ['INPUT', 'POWER', 'GROUND', 'INPUT', 'INPUT'], - {'bl': 'BL0', - 'br': 'BL1', - 'vdd': 'VPWR', - 'gnd': 'VGND', - 'gate': 'gate'}) +cell_properties.col_cap_1port_bitcell = cell(['bl', 'vdd', 'gnd', 'br', 'gate', 'vpb', 'vnb'], + ['INPUT', 'POWER', 'GROUND', 'INPUT', 'INPUT', 'BIAS', 'BIAS'], + {'bl': 'bl', + 'br': 'br', + 'vdd': 'vdd', + 'gnd': 'gnd', + 'gate': 'gate', + 'vnb': 'vnb', + 'vpb': 'vpb'}) cell_properties.col_cap_1port_bitcell.boundary_layer = "mem" cell_properties.col_cap_1port_strap_power = cell(['vdd', 'vpb', 'vnb'], From dc9ae6cd1a3b060a439497ec68fbcad6f589ca0f Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 16 Jun 2022 10:30:58 -0700 Subject: [PATCH 220/229] Increase column width in netgen LVS scripts --- compiler/verify/magic.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 0b3a8c26..2b5727ed 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -267,6 +267,11 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, out if os.path.exists(full_setup_file): # Copy setup.tcl file into temp dir shutil.copy(full_setup_file, output_path) + + setup_file_object = open(output_path + "/setup.tcl", 'a') + setup_file_object.write("# Increase the column sizes for ease of reading long names\n") + setup_file_object.write("::netgen::format 80\n") + else: setup_file = 'nosetup' From c479915c0232ae93d21139a092e59a7a3ce212db Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 16 Jun 2022 11:23:13 -0700 Subject: [PATCH 221/229] Update colenda with new device sizes. --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 29278892..3fac66b0 100644 --- a/Makefile +++ b/Makefile @@ -5,9 +5,12 @@ include $(TOP_DIR)/openram.mk # Skywater PDK SRAM library SRAM_LIB_DIR ?= $(PDK_ROOT)/sky130_fd_bd_sram +# Use this for release SRAM_LIB_GIT_REPO ?= https://github.com/vlsida/sky130_fd_bd_sram.git +# Use this for development +#SRAM_LIB_GIT_REPO ?= git@github.com:VLSIDA/sky130_fd_bd_sram.git #SRAM_LIB_GIT_REPO ?= https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git -SRAM_LIB_GIT_COMMIT ?= 9d452eea52cde23f0a5b03e1c5ccf1ca27dd771a +SRAM_LIB_GIT_COMMIT ?= a83b6468c48434d927b90058b22047843c58027b # Open PDKs OPEN_PDKS_DIR ?= $(PDK_ROOT)/open_pdks From 374562f3546232940a4390a057df37d84bfc2292 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Thu, 16 Jun 2022 15:17:07 -0700 Subject: [PATCH 222/229] rbc substrate issues --- .../sky130/modules/sky130_col_cap_array.py | 10 ++--- .../modules/sky130_replica_bitcell_array.py | 4 +- .../sky130/modules/sky130_replica_column.py | 44 ++++++++++--------- 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/technology/sky130/modules/sky130_col_cap_array.py b/technology/sky130/modules/sky130_col_cap_array.py index 29f0f9a5..214a53a8 100644 --- a/technology/sky130/modules/sky130_col_cap_array.py +++ b/technology/sky130/modules/sky130_col_cap_array.py @@ -135,7 +135,7 @@ class sky130_col_cap_array(sky130_bitcell_base_array): for fake_bl in range(self.cols): self.add_pin("fake_bl_{}".format(fake_bl), "OUTPUT") self.add_pin("fake_br_{}".format(fake_bl), "OUTPUT") - self.add_pin("fake_wl", "INPUT") + #self.add_pin("fake_wl", "INPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") self.add_pin("gate", "BIAS") @@ -150,26 +150,26 @@ class sky130_col_cap_array(sky130_bitcell_base_array): for pin in inst.get_pins(pin_name): if inst.mod.cell_name == 'sky130_fd_bd_sram__sram_sp_colend' or 'sky130_fd_bd_sram__sram_sp_colenda': if inst.mirror == "MY": - if pin_name == "vdd": + if pin_name == "vdd" and pin.layer == 'm1': self.add_layout_pin_rect_center(text="vdd", layer=pin.layer, offset=inst.lr(), width=pin.width(), height=pin.height()) - elif pin_name == "gnd": + elif pin_name == "gnd" and pin.layer == 'm1': self.add_layout_pin_rect_center(text="gnd", layer=pin.layer, offset=inst.ll(), width=pin.width(), height=pin.height()) else: - if pin_name == "vdd": + if pin_name == "vdd" and pin.layer == 'm1': self.add_layout_pin_rect_center(text="vdd", layer=pin.layer, offset=inst.ll(), width=pin.width(), height=pin.height()) - elif pin_name == "gnd": + elif pin_name == "gnd" and pin.layer == 'm1': self.add_layout_pin_rect_center(text="gnd", layer=pin.layer, offset=inst.lr(), diff --git a/technology/sky130/modules/sky130_replica_bitcell_array.py b/technology/sky130/modules/sky130_replica_bitcell_array.py index 19042982..09e00d4c 100644 --- a/technology/sky130/modules/sky130_replica_bitcell_array.py +++ b/technology/sky130/modules/sky130_replica_bitcell_array.py @@ -407,10 +407,10 @@ class sky130_replica_bitcell_array(replica_bitcell_array, sky130_bitcell_base_ar self.dummy_row_insts = [] self.dummy_row_insts.append(self.add_inst(name="dummy_row_bot", mod=self.col_cap_bottom)) - self.connect_inst(self.all_bitline_names + ["gnd"] * len(self.col_cap_bottom.get_wordline_names()) + self.supplies + ["gnd"]) + self.connect_inst(self.all_bitline_names + self.supplies + ["gnd"]) self.dummy_row_insts.append(self.add_inst(name="dummy_row_top", mod=self.col_cap_top)) - self.connect_inst(self.all_bitline_names + ["gnd"] * len(self.col_cap_top.get_wordline_names()) + self.supplies + ["gnd"]) + self.connect_inst(self.all_bitline_names + self.supplies + ["gnd"]) # Left/right Dummy columns self.dummy_col_insts = [] diff --git a/technology/sky130/modules/sky130_replica_column.py b/technology/sky130/modules/sky130_replica_column.py index 1dd1ba2b..f05f91b8 100644 --- a/technology/sky130/modules/sky130_replica_column.py +++ b/technology/sky130/modules/sky130_replica_column.py @@ -225,28 +225,32 @@ class sky130_replica_column(sky130_bitcell_base_array): # add only 1 label per col for pin_name in ["vdd", "gnd"]: self.copy_layout_pin(inst, pin_name) - if row == 2: - if 'VPB' or 'vpb' in self.cell_inst[row].mod.pins: - pin = inst.get_pin("vpb") - self.objs.append(geometry.rectangle(layer["nwell"], - pin.ll(), - pin.width(), - pin.height())) - self.objs.append(geometry.label("vdd", layer["nwell"], pin.center())) + #if row == 2: + if 'VPB' or 'vpb' in self.cell_inst[row].mod.pins: + pin = inst.get_pin("vpb") + self.objs.append(geometry.rectangle(layer["nwell"], + pin.ll(), + pin.width(), + pin.height())) + self.objs.append(geometry.label("vdd", layer["nwell"], pin.center())) - if 'VNB' or 'vnb' in self.cell_inst[row].mod.pins: - try: - from tech import layer_override - if layer_override['VNB']: - pin = inst.get_pin("vnb") - self.objs.append(geometry.label("gnd", layer["pwellp"], pin.center())) - self.objs.append(geometry.rectangle(layer["pwellp"], - pin.ll(), - pin.width(), - pin.height())) - except: + if 'VNB' or 'vnb' in self.cell_inst[row].mod.pins: + print("welling") + try: + from tech import layer_override + if layer_override['VNB']: pin = inst.get_pin("vnb") - self.add_label("vdd", pin.layer, pin.center()) + self.add_label("gnd", pin.layer, pin.center()) + self.objs.append(geometry.rectangle(layer["pwellp"], + pin.ll(), + pin.width(), + pin.height())) + self.objs.append(geometry.label("gnd", layer["pwellp"], pin.center())) + + + except: + pin = inst.get_pin("vnb") + self.add_label("gnd", pin.layer, pin.center()) def exclude_all_but_replica(self): """ From ac86ad0e8a505f0a03eb84b7d6fedcf62ea635f3 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 21 Jun 2022 12:10:15 -0700 Subject: [PATCH 223/229] Move pdk installation inside docker to use Magic from docker image. --- Makefile | 27 ++++++++++++++++----------- compiler/tests/Makefile | 13 +------------ docker/Makefile | 9 --------- docker/set-paths.sh | 7 ------- macros/Makefile | 10 +++++++--- openram.mk | 19 ++++++++++++++++++- 6 files changed, 42 insertions(+), 43 deletions(-) diff --git a/Makefile b/Makefile index 3fac66b0..89defd4f 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,7 @@ OPEN_PDKS_GIT_REPO ?= https://github.com/RTimothyEdwards/open_pdks.git OPEN_PDKS_GIT_COMMIT ?= 1.0.311 #OPEN_PDKS_GIT_COMMIT ?= 7ea416610339d3c29af9d0d748ceadd3fd368608 SKY130_PDK ?= $(PDK_ROOT)/sky130A +INSTALL_SRAM = false # Skywater PDK SKY130_PDKS_DIR ?= $(PDK_ROOT)/skywater-pdk @@ -53,32 +54,36 @@ ifndef PDK_ROOT endif $(SKY130_PDKS_DIR): check-pdk-root - git clone https://github.com/google/skywater-pdk.git $(PDK_ROOT)/skywater-pdk - cd $(SKY130_PDKS_DIR) && \ + @echo "Cloning skywater PDK..." + @[ -d $(PDK_ROOT)/skywater-pdk ] || \ + git clone https://github.com/google/skywater-pdk.git $(PDK_ROOT)/skywater-pdk + @cd $(SKY130_PDKS_DIR) && \ git checkout main && git pull && \ git checkout -qf $(SKY130_PDKS_GIT_COMMIT) && \ git submodule update --init libraries/sky130_fd_pr/latest $(OPEN_PDKS_DIR): $(SKY130_PDKS_DIR) @echo "Cloning open_pdks..." - git clone $(OPEN_PDKS_GIT_REPO) $(OPEN_PDKS_DIR) - cd $(OPEN_PDKS_DIR) && git checkout $(OPEN_PDKS_GIT_COMMIT) + @[ -d $(OPEN_PDKS_DIR) ] || \ + git clone $(OPEN_PDKS_GIT_REPO) $(OPEN_PDKS_DIR) + @cd $(OPEN_PDKS_DIR) && git pull && git checkout $(OPEN_PDKS_GIT_COMMIT) -$(SKY130_PDK): $(OPEN_PDKS_DIR) +$(SKY130_PDK): $(OPEN_PDKS_DIR) $(SKY130_PDKS_DIR) @echo "Installing open_pdks..." - cd $(OPEN_PDKS_DIR) && \ - ./configure --enable-sky130-pdk=$(PDK_ROOT)/skywater-pdk/libraries --with-sky130-local-path=$(PDK_ROOT) --enable-sram-sky130=$(INSTALL_SRAM) && \ + $(DOCKER_CMD) sh -c ". /home/cad-user/.bashrc && cd /pdk/open_pdks && \ + ./configure --enable-sky130-pdk=/pdk/skywater-pdk/libraries --with-sky130-local-path=/pdk --enable-sram-sky130=$(INSTALL_SRAM) && \ cd sky130 && \ make veryclean && \ make && \ - make SHARED_PDKS_PATH=$(PDK_ROOT) install + make SHARED_PDKS_PATH=/pdk install" $(SRAM_LIB_DIR): check-pdk-root + @echo "Cloning SRAM library..." @[ -d $(SRAM_LIB_DIR) ] || (\ - echo "Cloning SRAM library..." && git clone $(SRAM_LIB_GIT_REPO) $(SRAM_LIB_DIR) && \ - cd $(SRAM_LIB_DIR) && git checkout $(SRAM_LIB_GIT_COMMIT)) + git clone $(SRAM_LIB_GIT_REPO) $(SRAM_LIB_DIR) && \ + cd $(SRAM_LIB_DIR) && git pull && git checkout $(SRAM_LIB_GIT_COMMIT)) -install: $(SRAM_LIB_DIR) +install: $(SRAM_LIB_DIR) pdk @[ -d $(PDK_ROOT)/sky130A ] || \ (echo "Warning: $(PDK_ROOT)/sky130A not found!! Run make pdk first." && false) @[ -d $(PDK_ROOT)/skywater-pdk ] || \ diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 5c09d88f..f7bbc91b 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -118,18 +118,7 @@ $(TEST_BASES): @rm -rf results/$* @rm -rf results/$*.* @mkdir -p results/$*/tmp - @docker run \ - -v $(TOP_DIR):/openram \ - -v $(FREEPDK45):/freepdk45 \ - -e FREEPDK45=/freepdk45 \ - -v $(PDK_ROOT):/pdk \ - -e PDK_ROOT=/pdk \ - -e PDKPATH=/pdk/sky130A \ - -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \ - --user $(UID):$(GID) \ - -e OPENRAM_TMP=$(OPENRAM_DIR)/results/$*/tmp \ - vlsida/openram-ubuntu:latest \ - sh -c ". /home/cad-user/.bashrc && sleep 1 && python3 -u $(OPENRAM_DIR)/$(getfile).py \ + @$(DOCKER_CMD) sh -c ". /home/cad-user/.bashrc && sleep 1 && python3 -u $(OPENRAM_DIR)/$(getfile).py \ -t $(gettech) -k -v $(ARGS) -p $(OPENRAM_DIR)/results/$* > $(OPENRAM_DIR)/results/$*.out 2>&1 && touch $(OPENRAM_DIR)/results/$*.ok || touch $(OPENRAM_DIR)/results/$*.bad" @test -f $(TOP_DIR)/compiler/tests/results/$*.ok && echo "$* ... PASS!" && \ rm -rf $(TOP_DIR)/compiler/tests/results/$* || echo "$* ... FAIL!" diff --git a/docker/Makefile b/docker/Makefile index 5ef0d273..0e6a0143 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -19,12 +19,3 @@ push: pull: docker pull vlsida/openram-ubuntu:latest -mount: - docker run -it -v $(TOP_DIR):/openram \ - -v $(SKY130_PDK):$(SKY130_PDK) \ - -e PDK_ROOT=$(PDK_ROOT) \ - -e OPENRAM_HOME=/openram/compiler \ - -e OPENRAM_TECH=/openram/technology \ - --user $(UID):$(GID) \ - vlsida/openram-ubuntu:latest -.PHONY: mount diff --git a/docker/set-paths.sh b/docker/set-paths.sh index bbe2023d..1435f7cb 100644 --- a/docker/set-paths.sh +++ b/docker/set-paths.sh @@ -13,10 +13,3 @@ export PATH=$PATH:$XYCE_PATH export XYCE_LIB=$XYCE_HOME/lib export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$XYCE_LIB export XYCE_NO_TRACKING="anything at all" - -# OpenRAM -export OPENRAM_HOME=/openram/compiler -export OPENRAM_TECH=/openram/technology - -# FreePDK45 -export FREEPDK45=/freepdk45 diff --git a/macros/Makefile b/macros/Makefile index a51cd678..f2b02466 100644 --- a/macros/Makefile +++ b/macros/Makefile @@ -64,12 +64,16 @@ scn4m_subm: $(SCN4M_SUBM_STAMPS) %.ok: configs/%.py @echo "Building $*" @mkdir -p $* - docker run -v $(TOP_DIR):/openram \ - -v $(SKY130_PDK):$(SKY130_PDK) \ - -e PDK_ROOT=$(PDK_ROOT) \ + @docker run -v $(TOP_DIR):/openram \ + -v $(FREEPDK45):/freepdk45 \ + -e FREEPDK45=/freepdk45 \ + -v $(PDK_ROOT):/pdk \ + -e PDK_ROOT=/pdk \ + -e PDKPATH=/pdk/sky130A \ -e OPENRAM_HOME=/openram/compiler \ -e OPENRAM_TECH=/openram/technology \ -e OPENRAM_TMP=/openram/macros/$*/tmp \ + -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \ --user $(UID):$(GID) \ vlsida/openram-ubuntu:latest \ python3 -u /openram/compiler/openram.py $(OPENRAM_OPTS) -o $* -p /openram/macros/$* /openram/macros/$< && touch $@ diff --git a/openram.mk b/openram.mk index 742b31d0..b0e57268 100644 --- a/openram.mk +++ b/openram.mk @@ -17,8 +17,25 @@ export PDK_ROOT UID = $(shell id -u) GID = $(shell id -g) +export DOCKER_CMD= docker run \ + -v $(TOP_DIR):/openram \ + -v $(FREEPDK45):/freepdk45 \ + -e FREEPDK45=/freepdk45 \ + -v $(PDK_ROOT):/pdk \ + -e PDK_ROOT=/pdk \ + -e PDKPATH=/pdk/sky130A \ + -e OPENRAM_HOME=/openram/compiler \ + -e OPENRAM_TECH=/openram/technology \ + -e OPENRAM_TMP=$(OPENRAM_DIR)/results/$*/tmp \ + -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \ + --user $(UID):$(GID) \ + vlsida/openram-ubuntu:latest + mount: - @docker run -it -v $(TOP_DIR):/openram \ + @docker run -it \ + -v $(TOP_DIR):/openram \ + -v $(FREEPDK45):/freepdk45 \ + -e FREEPDK45=/freepdk45 \ -v $(PDK_ROOT):/pdk \ -e PDK_ROOT=/pdk \ -e PDKPATH=/pdk/sky130A \ From f7738c60a3e2fd5edbd70f1022d8fc7841b5dd9b Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 21 Jun 2022 13:53:08 -0700 Subject: [PATCH 224/229] Don't install SRAM macros. --- Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 89defd4f..9deeca29 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,6 @@ OPEN_PDKS_GIT_REPO ?= https://github.com/RTimothyEdwards/open_pdks.git OPEN_PDKS_GIT_COMMIT ?= 1.0.311 #OPEN_PDKS_GIT_COMMIT ?= 7ea416610339d3c29af9d0d748ceadd3fd368608 SKY130_PDK ?= $(PDK_ROOT)/sky130A -INSTALL_SRAM = false # Skywater PDK SKY130_PDKS_DIR ?= $(PDK_ROOT)/skywater-pdk @@ -71,7 +70,7 @@ $(OPEN_PDKS_DIR): $(SKY130_PDKS_DIR) $(SKY130_PDK): $(OPEN_PDKS_DIR) $(SKY130_PDKS_DIR) @echo "Installing open_pdks..." $(DOCKER_CMD) sh -c ". /home/cad-user/.bashrc && cd /pdk/open_pdks && \ - ./configure --enable-sky130-pdk=/pdk/skywater-pdk/libraries --with-sky130-local-path=/pdk --enable-sram-sky130=$(INSTALL_SRAM) && \ + ./configure --enable-sky130-pdk=/pdk/skywater-pdk/libraries --with-sky130-local-path=/pdk && \ cd sky130 && \ make veryclean && \ make && \ From 58ea148d4738683abfb73a7faa0b41dd06417b52 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 22 Jun 2022 09:53:10 -0700 Subject: [PATCH 225/229] Add dlxtn latch for open reg file --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9deeca29..214b834b 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,7 @@ SKY130_PDKS_GIT_COMMIT ?= f70d8ca46961ff92719d8870a18a076370b85f6c # Create lists of all the files to copy/link GDS_FILES := $(sort $(wildcard $(SRAM_LIB_DIR)/cells/*/*.gds)) +GDS_FILES := $(GDS_FILES) $(PDK_ROOT)/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/dlxtn/sky130_fd_sc_hd__dlxtn_1.gds MAG_FILES := $(sort $(wildcard $(SRAM_LIB_DIR)/cells/*/*.mag)) SPICE_SUFFIX := spice @@ -34,6 +35,7 @@ SPICE_CALIBRE_SUFFIX := lvs.calibre.$(SPICE_SUFFIX) SPICE_KLAYOUT_SUFFIX := lvs.klayout.$(SPICE_SUFFIX) SPICE_BASE_SUFFIX := base.$(SPICE_SUFFIX) ALL_SPICE_FILES := $(sort $(wildcard $(SRAM_LIB_DIR)/cells/*/*.$(SPICE_SUFFIX))) +ALL_SPICE_FILES := $(ALL_SPICE_FILES) $(PDK_ROOT)/skywater-pdk/libraries/sky130_fd_sc_hd/latest/cells/dlxtn/sky130_fd_sc_hd__dlxtn_1.spice MAGLEF_SUFFIX := maglef MAGLEF_FILES := $(sort $(wildcard $(SRAM_LIB_DIR)/cells/*/*.$(MAGLEF_SUFFIX))) @@ -59,7 +61,7 @@ $(SKY130_PDKS_DIR): check-pdk-root @cd $(SKY130_PDKS_DIR) && \ git checkout main && git pull && \ git checkout -qf $(SKY130_PDKS_GIT_COMMIT) && \ - git submodule update --init libraries/sky130_fd_pr/latest + git submodule update --init libraries/sky130_fd_pr/latest libraries/sky130_fd_sc_hd/latest $(OPEN_PDKS_DIR): $(SKY130_PDKS_DIR) @echo "Cloning open_pdks..." From d92c7a634dc845bcb3306f9260181305c894b06e Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 13 Jul 2022 10:57:56 -0700 Subject: [PATCH 226/229] Use packages for imports. Must set PYTHONPATH to include OPENRAM_HOME now. Reorganizes subdirs as packages. Rewrites unit tests to use packages. Update README.md with instructions, dependencies etc. Update sky130 module imports. Change tech specific package from modules to custom. --- README.md | 56 ++- compiler/base/__init__.py | 21 ++ compiler/base/channel_route.py | 6 +- compiler/base/contact.py | 60 +-- compiler/base/design.py | 205 +---------- compiler/base/geometry.py | 4 +- compiler/base/hierarchy_design.py | 10 +- compiler/base/hierarchy_layout.py | 343 +++++++++++++++--- compiler/base/hierarchy_spice.py | 12 +- compiler/base/lef.py | 4 +- .../{characterizer => base}/logical_effort.py | 4 +- compiler/base/pin_layout.py | 2 +- compiler/base/route.py | 8 +- compiler/base/utils.py | 6 +- compiler/{router => base}/vector3d.py | 0 compiler/base/wire.py | 18 +- compiler/base/wire_path.py | 6 +- compiler/characterizer/simulation.py | 4 +- compiler/datasheet/__init__.py | 1 + compiler/datasheet/datasheet.py | 2 +- compiler/datasheet/datasheet_gen.py | 18 +- compiler/datasheet/table_gen.py | 2 + compiler/drc/__init__.py | 6 + .../{base => drc}/custom_cell_properties.py | 0 .../{base => drc}/custom_layer_properties.py | 0 compiler/drc/design_rules.py | 4 +- compiler/{modules => drc}/module_type.py | 0 compiler/globals.py | 24 +- compiler/modules/__init__.py | 82 +++++ compiler/modules/and2_dec.py | 8 +- compiler/modules/and3_dec.py | 8 +- compiler/modules/and4_dec.py | 8 +- compiler/modules/bank.py | 6 +- compiler/modules/bank_select.py | 17 +- .../{bitcells => modules}/bitcell_1port.py | 4 +- .../{bitcells => modules}/bitcell_2port.py | 6 +- compiler/modules/bitcell_array.py | 2 +- .../{bitcells => modules}/bitcell_base.py | 22 +- compiler/modules/bitcell_base_array.py | 4 +- compiler/modules/col_cap_array.py | 2 +- .../col_cap_bitcell_1port.py | 4 +- .../col_cap_bitcell_2port.py | 4 +- compiler/modules/column_decoder.py | 6 +- compiler/{pgates => modules}/column_mux.py | 7 +- compiler/modules/column_mux_array.py | 6 +- compiler/modules/control_logic.py | 10 +- compiler/modules/delay_chain.py | 6 +- compiler/{custom => modules}/dff.py | 4 +- compiler/modules/dff_array.py | 6 +- compiler/modules/dff_buf.py | 6 +- compiler/modules/dff_buf_array.py | 6 +- compiler/modules/dff_inv.py | 6 +- compiler/modules/dff_inv_array.py | 6 +- compiler/modules/dummy_array.py | 2 +- .../dummy_bitcell_1port.py | 4 +- .../dummy_bitcell_2port.py | 4 +- .../{bitcells => modules}/dummy_pbitcell.py | 8 +- compiler/modules/global_bitcell_array.py | 6 +- compiler/modules/hierarchical_decoder.py | 6 +- compiler/modules/hierarchical_predecode.py | 6 +- compiler/modules/hierarchical_predecode2x4.py | 2 +- compiler/modules/hierarchical_predecode3x8.py | 2 +- .../modules/hierarchical_predecode4x16.py | 2 +- compiler/{custom => modules}/inv_dec.py | 18 +- compiler/modules/local_bitcell_array.py | 6 +- compiler/modules/multibank.py | 11 +- compiler/{custom => modules}/nand2_dec.py | 20 +- compiler/{custom => modules}/nand3_dec.py | 20 +- compiler/{custom => modules}/nand4_dec.py | 20 +- compiler/modules/orig_bitcell_array.py | 2 +- compiler/{pgates => modules}/pand2.py | 6 +- compiler/{pgates => modules}/pand3.py | 6 +- compiler/{pgates => modules}/pand4.py | 6 +- compiler/{bitcells => modules}/pbitcell.py | 63 ++-- compiler/{pgates => modules}/pbuf.py | 6 +- compiler/{pgates => modules}/pbuf_dec.py | 8 +- compiler/{pgates => modules}/pdriver.py | 6 +- compiler/{pgates => modules}/pgate.py | 17 +- compiler/{pgates => modules}/pinv.py | 33 +- compiler/{pgates => modules}/pinv_dec.py | 27 +- compiler/{pgates => modules}/pinvbuf.py | 6 +- compiler/{pgates => modules}/pnand2.py | 31 +- compiler/{pgates => modules}/pnand3.py | 27 +- compiler/{pgates => modules}/pnand4.py | 27 +- compiler/{pgates => modules}/pnor2.py | 6 +- compiler/modules/port_address.py | 6 +- compiler/modules/port_data.py | 6 +- compiler/{pgates => modules}/precharge.py | 15 +- compiler/modules/precharge_array.py | 6 +- compiler/{pgates => modules}/ptristate_inv.py | 27 +- compiler/{pgates => modules}/ptx.py | 23 +- compiler/{pgates => modules}/pwrite_driver.py | 6 +- .../replica_bitcell_1port.py | 10 +- .../replica_bitcell_2port.py | 10 +- compiler/modules/replica_bitcell_array.py | 9 +- compiler/modules/replica_column.py | 4 +- .../{bitcells => modules}/replica_pbitcell.py | 8 +- compiler/modules/row_cap_array.py | 2 +- .../row_cap_bitcell_1port.py | 4 +- .../row_cap_bitcell_2port.py | 4 +- compiler/{custom => modules}/sense_amp.py | 8 +- compiler/modules/sense_amp_array.py | 6 +- compiler/{sram => modules}/sram.py | 13 +- compiler/{sram => modules}/sram_1bank.py | 11 +- compiler/{sram => modules}/sram_2bank.py | 10 +- compiler/{sram => modules}/sram_base.py | 20 +- compiler/{sram => modules}/sram_config.py | 0 compiler/{custom => modules}/tri_gate.py | 4 +- compiler/modules/tri_gate_array.py | 6 +- compiler/modules/wordline_buffer_array.py | 8 +- .../{pgates => modules}/wordline_driver.py | 6 +- compiler/modules/wordline_driver_array.py | 6 +- compiler/{custom => modules}/write_driver.py | 4 +- compiler/modules/write_driver_array.py | 6 +- compiler/modules/write_mask_and_array.py | 6 +- compiler/openram.py | 4 +- compiler/router/__init__.py | 5 + compiler/router/direction.py | 2 +- compiler/router/grid.py | 4 +- compiler/router/grid_path.py | 6 +- compiler/router/grid_utils.py | 4 +- compiler/router/pin_group.py | 8 +- compiler/router/router.py | 20 +- compiler/router/router_tech.py | 4 +- compiler/router/signal_escape_router.py | 6 +- compiler/router/signal_grid.py | 7 +- compiler/router/supply_grid.py | 4 +- compiler/router/supply_grid_router.py | 12 +- compiler/router/supply_tree_router.py | 10 +- compiler/sram/__init__.py | 5 + compiler/sram_factory.py | 15 +- compiler/tests/00_code_format_check_test.py | 2 +- compiler/tests/01_library_test.py | 2 +- compiler/tests/03_contact_test.py | 2 +- compiler/tests/03_path_test.py | 22 +- compiler/tests/03_ptx_1finger_nmos_test.py | 2 +- compiler/tests/03_ptx_1finger_pmos_test.py | 2 +- compiler/tests/03_ptx_3finger_nmos_test.py | 2 +- compiler/tests/03_ptx_3finger_pmos_test.py | 2 +- compiler/tests/03_ptx_4finger_nmos_test.py | 2 +- compiler/tests/03_ptx_4finger_pmos_test.py | 2 +- compiler/tests/03_ptx_no_contacts_test.py | 2 +- compiler/tests/03_wire_test.py | 10 +- compiler/tests/04_and2_dec_test.py | 2 +- compiler/tests/04_and3_dec_test.py | 2 +- compiler/tests/04_and4_dec_test.py | 2 +- compiler/tests/04_column_mux_1rw_1r_test.py | 2 +- compiler/tests/04_column_mux_pbitcell_test.py | 2 +- compiler/tests/04_column_mux_test.py | 2 +- compiler/tests/04_dff_buf_test.py | 2 +- compiler/tests/04_dummy_pbitcell_test.py | 8 +- compiler/tests/04_pand2_test.py | 6 +- compiler/tests/04_pand3_test.py | 6 +- compiler/tests/04_pand4_test.py | 6 +- compiler/tests/04_pbitcell_test.py | 2 +- compiler/tests/04_pbuf_dec_8x_test.py | 2 +- compiler/tests/04_pbuf_test.py | 2 +- compiler/tests/04_pdriver_test.py | 2 +- compiler/tests/04_pinv_100x_test.py | 2 +- compiler/tests/04_pinv_10x_test.py | 2 +- compiler/tests/04_pinv_1x_beta_test.py | 2 +- compiler/tests/04_pinv_1x_test.py | 2 +- compiler/tests/04_pinv_2x_test.py | 2 +- compiler/tests/04_pinv_dec_1x_test.py | 2 +- compiler/tests/04_pinvbuf_test.py | 2 +- compiler/tests/04_pnand2_test.py | 2 +- compiler/tests/04_pnand3_test.py | 2 +- compiler/tests/04_pnand4_test.py | 2 +- compiler/tests/04_pnor2_test.py | 2 +- compiler/tests/04_precharge_1rw_1r_test.py | 2 +- compiler/tests/04_precharge_pbitcell_test.py | 2 +- compiler/tests/04_precharge_test.py | 2 +- compiler/tests/04_pwrite_driver_test.py | 2 +- compiler/tests/04_replica_pbitcell_test.py | 8 +- compiler/tests/04_wordline_driver_test.py | 2 +- .../tests/05_bitcell_array_1rw_1r_test.py | 2 +- compiler/tests/05_bitcell_array_test.py | 2 +- compiler/tests/05_dummy_array_test.py | 2 +- compiler/tests/05_pbitcell_array_test.py | 2 +- .../tests/06_column_decoder_16row_test.py | 2 +- ...hierarchical_decoder_132row_1rw_1r_test.py | 2 +- .../06_hierarchical_decoder_132row_test.py | 2 +- ..._hierarchical_decoder_16row_1rw_1r_test.py | 2 +- .../06_hierarchical_decoder_16row_test.py | 2 +- ..._hierarchical_decoder_17row_1rw_1r_test.py | 2 +- .../06_hierarchical_decoder_17row_test.py | 2 +- ..._hierarchical_decoder_32row_1rw_1r_test.py | 2 +- .../06_hierarchical_decoder_32row_test.py | 2 +- ...ierarchical_decoder_4096row_1rw_1r_test.py | 2 +- .../06_hierarchical_decoder_4096row_test.py | 2 +- ...hierarchical_decoder_512row_1rw_1r_test.py | 2 +- .../06_hierarchical_decoder_512row_test.py | 2 +- ..._hierarchical_decoder_64row_1rw_1r_test.py | 2 +- .../06_hierarchical_decoder_64row_test.py | 2 +- .../06_hierarchical_decoder_pbitcell_test.py | 2 +- ...6_hierarchical_predecode2x4_1rw_1r_test.py | 2 +- ...hierarchical_predecode2x4_pbitcell_test.py | 2 +- .../06_hierarchical_predecode2x4_test.py | 2 +- ...6_hierarchical_predecode3x8_1rw_1r_test.py | 2 +- ...hierarchical_predecode3x8_pbitcell_test.py | 2 +- .../06_hierarchical_predecode3x8_test.py | 2 +- .../06_hierarchical_predecode4x16_test.py | 2 +- .../07_column_mux_array_16mux_1rw_1r_test.py | 2 +- .../tests/07_column_mux_array_16mux_test.py | 2 +- .../07_column_mux_array_2mux_1rw_1r_test.py | 2 +- .../tests/07_column_mux_array_2mux_test.py | 2 +- .../07_column_mux_array_4mux_1rw_1r_test.py | 2 +- .../tests/07_column_mux_array_4mux_test.py | 2 +- .../07_column_mux_array_8mux_1rw_1r_test.py | 2 +- .../tests/07_column_mux_array_8mux_test.py | 2 +- .../07_column_mux_array_pbitcell_test.py | 2 +- .../tests/08_precharge_array_1rw_1r_test.py | 2 +- compiler/tests/08_precharge_array_test.py | 2 +- .../tests/08_wordline_buffer_array_test.py | 2 +- .../08_wordline_driver_array_1rw_1r_test.py | 2 +- .../08_wordline_driver_array_pbitcell_test.py | 2 +- .../tests/08_wordline_driver_array_test.py | 2 +- .../tests/09_sense_amp_array_1rw_1r_test.py | 2 +- .../tests/09_sense_amp_array_pbitcell_test.py | 2 +- .../09_sense_amp_array_spare_cols_test.py | 2 +- compiler/tests/09_sense_amp_array_test.py | 2 +- .../10_write_driver_array_1rw_1r_test.py | 2 +- .../10_write_driver_array_pbitcell_test.py | 2 +- .../10_write_driver_array_spare_cols_test.py | 2 +- compiler/tests/10_write_driver_array_test.py | 2 +- ..._write_driver_array_wmask_pbitcell_test.py | 2 +- ...rite_driver_array_wmask_spare_cols_test.py | 2 +- .../tests/10_write_driver_array_wmask_test.py | 2 +- .../10_write_mask_and_array_1rw_1r_test.py | 2 +- .../10_write_mask_and_array_pbitcell_test.py | 2 +- .../tests/10_write_mask_and_array_test.py | 2 +- compiler/tests/11_dff_array_test.py | 2 +- compiler/tests/11_dff_buf_array_test.py | 2 +- compiler/tests/12_tri_gate_array_test.py | 2 +- compiler/tests/13_delay_chain_test.py | 2 +- ...plica_bitcell_array_bothrbl_1rw_1r_test.py | 2 +- ...plica_bitcell_array_leftrbl_1rw_1r_test.py | 2 +- ...replica_bitcell_array_norbl_1rw_1r_test.py | 2 +- .../tests/14_replica_bitcell_array_test.py | 2 +- .../tests/14_replica_column_1rw_1r_test.py | 2 +- compiler/tests/14_replica_column_test.py | 2 +- .../tests/14_replica_pbitcell_array_test.py | 2 +- .../15_global_bitcell_array_1rw_1r_test.py | 2 +- .../tests/15_global_bitcell_array_test.py | 2 +- .../15_local_bitcell_array_1rw_1r_test.py | 2 +- compiler/tests/15_local_bitcell_array_test.py | 2 +- .../tests/16_control_logic_multiport_test.py | 4 +- compiler/tests/16_control_logic_r_test.py | 2 +- compiler/tests/16_control_logic_rw_test.py | 2 +- compiler/tests/16_control_logic_w_test.py | 2 +- .../18_port_address_16rows_1rw_1r_test.py | 2 +- compiler/tests/18_port_address_16rows_test.py | 2 +- .../18_port_address_256rows_1rw_1r_test.py | 2 +- .../tests/18_port_address_512rows_test.py | 2 +- .../tests/18_port_data_16mux_1rw_1r_test.py | 4 +- compiler/tests/18_port_data_16mux_test.py | 4 +- .../tests/18_port_data_2mux_1rw_1r_test.py | 4 +- compiler/tests/18_port_data_2mux_test.py | 4 +- .../tests/18_port_data_4mux_1rw_1r_test.py | 4 +- compiler/tests/18_port_data_4mux_test.py | 4 +- .../tests/18_port_data_8mux_1rw_1r_test.py | 4 +- compiler/tests/18_port_data_8mux_test.py | 4 +- .../tests/18_port_data_nomux_1rw_1r_test.py | 4 +- compiler/tests/18_port_data_nomux_test.py | 4 +- .../tests/18_port_data_spare_cols_test.py | 4 +- .../tests/18_port_data_wmask_1rw_1r_test.py | 4 +- compiler/tests/18_port_data_wmask_test.py | 4 +- .../tests/19_bank_select_pbitcell_test.py | 48 --- compiler/tests/19_bank_select_test.py | 35 -- compiler/tests/19_multi_bank_test.py | 4 +- compiler/tests/19_pmulti_bank_test.py | 4 +- compiler/tests/19_psingle_bank_test.py | 4 +- .../tests/19_single_bank_16mux_1rw_1r_test.py | 4 +- compiler/tests/19_single_bank_16mux_test.py | 4 +- compiler/tests/19_single_bank_1w_1r_test.py | 4 +- .../tests/19_single_bank_2mux_1rw_1r_test.py | 4 +- compiler/tests/19_single_bank_2mux_test.py | 4 +- .../tests/19_single_bank_4mux_1rw_1r_test.py | 4 +- compiler/tests/19_single_bank_4mux_test.py | 4 +- .../tests/19_single_bank_8mux_1rw_1r_test.py | 4 +- compiler/tests/19_single_bank_8mux_test.py | 4 +- .../19_single_bank_global_bitline_test.py | 4 +- .../tests/19_single_bank_nomux_1rw_1r_test.py | 4 +- compiler/tests/19_single_bank_nomux_test.py | 4 +- .../tests/19_single_bank_spare_cols_test.py | 4 +- .../tests/19_single_bank_wmask_1rw_1r_test.py | 4 +- compiler/tests/19_single_bank_wmask_test.py | 4 +- .../tests/20_psram_1bank_2mux_1rw_1w_test.py | 4 +- .../20_psram_1bank_2mux_1rw_1w_wmask_test.py | 4 +- .../tests/20_psram_1bank_2mux_1w_1r_test.py | 4 +- compiler/tests/20_psram_1bank_2mux_test.py | 4 +- .../tests/20_psram_1bank_4mux_1rw_1r_test.py | 4 +- .../tests/20_sram_1bank_16mux_1rw_1r_test.py | 4 +- compiler/tests/20_sram_1bank_16mux_test.py | 4 +- ..._sram_1bank_2mux_1rw_1r_spare_cols_test.py | 4 +- .../tests/20_sram_1bank_2mux_1rw_1r_test.py | 4 +- ...0_sram_1bank_2mux_1w_1r_spare_cols_test.py | 4 +- .../tests/20_sram_1bank_2mux_1w_1r_test.py | 4 +- .../tests/20_sram_1bank_2mux_global_test.py | 4 +- compiler/tests/20_sram_1bank_2mux_test.py | 4 +- ...0_sram_1bank_2mux_wmask_spare_cols_test.py | 4 +- .../tests/20_sram_1bank_2mux_wmask_test.py | 4 +- .../20_sram_1bank_32b_1024_wmask_test.py | 4 +- .../tests/20_sram_1bank_4mux_1rw_1r_test.py | 4 +- compiler/tests/20_sram_1bank_4mux_test.py | 4 +- .../tests/20_sram_1bank_8mux_1rw_1r_test.py | 4 +- compiler/tests/20_sram_1bank_8mux_test.py | 4 +- ...sram_1bank_nomux_1rw_1r_spare_cols_test.py | 4 +- .../tests/20_sram_1bank_nomux_1rw_1r_test.py | 4 +- .../20_sram_1bank_nomux_spare_cols_test.py | 4 +- compiler/tests/20_sram_1bank_nomux_test.py | 3 +- ...0_sram_1bank_nomux_wmask_sparecols_test.py | 4 +- .../tests/20_sram_1bank_nomux_wmask_test.py | 4 +- compiler/tests/20_sram_1bank_ring_test.py | 4 +- compiler/tests/20_sram_2bank_test.py | 4 +- compiler/tests/21_hspice_delay_test.py | 4 +- compiler/tests/21_hspice_setuphold_test.py | 2 +- compiler/tests/21_model_delay_test.py | 6 +- .../tests/21_ngspice_delay_extra_rows_test.py | 4 +- .../tests/21_ngspice_delay_global_test.py | 4 +- compiler/tests/21_ngspice_delay_test.py | 4 +- compiler/tests/21_ngspice_setuphold_test.py | 2 +- compiler/tests/21_regression_delay_test.py | 6 +- compiler/tests/21_xyce_delay_test.py | 4 +- compiler/tests/21_xyce_setuphold_test.py | 2 +- .../tests/22_psram_1bank_2mux_func_test.py | 4 +- .../tests/22_psram_1bank_4mux_func_test.py | 4 +- .../tests/22_psram_1bank_8mux_func_test.py | 4 +- .../tests/22_psram_1bank_nomux_func_test.py | 4 +- .../tests/22_sram_1bank_2mux_func_test.py | 4 +- .../22_sram_1bank_2mux_global_func_test.py | 4 +- .../22_sram_1bank_2mux_sparecols_func_test.py | 4 +- .../tests/22_sram_1bank_4mux_func_test.py | 4 +- .../tests/22_sram_1bank_8mux_func_test.py | 4 +- .../22_sram_1bank_nomux_1rw_1r_func_test.py | 4 +- .../tests/22_sram_1bank_nomux_func_test.py | 4 +- ...22_sram_1bank_nomux_sparecols_func_test.py | 4 +- .../22_sram_1bank_wmask_1rw_1r_func_test.py | 4 +- compiler/tests/22_sram_wmask_func_test.py | 4 +- .../23_lib_sram_linear_regression_test.py | 6 +- .../tests/23_lib_sram_model_corners_test.py | 6 +- compiler/tests/23_lib_sram_model_test.py | 6 +- compiler/tests/23_lib_sram_prune_test.py | 6 +- compiler/tests/23_lib_sram_test.py | 6 +- compiler/tests/24_lef_sram_test.py | 6 +- compiler/tests/25_verilog_sram_test.py | 6 +- compiler/tests/26_hspice_pex_pinv_test.py | 2 +- compiler/tests/26_ngspice_pex_pinv_test.py | 2 +- compiler/tests/26_sram_pex_test.py | 4 +- compiler/tests/30_openram_back_end_test.py | 2 +- compiler/tests/30_openram_front_end_test.py | 2 +- compiler/tests/50_riscv_1k_1rw1r_func_test.py | 4 +- compiler/tests/50_riscv_1k_1rw_func_test.py | 4 +- compiler/tests/50_riscv_1rw1r_func_test.py | 4 +- compiler/tests/50_riscv_1rw1r_phys_test.py | 4 +- compiler/tests/50_riscv_1rw_func_test.py | 4 +- compiler/tests/50_riscv_1rw_phys_test.py | 4 +- compiler/tests/50_riscv_2k_1rw1r_func_test.py | 4 +- compiler/tests/50_riscv_2k_1rw_func_test.py | 4 +- compiler/tests/50_riscv_4k_1rw1r_func_test.py | 4 +- compiler/tests/50_riscv_4k_1rw_func_test.py | 4 +- .../tests/50_riscv_512b_1rw1r_func_test.py | 4 +- compiler/tests/50_riscv_512b_1rw_func_test.py | 4 +- compiler/tests/50_riscv_8k_1rw1r_func_test.py | 4 +- compiler/tests/50_riscv_8k_1rw_func_test.py | 4 +- compiler/tests/testutils.py | 5 +- compiler/verify/calibre.py | 4 +- compiler/verify/klayout.py | 2 +- compiler/verify/magic.py | 4 +- openram.mk | 2 + technology/freepdk45/tech/tech.py | 21 +- technology/scn4m_subm/tech/tech.py | 17 +- technology/sky130/custom/__init__.py | 0 .../{modules => custom}/sky130_bitcell.py | 4 +- .../sky130_bitcell_array.py | 4 +- .../sky130_bitcell_base_array.py | 4 +- .../{modules => custom}/sky130_col_cap.py | 4 +- .../sky130_col_cap_array.py | 4 +- .../{modules => custom}/sky130_corner.py | 16 +- .../{modules => custom}/sky130_dummy_array.py | 4 +- .../sky130_dummy_bitcell.py | 4 +- .../{modules => custom}/sky130_internal.py | 16 +- .../sky130_replica_bitcell.py | 8 +- .../sky130_replica_bitcell_array.py | 8 +- .../sky130_replica_column.py | 4 +- .../{modules => custom}/sky130_row_cap.py | 4 +- .../sky130_row_cap_array.py | 2 +- technology/sky130/tech/tech.py | 22 +- 388 files changed, 1450 insertions(+), 1391 deletions(-) create mode 100644 compiler/base/__init__.py rename compiler/{characterizer => base}/logical_effort.py (97%) rename compiler/{router => base}/vector3d.py (100%) create mode 100644 compiler/datasheet/__init__.py create mode 100644 compiler/drc/__init__.py rename compiler/{base => drc}/custom_cell_properties.py (100%) rename compiler/{base => drc}/custom_layer_properties.py (100%) rename compiler/{modules => drc}/module_type.py (100%) create mode 100644 compiler/modules/__init__.py rename compiler/{bitcells => modules}/bitcell_1port.py (93%) rename compiler/{bitcells => modules}/bitcell_2port.py (97%) rename compiler/{bitcells => modules}/bitcell_base.py (95%) rename compiler/{bitcells => modules}/col_cap_bitcell_1port.py (88%) rename compiler/{bitcells => modules}/col_cap_bitcell_2port.py (88%) rename compiler/{pgates => modules}/column_mux.py (99%) rename compiler/{custom => modules}/dff.py (96%) rename compiler/{bitcells => modules}/dummy_bitcell_1port.py (89%) rename compiler/{bitcells => modules}/dummy_bitcell_2port.py (89%) rename compiler/{bitcells => modules}/dummy_pbitcell.py (96%) rename compiler/{custom => modules}/inv_dec.py (82%) rename compiler/{custom => modules}/nand2_dec.py (87%) rename compiler/{custom => modules}/nand3_dec.py (87%) rename compiler/{custom => modules}/nand4_dec.py (87%) rename compiler/{pgates => modules}/pand2.py (98%) rename compiler/{pgates => modules}/pand3.py (98%) rename compiler/{pgates => modules}/pand4.py (98%) rename compiler/{bitcells => modules}/pbitcell.py (96%) rename compiler/{pgates => modules}/pbuf.py (98%) rename compiler/{pgates => modules}/pbuf_dec.py (96%) rename compiler/{pgates => modules}/pdriver.py (98%) rename compiler/{pgates => modules}/pgate.py (98%) rename compiler/{pgates => modules}/pinv.py (94%) rename compiler/{pgates => modules}/pinv_dec.py (92%) rename compiler/{pgates => modules}/pinvbuf.py (99%) rename compiler/{pgates => modules}/pnand2.py (94%) rename compiler/{pgates => modules}/pnand3.py (96%) rename compiler/{pgates => modules}/pnand4.py (96%) rename compiler/{pgates => modules}/pnor2.py (99%) rename compiler/{pgates => modules}/precharge.py (96%) rename compiler/{pgates => modules}/ptristate_inv.py (89%) rename compiler/{pgates => modules}/ptx.py (97%) rename compiler/{pgates => modules}/pwrite_driver.py (99%) rename compiler/{bitcells => modules}/replica_bitcell_1port.py (89%) rename compiler/{bitcells => modules}/replica_bitcell_2port.py (90%) rename compiler/{bitcells => modules}/replica_pbitcell.py (95%) rename compiler/{bitcells => modules}/row_cap_bitcell_1port.py (87%) rename compiler/{bitcells => modules}/row_cap_bitcell_2port.py (87%) rename compiler/{custom => modules}/sense_amp.py (96%) rename compiler/{sram => modules}/sram.py (95%) rename compiler/{sram => modules}/sram_1bank.py (99%) rename compiler/{sram => modules}/sram_2bank.py (98%) rename compiler/{sram => modules}/sram_base.py (98%) rename compiler/{sram => modules}/sram_config.py (100%) rename compiler/{custom => modules}/tri_gate.py (96%) rename compiler/{pgates => modules}/wordline_driver.py (98%) rename compiler/{custom => modules}/write_driver.py (96%) create mode 100644 compiler/router/__init__.py create mode 100644 compiler/sram/__init__.py delete mode 100755 compiler/tests/19_bank_select_pbitcell_test.py delete mode 100755 compiler/tests/19_bank_select_test.py create mode 100644 technology/sky130/custom/__init__.py rename technology/sky130/{modules => custom}/sky130_bitcell.py (94%) rename technology/sky130/{modules => custom}/sky130_bitcell_array.py (97%) rename technology/sky130/{modules => custom}/sky130_bitcell_base_array.py (99%) rename technology/sky130/{modules => custom}/sky130_col_cap.py (96%) rename technology/sky130/{modules => custom}/sky130_col_cap_array.py (99%) rename technology/sky130/{modules => custom}/sky130_corner.py (63%) rename technology/sky130/{modules => custom}/sky130_dummy_array.py (98%) rename technology/sky130/{modules => custom}/sky130_dummy_bitcell.py (91%) rename technology/sky130/{modules => custom}/sky130_internal.py (64%) rename technology/sky130/{modules => custom}/sky130_replica_bitcell.py (90%) rename technology/sky130/{modules => custom}/sky130_replica_bitcell_array.py (99%) rename technology/sky130/{modules => custom}/sky130_replica_column.py (99%) rename technology/sky130/{modules => custom}/sky130_row_cap.py (93%) rename technology/sky130/{modules => custom}/sky130_row_cap_array.py (98%) diff --git a/README.md b/README.md index 4a3ec69a..438c33db 100644 --- a/README.md +++ b/README.md @@ -26,28 +26,33 @@ things that need to be fixed. # Basic Setup -## Docker - -We have a [docker setup](./docker) to run OpenRAM. - ## Dependencies -The OpenRAM compiler has very few dependencies: -+ [Ngspice] 34 (or later) or HSpice I-2013.12-1 (or later) or CustomSim 2017 (or later) or [Xyce] 7.4 (or later) +Please see the Dockerfile for the required versions of tools. + +In general, the OpenRAM compiler has very few dependencies: ++ Docker ++ Make + Python 3.6 or higher + Various Python packages (pip install -r requirements.txt) + [Git] -If you want to perform DRC and LVS, you will need either: -+ Calibre (for [FreePDK45]) -+ [Magic] 8.3.197 or newer -+ [Netgen] 1.5.195 or newer +## Docker + +We have a [docker setup](./docker) to run OpenRAM. To use this, you should run: +``` +cd openram/docker +make build +``` +This must be run once and will take a while to build all the tools. + + +## Environment You must set two environment variables: + OPENRAM\_HOME should point to the compiler source directory. + OPENERAM\_TECH should point to one or more root technology directories (colon separated). -## Environment For example add this to your .bashrc: @@ -56,17 +61,23 @@ For example add this to your .bashrc: export OPENRAM_TECH="$HOME/openram/technology" ``` -You may also wish to add OPENRAM\_HOME to your PYTHONPATH: +You should also add OPENRAM\_HOME to your PYTHONPATH: ``` - export PYTHONPATH="$PYTHONPATH:$OPENRAM_HOME" + export PYTHONPATH=$OPENRAM_HOME +``` +Note that if you want symbols to resolve in your editor, you may also want to add the specific technology +directory that you use and any custom technology modules as well. For example: +``` + export PYTHONPATH="$OPENRAM_HOME:$OPENRAM_TECH/sky130:$OPENRAM_TECH/sky130/custom" +``` We include the tech files necessary for [SCMOS] SCN4M_SUBM, [FreePDK45]. The [SCMOS] spice models, however, are generic and should be replaced with foundry models. You may get the entire [FreePDK45 PDK here][FreePDK45]. -``` + ### Sky130 Setup To install [Sky130], you must have the open_pdks files installed in $PDK_ROOT. @@ -80,7 +91,7 @@ by running: cd $HOME/openram make install -``` + # Basic Usage Once you have defined the environment, you can run OpenRAM from the command line @@ -88,7 +99,7 @@ using a single configuration file written in Python. For example, create a file called *myconfig.py* specifying the following parameters for your memory: - +``` # Data word size word_size = 2 # Number of words in the memory @@ -142,9 +153,9 @@ make -j 3 ``` The -j can run with 3 threads. By default, this will run in all technologies. -To run a specific test: +To run a specific test in all technologies: ``` -ce openram/compiler/tests +cd openram/compiler/tests make 05_bitcell_array_test ``` To run a specific technology: @@ -159,6 +170,14 @@ pass it as an argument to OpenRAM: ARGS="-v" make 05_bitcell_array_test ``` +Unit test results are put in a directory: +``` +openram/compiler/tests/results// +``` +If the test fails, there will be a tmp directory with intermediate results. +If the test passes, this directory will be deleted to save space. +You can view the .out file to see what the output of a test is in either case. + # Get Involved + [Port it](./PORTING.md) to a new technology. @@ -207,6 +226,7 @@ If I forgot to add you, please let me know! [dev-group-subscribe]: mailto:openram-dev-group+subscribe@ucsc.edu [user-group-subscribe]: mailto:openram-user-group+subscribe@ucsc.edu +[Klayout]: https://www.klayout.de/ [Magic]: http://opencircuitdesign.com/magic/ [Netgen]: http://opencircuitdesign.com/netgen/ [Qflow]: http://opencircuitdesign.com/qflow/history.html diff --git a/compiler/base/__init__.py b/compiler/base/__init__.py new file mode 100644 index 00000000..25f44cf7 --- /dev/null +++ b/compiler/base/__init__.py @@ -0,0 +1,21 @@ +from .channel_route import * +from .contact import * +from .delay_data import * +from .design import * +from .errors import * +from .geometry import * +from .hierarchy_design import * +from .hierarchy_layout import * +from .hierarchy_spice import * +from .lef import * +from .logical_effort import * +from .pin_layout import * +from .power_data import * +from .route import * +from .timing_graph import * +from .utils import * +from .vector import * +from .verilog import * +from .wire_path import * +from .wire import * +from .wire_spice_model import * diff --git a/compiler/base/channel_route.py b/compiler/base/channel_route.py index d64b7e3c..7cd1fb53 100644 --- a/compiler/base/channel_route.py +++ b/compiler/base/channel_route.py @@ -8,8 +8,8 @@ import collections import debug from tech import drc -from vector import vector -import design +from .vector import vector +from .design import design class channel_net(): @@ -75,7 +75,7 @@ class channel_net(): return min_overlap or max_overlap -class channel_route(design.design): +class channel_route(design): unique_id = 0 diff --git a/compiler/base/contact.py b/compiler/base/contact.py index bb6eb391..5f2f41d0 100644 --- a/compiler/base/contact.py +++ b/compiler/base/contact.py @@ -5,16 +5,14 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import hierarchy_design import debug -from tech import drc, layer -import tech -from vector import vector -from sram_factory import factory -import sys +from .hierarchy_design import hierarchy_design +from .vector import vector +from tech import drc, layer, preferred_directions +from tech import layer as tech_layers -class contact(hierarchy_design.hierarchy_design): +class contact(hierarchy_design): """ Object for a contact shape with its conductor enclosures. Creates a contact array minimum active or poly enclosure and metal1 @@ -51,20 +49,20 @@ class contact(hierarchy_design.hierarchy_design): # Non-preferred directions if directions == "nonpref": - first_dir = "H" if tech.preferred_directions[layer_stack[0]]=="V" else "V" - second_dir = "H" if tech.preferred_directions[layer_stack[2]]=="V" else "V" + first_dir = "H" if preferred_directions[layer_stack[0]]=="V" else "V" + second_dir = "H" if preferred_directions[layer_stack[2]]=="V" else "V" self.directions = (first_dir, second_dir) # Preferred directions elif directions == "pref": - self.directions = (tech.preferred_directions[layer_stack[0]], - tech.preferred_directions[layer_stack[2]]) + self.directions = (preferred_directions[layer_stack[0]], + preferred_directions[layer_stack[2]]) # User directions elif directions: self.directions = directions # Preferred directions else: - self.directions = (tech.preferred_directions[layer_stack[0]], - tech.preferred_directions[layer_stack[2]]) + self.directions = (preferred_directions[layer_stack[0]], + preferred_directions[layer_stack[2]]) self.offset = vector(0, 0) self.implant_type = implant_type self.well_type = well_type @@ -101,7 +99,7 @@ class contact(hierarchy_design.hierarchy_design): self.second_layer_name = second_layer # Contacts will have unique per first layer - if via_layer in tech.layer: + if via_layer in tech_layers: self.via_layer_name = via_layer elif via_layer == "contact": if first_layer in ("active", "poly"): @@ -194,7 +192,7 @@ class contact(hierarchy_design.hierarchy_design): def create_nitride_cut_enclosure(self): """ Special layer that encloses poly contacts in some processes """ # Check if there is a special poly nitride cut layer - if "npc" not in tech.layer: + if "npc" not in tech_layers: return npc_enclose_poly = drc("npc_enclose_poly") @@ -256,7 +254,7 @@ class contact(hierarchy_design.hierarchy_design): # Optionally implant well if layer exists well_layer = "{}well".format(self.well_type) - if well_layer in tech.layer: + if well_layer in tech_layers: well_width_rule = drc("minwidth_" + well_layer) self.well_enclose_active = drc(well_layer + "_enclose_active") self.well_width = max(self.first_layer_width + 2 * self.well_enclose_active, @@ -275,33 +273,3 @@ class contact(hierarchy_design.hierarchy_design): return self.return_power() -# Set up a static for each layer to be used for measurements -for layer_stack in tech.layer_stacks: - (layer1, via, layer2) = layer_stack - cont = factory.create(module_type="contact", - layer_stack=layer_stack) - module = sys.modules[__name__] - # Also create a contact that is just the first layer - if layer1 == "poly" or layer1 == "active": - setattr(module, layer1 + "_contact", cont) - else: - setattr(module, layer1 + "_via", cont) - -# Set up a static for each well contact for measurements -if "nwell" in tech.layer: - cont = factory.create(module_type="contact", - layer_stack=tech.active_stack, - implant_type="n", - well_type="n") - module = sys.modules[__name__] - setattr(module, "nwell_contact", cont) - -if "pwell" in tech.layer: - cont = factory.create(module_type="contact", - layer_stack=tech.active_stack, - implant_type="p", - well_type="p") - module = sys.modules[__name__] - setattr(module, "pwell_contact", cont) - - diff --git a/compiler/base/design.py b/compiler/base/design.py index f8ca0cb1..ccd9cec1 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -5,15 +5,13 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -from hierarchy_design import hierarchy_design -import utils -import contact +import debug from tech import GDS, layer from tech import preferred_directions from tech import cell_properties as props from globals import OPTS -import re -import debug +from . import utils +from .hierarchy_design import hierarchy_design class design(hierarchy_design): @@ -82,201 +80,6 @@ class design(hierarchy_design): for pin in pins: print(pin_name, pin) - @classmethod - def setup_drc_constants(design): - """ - These are some DRC constants used in many places - in the compiler. - """ - # Make some local rules for convenience - from tech import drc - for rule in drc.keys(): - # Single layer width rules - match = re.search(r"minwidth_(.*)", rule) - if match: - if match.group(1) == "active_contact": - setattr(design, "contact_width", drc(match.group(0))) - else: - setattr(design, match.group(1) + "_width", drc(match.group(0))) - - # Single layer area rules - match = re.search(r"minarea_(.*)", rule) - if match: - setattr(design, match.group(0), drc(match.group(0))) - - # Single layer spacing rules - match = re.search(r"(.*)_to_(.*)", rule) - if match and match.group(1) == match.group(2): - setattr(design, match.group(1) + "_space", drc(match.group(0))) - elif match and match.group(1) != match.group(2): - if match.group(2) == "poly_active": - setattr(design, match.group(1) + "_to_contact", - drc(match.group(0))) - else: - setattr(design, match.group(0), drc(match.group(0))) - - match = re.search(r"(.*)_enclose_(.*)", rule) - if match: - setattr(design, match.group(0), drc(match.group(0))) - - match = re.search(r"(.*)_extend_(.*)", rule) - if match: - setattr(design, match.group(0), drc(match.group(0))) - - # Create the maximum well extend active that gets used - # by cells to extend the wells for interaction with other cells - from tech import layer - design.well_extend_active = 0 - if "nwell" in layer: - design.well_extend_active = max(design.well_extend_active, design.nwell_extend_active) - if "pwell" in layer: - design.well_extend_active = max(design.well_extend_active, design.pwell_extend_active) - - # The active offset is due to the well extension - if "pwell" in layer: - design.pwell_enclose_active = drc("pwell_enclose_active") - else: - design.pwell_enclose_active = 0 - if "nwell" in layer: - design.nwell_enclose_active = drc("nwell_enclose_active") - else: - design.nwell_enclose_active = 0 - # Use the max of either so that the poly gates will align properly - design.well_enclose_active = max(design.pwell_enclose_active, - design.nwell_enclose_active, - design.active_space) - - # These are for debugging previous manual rules - if False: - print("poly_width", design.poly_width) - print("poly_space", design.poly_space) - print("m1_width", design.m1_width) - print("m1_space", design.m1_space) - print("m2_width", design.m2_width) - print("m2_space", design.m2_space) - print("m3_width", design.m3_width) - print("m3_space", design.m3_space) - print("m4_width", design.m4_width) - print("m4_space", design.m4_space) - print("active_width", design.active_width) - print("active_space", design.active_space) - print("contact_width", design.contact_width) - print("poly_to_active", design.poly_to_active) - print("poly_extend_active", design.poly_extend_active) - print("poly_to_contact", design.poly_to_contact) - print("active_contact_to_gate", design.active_contact_to_gate) - print("poly_contact_to_gate", design.poly_contact_to_gate) - print("well_enclose_active", design.well_enclose_active) - print("implant_enclose_active", design.implant_enclose_active) - print("implant_space", design.implant_space) - import sys - sys.exit(1) - - @classmethod - def setup_layer_constants(design): - """ - These are some layer constants used - in many places in the compiler. - """ - - from tech import layer_indices - import tech - for layer_id in layer_indices: - key = "{}_stack".format(layer_id) - - # Set the stack as a local helper - try: - layer_stack = getattr(tech, key) - setattr(design, key, layer_stack) - except AttributeError: - pass - - # Skip computing the pitch for non-routing layers - if layer_id in ["active", "nwell"]: - continue - - # Add the pitch - setattr(design, - "{}_pitch".format(layer_id), - design.compute_pitch(layer_id, True)) - - # Add the non-preferrd pitch (which has vias in the "wrong" way) - setattr(design, - "{}_nonpref_pitch".format(layer_id), - design.compute_pitch(layer_id, False)) - - if False: - from tech import preferred_directions - print(preferred_directions) - from tech import layer_indices - for name in layer_indices: - if name == "active": - continue - try: - print("{0} width {1} space {2}".format(name, - getattr(design, "{}_width".format(name)), - getattr(design, "{}_space".format(name)))) - - print("pitch {0} nonpref {1}".format(getattr(design, "{}_pitch".format(name)), - getattr(design, "{}_nonpref_pitch".format(name)))) - except AttributeError: - pass - import sys - sys.exit(1) - - @staticmethod - def compute_pitch(layer, preferred=True): - - """ - This is the preferred direction pitch - i.e. we take the minimum or maximum contact dimension - """ - # Find the layer stacks this is used in - from tech import layer_stacks - pitches = [] - for stack in layer_stacks: - # Compute the pitch with both vias above and below (if they exist) - if stack[0] == layer: - pitches.append(design.compute_layer_pitch(stack, preferred)) - if stack[2] == layer: - pitches.append(design.compute_layer_pitch(stack[::-1], True)) - - return max(pitches) - - @staticmethod - def get_preferred_direction(layer): - return preferred_directions[layer] - - @staticmethod - def compute_layer_pitch(layer_stack, preferred): - - (layer1, via, layer2) = layer_stack - try: - if layer1 == "poly" or layer1 == "active": - contact1 = getattr(contact, layer1 + "_contact") - else: - contact1 = getattr(contact, layer1 + "_via") - except AttributeError: - contact1 = getattr(contact, layer2 + "_via") - - if preferred: - if preferred_directions[layer1] == "V": - contact_width = contact1.first_layer_width - else: - contact_width = contact1.first_layer_height - else: - if preferred_directions[layer1] == "V": - contact_width = contact1.first_layer_height - else: - contact_width = contact1.first_layer_width - layer_space = getattr(design, layer1 + "_space") - - #print(layer_stack) - #print(contact1) - pitch = contact_width + layer_space - - return utils.round_to_grid(pitch) - def setup_multiport_constants(self): """ These are contants and lists that aid multiport design. @@ -324,6 +127,4 @@ class design(hierarchy_design): total_module_power += inst.mod.analytical_power(corner, load) return total_module_power -design.setup_drc_constants() -design.setup_layer_constants() diff --git a/compiler/base/geometry.py b/compiler/base/geometry.py index d2f4e98e..3ca87e2e 100644 --- a/compiler/base/geometry.py +++ b/compiler/base/geometry.py @@ -9,13 +9,13 @@ This provides a set of useful generic types for the gdsMill interface. """ import debug -from vector import vector +from .vector import vector import tech import math import copy import numpy as np from globals import OPTS -from utils import round_to_grid +from .utils import round_to_grid class geometry: diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py index 5e9bec3f..c25864f9 100644 --- a/compiler/base/hierarchy_design.py +++ b/compiler/base/hierarchy_design.py @@ -5,14 +5,14 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import hierarchy_layout -import hierarchy_spice +from .hierarchy_layout import layout +from .hierarchy_spice import spice import debug import os from globals import OPTS -class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): +class hierarchy_design(spice, layout): """ Design Class for all modules to inherit the base features. Class consisting of a set of modules and instances of these modules @@ -32,8 +32,8 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): name = OPTS.output_name + "_" + name cell_name = name - hierarchy_spice.spice.__init__(self, name, cell_name) - hierarchy_layout.layout.__init__(self, name, cell_name) + spice.__init__(self, name, cell_name) + layout.__init__(self, name, cell_name) self.init_graph_params() def get_layout_pins(self, inst): diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 68476a00..fe108c01 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -5,21 +5,26 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import geometry -import gdsMill -import debug -from math import sqrt -from tech import drc, GDS -from tech import layer as techlayer -from tech import layer_indices -from tech import layer_stacks -from tech import preferred_directions import os import sys +import re +from math import sqrt +import debug +from gdsMill import gdsMill +import tech +from tech import drc, GDS +from tech import layer as tech_layer +from tech import layer_indices as tech_layer_indices +from tech import preferred_directions +from tech import layer_stacks as tech_layer_stacks +from tech import active_stack as tech_active_stack +from sram_factory import factory from globals import OPTS -from vector import vector -from pin_layout import pin_layout -from utils import round_to_grid +from .vector import vector +from .pin_layout import pin_layout +from .utils import round_to_grid +from . import geometry + try: from tech import special_purposes except ImportError: @@ -64,11 +69,241 @@ class layout(): self.gds_read() + if "contact" not in self.name: + if not hasattr(layout, "_drc_constants"): + layout._drc_constants = True + layout.setup_drc_constants() + layout.setup_contacts() + layout.setup_layer_constants() + + + @classmethod + def setup_drc_constants(layout): + """ + These are some DRC constants used in many places + in the compiler. + """ + + # Make some local rules for convenience + for rule in drc.keys(): + # Single layer width rules + match = re.search(r"minwidth_(.*)", rule) + if match: + if match.group(1) == "active_contact": + setattr(layout, "contact_width", drc(match.group(0))) + else: + setattr(layout, match.group(1) + "_width", drc(match.group(0))) + + # Single layer area rules + match = re.search(r"minarea_(.*)", rule) + if match: + setattr(layout, match.group(0), drc(match.group(0))) + + # Single layer spacing rules + match = re.search(r"(.*)_to_(.*)", rule) + if match and match.group(1) == match.group(2): + setattr(layout, match.group(1) + "_space", drc(match.group(0))) + elif match and match.group(1) != match.group(2): + if match.group(2) == "poly_active": + setattr(layout, match.group(1) + "_to_contact", + drc(match.group(0))) + else: + setattr(layout, match.group(0), drc(match.group(0))) + + match = re.search(r"(.*)_enclose_(.*)", rule) + if match: + setattr(layout, match.group(0), drc(match.group(0))) + + match = re.search(r"(.*)_extend_(.*)", rule) + if match: + setattr(layout, match.group(0), drc(match.group(0))) + + # Create the maximum well extend active that gets used + # by cells to extend the wells for interaction with other cells + layout.well_extend_active = 0 + if "nwell" in tech_layer: + layout.well_extend_active = max(layout.well_extend_active, layout.nwell_extend_active) + if "pwell" in tech_layer: + layout.well_extend_active = max(layout.well_extend_active, layout.pwell_extend_active) + + # The active offset is due to the well extension + if "pwell" in tech_layer: + layout.pwell_enclose_active = drc("pwell_enclose_active") + else: + layout.pwell_enclose_active = 0 + if "nwell" in tech_layer: + layout.nwell_enclose_active = drc("nwell_enclose_active") + else: + layout.nwell_enclose_active = 0 + # Use the max of either so that the poly gates will align properly + layout.well_enclose_active = max(layout.pwell_enclose_active, + layout.nwell_enclose_active, + layout.active_space) + + # These are for debugging previous manual rules + if False: + print("poly_width", layout.poly_width) + print("poly_space", layout.poly_space) + print("m1_width", layout.m1_width) + print("m1_space", layout.m1_space) + print("m2_width", layout.m2_width) + print("m2_space", layout.m2_space) + print("m3_width", layout.m3_width) + print("m3_space", layout.m3_space) + print("m4_width", layout.m4_width) + print("m4_space", layout.m4_space) + print("active_width", layout.active_width) + print("active_space", layout.active_space) + print("contact_width", layout.contact_width) + print("poly_to_active", layout.poly_to_active) + print("poly_extend_active", layout.poly_extend_active) + print("poly_to_contact", layout.poly_to_contact) + print("active_contact_to_gate", layout.active_contact_to_gate) + print("poly_contact_to_gate", layout.poly_contact_to_gate) + print("well_enclose_active", layout.well_enclose_active) + print("implant_enclose_active", layout.implant_enclose_active) + print("implant_space", layout.implant_space) + import sys + sys.exit(1) + + @classmethod + def setup_layer_constants(layout): + """ + These are some layer constants used + in many places in the compiler. + """ try: from tech import power_grid - self.pwr_grid_layers = [power_grid[0], power_grid[2]] + layout.pwr_grid_layers = [power_grid[0], power_grid[2]] except ImportError: - self.pwr_grid_layers = ["m3", "m4"] + layout.pwr_grid_layers = ["m3", "m4"] + + for layer_id in tech_layer_indices: + key = "{}_stack".format(layer_id) + + # Set the stack as a local helper + try: + layer_stack = getattr(tech, key) + setattr(layout, key, layer_stack) + except AttributeError: + pass + + # Skip computing the pitch for non-routing layers + if layer_id in ["active", "nwell"]: + continue + + # Add the pitch + setattr(layout, + "{}_pitch".format(layer_id), + layout.compute_pitch(layer_id, True)) + + # Add the non-preferrd pitch (which has vias in the "wrong" way) + setattr(layout, + "{}_nonpref_pitch".format(layer_id), + layout.compute_pitch(layer_id, False)) + + if False: + for name in tech_layer_indices: + if name == "active": + continue + try: + print("{0} width {1} space {2}".format(name, + getattr(layout, "{}_width".format(name)), + getattr(layout, "{}_space".format(name)))) + + print("pitch {0} nonpref {1}".format(getattr(layout, "{}_pitch".format(name)), + getattr(layout, "{}_nonpref_pitch".format(name)))) + except AttributeError: + pass + import sys + sys.exit(1) + + @staticmethod + def compute_pitch(layer, preferred=True): + """ + This is the preferred direction pitch + i.e. we take the minimum or maximum contact dimension + """ + # Find the layer stacks this is used in + pitches = [] + for stack in tech_layer_stacks: + # Compute the pitch with both vias above and below (if they exist) + if stack[0] == layer: + pitches.append(layout.compute_layer_pitch(stack, preferred)) + if stack[2] == layer: + pitches.append(layout.compute_layer_pitch(stack[::-1], True)) + + return max(pitches) + + @staticmethod + def get_preferred_direction(layer): + return preferred_directions[layer] + + @staticmethod + def compute_layer_pitch(layer_stack, preferred): + + (layer1, via, layer2) = layer_stack + try: + if layer1 == "poly" or layer1 == "active": + contact1 = getattr(layout, layer1 + "_contact") + else: + contact1 = getattr(layout, layer1 + "_via") + except AttributeError: + contact1 = getattr(layout, layer2 + "_via") + + if preferred: + if preferred_directions[layer1] == "V": + contact_width = contact1.first_layer_width + else: + contact_width = contact1.first_layer_height + else: + if preferred_directions[layer1] == "V": + contact_width = contact1.first_layer_height + else: + contact_width = contact1.first_layer_width + layer_space = getattr(layout, layer1 + "_space") + + #print(layer_stack) + #print(contact1) + pitch = contact_width + layer_space + + return round_to_grid(pitch) + + + @classmethod + def setup_contacts(layout): + # Set up a static for each layer to be used for measurements + # unless we are a contact class! + + for layer_stack in tech_layer_stacks: + (layer1, via, layer2) = layer_stack + cont = factory.create(module_type="contact", + layer_stack=layer_stack) + module = sys.modules[__name__] + # Also create a contact that is just the first layer + if layer1 == "poly" or layer1 == "active": + setattr(layout, layer1 + "_contact", cont) + else: + setattr(layout, layer1 + "_via", cont) + + # Set up a static for each well contact for measurements + if "nwell" in tech_layer: + cont = factory.create(module_type="contact", + layer_stack=tech_active_stack, + implant_type="n", + well_type="n") + module = sys.modules[__name__] + setattr(layout, "nwell_contact", cont) + + if "pwell" in tech_layer: + cont = factory.create(module_type="contact", + layer_stack=tech_active_stack, + implant_type="p", + well_type="p") + module = sys.modules[__name__] + setattr(layout, "pwell_contact", cont) + + ############################################################ # GDS layout @@ -171,7 +406,7 @@ class layout(): this layout on a layer """ # Only consider the layer not the purpose for now - layerNumber = techlayer[layer][0] + layerNumber = tech_layer[layer][0] try: highestx = max(obj.rx() for obj in self.objs if obj.layerNumber == layerNumber) except ValueError: @@ -195,7 +430,7 @@ class layout(): this layout on a layer """ # Only consider the layer not the purpose for now - layerNumber = techlayer[layer][0] + layerNumber = tech_layer[layer][0] try: lowestx = min(obj.lx() for obj in self.objs if obj.layerNumber == layerNumber) except ValueError: @@ -273,7 +508,7 @@ class layout(): width = drc["minwidth_{}".format(layer)] if not height: height = drc["minwidth_{}".format(layer)] - lpp = techlayer[layer] + lpp = tech_layer[layer] self.objs.append(geometry.rectangle(lpp, offset, width, @@ -289,7 +524,7 @@ class layout(): width = drc["minwidth_{}".format(layer)] if not height: height = drc["minwidth_{}".format(layer)] - lpp = techlayer[layer] + lpp = tech_layer[layer] corrected_offset = offset - vector(0.5 * width, 0.5 * height) self.objs.append(geometry.rectangle(lpp, corrected_offset, @@ -599,10 +834,10 @@ class layout(): def get_metal_layers(self, from_layer, to_layer): - from_id = layer_indices[from_layer] - to_id = layer_indices[to_layer] + from_id = tech_layer_indices[from_layer] + to_id = tech_layer_indices[to_layer] - layer_list = [x for x in layer_indices.keys() if layer_indices[x] >= from_id and layer_indices[x] < to_id] + layer_list = [x for x in tech_layer_indices.keys() if tech_layer_indices[x] >= from_id and tech_layer_indices[x] < to_id] return layer_list @@ -938,22 +1173,22 @@ class layout(): def add_label(self, text, layer, offset=[0, 0], zoom=None): """Adds a text label on the given layer,offset, and zoom level""" debug.info(5, "add label " + str(text) + " " + layer + " " + str(offset)) - lpp = techlayer[layer] + lpp = tech_layer[layer] self.objs.append(geometry.label(text, lpp, offset, zoom)) return self.objs[-1] def add_path(self, layer, coordinates, width=None): """Connects a routing path on given layer,coordinates,width.""" debug.info(4, "add path " + str(layer) + " " + str(coordinates)) - import wire_path + from . import wire_path # NOTE: (UNTESTED) add_path(...) is currently not used - # lpp = techlayer[layer] + # lpp = tech_layer[layer] # self.objs.append(geometry.path(lpp, coordinates, width)) - wire_path.wire_path(obj=self, - layer=layer, - position_list=coordinates, - width=width) + wire_path(obj=self, + layer=layer, + position_list=coordinates, + width=width) def add_route(self, layers, coordinates, layer_widths): """Connects a routing path on given layer,coordinates,width. The @@ -961,13 +1196,13 @@ class layout(): preferred direction routing whereas this includes layers in the coordinates. """ - import route + from . import route debug.info(4, "add route " + str(layers) + " " + str(coordinates)) # add an instance of our path that breaks down into rectangles and contacts - route.route(obj=self, - layer_stack=layers, - path=coordinates, - layer_widths=layer_widths) + route(obj=self, + layer_stack=layers, + path=coordinates, + layer_widths=layer_widths) def add_zjog(self, layer, start, end, first_direction="H", var_offset=0.5, fixed_offset=None): """ @@ -994,9 +1229,9 @@ class layout(): else: debug.error("Invalid direction for jog -- must be H or V.") - if layer in layer_stacks: + if layer in tech_layer_stacks: self.add_wire(layer, [start, mid1, mid2, end]) - elif layer in techlayer: + elif layer in tech_layer: self.add_path(layer, [start, mid1, mid2, end]) else: debug.error("Could not find layer {}".format(layer)) @@ -1012,13 +1247,13 @@ class layout(): def add_wire(self, layers, coordinates, widen_short_wires=True): """Connects a routing path on given layer,coordinates,width. The layers are the (horizontal, via, vertical). """ - import wire + from . import wire # add an instance of our path that breaks down # into rectangles and contacts - wire.wire(obj=self, - layer_stack=layers, - position_list=coordinates, - widen_short_wires=widen_short_wires) + wire(obj=self, + layer_stack=layers, + position_list=coordinates, + widen_short_wires=widen_short_wires) def add_via(self, layers, offset, size=[1, 1], directions=None, implant_type=None, well_type=None): """ Add a three layer via structure. """ @@ -1086,8 +1321,8 @@ class layout(): via = None cur_layer = from_layer while cur_layer != to_layer: - from_id = layer_indices[cur_layer] - to_id = layer_indices[to_layer] + from_id = tech_layer_indices[cur_layer] + to_id = tech_layer_indices[to_layer] if from_id < to_id: # grow the stack up search_id = 0 @@ -1096,7 +1331,7 @@ class layout(): search_id = 2 next_id = 0 - curr_stack = next(filter(lambda stack: stack[search_id] == cur_layer, layer_stacks), None) + curr_stack = next(filter(lambda stack: stack[search_id] == cur_layer, tech_layer_stacks), None) via = self.add_via_center(layers=curr_stack, size=size, @@ -1209,9 +1444,9 @@ class layout(): if not self.is_library_cell and not self.bounding_box: # If there is a boundary layer, and we didn't create one, add one. boundary_layers = [] - if "boundary" in techlayer.keys(): + if "boundary" in tech_layer.keys(): boundary_layers.append("boundary") - if "stdc" in techlayer.keys(): + if "stdc" in tech_layer.keys(): boundary_layers.append("stdc") boundary = [self.find_lowest_coords(), self.find_highest_coords()] @@ -1221,7 +1456,7 @@ class layout(): width = boundary[1][0] - boundary[0][0] for boundary_layer in boundary_layers: - (layer_number, layer_purpose) = techlayer[boundary_layer] + (layer_number, layer_purpose) = tech_layer[boundary_layer] gds_layout.addBox(layerNumber=layer_number, purposeNumber=layer_purpose, offsetInMicrons=boundary[0], @@ -1270,7 +1505,7 @@ class layout(): Do not write the pins since they aren't obstructions. """ if type(layer) == str: - lpp = techlayer[layer] + lpp = tech_layer[layer] else: lpp = layer @@ -1514,8 +1749,8 @@ class layout(): """ Wrapper to create a vertical channel route """ - import channel_route - cr = channel_route.channel_route(netlist, offset, layer_stack, directions, vertical=True, parent=self) + from .channel_route import channel_route + cr = channel_route(netlist, offset, layer_stack, directions, vertical=True, parent=self) # This causes problem in magic since it sometimes cannot extract connectivity of isntances # with no active devices. # self.add_inst(cr.name, cr) @@ -1526,8 +1761,8 @@ class layout(): """ Wrapper to create a horizontal channel route """ - import channel_route - cr = channel_route.channel_route(netlist, offset, layer_stack, directions, vertical=False, parent=self) + from .channel_route import channel_route + cr = channel_route(netlist, offset, layer_stack, directions, vertical=False, parent=self) # This causes problem in magic since it sometimes cannot extract connectivity of isntances # with no active devices. # self.add_inst(cr.name, cr) @@ -1540,9 +1775,9 @@ class layout(): return boundary_layers = [] - if "stdc" in techlayer.keys(): + if "stdc" in tech_layer.keys(): boundary_layers.append("stdc") - if "boundary" in techlayer.keys(): + if "boundary" in tech_layer.keys(): boundary_layers.append("boundary") # Save the last one as self.bounding_box for boundary_layer in boundary_layers: @@ -1791,7 +2026,7 @@ class layout(): def add_dnwell(self, bbox=None, inflate=1): """ Create a dnwell, along with nwell moat at border. """ - if "dnwell" not in techlayer: + if "dnwell" not in tech_layer: return if not bbox: diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index ee50ad4b..1216edc5 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -12,10 +12,10 @@ import math import tech from globals import OPTS from pprint import pformat -from delay_data import delay_data -from wire_spice_model import wire_spice_model -from power_data import power_data -import logical_effort +from .delay_data import delay_data +from .wire_spice_model import wire_spice_model +from .power_data import power_data +from .logical_effort import convert_relative_c_to_farad, convert_farad_to_relative_c class spice(): @@ -443,7 +443,7 @@ class spice(): # FIXME: Slew is not used in the model right now. # Can be added heuristically as linear factor - relative_cap = logical_effort.convert_farad_to_relative_c(load) + relative_cap = convert_farad_to_relative_c(load) stage_effort = self.get_stage_effort(relative_cap) # If it fails, then keep running with a valid object. @@ -511,7 +511,7 @@ class spice(): # Override this function within a module if a more accurate input capacitance is needed. # Input/outputs with differing capacitances is not implemented. relative_cap = self.input_load() - return logical_effort.convert_relative_c_to_farad(relative_cap) + return convert_relative_c_to_farad(relative_cap) def input_load(self): """Inform users undefined relative capacitance functions used for analytical delays.""" diff --git a/compiler/base/lef.py b/compiler/base/lef.py index 8a54253f..799890e0 100644 --- a/compiler/base/lef.py +++ b/compiler/base/lef.py @@ -6,12 +6,12 @@ # All rights reserved. # import debug +from base import vector +from base import pin_layout from tech import layer_names import os import shutil from globals import OPTS -from vector import vector -from pin_layout import pin_layout class lef: diff --git a/compiler/characterizer/logical_effort.py b/compiler/base/logical_effort.py similarity index 97% rename from compiler/characterizer/logical_effort.py rename to compiler/base/logical_effort.py index 20225ebe..15f2b209 100644 --- a/compiler/characterizer/logical_effort.py +++ b/compiler/base/logical_effort.py @@ -6,7 +6,7 @@ # All rights reserved. # import debug -from tech import drc, parameter, spice +from tech import parameter class logical_effort(): """ @@ -81,4 +81,4 @@ def convert_farad_to_relative_c(c_farad): def convert_relative_c_to_farad(c_relative): """Converts capacitance in logical effort relative units to Femto-Farads.""" - return c_relative/parameter['cap_relative_per_ff'] \ No newline at end of file + return c_relative/parameter['cap_relative_per_ff'] diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index 82590ee6..f9b66612 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -7,7 +7,7 @@ # import debug from tech import GDS, drc -from vector import vector +from .vector import vector from tech import layer, layer_indices import math diff --git a/compiler/base/route.py b/compiler/base/route.py index 812318da..2a6376e3 100644 --- a/compiler/base/route.py +++ b/compiler/base/route.py @@ -5,12 +5,12 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -from tech import drc import debug -from design import design +from .design import design +from .vector import vector +from .vector3d import vector3d +from tech import drc from itertools import tee -from vector import vector -from vector3d import vector3d from sram_factory import factory class route(design): diff --git a/compiler/base/utils.py b/compiler/base/utils.py index fe27c9c0..f80b23e3 100644 --- a/compiler/base/utils.py +++ b/compiler/base/utils.py @@ -8,12 +8,12 @@ import os import math -import gdsMill +from gdsMill import gdsMill import tech import globals import debug -from vector import vector -from pin_layout import pin_layout +from .vector import vector +from .pin_layout import pin_layout try: from tech import special_purposes except ImportError: diff --git a/compiler/router/vector3d.py b/compiler/base/vector3d.py similarity index 100% rename from compiler/router/vector3d.py rename to compiler/base/vector3d.py diff --git a/compiler/base/wire.py b/compiler/base/wire.py index 5c78755a..7114687c 100644 --- a/compiler/base/wire.py +++ b/compiler/base/wire.py @@ -6,8 +6,7 @@ # All rights reserved. # from tech import drc -import contact -from wire_path import wire_path +from .wire_path import wire_path from sram_factory import factory @@ -69,15 +68,24 @@ class wire(wire_path): This is contact direction independent pitch, i.e. we take the maximum contact dimension """ + + # This is here for the unit tests which may not have + # initialized the static parts of the layout class yet. + from base import layout + layout("fake", "fake") + (layer1, via, layer2) = layer_stack if layer1 == "poly" or layer1 == "active": - contact1 = getattr(contact, layer1 + "_contact") + try: + contact1 = getattr(layout, layer1 + "_contact") + except AttributeError: + breakpoint() else: try: - contact1 = getattr(contact, layer1 + "_via") + contact1 = getattr(layout, layer1 + "_via") except AttributeError: - contact1 = getattr(contact, layer2 + "_via") + contact1 = getattr(layout, layer2 + "_via") max_contact = max(contact1.width, contact1.height) layer1_space = drc("{0}_to_{0}".format(layer1)) diff --git a/compiler/base/wire_path.py b/compiler/base/wire_path.py index 411b9ede..363a41f3 100644 --- a/compiler/base/wire_path.py +++ b/compiler/base/wire_path.py @@ -5,11 +5,11 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # +from .vector import vector +from .utils import snap_to_grid +from .design import design from tech import drc from tech import layer as techlayer -import debug -from vector import vector -from utils import snap_to_grid def create_rectilinear_route(my_list): """ Add intermediate nodes if it isn't rectilinear. Also skip diff --git a/compiler/characterizer/simulation.py b/compiler/characterizer/simulation.py index b0ee56f3..b2ccd79e 100644 --- a/compiler/characterizer/simulation.py +++ b/compiler/characterizer/simulation.py @@ -10,7 +10,7 @@ import math import tech from globals import OPTS from sram_factory import factory -import timing_graph +from base import timing_graph class simulation(): @@ -572,7 +572,7 @@ class simulation(): self.sram.graph_exclude_column_mux(self.bitline_column, port) # Generate new graph every analysis as edges might change depending on test bit - self.graph = timing_graph.timing_graph() + self.graph = timing_graph() self.sram_instance_name = "X{}".format(self.sram.name) self.sram.build_graph(self.graph, self.sram_instance_name, self.pins) diff --git a/compiler/datasheet/__init__.py b/compiler/datasheet/__init__.py new file mode 100644 index 00000000..369ba8fe --- /dev/null +++ b/compiler/datasheet/__init__.py @@ -0,0 +1 @@ +from .datasheet_gen import datasheet_gen diff --git a/compiler/datasheet/datasheet.py b/compiler/datasheet/datasheet.py index 612a91df..d1fb3731 100644 --- a/compiler/datasheet/datasheet.py +++ b/compiler/datasheet/datasheet.py @@ -5,7 +5,7 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -from table_gen import * +from .table_gen import * import os import base64 from globals import OPTS diff --git a/compiler/datasheet/datasheet_gen.py b/compiler/datasheet/datasheet_gen.py index 5a9e628b..f77458b4 100644 --- a/compiler/datasheet/datasheet_gen.py +++ b/compiler/datasheet/datasheet_gen.py @@ -19,8 +19,8 @@ from globals import OPTS import os import math import csv -import datasheet -import table_gen +from .datasheet import datasheet +from .table_gen import table_gen # def process_name(corner): # """ @@ -400,7 +400,7 @@ def parse_characterizer_csv(f, pages): if found == 0: # if this is the first corner for this sram, run first time configuration and set up tables - new_sheet = datasheet.datasheet(NAME) + new_sheet = datasheet(NAME) pages.append(new_sheet) new_sheet.git_id = ORIGIN_ID @@ -411,12 +411,12 @@ def parse_characterizer_csv(f, pages): new_sheet.description = [NAME, NUM_WORDS, NUM_BANKS, NUM_RW_PORTS, NUM_W_PORTS, NUM_R_PORTS, TECH_NAME, MIN_PERIOD, WORD_SIZE, ORIGIN_ID, DATETIME] - new_sheet.corners_table = table_gen.table_gen("corners") + new_sheet.corners_table = table_gen("corners") new_sheet.corners_table.add_row( ['Transistor Type', 'Power Supply', 'Temperature', 'Corner Name']) new_sheet.corners_table.add_row( [PROC, VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')]) - new_sheet.operating_table = table_gen.table_gen( + new_sheet.operating_table = table_gen( "operating_table") new_sheet.operating_table.add_row( ['Parameter', 'Min', 'Typ', 'Max', 'Units']) @@ -432,10 +432,10 @@ def parse_characterizer_csv(f, pages): # failed to provide non-zero MIN_PERIOD new_sheet.operating_table.add_row( ['Operating Frequency (F)', '', '', "not available in netlist only", 'MHz']) - new_sheet.power_table = table_gen.table_gen("power") + new_sheet.power_table = table_gen("power") new_sheet.power_table.add_row( ['Pins', 'Mode', 'Power', 'Units']) - new_sheet.timing_table = table_gen.table_gen("timing") + new_sheet.timing_table = table_gen("timing") new_sheet.timing_table.add_row( ['Parameter', 'Min', 'Max', 'Units']) # parse initial timing information @@ -592,10 +592,10 @@ def parse_characterizer_csv(f, pages): else: break - new_sheet.dlv_table = table_gen.table_gen("dlv") + new_sheet.dlv_table = table_gen("dlv") new_sheet.dlv_table.add_row(['Type', 'Description', 'Link']) - new_sheet.io_table = table_gen.table_gen("io") + new_sheet.io_table = table_gen("io") new_sheet.io_table.add_row(['Type', 'Value']) if not OPTS.netlist_only: diff --git a/compiler/datasheet/table_gen.py b/compiler/datasheet/table_gen.py index cc0d215e..99e70411 100644 --- a/compiler/datasheet/table_gen.py +++ b/compiler/datasheet/table_gen.py @@ -5,6 +5,8 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # + + class table_gen: """small library of functions to generate the html tables""" diff --git a/compiler/drc/__init__.py b/compiler/drc/__init__.py new file mode 100644 index 00000000..40e3a45c --- /dev/null +++ b/compiler/drc/__init__.py @@ -0,0 +1,6 @@ +from .custom_cell_properties import * +from .custom_layer_properties import * +from .design_rules import * +from .module_type import * +from .drc_lut import * +from .drc_value import * diff --git a/compiler/base/custom_cell_properties.py b/compiler/drc/custom_cell_properties.py similarity index 100% rename from compiler/base/custom_cell_properties.py rename to compiler/drc/custom_cell_properties.py diff --git a/compiler/base/custom_layer_properties.py b/compiler/drc/custom_layer_properties.py similarity index 100% rename from compiler/base/custom_layer_properties.py rename to compiler/drc/custom_layer_properties.py diff --git a/compiler/drc/design_rules.py b/compiler/drc/design_rules.py index 56d0e8b6..dfa23c2a 100644 --- a/compiler/drc/design_rules.py +++ b/compiler/drc/design_rules.py @@ -6,8 +6,8 @@ # All rights reserved. # import debug -from drc_value import * -from drc_lut import * +from .drc_value import * +from .drc_lut import * class design_rules(dict): diff --git a/compiler/modules/module_type.py b/compiler/drc/module_type.py similarity index 100% rename from compiler/modules/module_type.py rename to compiler/drc/module_type.py diff --git a/compiler/globals.py b/compiler/globals.py index d0c0d673..c216858e 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -252,7 +252,8 @@ def setup_bitcell(): # See if bitcell exists try: - __import__(OPTS.bitcell) + c = importlib.import_module("modules." + OPTS.bitcell) + mod = getattr(c, OPTS.bitcell) except ImportError: # Use the pbitcell if we couldn't find a custom bitcell # or its custom replica bitcell @@ -430,19 +431,12 @@ def setup_paths(): OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME")) except: debug.error("$OPENRAM_HOME is not properly defined.", 1) + debug.check(os.path.isdir(OPENRAM_HOME), "$OPENRAM_HOME does not exist: {0}".format(OPENRAM_HOME)) - # Add all of the subdirs to the python path - # These subdirs are modules and don't need - # to be added: characterizer, verify - subdirlist = [item for item in os.listdir(OPENRAM_HOME) if os.path.isdir(os.path.join(OPENRAM_HOME, item))] - for subdir in subdirlist: - full_path = "{0}/{1}".format(OPENRAM_HOME, subdir) - debug.check(os.path.isdir(full_path), - "$OPENRAM_HOME/{0} does not exist: {1}".format(subdir, full_path)) - if "__pycache__" not in full_path: - sys.path.append("{0}".format(full_path)) + if OPENRAM_HOME not in sys.path: + debug.error("Please add OPENRAM_HOME to the PYTHONPATH.", -1) # Use a unique temp subdirectory if multithreaded if OPTS.num_threads > 1 or OPTS.openram_temp == "/tmp": @@ -569,18 +563,18 @@ def import_tech(): OPTS.openram_tech = os.path.dirname(tech_mod.__file__) + "/" - # Add the tech directory + # Prepend the tech directory so it is sourced FIRST tech_path = OPTS.openram_tech - sys.path.append(tech_path) + sys.path.insert(0, tech_path) try: import tech except ImportError: debug.error("Could not load tech module.", -1) - # Add custom modules of the technology to the path, if they exist + # Prepend custom modules of the technology to the path, if they exist custom_mod_path = os.path.join(tech_path, "modules/") if os.path.exists(custom_mod_path): - sys.path.append(custom_mod_path) + sys.path.insert(0, custom_mod_path) def print_time(name, now_time, last_time=None, indentation=2): diff --git a/compiler/modules/__init__.py b/compiler/modules/__init__.py new file mode 100644 index 00000000..b2f78ba7 --- /dev/null +++ b/compiler/modules/__init__.py @@ -0,0 +1,82 @@ +from .and2_dec import * +from .and3_dec import * +from .and4_dec import * +from .bank import * +from .bitcell_1port import * +from .bitcell_2port import * +from .bitcell_array import * +from .bitcell_base_array import * +from .bitcell_base import * +from .col_cap_array import * +from .col_cap_bitcell_1port import * +from .col_cap_bitcell_2port import * +from .column_decoder import * +from .column_mux_array import * +from .column_mux import * +from .control_logic import * +from .delay_chain import * +from .dff_array import * +from .dff_buf_array import * +from .dff_buf import * +from .dff_inv_array import * +from .dff_inv import * +from .dff import * +from .dummy_array import * +from .dummy_bitcell_1port import * +from .dummy_bitcell_2port import * +from .dummy_pbitcell import * +from .global_bitcell_array import * +from .hierarchical_decoder import * +from .hierarchical_predecode2x4 import * +from .hierarchical_predecode3x8 import * +from .hierarchical_predecode4x16 import * +from .hierarchical_predecode import * +from .inv_dec import * +from .local_bitcell_array import * +from .nand2_dec import * +from .nand3_dec import * +from .nand4_dec import * +from .orig_bitcell_array import * +from .pand2 import * +from .pand3 import * +from .pand4 import * +from .pbitcell import * +from .pbuf_dec import * +from .pbuf import * +from .pdriver import * +from .pgate import * +from .pinvbuf import * +from .pinv_dec import * +from .pinv import * +from .pnand2 import * +from .pnand3 import * +from .pnand4 import * +from .pnor2 import * +from .port_address import * +from .port_data import * +from .precharge_array import * +from .precharge import * +from .ptristate_inv import * +from .ptx import * +from .pwrite_driver import * +from .replica_bitcell_1port import * +from .replica_bitcell_2port import * +from .replica_bitcell_array import * +from .replica_column import * +from .replica_pbitcell import * +from .row_cap_array import * +from .row_cap_bitcell_1port import * +from .row_cap_bitcell_2port import * +from .sense_amp_array import * +from .sense_amp import * +from .tri_gate_array import * +from .tri_gate import * +from .wordline_buffer_array import * +from .wordline_driver_array import * +from .wordline_driver import * +from .write_driver_array import * +from .write_driver import * +from .write_mask_and_array import * +from .sram_1bank import * +from .sram_config import * +from .sram import * diff --git a/compiler/modules/and2_dec.py b/compiler/modules/and2_dec.py index 92130b7b..8ce10caa 100644 --- a/compiler/modules/and2_dec.py +++ b/compiler/modules/and2_dec.py @@ -6,20 +6,20 @@ # All rights reserved. # import debug -from vector import vector -import design +from base import vector +from base import design from sram_factory import factory from globals import OPTS from tech import layer -class and2_dec(design.design): +class and2_dec(design): """ This is an AND with configurable drive strength. """ def __init__(self, name, size=1, height=None, add_wells=True): - design.design.__init__(self, name) + design.__init__(self, name) debug.info(1, "Creating and2_dec {}".format(name)) self.add_comment("size: {}".format(size)) diff --git a/compiler/modules/and3_dec.py b/compiler/modules/and3_dec.py index 6f788824..9c8ee348 100644 --- a/compiler/modules/and3_dec.py +++ b/compiler/modules/and3_dec.py @@ -6,19 +6,19 @@ # All rights reserved. # import debug -from vector import vector -import design +from base import design +from base import vector from sram_factory import factory from globals import OPTS from tech import layer -class and3_dec(design.design): +class and3_dec(design): """ This is an AND with configurable drive strength. """ def __init__(self, name, size=1, height=None, add_wells=True): - design.design.__init__(self, name) + design.__init__(self, name) debug.info(1, "Creating and3_dec {}".format(name)) self.add_comment("size: {}".format(size)) self.size = size diff --git a/compiler/modules/and4_dec.py b/compiler/modules/and4_dec.py index 879f581b..6d75eedd 100644 --- a/compiler/modules/and4_dec.py +++ b/compiler/modules/and4_dec.py @@ -6,20 +6,20 @@ # All rights reserved. # import debug -from vector import vector -import design +from base import design +from base import vector from sram_factory import factory from globals import OPTS from tech import layer -class and4_dec(design.design): +class and4_dec(design): """ This is an AND with configurable drive strength. """ def __init__(self, name, size=1, height=None, add_wells=True): - design.design.__init__(self, name) + design.__init__(self, name) debug.info(1, "Creating and4_dec {}".format(name)) self.add_comment("size: {}".format(size)) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 1f807d63..88d8abc7 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -6,16 +6,16 @@ # All rights reserved. # import debug -import design +from base import design +from base import vector from sram_factory import factory from math import log, ceil, floor from tech import drc -from vector import vector from globals import OPTS from tech import layer_properties as layer_props -class bank(design.design): +class bank(design): """ Dynamically generated a single bank including bitcell array, hierarchical_decoder, precharge, (optional column_mux and column decoder), diff --git a/compiler/modules/bank_select.py b/compiler/modules/bank_select.py index 9b375c00..4d299c6e 100644 --- a/compiler/modules/bank_select.py +++ b/compiler/modules/bank_select.py @@ -5,19 +5,16 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import sys -from tech import drc, parameter -import debug -import design -import contact -from pinv import pinv -from pnand2 import pnand2 -from pnor2 import pnor2 -from vector import vector +from tech import drc +from base import design +from base import vector +from pgates import pinv +from pgates import pnand2 +from pgates import pnor2 from sram_factory import factory from globals import OPTS -class bank_select(design.design): +class bank_select(design): """Create a bank select signal that is combined with an array of NOR+INV gates to gate the control signals in case of multiple banks are created in upper level SRAM module diff --git a/compiler/bitcells/bitcell_1port.py b/compiler/modules/bitcell_1port.py similarity index 93% rename from compiler/bitcells/bitcell_1port.py rename to compiler/modules/bitcell_1port.py index 12c3c3ce..ed8bc8f3 100644 --- a/compiler/bitcells/bitcell_1port.py +++ b/compiler/modules/bitcell_1port.py @@ -7,10 +7,10 @@ # import debug from tech import cell_properties as props -import bitcell_base +from .bitcell_base import bitcell_base -class bitcell_1port(bitcell_base.bitcell_base): +class bitcell_1port(bitcell_base): """ A single bit cell (6T, 8T, etc.) This module implements the single memory cell used in the design. It is a hand-made cell, so diff --git a/compiler/bitcells/bitcell_2port.py b/compiler/modules/bitcell_2port.py similarity index 97% rename from compiler/bitcells/bitcell_2port.py rename to compiler/modules/bitcell_2port.py index 75d654c0..86eddf7e 100644 --- a/compiler/bitcells/bitcell_2port.py +++ b/compiler/modules/bitcell_2port.py @@ -7,10 +7,10 @@ # import debug from tech import cell_properties as props -import bitcell_base +from .bitcell_base import bitcell_base -class bitcell_2port(bitcell_base.bitcell_base): +class bitcell_2port(bitcell_base): """ A single bit cell (6T, 8T, etc.) This module implements the single memory cell used in the design. It is a hand-made cell, so @@ -103,4 +103,4 @@ class bitcell_2port(bitcell_base.bitcell_base): def is_non_inverting(self): """Return input to output polarity for module""" - return False \ No newline at end of file + return False diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index 0432dec2..e50c5b73 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -6,7 +6,7 @@ # All rights reserved. # import debug -from bitcell_base_array import bitcell_base_array +from .bitcell_base_array import bitcell_base_array from tech import drc, spice from globals import OPTS from sram_factory import factory diff --git a/compiler/bitcells/bitcell_base.py b/compiler/modules/bitcell_base.py similarity index 95% rename from compiler/bitcells/bitcell_base.py rename to compiler/modules/bitcell_base.py index 30e09825..ec2e108e 100644 --- a/compiler/bitcells/bitcell_base.py +++ b/compiler/modules/bitcell_base.py @@ -7,18 +7,18 @@ # import debug -import design +from base import design from globals import OPTS -import logical_effort +from base import logical_effort from tech import parameter, drc, layer, spice -class bitcell_base(design.design): +class bitcell_base(design): """ Base bitcell parameters to be over-riden. """ def __init__(self, name, cell_name=None, prop=None): - design.design.__init__(self, name, cell_name, prop) + design.__init__(self, name, cell_name, prop) # Set the bitcell specific properties if prop: @@ -37,12 +37,12 @@ class bitcell_base(design.design): # min size NMOS gate load read_port_load = 0.5 - return logical_effort.logical_effort('bitline', - size, - cin, - load + read_port_load, - parasitic_delay, - False) + return logical_effort('bitline', + size, + cin, + load + read_port_load, + parasitic_delay, + False) def analytical_power(self, corner, load): """Bitcell power in nW. Only characterizes leakage.""" @@ -264,4 +264,4 @@ class bitcell_base(design.design): else: delay = math.sqrt(2*tstep*(vdd-spice["nom_threshold"])/m) - return delay \ No newline at end of file + return delay diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index 45285267..062a74a0 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -6,12 +6,12 @@ # All rights reserved. # import debug -import design +from base import design from sram_factory import factory from globals import OPTS -class bitcell_base_array(design.design): +class bitcell_base_array(design): """ Abstract base class for bitcell-arrays -- bitcell, dummy, replica """ diff --git a/compiler/modules/col_cap_array.py b/compiler/modules/col_cap_array.py index 27194a89..158cf04b 100644 --- a/compiler/modules/col_cap_array.py +++ b/compiler/modules/col_cap_array.py @@ -3,7 +3,7 @@ # Copyright (c) 2016-2021 Regents of the University of California # All rights reserved. # -from bitcell_base_array import bitcell_base_array +from .bitcell_base_array import bitcell_base_array from sram_factory import factory from globals import OPTS diff --git a/compiler/bitcells/col_cap_bitcell_1port.py b/compiler/modules/col_cap_bitcell_1port.py similarity index 88% rename from compiler/bitcells/col_cap_bitcell_1port.py rename to compiler/modules/col_cap_bitcell_1port.py index d2771e6d..b57cfa3f 100644 --- a/compiler/bitcells/col_cap_bitcell_1port.py +++ b/compiler/modules/col_cap_bitcell_1port.py @@ -7,10 +7,10 @@ # import debug from tech import cell_properties as props -import bitcell_base +from .bitcell_base import bitcell_base -class col_cap_bitcell_1port(bitcell_base.bitcell_base): +class col_cap_bitcell_1port(bitcell_base): """ Column end cap cell. """ diff --git a/compiler/bitcells/col_cap_bitcell_2port.py b/compiler/modules/col_cap_bitcell_2port.py similarity index 88% rename from compiler/bitcells/col_cap_bitcell_2port.py rename to compiler/modules/col_cap_bitcell_2port.py index 71b27619..acc0e489 100644 --- a/compiler/bitcells/col_cap_bitcell_2port.py +++ b/compiler/modules/col_cap_bitcell_2port.py @@ -7,10 +7,10 @@ # import debug from tech import cell_properties as props -import bitcell_base +from .bitcell_base import bitcell_base -class col_cap_bitcell_2port(bitcell_base.bitcell_base): +class col_cap_bitcell_2port(bitcell_base): """ Column end cap cell. """ diff --git a/compiler/modules/column_decoder.py b/compiler/modules/column_decoder.py index f94786a2..2c7199b8 100644 --- a/compiler/modules/column_decoder.py +++ b/compiler/modules/column_decoder.py @@ -5,16 +5,16 @@ # from tech import drc import debug -import design +from base import design import math from sram_factory import factory -from vector import vector +from base import vector from globals import OPTS from tech import cell_properties from tech import layer_properties as layer_props -class column_decoder(design.design): +class column_decoder(design): """ Create the column mux decoder. """ diff --git a/compiler/pgates/column_mux.py b/compiler/modules/column_mux.py similarity index 99% rename from compiler/pgates/column_mux.py rename to compiler/modules/column_mux.py index bf489e87..67c44894 100644 --- a/compiler/pgates/column_mux.py +++ b/compiler/modules/column_mux.py @@ -5,16 +5,17 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import pgate +from .pgate import * import debug from tech import drc, layer -from vector import vector +from base import vector +from .pgate import * from sram_factory import factory from tech import cell_properties as cell_props from globals import OPTS -class column_mux(pgate.pgate): +class column_mux(pgate): """ This module implements the columnmux bitline cell used in the design. Creates a single column mux cell with the given integer size relative diff --git a/compiler/modules/column_mux_array.py b/compiler/modules/column_mux_array.py index 36d4080e..fa264d37 100644 --- a/compiler/modules/column_mux_array.py +++ b/compiler/modules/column_mux_array.py @@ -5,16 +5,16 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import design +from base import design import debug from tech import layer, preferred_directions -from vector import vector +from base import vector from sram_factory import factory from globals import OPTS from tech import layer_properties as layer_props -class column_mux_array(design.design): +class column_mux_array(design): """ Dynamically generated column mux array. Array of column mux to read the bitlines through the 6T. diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 79ce3e30..e7c1d345 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -5,16 +5,16 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import design +from base import design import debug from sram_factory import factory import math -from vector import vector +from base import vector from globals import OPTS -import logical_effort +from base import logical_effort -class control_logic(design.design): +class control_logic(design): """ Dynamically generated Control logic for the total SRAM circuit. """ @@ -43,7 +43,7 @@ class control_logic(design.design): self.num_words = num_rows * words_per_row self.enable_delay_chain_resizing = False - self.inv_parasitic_delay = logical_effort.logical_effort.pinv + self.inv_parasitic_delay = logical_effort.pinv # Determines how much larger the sen delay should be. Accounts for possible error in model. # FIXME: This should be made a parameter diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index f90191ef..c393e280 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -6,13 +6,13 @@ # All rights reserved. # import debug -import design -from vector import vector +from base import design +from base import vector from globals import OPTS from sram_factory import factory -class delay_chain(design.design): +class delay_chain(design): """ Generate a delay chain with the given number of stages and fanout. Input is a list contains the electrical effort (fanout) of each stage. diff --git a/compiler/custom/dff.py b/compiler/modules/dff.py similarity index 96% rename from compiler/custom/dff.py rename to compiler/modules/dff.py index 33bd2b3a..0f7cb777 100644 --- a/compiler/custom/dff.py +++ b/compiler/modules/dff.py @@ -5,12 +5,12 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import design +from base import design from tech import cell_properties as props from tech import spice -class dff(design.design): +class dff(design): """ Memory address flip-flop """ diff --git a/compiler/modules/dff_array.py b/compiler/modules/dff_array.py index 86805407..5a9070c7 100644 --- a/compiler/modules/dff_array.py +++ b/compiler/modules/dff_array.py @@ -6,13 +6,13 @@ # All rights reserved. # import debug -import design -from vector import vector +from base import design +from base import vector from sram_factory import factory from globals import OPTS -class dff_array(design.design): +class dff_array(design): """ This is a simple row (or multiple rows) of flops. Unlike the data flops, these are never spaced out. diff --git a/compiler/modules/dff_buf.py b/compiler/modules/dff_buf.py index 9ff31bae..b0cd619c 100644 --- a/compiler/modules/dff_buf.py +++ b/compiler/modules/dff_buf.py @@ -6,14 +6,14 @@ # All rights reserved. # import debug -import design +from base import design from tech import layer -from vector import vector +from base import vector from globals import OPTS from sram_factory import factory -class dff_buf(design.design): +class dff_buf(design): """ This is a simple buffered DFF. The output is buffered with two inverters, of variable size, to provide q diff --git a/compiler/modules/dff_buf_array.py b/compiler/modules/dff_buf_array.py index 6c8f88de..e284b589 100644 --- a/compiler/modules/dff_buf_array.py +++ b/compiler/modules/dff_buf_array.py @@ -6,13 +6,13 @@ # All rights reserved. # import debug -import design -from vector import vector +from base import design +from base import vector from globals import OPTS from sram_factory import factory -class dff_buf_array(design.design): +class dff_buf_array(design): """ This is a simple row (or multiple rows) of flops. Unlike the data flops, these are never spaced out. diff --git a/compiler/modules/dff_inv.py b/compiler/modules/dff_inv.py index 840ba40f..4d162c23 100644 --- a/compiler/modules/dff_inv.py +++ b/compiler/modules/dff_inv.py @@ -6,13 +6,13 @@ # All rights reserved. # import debug -import design -from vector import vector +from base import design +from base import vector from globals import OPTS from sram_factory import factory -class dff_inv(design.design): +class dff_inv(design): """ This is a simple DFF with an inverted output. Some DFFs do not have Qbar, so this will create it. diff --git a/compiler/modules/dff_inv_array.py b/compiler/modules/dff_inv_array.py index 20d59939..97cbd590 100644 --- a/compiler/modules/dff_inv_array.py +++ b/compiler/modules/dff_inv_array.py @@ -6,13 +6,13 @@ # All rights reserved. # import debug -import design -from vector import vector +from base import design +from base import vector from globals import OPTS from sram_factory import factory -class dff_inv_array(design.design): +class dff_inv_array(design): """ This is a simple row (or multiple rows) of flops. Unlike the data flops, these are never spaced out. diff --git a/compiler/modules/dummy_array.py b/compiler/modules/dummy_array.py index 83449a70..566122e7 100644 --- a/compiler/modules/dummy_array.py +++ b/compiler/modules/dummy_array.py @@ -3,7 +3,7 @@ # Copyright (c) 2016-2021 Regents of the University of California # All rights reserved. # -from bitcell_base_array import bitcell_base_array +from .bitcell_base_array import bitcell_base_array from sram_factory import factory from globals import OPTS diff --git a/compiler/bitcells/dummy_bitcell_1port.py b/compiler/modules/dummy_bitcell_1port.py similarity index 89% rename from compiler/bitcells/dummy_bitcell_1port.py rename to compiler/modules/dummy_bitcell_1port.py index 6573394e..3c6f9da6 100644 --- a/compiler/bitcells/dummy_bitcell_1port.py +++ b/compiler/modules/dummy_bitcell_1port.py @@ -7,10 +7,10 @@ # import debug from tech import cell_properties as props -import bitcell_base +from .bitcell_base import bitcell_base -class dummy_bitcell_1port(bitcell_base.bitcell_base): +class dummy_bitcell_1port(bitcell_base): """ A single bit cell (6T, 8T, etc.) This module implements the single memory cell used in the design. It is a hand-made cell, so diff --git a/compiler/bitcells/dummy_bitcell_2port.py b/compiler/modules/dummy_bitcell_2port.py similarity index 89% rename from compiler/bitcells/dummy_bitcell_2port.py rename to compiler/modules/dummy_bitcell_2port.py index a1a96810..94f99f39 100644 --- a/compiler/bitcells/dummy_bitcell_2port.py +++ b/compiler/modules/dummy_bitcell_2port.py @@ -7,10 +7,10 @@ # import debug from tech import cell_properties as props -import bitcell_base +from .bitcell_base import bitcell_base -class dummy_bitcell_2port(bitcell_base.bitcell_base): +class dummy_bitcell_2port(bitcell_base): """ A single bit cell which is forced to store a 0. This module implements the single memory cell used in the design. It diff --git a/compiler/bitcells/dummy_pbitcell.py b/compiler/modules/dummy_pbitcell.py similarity index 96% rename from compiler/bitcells/dummy_pbitcell.py rename to compiler/modules/dummy_pbitcell.py index 7cf8f664..7b099218 100644 --- a/compiler/bitcells/dummy_pbitcell.py +++ b/compiler/modules/dummy_pbitcell.py @@ -6,13 +6,13 @@ # All rights reserved. # import debug -import design -from vector import vector +from base import design +from base import vector from globals import OPTS from sram_factory import factory -class dummy_pbitcell(design.design): +class dummy_pbitcell(design): """ Creates a replica bitcell using pbitcell """ @@ -23,7 +23,7 @@ class dummy_pbitcell(design.design): self.num_r_ports = OPTS.num_r_ports self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports - design.design.__init__(self, name) + design.__init__(self, name) debug.info(1, "create a dummy bitcell using pbitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports)) diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py index 9c493e55..b25c37de 100644 --- a/compiler/modules/global_bitcell_array.py +++ b/compiler/modules/global_bitcell_array.py @@ -5,16 +5,16 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import bitcell_base_array +from .bitcell_base_array import bitcell_base_array from globals import OPTS from sram_factory import factory -from vector import vector +from base import vector import debug from numpy import cumsum from tech import layer_properties as layer_props -class global_bitcell_array(bitcell_base_array.bitcell_base_array): +class global_bitcell_array(bitcell_base_array): """ Creates a global bitcell array. Rows is an integer number for all local arrays. diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index 40c2a93a..52b71229 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -6,17 +6,17 @@ # All rights reserved. # import debug -import design +from base import design import math from sram_factory import factory -from vector import vector +from base import vector from globals import OPTS from tech import layer_indices from tech import layer_stacks from tech import layer_properties as layer_props from tech import drc -class hierarchical_decoder(design.design): +class hierarchical_decoder(design): """ Dynamically generated hierarchical decoder. """ diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index 1431d75c..867b113b 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -6,9 +6,9 @@ # All rights reserved. # import debug -import design +from base import design import math -from vector import vector +from base import vector from sram_factory import factory from globals import OPTS from tech import layer_properties as layer_props @@ -18,7 +18,7 @@ from tech import preferred_directions from tech import drc -class hierarchical_predecode(design.design): +class hierarchical_predecode(design): """ Pre 2x4 and 3x8 and TBD 4x16 decoder shared code. """ diff --git a/compiler/modules/hierarchical_predecode2x4.py b/compiler/modules/hierarchical_predecode2x4.py index 941a0756..bdd01499 100644 --- a/compiler/modules/hierarchical_predecode2x4.py +++ b/compiler/modules/hierarchical_predecode2x4.py @@ -5,7 +5,7 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -from hierarchical_predecode import hierarchical_predecode +from .hierarchical_predecode import hierarchical_predecode from globals import OPTS diff --git a/compiler/modules/hierarchical_predecode3x8.py b/compiler/modules/hierarchical_predecode3x8.py index ef70a282..dc8e026c 100644 --- a/compiler/modules/hierarchical_predecode3x8.py +++ b/compiler/modules/hierarchical_predecode3x8.py @@ -5,7 +5,7 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -from hierarchical_predecode import hierarchical_predecode +from .hierarchical_predecode import hierarchical_predecode from globals import OPTS diff --git a/compiler/modules/hierarchical_predecode4x16.py b/compiler/modules/hierarchical_predecode4x16.py index 64eef96d..7227bf3b 100644 --- a/compiler/modules/hierarchical_predecode4x16.py +++ b/compiler/modules/hierarchical_predecode4x16.py @@ -5,7 +5,7 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -from hierarchical_predecode import hierarchical_predecode +from .hierarchical_predecode import hierarchical_predecode from globals import OPTS diff --git a/compiler/custom/inv_dec.py b/compiler/modules/inv_dec.py similarity index 82% rename from compiler/custom/inv_dec.py rename to compiler/modules/inv_dec.py index d963783f..8f143e29 100644 --- a/compiler/custom/inv_dec.py +++ b/compiler/modules/inv_dec.py @@ -5,13 +5,13 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import design -import logical_effort +from base import design +from base import logical_effort from tech import cell_properties as props from tech import spice, parameter -class inv_dec(design.design): +class inv_dec(design): """ INV for address decoders. """ @@ -51,12 +51,12 @@ class inv_dec(design.design): Input inverted by this stage. """ parasitic_delay = 1 - return logical_effort.logical_effort(self.name, - self.size, - self.input_load(), - cout, - parasitic_delay, - not inp_is_rise) + return logical_effort(self.name, + self.size, + self.input_load(), + cout, + parasitic_delay, + not inp_is_rise) def build_graph(self, graph, inst_name, port_nets): """ diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index 18b33c0f..ba253e9d 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -5,15 +5,15 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import bitcell_base_array +from .bitcell_base_array import bitcell_base_array from globals import OPTS from sram_factory import factory -from vector import vector +from base import vector import debug from tech import layer_properties as layer_props -class local_bitcell_array(bitcell_base_array.bitcell_base_array): +class local_bitcell_array(bitcell_base_array): """ A local bitcell array is a bitcell array with a wordline driver. This can either be a single aray on its own if there is no hierarchical WL diff --git a/compiler/modules/multibank.py b/compiler/modules/multibank.py index 45f46496..e5c4bbfc 100644 --- a/compiler/modules/multibank.py +++ b/compiler/modules/multibank.py @@ -8,15 +8,14 @@ import sys from tech import drc, parameter import debug -import design +from base import design import math from math import log,sqrt,ceil -import contact -from vector import vector +from base import vector from sram_factory import factory from globals import OPTS -class multibank(design.design): +class multibank(design): """ Dynamically generated a single bank including bitcell array, hierarchical_decoder, precharge, (optional column_mux and column decoder), @@ -799,7 +798,7 @@ class multibank(design.design): self.add_wire(("m3","via2","m2"),[in_pin, rail_pos, rail_pos - vector(0,self.m2_pitch)]) # Bring it up to M2 for M2/M3 routing self.add_via(layers=self.m1_stack, - offset=in_pin + contact.m1_via.offset, + offset=in_pin + self.m1_via.offset, rotate=90) self.add_via(layers=self.m2_stack, offset=in_pin + self.m2m3_via_offset, @@ -812,7 +811,7 @@ class multibank(design.design): rail_pos = vector(self.rail_1_x_offsets[rail], in_pin.y) self.add_wire(("m3","via2","m2"),[in_pin, rail_pos, rail_pos - vector(0,self.m2_pitch)]) self.add_via(layers=self.m1_stack, - offset=in_pin + contact.m1_via.offset, + offset=in_pin + self.m1_via.offset, rotate=90) self.add_via(layers=self.m2_stack, offset=in_pin + self.m2m3_via_offset, diff --git a/compiler/custom/nand2_dec.py b/compiler/modules/nand2_dec.py similarity index 87% rename from compiler/custom/nand2_dec.py rename to compiler/modules/nand2_dec.py index 33b7729b..493facb8 100644 --- a/compiler/custom/nand2_dec.py +++ b/compiler/modules/nand2_dec.py @@ -5,13 +5,13 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import design +from base import design from tech import spice, parameter, drc from tech import cell_properties as props -import logical_effort +from base import logical_effort -class nand2_dec(design.design): +class nand2_dec(design): """ 2-input NAND decoder for address decoders. """ @@ -56,12 +56,12 @@ class nand2_dec(design.design): Input inverted by this stage. """ parasitic_delay = 2 - return logical_effort.logical_effort(self.name, - self.size, - self.input_load(), - cout, - parasitic_delay, - not inp_is_rise) + return logical_effort(self.name, + self.size, + self.input_load(), + cout, + parasitic_delay, + not inp_is_rise) def build_graph(self, graph, inst_name, port_nets): """ @@ -96,4 +96,4 @@ class nand2_dec(design.design): pmos_drain_c = self.drain_c_(self.pmos_width*mult, 1, mult) - return nmos_drain_c + pmos_drain_c \ No newline at end of file + return nmos_drain_c + pmos_drain_c diff --git a/compiler/custom/nand3_dec.py b/compiler/modules/nand3_dec.py similarity index 87% rename from compiler/custom/nand3_dec.py rename to compiler/modules/nand3_dec.py index af0d2f1f..08978d46 100644 --- a/compiler/custom/nand3_dec.py +++ b/compiler/modules/nand3_dec.py @@ -5,13 +5,13 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import design +from base import design from tech import spice, parameter, drc from tech import cell_properties as props -import logical_effort +from base import logical_effort -class nand3_dec(design.design): +class nand3_dec(design): """ 3-input NAND decoder for address decoders. """ @@ -56,12 +56,12 @@ class nand3_dec(design.design): Input inverted by this stage. """ parasitic_delay = 2 - return logical_effort.logical_effort(self.name, - self.size, - self.input_load(), - cout, - parasitic_delay, - not inp_is_rise) + return logical_effort(self.name, + self.size, + self.input_load(), + cout, + parasitic_delay, + not inp_is_rise) def build_graph(self, graph, inst_name, port_nets): """ @@ -96,4 +96,4 @@ class nand3_dec(design.design): pmos_drain_c = self.drain_c_(self.pmos_width*mult, 1, mult) - return nmos_drain_c + pmos_drain_c \ No newline at end of file + return nmos_drain_c + pmos_drain_c diff --git a/compiler/custom/nand4_dec.py b/compiler/modules/nand4_dec.py similarity index 87% rename from compiler/custom/nand4_dec.py rename to compiler/modules/nand4_dec.py index a4afadbe..8dd4a039 100644 --- a/compiler/custom/nand4_dec.py +++ b/compiler/modules/nand4_dec.py @@ -5,13 +5,13 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import design +from base import design from tech import spice, parameter, drc from tech import cell_properties as props -import logical_effort +from base import logical_effort -class nand4_dec(design.design): +class nand4_dec(design): """ 4-input NAND decoder for address decoders. """ @@ -56,12 +56,12 @@ class nand4_dec(design.design): Input inverted by this stage. """ parasitic_delay = 2 - return logical_effort.logical_effort(self.name, - self.size, - self.input_load(), - cout, - parasitic_delay, - not inp_is_rise) + return logical_effort(self.name, + self.size, + self.input_load(), + cout, + parasitic_delay, + not inp_is_rise) def build_graph(self, graph, inst_name, port_nets): """ @@ -96,4 +96,4 @@ class nand4_dec(design.design): pmos_drain_c = self.drain_c_(self.pmos_width*mult, 1, mult) - return nmos_drain_c + pmos_drain_c \ No newline at end of file + return nmos_drain_c + pmos_drain_c diff --git a/compiler/modules/orig_bitcell_array.py b/compiler/modules/orig_bitcell_array.py index ab154bec..2e3088af 100644 --- a/compiler/modules/orig_bitcell_array.py +++ b/compiler/modules/orig_bitcell_array.py @@ -5,7 +5,7 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -from bitcell_base_array import bitcell_base_array +from .bitcell_base_array import bitcell_base_array from tech import drc, spice from globals import OPTS from sram_factory import factory diff --git a/compiler/pgates/pand2.py b/compiler/modules/pand2.py similarity index 98% rename from compiler/pgates/pand2.py rename to compiler/modules/pand2.py index ab601096..8bd17589 100644 --- a/compiler/pgates/pand2.py +++ b/compiler/modules/pand2.py @@ -6,12 +6,12 @@ # All rights reserved. # import debug -from vector import vector -import pgate +from base import vector +from .pgate import * from sram_factory import factory -class pand2(pgate.pgate): +class pand2(pgate): """ This is an AND (or NAND) with configurable drive strength. """ diff --git a/compiler/pgates/pand3.py b/compiler/modules/pand3.py similarity index 98% rename from compiler/pgates/pand3.py rename to compiler/modules/pand3.py index 477872c8..f63b8c41 100644 --- a/compiler/pgates/pand3.py +++ b/compiler/modules/pand3.py @@ -6,12 +6,12 @@ # All rights reserved. # import debug -from vector import vector -import pgate +from base import vector +from .pgate import * from sram_factory import factory -class pand3(pgate.pgate): +class pand3(pgate): """ This is a simple buffer used for driving loads. """ diff --git a/compiler/pgates/pand4.py b/compiler/modules/pand4.py similarity index 98% rename from compiler/pgates/pand4.py rename to compiler/modules/pand4.py index 8911364c..9b5a31d6 100644 --- a/compiler/pgates/pand4.py +++ b/compiler/modules/pand4.py @@ -6,12 +6,12 @@ # All rights reserved. # import debug -from vector import vector -import pgate +from base import vector +from .pgate import * from sram_factory import factory -class pand4(pgate.pgate): +class pand4(pgate): """ This is a simple buffer used for driving loads. """ diff --git a/compiler/bitcells/pbitcell.py b/compiler/modules/pbitcell.py similarity index 96% rename from compiler/bitcells/pbitcell.py rename to compiler/modules/pbitcell.py index d1e7927b..516dca3f 100644 --- a/compiler/bitcells/pbitcell.py +++ b/compiler/modules/pbitcell.py @@ -5,18 +5,17 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import contact import debug +from base import logical_effort +from base import vector from tech import drc, parameter, layer from tech import cell_properties as props -from vector import vector -from ptx import ptx from globals import OPTS -import logical_effort -import bitcell_base +from .ptx import ptx +from .bitcell_base import bitcell_base -class pbitcell(bitcell_base.bitcell_base): +class pbitcell(bitcell_base): """ This module implements a parametrically sized multi-port bitcell, with a variable number of read/write, write, and read ports @@ -45,7 +44,7 @@ class pbitcell(bitcell_base.bitcell_base): self.gnd_layer = "m1" self.gnd_dir = "H" - bitcell_base.bitcell_base.__init__(self, name) + bitcell_base.__init__(self, name) fmt_str = "{0} rw ports, {1} w ports and {2} r ports" info_string = fmt_str.format(self.num_rw_ports, self.num_w_ports, @@ -222,20 +221,20 @@ class pbitcell(bitcell_base.bitcell_base): # y-offset for the access transistor's gate contact self.gate_contact_yoffset = max_contact_extension + self.m2_space \ - + 0.5 * max(contact.poly_contact.height, contact.m1_via.height) + + 0.5 * max(self.poly_contact.height, self.m1_via.height) # y-position of access transistors - self.port_ypos = self.m1_space + 0.5 * contact.m1_via.height + self.gate_contact_yoffset + self.port_ypos = self.m1_space + 0.5 * self.m1_via.height + self.gate_contact_yoffset # y-position of inverter nmos self.inverter_nmos_ypos = self.port_ypos # spacing between ports (same for read/write and write ports) self.bitline_offset = -0.5 * self.readwrite_nmos.active_width \ - + 0.5 * contact.m1_via.height \ + + 0.5 * self.m1_via.height \ + self.m2_space + self.m2_width m2_constraint = self.bitline_offset + self.m2_space \ - + 0.5 * contact.m1_via.height \ + + 0.5 * self.m1_via.height \ - 0.5 * self.readwrite_nmos.active_width self.write_port_spacing = max(self.active_space, self.m1_space, @@ -243,7 +242,7 @@ class pbitcell(bitcell_base.bitcell_base): self.read_port_spacing = self.bitline_offset + self.m2_space # spacing between cross coupled inverters - self.inverter_to_inverter_spacing = contact.poly_contact.width + self.m1_space + self.inverter_to_inverter_spacing = self.poly_contact.width + self.m1_space # calculations related to inverter connections inverter_pmos_contact_extension = 0.5 * \ @@ -252,19 +251,19 @@ class pbitcell(bitcell_base.bitcell_base): (self.inverter_nmos.active_contact.height - self.inverter_nmos.active_height) self.inverter_gap = max(self.poly_to_active, self.m1_space + inverter_nmos_contact_extension) \ - + self.poly_to_contact + 2 * contact.poly_contact.width \ + + self.poly_to_contact + 2 * self.poly_contact.width \ + self.m1_space + inverter_pmos_contact_extension self.cross_couple_lower_ypos = self.inverter_nmos_ypos \ + self.inverter_nmos.active_height \ + max(self.poly_to_active, self.m1_space + inverter_nmos_contact_extension) \ - + 0.5 * contact.poly_contact.width + + 0.5 * self.poly_contact.width self.cross_couple_upper_ypos = self.inverter_nmos_ypos \ + self.inverter_nmos.active_height \ + max(self.poly_to_active, self.m1_space + inverter_nmos_contact_extension) \ + self.poly_to_contact \ - + 1.5 * contact.poly_contact.width + + 1.5 * self.poly_contact.width # spacing between wordlines (and gnd) self.m1_offset = -0.5 * self.m1_width @@ -300,7 +299,7 @@ class pbitcell(bitcell_base.bitcell_base): (self.write_nmos.active_width + self.write_port_spacing) \ - self.num_r_ports * \ (self.read_port_width + self.read_port_spacing) \ - - self.bitline_offset - 0.5 * contact.m1_via.width + - self.bitline_offset - 0.5 * self.m1_via.width self.width = -2 * self.leftmost_xpos self.height = self.topmost_ypos - self.botmost_ypos @@ -390,14 +389,14 @@ class pbitcell(bitcell_base.bitcell_base): # add contacts to connect gate poly to drain/source # metal1 (to connect Q to Q_bar) contact_offset_left = vector(self.inverter_nmos_left.get_pin("D").rc().x \ - + 0.5 * contact.poly_contact.height, + + 0.5 * self.poly_contact.height, self.cross_couple_upper_ypos) self.add_via_center(layers=self.poly_stack, offset=contact_offset_left, directions=("H", "H")) contact_offset_right = vector(self.inverter_nmos_right.get_pin("S").lc().x \ - - 0.5*contact.poly_contact.height, + - 0.5*self.poly_contact.height, self.cross_couple_lower_ypos) self.add_via_center(layers=self.poly_stack, offset=contact_offset_right, @@ -414,11 +413,11 @@ class pbitcell(bitcell_base.bitcell_base): if OPTS.use_pex: # add labels to cross couple inverter for extracted simulation contact_offset_left_output = vector(self.inverter_nmos_left.get_pin("D").rc().x \ - + 0.5 * contact.poly.height, + + 0.5 * self.poly.height, self.cross_couple_upper_ypos) contact_offset_right_output = vector(self.inverter_nmos_right.get_pin("S").lc().x \ - - 0.5*contact.poly.height, + - 0.5*self.poly.height, self.cross_couple_lower_ypos) self.add_pex_labels(contact_offset_left_output, contact_offset_right_output) @@ -896,7 +895,7 @@ class pbitcell(bitcell_base.bitcell_base): directions="nonpref") self.add_path("m2", - [port_contact_offest, bl_offset], width=contact.m1_via.height) + [port_contact_offest, bl_offset], width=self.m1_via.height) for k in range(self.total_ports): port_contact_offest = right_port_transistors[k].get_pin("D").center() @@ -909,7 +908,7 @@ class pbitcell(bitcell_base.bitcell_base): directions="nonpref") self.add_path("m2", - [port_contact_offest, br_offset], width=contact.m1_via.height) + [port_contact_offest, br_offset], width=self.m1_via.height) def route_supplies(self): """ Route inverter nmos and read-access nmos to gnd. Route inverter pmos to vdd. """ @@ -928,9 +927,9 @@ class pbitcell(bitcell_base.bitcell_base): if position.x > 0: - contact_correct = 0.5 * contact.m1_via.height + contact_correct = 0.5 * self.m1_via.height else: - contact_correct = -0.5 * contact.m1_via.height + contact_correct = -0.5 * self.m1_via.height supply_offset = vector(position.x + contact_correct, self.gnd_position.y) self.add_via_center(layers=self.m1_stack, @@ -997,7 +996,7 @@ class pbitcell(bitcell_base.bitcell_base): """ # add poly to metal1 contacts for gates of the inverters left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x \ - - self.poly_to_contact - 0.5*contact.poly_contact.width, + - self.poly_to_contact - 0.5*self.poly_contact.width, self.cross_couple_upper_ypos) self.add_via_center(layers=self.poly_stack, offset=left_storage_contact, @@ -1005,7 +1004,7 @@ class pbitcell(bitcell_base.bitcell_base): right_storage_contact = vector(self.inverter_nmos_right.get_pin("G").rc().x \ - + self.poly_to_contact + 0.5*contact.poly_contact.width, + + self.poly_to_contact + 0.5*self.poly_contact.width, self.cross_couple_upper_ypos) self.add_via_center(layers=self.poly_stack, offset=right_storage_contact, @@ -1192,12 +1191,12 @@ class pbitcell(bitcell_base.bitcell_base): # min size NMOS gate load read_port_load = self.num_r_ports / 2 total_load = load + read_port_load + write_port_load - return logical_effort.logical_effort('bitline', - size, - cin, - load + read_port_load, - parasitic_delay, - False) + return logical_effort('bitline', + size, + cin, + load + read_port_load, + parasitic_delay, + False) def input_load(self): """ Return the relative capacitance of the access transistor gates """ diff --git a/compiler/pgates/pbuf.py b/compiler/modules/pbuf.py similarity index 98% rename from compiler/pgates/pbuf.py rename to compiler/modules/pbuf.py index 5ed11f39..ba44fe2f 100644 --- a/compiler/pgates/pbuf.py +++ b/compiler/modules/pbuf.py @@ -6,12 +6,12 @@ # All rights reserved. # import debug -from vector import vector -import pgate +from base import vector +from .pgate import * from sram_factory import factory -class pbuf(pgate.pgate): +class pbuf(pgate): """ This is a simple buffer used for driving loads. """ diff --git a/compiler/pgates/pbuf_dec.py b/compiler/modules/pbuf_dec.py similarity index 96% rename from compiler/pgates/pbuf_dec.py rename to compiler/modules/pbuf_dec.py index a0cbafca..c04d4922 100644 --- a/compiler/pgates/pbuf_dec.py +++ b/compiler/modules/pbuf_dec.py @@ -6,12 +6,12 @@ # All rights reserved. # import debug -from vector import vector -import pgate +from base import vector +from .pgate import * from sram_factory import factory -class pbuf_dec(pgate.pgate): +class pbuf_dec(pgate): """ This is a simple buffer used for driving wordlines. """ @@ -25,7 +25,7 @@ class pbuf_dec(pgate.pgate): self.height = height # Creates the netlist and layout - pgate.pgate.__init__(self, name, height) + pgate.__init__(self, name, height) def create_netlist(self): self.add_pins() diff --git a/compiler/pgates/pdriver.py b/compiler/modules/pdriver.py similarity index 98% rename from compiler/pgates/pdriver.py rename to compiler/modules/pdriver.py index 1948b839..a9241af5 100644 --- a/compiler/pgates/pdriver.py +++ b/compiler/modules/pdriver.py @@ -6,12 +6,12 @@ # All rights reserved. # import debug -import pgate -from vector import vector +from .pgate import * +from base import vector from sram_factory import factory -class pdriver(pgate.pgate): +class pdriver(pgate): """ This instantiates an even or odd number of inverters sized for driving a load. diff --git a/compiler/pgates/pgate.py b/compiler/modules/pgate.py similarity index 98% rename from compiler/pgates/pgate.py rename to compiler/modules/pgate.py index 6a92fa0e..ad61cb68 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/modules/pgate.py @@ -5,20 +5,20 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import contact -import design +from base import design +from base import vector import debug import math from bisect import bisect_left from tech import layer, drc -from vector import vector from globals import OPTS from tech import cell_properties as cell_props + if cell_props.ptx.bin_spice_models: from tech import nmos_bins, pmos_bins -class pgate(design.design): +class pgate(design): """ This is a module that implements some shared functions for parameterized gates. @@ -113,14 +113,14 @@ class pgate(design.design): left_gate_offset = vector(nmos_gate_pin.lx(), ypos) # Center is completely symmetric. - contact_width = contact.poly_contact.width + contact_width = self.poly_contact.width if position == "center": contact_offset = left_gate_offset \ + vector(0.5 * self.poly_width, 0) elif position == "farleft": contact_offset = left_gate_offset \ - - vector(0.5 * contact.poly_contact.width, 0) + - vector(0.5 * self.poly_contact.width, 0) elif position == "left": contact_offset = left_gate_offset \ - vector(0.5 * contact_width - 0.5 * self.poly_width, 0) @@ -146,7 +146,7 @@ class pgate(design.design): + left_gate_offset.scale(0.5, 0) self.add_rect_center(layer="poly", offset=mid_point, - height=contact.poly_contact.first_layer_width, + height=self.poly_contact.first_layer_width, width=left_gate_offset.x - contact_offset.x) return via @@ -216,6 +216,7 @@ class pgate(design.design): # Offset by half a contact in x and y contact_offset += vector(0.5 * pmos.active_contact.first_layer_width, 0.5 * pmos.active_contact.first_layer_height) + # This over-rides the default one with a custom direction self.nwell_contact = self.add_via_center(layers=layer_stack, offset=contact_offset, implant_type="n", @@ -372,7 +373,7 @@ class pgate(design.design): # It was already set or is left as default (minimum) # Width is determined by well contact and spacing and allowing a supply via between each cell if self.add_wells: - width = max(self.nwell_contact.rx(), self.pwell_contact.rx()) + self.m1_space + 0.5 * contact.m1_via.width + width = max(self.nwell_contact.rx(), self.pwell_contact.rx()) + self.m1_space + 0.5 * self.m1_via.width # Height is an input parameter, so it is not recomputed. else: max_active_xoffset = self.find_highest_layer_coords("active").x diff --git a/compiler/pgates/pinv.py b/compiler/modules/pinv.py similarity index 94% rename from compiler/pgates/pinv.py rename to compiler/modules/pinv.py index c458a3f0..a60bed13 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/modules/pinv.py @@ -5,22 +5,21 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import contact -import pgate import debug +from .pgate import * +from base import vector +from base import logical_effort +from base.utils import round_to_grid +from base.errors import drc_error import operator from tech import drc, parameter, spice -from vector import vector from math import ceil from globals import OPTS -from utils import round_to_grid -import logical_effort from sram_factory import factory -from errors import drc_error from tech import cell_properties as cell_props -class pinv(pgate.pgate): +class pinv(pgate): """ Pinv generates gds of a parametrically sized inverter. The size is specified as the drive size (relative to minimum NMOS) and @@ -89,8 +88,8 @@ class pinv(pgate.pgate): self.nmos_width = self.nmos_size * drc("minwidth_tx") self.pmos_width = self.pmos_size * drc("minwidth_tx") if cell_props.ptx.bin_spice_models: - (self.nmos_width, self.tx_mults) = pgate.pgate.best_bin("nmos", self.nmos_width) - (self.pmos_width, self.tx_mults) = pgate.pgate.best_bin("pmos", self.pmos_width) + (self.nmos_width, self.tx_mults) = pgate.best_bin("nmos", self.nmos_width) + (self.pmos_width, self.tx_mults) = pgate.best_bin("pmos", self.pmos_width) return # Do a quick sanity check and bail if unlikely feasible height @@ -106,8 +105,8 @@ class pinv(pgate.pgate): tx_type="pmos") tx_height = nmos.poly_height + pmos.poly_height # rotated m1 pitch or poly to active spacing - min_channel = max(contact.poly_contact.width + self.m1_space, - contact.poly_contact.width + 2 * self.poly_to_active) + min_channel = max(self.poly_contact.width + self.m1_space, + self.poly_contact.width + 2 * self.poly_to_active) total_height = tx_height + min_channel + 2 * self.top_bottom_space # debug.check(self.height > total_height, @@ -322,12 +321,12 @@ class pinv(pgate.pgate): Input inverted by this stage. """ parasitic_delay = 1 - return logical_effort.logical_effort(self.name, - self.size, - self.input_load(), - cout, - parasitic_delay, - not inp_is_rise) + return logical_effort(self.name, + self.size, + self.input_load(), + cout, + parasitic_delay, + not inp_is_rise) def build_graph(self, graph, inst_name, port_nets): """ diff --git a/compiler/pgates/pinv_dec.py b/compiler/modules/pinv_dec.py similarity index 92% rename from compiler/pgates/pinv_dec.py rename to compiler/modules/pinv_dec.py index b738f5fb..7b378f08 100644 --- a/compiler/pgates/pinv_dec.py +++ b/compiler/modules/pinv_dec.py @@ -5,17 +5,16 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import contact -import pinv import debug +from base import vector +from .pinv import pinv from tech import drc, parameter, layer -from vector import vector from globals import OPTS from sram_factory import factory from tech import cell_properties as cell_props -class pinv_dec(pinv.pinv): +class pinv_dec(pinv): """ This is another version of pinv but with layout for the decoder. Other stuff is the same (netlist, sizes, etc.) @@ -78,7 +77,7 @@ class pinv_dec(pinv.pinv): self.add_path("poly", [nmos_gate_pos, pmos_gate_pos]) # Center is completely symmetric. - contact_width = contact.poly_contact.width + contact_width = self.poly_contact.width contact_offset = nmos_gate_pin.lc() \ - vector(self.poly_extend_active + 0.5 * contact_width, 0) via = self.add_via_stack_center(from_layer="poly", @@ -126,7 +125,7 @@ class pinv_dec(pinv.pinv): y_offset = (0.5 * (self.height - self.nmos.width) + self.nmos.width) * 0.9 # offset so that the input contact is over from the left edge by poly spacing - x_offset = self.nmos.active_offset.y + contact.poly_contact.width + self.poly_space + x_offset = self.nmos.active_offset.y + self.poly_contact.width + self.poly_space self.nmos_pos = vector(x_offset, y_offset) self.nmos_inst.place(self.nmos_pos, rotate=270) @@ -192,20 +191,20 @@ class pinv_dec(pinv.pinv): source_pos = self.pmos_inst.get_pin("S").center() contact_pos = vector(source_pos.x, self.height) - self.nwell_contact = self.add_via_center(layers=self.active_stack, - offset=contact_pos, - implant_type="n", - well_type="n") + self.add_via_center(layers=self.active_stack, + offset=contact_pos, + implant_type="n", + well_type="n") self.add_via_stack_center(offset=contact_pos, from_layer=self.active_stack[2], to_layer=self.supply_layer) source_pos = self.nmos_inst.get_pin("S").center() contact_pos = vector(source_pos.x, self.height) - self.pwell_contact= self.add_via_center(layers=self.active_stack, - offset=contact_pos, - implant_type="p", - well_type="p") + self.add_via_center(layers=self.active_stack, + offset=contact_pos, + implant_type="p", + well_type="p") self.add_via_stack_center(offset=contact_pos, from_layer=self.active_stack[2], to_layer=self.supply_layer) diff --git a/compiler/pgates/pinvbuf.py b/compiler/modules/pinvbuf.py similarity index 99% rename from compiler/pgates/pinvbuf.py rename to compiler/modules/pinvbuf.py index a48f1cf9..78dca7b5 100644 --- a/compiler/pgates/pinvbuf.py +++ b/compiler/modules/pinvbuf.py @@ -6,12 +6,12 @@ # All rights reserved. # import debug -import pgate -from vector import vector +from .pgate import * +from base import vector from sram_factory import factory from tech import layer -class pinvbuf(pgate.pgate): +class pinvbuf(pgate): """ This is a simple inverter/buffer used for driving loads. It is used in the column decoder for 1:2 decoding and as the clock buffer. diff --git a/compiler/pgates/pnand2.py b/compiler/modules/pnand2.py similarity index 94% rename from compiler/pgates/pnand2.py rename to compiler/modules/pnand2.py index 08b01d4c..9262b2f8 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/modules/pnand2.py @@ -5,17 +5,16 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import pgate +from .pgate import * import debug from tech import drc, parameter, spice -from vector import vector -import logical_effort +from base import vector +from base import logical_effort from sram_factory import factory -import contact from tech import cell_properties as cell_props -class pnand2(pgate.pgate): +class pnand2(pgate): """ This module generates gds of a parametrically sized 2-input nand. This model use ptx to generate a 2-input nand within a cetrain height. @@ -175,11 +174,11 @@ class pnand2(pgate.pgate): # Top of NMOS drain bottom_pin = self.nmos1_inst.get_pin("D") # active contact metal to poly contact metal spacing - active_contact_to_poly_contact = bottom_pin.uy() + self.route_layer_space + 0.5 * contact.poly_contact.second_layer_height + active_contact_to_poly_contact = bottom_pin.uy() + self.route_layer_space + 0.5 * self.poly_contact.second_layer_height # active diffusion to poly contact spacing # doesn't use nmos uy because that is calculated using offset + poly height active_top = self.nmos1_inst.by() + self.nmos1_inst.mod.active_height - active_to_poly_contact = active_top + self.poly_to_active + 0.5 * contact.poly_contact.first_layer_height + active_to_poly_contact = active_top + self.poly_to_active + 0.5 * self.poly_contact.first_layer_height active_to_poly_contact2 = active_top + self.poly_contact_to_gate + 0.5 * self.route_layer_width self.inputA_yoffset = max(active_contact_to_poly_contact, active_to_poly_contact, @@ -193,9 +192,9 @@ class pnand2(pgate.pgate): self.inputB_yoffset = self.inputA_yoffset + 2 * self.m3_pitch # # active contact metal to poly contact metal spacing - # active_contact_to_poly_contact = self.output_yoffset - self.route_layer_space - 0.5 * contact.poly_contact.second_layer_height + # active_contact_to_poly_contact = self.output_yoffset - self.route_layer_space - 0.5 * self.poly_contact.second_layer_height # active_bottom = self.pmos1_inst.by() - # active_to_poly_contact = active_bottom - self.poly_to_active - 0.5 * contact.poly_contact.first_layer_height + # active_to_poly_contact = active_bottom - self.poly_to_active - 0.5 * self.poly_contact.first_layer_height # active_to_poly_contact2 = active_bottom - self.poly_contact_to_gate - 0.5 * self.route_layer_width # self.inputB_yoffset = min(active_contact_to_poly_contact, # active_to_poly_contact, @@ -215,7 +214,7 @@ class pnand2(pgate.pgate): """ Route the Z output """ # One routing track layer below the PMOS contacts - route_layer_offset = 0.5 * contact.poly_contact.second_layer_height + self.route_layer_space + route_layer_offset = 0.5 * self.poly_contact.second_layer_height + self.route_layer_space self.output_yoffset = self.pmos1_inst.get_pin("D").by() - route_layer_offset @@ -297,12 +296,12 @@ class pnand2(pgate.pgate): Input inverted by this stage. """ parasitic_delay = 2 - return logical_effort.logical_effort(self.name, - self.size, - self.input_load(), - cout, - parasitic_delay, - not inp_is_rise) + return logical_effort(self.name, + self.size, + self.input_load(), + cout, + parasitic_delay, + not inp_is_rise) def build_graph(self, graph, inst_name, port_nets): """ diff --git a/compiler/pgates/pnand3.py b/compiler/modules/pnand3.py similarity index 96% rename from compiler/pgates/pnand3.py rename to compiler/modules/pnand3.py index 0186907f..31a1b400 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/modules/pnand3.py @@ -5,17 +5,16 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import pgate +from .pgate import * import debug from tech import drc, parameter, spice -from vector import vector -import logical_effort +from base import vector +from base import logical_effort from sram_factory import factory -import contact from tech import cell_properties as cell_props -class pnand3(pgate.pgate): +class pnand3(pgate): """ This module generates gds of a parametrically sized 2-input nand. This model use ptx to generate a 2-input nand within a cetrain height. @@ -204,17 +203,17 @@ class pnand3(pgate.pgate): """ Route the A and B and C inputs """ # We can use this pitch because the contacts and overlap won't be adjacent - non_contact_pitch = 0.5 * self.m1_width + self.m1_space + 0.5 * contact.poly_contact.second_layer_height + non_contact_pitch = 0.5 * self.m1_width + self.m1_space + 0.5 * self.poly_contact.second_layer_height pmos_drain_bottom = self.pmos1_inst.get_pin("D").by() self.output_yoffset = pmos_drain_bottom - 0.5 * self.route_layer_width - self.route_layer_space bottom_pin = self.nmos1_inst.get_pin("D") # active contact metal to poly contact metal spacing - active_contact_to_poly_contact = bottom_pin.uy() + self.m1_space + 0.5 * contact.poly_contact.second_layer_height + active_contact_to_poly_contact = bottom_pin.uy() + self.m1_space + 0.5 * self.poly_contact.second_layer_height # active diffusion to poly contact spacing # doesn't use nmos uy because that is calculated using offset + poly height active_top = self.nmos1_inst.by() + self.nmos1_inst.mod.active_height - active_to_poly_contact = active_top + self.poly_to_active + 0.5 * contact.poly_contact.first_layer_height + active_to_poly_contact = active_top + self.poly_to_active + 0.5 * self.poly_contact.first_layer_height active_to_poly_contact2 = active_top + self.poly_contact_to_gate + 0.5 * self.route_layer_width self.inputA_yoffset = max(active_contact_to_poly_contact, active_to_poly_contact, @@ -328,12 +327,12 @@ class pnand3(pgate.pgate): Input inverted by this stage. """ parasitic_delay = 3 - return logical_effort.logical_effort(self.name, - self.size, - self.input_load(), - cout, - parasitic_delay, - not inp_is_rise) + return logical_effort(self.name, + self.size, + self.input_load(), + cout, + parasitic_delay, + not inp_is_rise) def build_graph(self, graph, inst_name, port_nets): """ diff --git a/compiler/pgates/pnand4.py b/compiler/modules/pnand4.py similarity index 96% rename from compiler/pgates/pnand4.py rename to compiler/modules/pnand4.py index eed71eb9..906cb0e8 100644 --- a/compiler/pgates/pnand4.py +++ b/compiler/modules/pnand4.py @@ -5,17 +5,16 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import pgate +from .pgate import * import debug from tech import drc, parameter, spice -from vector import vector -import logical_effort +from base import vector +from base import logical_effort from sram_factory import factory -import contact from tech import cell_properties as cell_props -class pnand4(pgate.pgate): +class pnand4(pgate): """ This module generates gds of a parametrically sized 4-input nand. This model use ptx to generate a 4-input nand within a cetrain height. @@ -225,11 +224,11 @@ class pnand4(pgate.pgate): bottom_pin = self.nmos1_inst.get_pin("D") # active contact metal to poly contact metal spacing - active_contact_to_poly_contact = bottom_pin.uy() + self.m1_space + 0.5 * contact.poly_contact.second_layer_height + active_contact_to_poly_contact = bottom_pin.uy() + self.m1_space + 0.5 * self.poly_contact.second_layer_height # active diffusion to poly contact spacing # doesn't use nmos uy because that is calculated using offset + poly height active_top = self.nmos1_inst.by() + self.nmos1_inst.mod.active_height - active_to_poly_contact = active_top + self.poly_to_active + 0.5 * contact.poly_contact.first_layer_height + active_to_poly_contact = active_top + self.poly_to_active + 0.5 * self.poly_contact.first_layer_height active_to_poly_contact2 = active_top + self.poly_contact_to_gate + 0.5 * self.route_layer_width self.inputA_yoffset = max(active_contact_to_poly_contact, active_to_poly_contact, @@ -350,12 +349,12 @@ class pnand4(pgate.pgate): Input inverted by this stage. """ parasitic_delay = 3 - return logical_effort.logical_effort(self.name, - self.size, - self.input_load(), - cout, - parasitic_delay, - not inp_is_rise) + return logical_effort(self.name, + self.size, + self.input_load(), + cout, + parasitic_delay, + not inp_is_rise) def build_graph(self, graph, inst_name, port_nets): """ @@ -384,4 +383,4 @@ class pnand4(pgate.pgate): pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults, 1, self.tx_mults) - return nmos_drain_c + pmos_drain_c \ No newline at end of file + return nmos_drain_c + pmos_drain_c diff --git a/compiler/pgates/pnor2.py b/compiler/modules/pnor2.py similarity index 99% rename from compiler/pgates/pnor2.py rename to compiler/modules/pnor2.py index d6384676..35df000f 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/modules/pnor2.py @@ -5,15 +5,15 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import pgate +from .pgate import * import debug from tech import drc, parameter, spice -from vector import vector +from base import vector from sram_factory import factory from tech import cell_properties as cell_props -class pnor2(pgate.pgate): +class pnor2(pgate): """ This module generates gds of a parametrically sized 2-input nor. This model use ptx to generate a 2-input nor within a cetrain height. diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index a96a556e..26dc3405 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -5,15 +5,15 @@ # from math import log, ceil import debug -import design +from base import design from sram_factory import factory -from vector import vector +from base import vector from tech import layer, drc from globals import OPTS from tech import layer_properties as layer_props -class port_address(design.design): +class port_address(design): """ Create the address port (row decoder and wordline driver).. """ diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index 270cfed5..a8f5300f 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -5,17 +5,17 @@ # from tech import drc import debug -import design +from base import design import math from sram_factory import factory from collections import namedtuple -from vector import vector +from base import vector from globals import OPTS from tech import cell_properties from tech import layer_properties as layer_props -class port_data(design.design): +class port_data(design): """ Create the data port (column mux, sense amps, write driver, etc.) for the given port number. Port 0 always has the RBL on the left while port 1 is on the right. diff --git a/compiler/pgates/precharge.py b/compiler/modules/precharge.py similarity index 96% rename from compiler/pgates/precharge.py rename to compiler/modules/precharge.py index 1538e0a5..4a1267e5 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/modules/precharge.py @@ -5,18 +5,17 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import contact -import design +from base import design import debug -from pgate import pgate +from .pgate import * from tech import parameter, drc -from vector import vector +from base import vector from globals import OPTS from sram_factory import factory from tech import cell_properties as cell_props -class precharge(design.design): +class precharge(design): """ Creates a single precharge cell This module implements the precharge bitline cell used in the design. @@ -178,7 +177,7 @@ class precharge(design.design): pin_offset = self.lower_pmos_inst.get_pin("G").lr() # This is an extra space down for some techs with contact to active spacing contact_space = max(self.poly_space, - self.poly_contact_to_gate) + 0.5 * contact.poly_contact.first_layer_height + self.poly_contact_to_gate) + 0.5 * self.poly_contact.first_layer_height offset = pin_offset - vector(0, contact_space) self.add_via_stack_center(from_layer="poly", to_layer=self.en_layer, @@ -198,7 +197,7 @@ class precharge(design.design): # adds the contact from active to metal1 offset_height = self.upper_pmos1_inst.uy() + \ - contact.active_contact.height + \ + self.active_contact.height + \ self.nwell_extend_active self.well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1, 0) + \ vector(0, offset_height) @@ -210,7 +209,7 @@ class precharge(design.design): to_layer=self.bitline_layer, offset=self.well_contact_pos) - self.height = self.well_contact_pos.y + contact.active_contact.height + self.m1_space + self.height = self.well_contact_pos.y + self.active_contact.height + self.m1_space # nwell should span the whole design since it is pmos only self.add_rect(layer="nwell", diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index 372a5629..3c7ab681 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -5,14 +5,14 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import design +from base import design import debug -from vector import vector +from base import vector from sram_factory import factory from globals import OPTS -class precharge_array(design.design): +class precharge_array(design): """ Dynamically generated precharge array of all bitlines. Cols is number of bit line columns, height is the height of the bit-cell array. diff --git a/compiler/pgates/ptristate_inv.py b/compiler/modules/ptristate_inv.py similarity index 89% rename from compiler/pgates/ptristate_inv.py rename to compiler/modules/ptristate_inv.py index b37c36ae..583b68ea 100644 --- a/compiler/pgates/ptristate_inv.py +++ b/compiler/modules/ptristate_inv.py @@ -5,15 +5,14 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import contact -import pgate +from .pgate import * import debug from tech import drc, parameter, spice -from vector import vector +from base import vector from sram_factory import factory -class ptristate_inv(pgate.pgate): +class ptristate_inv(pgate): """ ptristate generates gds of a parametrically sized tristate inverter. There is some flexibility in the size, but we do not allow multiple fingers @@ -131,8 +130,8 @@ class ptristate_inv(pgate.pgate): """ pmos_yoff = self.height - self.pmos.active_height \ - - self.top_bottom_space - 0.5 * contact.active_contact.height - nmos_yoff = self.top_bottom_space + 0.5 * contact.active_contact.height + - self.top_bottom_space - 0.5 * self.active_contact.height + nmos_yoff = self.top_bottom_space + 0.5 * self.active_contact.height # Tristate transistors pmos1_pos = vector(self.pmos.active_offset.x, pmos_yoff) @@ -188,16 +187,16 @@ class ptristate_inv(pgate.pgate): drain_pos = self.nmos1_inst.get_pin("S").center() vdd_pos = self.get_pin("vdd").center() - self.nwell_contact = self.add_via_center(layers=layer_stack, - offset=vector(drain_pos.x, vdd_pos.y), - implant_type="n", - well_type="n") + self.add_via_center(layers=layer_stack, + offset=vector(drain_pos.x, vdd_pos.y), + implant_type="n", + well_type="n") gnd_pos = self.get_pin("gnd").center() - self.pwell_contact = self.add_via_center(layers=layer_stack, - offset=vector(drain_pos.x, gnd_pos.y), - implant_type="p", - well_type="p") + self.add_via_center(layers=layer_stack, + offset=vector(drain_pos.x, gnd_pos.y), + implant_type="p", + well_type="p") def connect_rails(self): """ Connect the nmos and pmos to its respective power rails """ diff --git a/compiler/pgates/ptx.py b/compiler/modules/ptx.py similarity index 97% rename from compiler/pgates/ptx.py rename to compiler/modules/ptx.py index e49df518..d1bd13c8 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/modules/ptx.py @@ -5,18 +5,17 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import design import debug +from base import design +from base import logical_effort +from base import vector from tech import layer, drc, spice -from vector import vector from sram_factory import factory -import contact -import logical_effort from globals import OPTS from tech import cell_properties as cell_props -class ptx(design.design): +class ptx(design): """ This module generates gds and spice of a parametrically NMOS or PMOS sized transistor. Pins are accessed as D, G, S, B. Width is @@ -198,12 +197,12 @@ class ptx(design.design): # This is the extra poly spacing due to the poly contact to poly contact pitch # of contacted gates - extra_poly_contact_width = contact.poly_contact.width - self.poly_width + extra_poly_contact_width = self.poly_contact.width - self.poly_width # This is the spacing between S/D contacts # This is the spacing between the poly gates self.min_poly_pitch = self.poly_space + self.poly_width - self.contacted_poly_pitch = self.poly_space + contact.poly_contact.width + self.contacted_poly_pitch = self.poly_space + self.poly_contact.width self.contact_pitch = 2 * self.active_contact_to_gate + self.poly_width + self.contact_width self.poly_pitch = max(self.min_poly_pitch, self.contacted_poly_pitch, @@ -487,11 +486,11 @@ class ptx(design.design): # FIXME: Using the same definition as the pinv.py. parasitic_delay = 1 size = self.mults * self.tx_width / drc("minwidth_tx") - return logical_effort.logical_effort(self.name, - size, - self.input_load(), - cout, - parasitic_delay) + return logical_effort(self.name, + size, + self.input_load(), + cout, + parasitic_delay) def input_load(self): """ diff --git a/compiler/pgates/pwrite_driver.py b/compiler/modules/pwrite_driver.py similarity index 99% rename from compiler/pgates/pwrite_driver.py rename to compiler/modules/pwrite_driver.py index 103e902b..9af6c78f 100644 --- a/compiler/pgates/pwrite_driver.py +++ b/compiler/modules/pwrite_driver.py @@ -5,15 +5,15 @@ #(acting for and on behalf of Oklahoma State University) #All rights reserved. # -import design +from base import design from tech import parameter import debug -from vector import vector +from base import vector from globals import OPTS from sram_factory import factory -class pwrite_driver(design.design): +class pwrite_driver(design): """ The pwrite_driver is two tristate inverters that drive the bitlines. The data input is first inverted before one tristate. diff --git a/compiler/bitcells/replica_bitcell_1port.py b/compiler/modules/replica_bitcell_1port.py similarity index 89% rename from compiler/bitcells/replica_bitcell_1port.py rename to compiler/modules/replica_bitcell_1port.py index 191ba4a7..f33fc2f9 100644 --- a/compiler/bitcells/replica_bitcell_1port.py +++ b/compiler/modules/replica_bitcell_1port.py @@ -6,13 +6,13 @@ # All rights reserved. # import debug -import bitcell_base +from .bitcell_base import bitcell_base from tech import cell_properties as props from tech import parameter, drc -import logical_effort +from base import logical_effort -class replica_bitcell_1port(bitcell_base.bitcell_base): +class replica_bitcell_1port(bitcell_base): """ A single bit cell (6T, 8T, etc.) This module implements the single memory cell used in the design. It @@ -28,7 +28,7 @@ class replica_bitcell_1port(bitcell_base.bitcell_base): size = 0.5 # This accounts for bitline being drained thought the access TX and internal node cin = 3 # Assumes always a minimum sizes inverter. Could be specified in the tech.py file. read_port_load = 0.5 # min size NMOS gate load - return logical_effort.logical_effort('bitline', size, cin, load + read_port_load, parasitic_delay, False) + return logical_effort('bitline', size, cin, load + read_port_load, parasitic_delay, False) def input_load(self): """Return the relative capacitance of the access transistor gates""" @@ -52,4 +52,4 @@ class replica_bitcell_1port(bitcell_base.bitcell_base): def is_non_inverting(self): """Return input to output polarity for module""" - return False \ No newline at end of file + return False diff --git a/compiler/bitcells/replica_bitcell_2port.py b/compiler/modules/replica_bitcell_2port.py similarity index 90% rename from compiler/bitcells/replica_bitcell_2port.py rename to compiler/modules/replica_bitcell_2port.py index 8d113805..64c3c4e1 100644 --- a/compiler/bitcells/replica_bitcell_2port.py +++ b/compiler/modules/replica_bitcell_2port.py @@ -6,13 +6,13 @@ # All rights reserved. # import debug -import bitcell_base +from .bitcell_base import bitcell_base from tech import cell_properties as props from tech import parameter, drc -import logical_effort +from base import logical_effort -class replica_bitcell_2port(bitcell_base.bitcell_base): +class replica_bitcell_2port(bitcell_base): """ A single bit cell which is forced to store a 0. This module implements the single memory cell used in the design. It @@ -28,7 +28,7 @@ class replica_bitcell_2port(bitcell_base.bitcell_base): size = 0.5 # This accounts for bitline being drained thought the access TX and internal node cin = 3 # Assumes always a minimum sizes inverter. Could be specified in the tech.py file. read_port_load = 0.5 # min size NMOS gate load - return logical_effort.logical_effort('bitline', size, cin, load + read_port_load, parasitic_delay, False) + return logical_effort('bitline', size, cin, load + read_port_load, parasitic_delay, False) def input_load(self): """Return the relative capacitance of the access transistor gates""" @@ -53,4 +53,4 @@ class replica_bitcell_2port(bitcell_base.bitcell_base): def is_non_inverting(self): """Return input to output polarity for module""" - return False \ No newline at end of file + return False diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 92a0358b..609aa566 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -5,12 +5,11 @@ # import debug -from bitcell_base_array import bitcell_base_array -from pbitcell import pbitcell -from contact import contact -from tech import drc, spice, preferred_directions +from base import vector +from base import contact +from .bitcell_base_array import bitcell_base_array +from tech import drc, spice from tech import cell_properties as props -from vector import vector from globals import OPTS from sram_factory import factory diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index 43a3cda3..5f59c016 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -4,9 +4,9 @@ # All rights reserved. # import debug -from bitcell_base_array import bitcell_base_array +from .bitcell_base_array import bitcell_base_array from sram_factory import factory -from vector import vector +from base import vector from globals import OPTS from tech import layer_properties as layer_props diff --git a/compiler/bitcells/replica_pbitcell.py b/compiler/modules/replica_pbitcell.py similarity index 95% rename from compiler/bitcells/replica_pbitcell.py rename to compiler/modules/replica_pbitcell.py index bf2fa032..54fda10a 100644 --- a/compiler/bitcells/replica_pbitcell.py +++ b/compiler/modules/replica_pbitcell.py @@ -6,13 +6,13 @@ # All rights reserved. # import debug -import design -from vector import vector +from base import design +from base import vector from globals import OPTS from sram_factory import factory -class replica_pbitcell(design.design): +class replica_pbitcell(design): """ Creates a replica bitcell using pbitcell """ @@ -25,7 +25,7 @@ class replica_pbitcell(design.design): self.num_r_ports = OPTS.num_r_ports self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports - design.design.__init__(self, name, cell_name) + design.__init__(self, name, cell_name) debug.info(1, "create a replica bitcell using pbitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports)) diff --git a/compiler/modules/row_cap_array.py b/compiler/modules/row_cap_array.py index 8f092dc4..61b736b3 100644 --- a/compiler/modules/row_cap_array.py +++ b/compiler/modules/row_cap_array.py @@ -3,7 +3,7 @@ # Copyright (c) 2016-2021 Regents of the University of California # All rights reserved. # -from bitcell_base_array import bitcell_base_array +from .bitcell_base_array import bitcell_base_array from sram_factory import factory from globals import OPTS diff --git a/compiler/bitcells/row_cap_bitcell_1port.py b/compiler/modules/row_cap_bitcell_1port.py similarity index 87% rename from compiler/bitcells/row_cap_bitcell_1port.py rename to compiler/modules/row_cap_bitcell_1port.py index 9fb1f813..82849000 100644 --- a/compiler/bitcells/row_cap_bitcell_1port.py +++ b/compiler/modules/row_cap_bitcell_1port.py @@ -7,10 +7,10 @@ # import debug from tech import cell_properties as props -import bitcell_base +from .bitcell_base import bitcell_base -class row_cap_bitcell_1port(bitcell_base.bitcell_base): +class row_cap_bitcell_1port(bitcell_base): """ Row end cap cell. """ diff --git a/compiler/bitcells/row_cap_bitcell_2port.py b/compiler/modules/row_cap_bitcell_2port.py similarity index 87% rename from compiler/bitcells/row_cap_bitcell_2port.py rename to compiler/modules/row_cap_bitcell_2port.py index 0c2989b0..771e9043 100644 --- a/compiler/bitcells/row_cap_bitcell_2port.py +++ b/compiler/modules/row_cap_bitcell_2port.py @@ -7,10 +7,10 @@ # import debug from tech import cell_properties as props -import bitcell_base +from .bitcell_base import bitcell_base -class row_cap_bitcell_2port(bitcell_base.bitcell_base): +class row_cap_bitcell_2port(bitcell_base): """ Row end cap cell. """ diff --git a/compiler/custom/sense_amp.py b/compiler/modules/sense_amp.py similarity index 96% rename from compiler/custom/sense_amp.py rename to compiler/modules/sense_amp.py index 51328a54..3440e5a7 100644 --- a/compiler/custom/sense_amp.py +++ b/compiler/modules/sense_amp.py @@ -5,14 +5,14 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import design +from base import design import debug from tech import parameter, drc, spice from tech import cell_properties as props -import logical_effort +from base import logical_effort -class sense_amp(design.design): +class sense_amp(design): """ This module implements the single sense amp cell used in the design. It is a hand-made cell, so the layout and netlist should be available in @@ -55,7 +55,7 @@ class sense_amp(design.design): cin = (parameter["sa_inv_pmos_size"] + parameter["sa_inv_nmos_size"]) / drc("minwidth_tx") sa_size = parameter["sa_inv_nmos_size"] / drc("minwidth_tx") cc_inv_cin = cin - return logical_effort.logical_effort('column_mux', sa_size, cin, load + cc_inv_cin, parasitic_delay, False) + return logical_effort('column_mux', sa_size, cin, load + cc_inv_cin, parasitic_delay, False) def analytical_power(self, corner, load): """Returns dynamic and leakage power. Results in nW""" diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index daabf8df..3e98a517 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -5,15 +5,15 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import design -from vector import vector +from base import design +from base import vector from sram_factory import factory from tech import cell_properties import debug from globals import OPTS -class sense_amp_array(design.design): +class sense_amp_array(design): """ Array of sense amplifiers to read the bitlines through the column mux. Dynamically generated sense amp array for all bitlines. diff --git a/compiler/sram/sram.py b/compiler/modules/sram.py similarity index 95% rename from compiler/sram/sram.py rename to compiler/modules/sram.py index b656f547..70d8afce 100644 --- a/compiler/sram/sram.py +++ b/compiler/modules/sram.py @@ -8,7 +8,6 @@ import datetime import os import debug -import verify from characterizer import functional from globals import OPTS, print_time import shutil @@ -27,7 +26,7 @@ class sram(): # reset the static duplicate name checker for unit tests # in case we create more than one SRAM - from design import design + from base import design design.name_map=[] debug.info(2, "create sram of size {0} with {1} num of words {2} banks".format(self.word_size, @@ -38,9 +37,9 @@ class sram(): self.name = name if self.num_banks == 1: - from sram_1bank import sram_1bank as sram + from .sram_1bank import sram_1bank as sram elif self.num_banks == 2: - from sram_2bank import sram_2bank as sram + from .sram_2bank import sram_2bank as sram else: debug.error("Invalid number of banks.", -1) @@ -79,6 +78,10 @@ class sram(): def save(self): """ Save all the output files while reporting time to do it as well. """ + # Import this at the last minute so that the proper tech file + # is loaded and the right tools are selected + import verify + # Save the spice file start_time = datetime.datetime.now() spname = OPTS.output_path + self.s.name + ".sp" @@ -155,7 +158,7 @@ class sram(): # Write the datasheet start_time = datetime.datetime.now() - from datasheet_gen import datasheet_gen + from datasheet import datasheet_gen dname = OPTS.output_path + self.s.name + ".html" debug.print_raw("Datasheet: Writing to {0}".format(dname)) datasheet_gen.datasheet_write(dname) diff --git a/compiler/sram/sram_1bank.py b/compiler/modules/sram_1bank.py similarity index 99% rename from compiler/sram/sram_1bank.py rename to compiler/modules/sram_1bank.py index a410e04a..a26ea7e8 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/modules/sram_1bank.py @@ -5,11 +5,10 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -from vector import vector -from sram_base import sram_base -from contact import m2_via -from channel_route import channel_route -from router_tech import router_tech +from base import vector +from .sram_base import sram_base +from base import channel_route +from router import router_tech from globals import OPTS @@ -537,7 +536,7 @@ class sram_1bank(sram_base): # so make the wire as wide as the contacts self.add_path("m2", [mid_pos, clk_steiner_pos], - width=max(m2_via.width, m2_via.height)) + width=max(self.m2_via.width, self.m2_via.height)) self.add_wire(self.m2_stack[::-1], [data_dff_clk_pos, mid_pos, clk_steiner_pos]) diff --git a/compiler/sram/sram_2bank.py b/compiler/modules/sram_2bank.py similarity index 98% rename from compiler/sram/sram_2bank.py rename to compiler/modules/sram_2bank.py index 421641ac..69ecb496 100644 --- a/compiler/sram/sram_2bank.py +++ b/compiler/modules/sram_2bank.py @@ -11,13 +11,13 @@ import debug from math import log,sqrt,ceil import datetime import getpass -from vector import vector +from base import vector from globals import OPTS, print_time -from sram_base import sram_base -from bank import bank -from dff_buf_array import dff_buf_array -from dff_array import dff_array +from .sram_base import sram_base +from modules import bank +from modules import dff_buf_array +from modules import dff_array class sram_2bank(sram_base): """ diff --git a/compiler/sram/sram_base.py b/compiler/modules/sram_base.py similarity index 98% rename from compiler/sram/sram_base.py rename to compiler/modules/sram_base.py index 6feda56f..722a649d 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/modules/sram_base.py @@ -7,13 +7,13 @@ # import datetime import debug -from math import log, ceil -from importlib import reload -from vector import vector from globals import OPTS, print_time -from design import design -from verilog import verilog -from lef import lef +from math import log, ceil +import importlib +from base.vector import vector +from base.design import design +from base.verilog import verilog +from base.lef import lef from sram_factory import factory from tech import spice @@ -248,9 +248,9 @@ class sram_base(design, verilog, lef): # Do not route the power supply (leave as must-connect pins) return elif OPTS.route_supplies == "grid": - from supply_grid_router import supply_grid_router as router + from router import supply_grid_router as router else: - from supply_tree_router import supply_tree_router as router + from router import supply_tree_router as router rtr=router(layers=self.supply_stack, design=self, @@ -364,7 +364,7 @@ class sram_base(design, verilog, lef): for bit in range(self.num_spare_cols): pins_to_route.append("spare_wen{0}[{1}]".format(port, bit)) - from signal_escape_router import signal_escape_router as router + from router import signal_escape_router as router rtr=router(layers=self.m3_stack, design=self, bbox=bbox) @@ -500,7 +500,7 @@ class sram_base(design, verilog, lef): self.bank_count = 0 - c = reload(__import__(OPTS.control_logic)) + c = importlib.import_module("modules." + OPTS.control_logic) self.mod_control_logic = getattr(c, OPTS.control_logic) # Create the control logic module for each port type diff --git a/compiler/sram/sram_config.py b/compiler/modules/sram_config.py similarity index 100% rename from compiler/sram/sram_config.py rename to compiler/modules/sram_config.py diff --git a/compiler/custom/tri_gate.py b/compiler/modules/tri_gate.py similarity index 96% rename from compiler/custom/tri_gate.py rename to compiler/modules/tri_gate.py index f0c0afeb..c5d65d57 100644 --- a/compiler/custom/tri_gate.py +++ b/compiler/modules/tri_gate.py @@ -6,11 +6,11 @@ # All rights reserved. # import debug -import design +from base import design from tech import spice -class tri_gate(design.design): +class tri_gate(design): """ This module implements the tri gate cell used in the design forS bit-line isolation. It is a hand-made cell, so the layout and diff --git a/compiler/modules/tri_gate_array.py b/compiler/modules/tri_gate_array.py index b1e9eebe..984d8039 100644 --- a/compiler/modules/tri_gate_array.py +++ b/compiler/modules/tri_gate_array.py @@ -7,12 +7,12 @@ # import debug from tech import drc -import design -from vector import vector +from base import design +from base import vector from sram_factory import factory from globals import OPTS -class tri_gate_array(design.design): +class tri_gate_array(design): """ Dynamically generated tri gate array of all bitlines. words_per_row """ diff --git a/compiler/modules/wordline_buffer_array.py b/compiler/modules/wordline_buffer_array.py index 9c74b79d..d624d5db 100644 --- a/compiler/modules/wordline_buffer_array.py +++ b/compiler/modules/wordline_buffer_array.py @@ -6,21 +6,21 @@ # All rights reserved. # import debug -import design +from base import design from tech import layer -from vector import vector +from base import vector from sram_factory import factory from globals import OPTS from tech import layer_properties as layer_props -class wordline_buffer_array(design.design): +class wordline_buffer_array(design): """ Creates a Wordline Buffer/Inverter array """ def __init__(self, name, rows, cols): - design.design.__init__(self, name) + design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("rows: {0} cols: {1}".format(rows, cols)) diff --git a/compiler/pgates/wordline_driver.py b/compiler/modules/wordline_driver.py similarity index 98% rename from compiler/pgates/wordline_driver.py rename to compiler/modules/wordline_driver.py index d0f72c23..e8fd8901 100644 --- a/compiler/pgates/wordline_driver.py +++ b/compiler/modules/wordline_driver.py @@ -6,15 +6,15 @@ # All rights reserved. # import debug -from vector import vector -import design +from base import vector +from base import design from sram_factory import factory from globals import OPTS from tech import layer from tech import layer_properties as layer_props -class wordline_driver(design.design): +class wordline_driver(design): """ This is an AND (or NAND) with configurable drive strength to drive the wordlines. It is matched to the bitcell height. diff --git a/compiler/modules/wordline_driver_array.py b/compiler/modules/wordline_driver_array.py index 63c39a7c..8a1e100a 100644 --- a/compiler/modules/wordline_driver_array.py +++ b/compiler/modules/wordline_driver_array.py @@ -6,15 +6,15 @@ # All rights reserved. # import debug -import design +from base import design from tech import drc, layer -from vector import vector +from base import vector from sram_factory import factory from globals import OPTS from tech import layer_properties as layer_props -class wordline_driver_array(design.design): +class wordline_driver_array(design): """ Creates a Wordline Driver Generates the wordline-driver to drive the bitcell diff --git a/compiler/custom/write_driver.py b/compiler/modules/write_driver.py similarity index 96% rename from compiler/custom/write_driver.py rename to compiler/modules/write_driver.py index 6d5c4018..00afa0ee 100644 --- a/compiler/custom/write_driver.py +++ b/compiler/modules/write_driver.py @@ -6,11 +6,11 @@ # All rights reserved. # import debug -import design +from base import design from tech import cell_properties as props -class write_driver(design.design): +class write_driver(design): """ Tristate write driver to be active during write operations only. This module implements the write driver cell used in the design. It diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 3262e555..ee3d3c2f 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -5,16 +5,16 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import design +from base import design import debug import math from tech import drc from sram_factory import factory -from vector import vector +from base import vector from globals import OPTS -class write_driver_array(design.design): +class write_driver_array(design): """ Array of tristate drivers to write to the bitlines through the column mux. Dynamically generated write driver array of all bitlines. diff --git a/compiler/modules/write_mask_and_array.py b/compiler/modules/write_mask_and_array.py index f7818e12..f3e7e9bc 100644 --- a/compiler/modules/write_mask_and_array.py +++ b/compiler/modules/write_mask_and_array.py @@ -5,15 +5,15 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import design +from base import design import debug import math from sram_factory import factory -from vector import vector +from base import vector from globals import OPTS -class write_mask_and_array(design.design): +class write_mask_and_array(design): """ Array of AND gates to turn write mask signal on only when w_en is on. The write mask AND array goes between the write driver array and the sense amp array. diff --git a/compiler/openram.py b/compiler/openram.py index 8ce6ae1e..fbbf4466 100755 --- a/compiler/openram.py +++ b/compiler/openram.py @@ -47,7 +47,7 @@ g.print_time("Start", start_time) # Output info about this run g.report_status() -from sram_config import sram_config +from modules import sram_config # Configure the SRAM organization @@ -73,7 +73,7 @@ for path in output_files: debug.print_raw(path) -from sram import sram +from modules import sram s = sram(name=OPTS.output_name, sram_config=c) diff --git a/compiler/router/__init__.py b/compiler/router/__init__.py new file mode 100644 index 00000000..a4496fb0 --- /dev/null +++ b/compiler/router/__init__.py @@ -0,0 +1,5 @@ +from .router import * +from .signal_escape_router import * +from .signal_router import * +from .supply_grid_router import * +from .supply_tree_router import * diff --git a/compiler/router/direction.py b/compiler/router/direction.py index c13abdd3..a7eeb727 100644 --- a/compiler/router/direction.py +++ b/compiler/router/direction.py @@ -6,7 +6,7 @@ # All rights reserved. # from enum import Enum -from vector3d import vector3d +from base.vector3d import vector3d import debug diff --git a/compiler/router/grid.py b/compiler/router/grid.py index a366ebe0..8fd1de72 100644 --- a/compiler/router/grid.py +++ b/compiler/router/grid.py @@ -6,8 +6,8 @@ # All rights reserved. # import debug -from vector3d import vector3d -from grid_cell import grid_cell +from base.vector3d import vector3d +from .grid_cell import grid_cell class grid: diff --git a/compiler/router/grid_path.py b/compiler/router/grid_path.py index d47b2677..1c7c576a 100644 --- a/compiler/router/grid_path.py +++ b/compiler/router/grid_path.py @@ -5,10 +5,10 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -from vector3d import vector3d from itertools import tee -from grid import grid -from direction import direction +from base.vector3d import vector3d +from .grid import grid +from .direction import direction class grid_path: diff --git a/compiler/router/grid_utils.py b/compiler/router/grid_utils.py index 1085f5c7..0bf954a3 100644 --- a/compiler/router/grid_utils.py +++ b/compiler/router/grid_utils.py @@ -10,8 +10,8 @@ Some utility functions for sets of grid cells. """ import math -from direction import direction -from vector3d import vector3d +from .direction import direction +from base.vector3d import vector3d def increment_set(curset, direct): diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index d67200d5..0819d62a 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -5,11 +5,11 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -from direction import direction -from pin_layout import pin_layout -from vector import vector -from vector3d import vector3d import debug +from base.vector import vector +from base.vector3d import vector3d +from base.pin_layout import pin_layout +from .direction import direction class pin_group: diff --git a/compiler/router/router.py b/compiler/router/router.py index 2e5236ea..756047e9 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -8,18 +8,18 @@ import itertools import math -import gdsMill +from datetime import datetime +from gdsMill import gdsMill +import debug +from globals import OPTS, print_time from tech import drc, GDS from tech import layer as techlayer -import debug -from router_tech import router_tech -from pin_layout import pin_layout -from pin_group import pin_group -from vector import vector -from vector3d import vector3d -from globals import OPTS, print_time -import grid_utils -from datetime import datetime +from base.vector import vector +from base.vector3d import vector3d +from base.pin_layout import pin_layout +from .router_tech import router_tech +from .pin_group import pin_group +from . import grid_utils class router(router_tech): diff --git a/compiler/router/router_tech.py b/compiler/router/router_tech.py index 6cbbd422..22f1fd15 100644 --- a/compiler/router/router_tech.py +++ b/compiler/router/router_tech.py @@ -6,8 +6,8 @@ # All rights reserved. # from tech import drc, layer, preferred_directions -from contact import contact -from vector import vector +from base.contact import contact +from base.vector import vector import debug import math diff --git a/compiler/router/signal_escape_router.py b/compiler/router/signal_escape_router.py index d727e900..11d689c7 100644 --- a/compiler/router/signal_escape_router.py +++ b/compiler/router/signal_escape_router.py @@ -5,11 +5,11 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # +from datetime import datetime import debug from globals import print_time -from router import router -from datetime import datetime -from signal_grid import signal_grid +from .router import router +from .signal_grid import signal_grid class signal_escape_router(router): diff --git a/compiler/router/signal_grid.py b/compiler/router/signal_grid.py index 3d8c69eb..f6ea31f5 100644 --- a/compiler/router/signal_grid.py +++ b/compiler/router/signal_grid.py @@ -8,10 +8,9 @@ import debug from heapq import heappush,heappop from copy import deepcopy - -from grid import grid -from grid_path import grid_path -from vector3d import vector3d +from base.vector3d import vector3d +from .grid import grid +from .grid_path import grid_path class signal_grid(grid): diff --git a/compiler/router/supply_grid.py b/compiler/router/supply_grid.py index a5f2248f..0ed66c7a 100644 --- a/compiler/router/supply_grid.py +++ b/compiler/router/supply_grid.py @@ -5,8 +5,8 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -from signal_grid import signal_grid -from grid_path import grid_path +from .signal_grid import signal_grid +from .grid_path import grid_path class supply_grid(signal_grid): diff --git a/compiler/router/supply_grid_router.py b/compiler/router/supply_grid_router.py index 06831299..e592e02d 100644 --- a/compiler/router/supply_grid_router.py +++ b/compiler/router/supply_grid_router.py @@ -5,14 +5,14 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # +from datetime import datetime import debug from globals import print_time -from vector3d import vector3d -from router import router -from direction import direction -from datetime import datetime -from supply_grid import supply_grid -import grid_utils +from base.vector3d import vector3d +from .router import router +from .direction import direction +from .supply_grid import supply_grid +from . import grid_utils class supply_grid_router(router): diff --git a/compiler/router/supply_tree_router.py b/compiler/router/supply_tree_router.py index a018a129..80a386e0 100644 --- a/compiler/router/supply_tree_router.py +++ b/compiler/router/supply_tree_router.py @@ -5,14 +5,14 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import debug -from globals import print_time -from router import router from datetime import datetime -import grid_utils from scipy.sparse import csr_matrix from scipy.sparse.csgraph import minimum_spanning_tree -from signal_grid import signal_grid +import debug +from globals import print_time +from .router import router +from . import grid_utils +from .signal_grid import signal_grid class supply_tree_router(router): diff --git a/compiler/sram/__init__.py b/compiler/sram/__init__.py new file mode 100644 index 00000000..93bb0cbb --- /dev/null +++ b/compiler/sram/__init__.py @@ -0,0 +1,5 @@ +from .sram_1bank import * +from .sram_2bank import * +from .sram_base import * +from .sram_config import * +from .sram import * diff --git a/compiler/sram_factory.py b/compiler/sram_factory.py index 1fd145b7..0ebb6865 100644 --- a/compiler/sram_factory.py +++ b/compiler/sram_factory.py @@ -6,6 +6,7 @@ # All rights reserved. # from globals import OPTS +import importlib class sram_factory: @@ -101,10 +102,18 @@ class sram_factory: # Load a cached version from previous usage mod = self.modules[real_module_type] except KeyError: - # Dynamically load the module - import importlib - c = importlib.reload(__import__(real_module_type)) + try: + # Dynamically load the module + if real_module_type == "contact": + c = importlib.import_module("base.contact") + else: + c = importlib.import_module("modules."+real_module_type) + except ModuleNotFoundError: + # Check if it is a technology specific module + c = importlib.import_module("custom."+real_module_type) + mod = getattr(c, real_module_type) + self.modules[real_module_type] = mod self.module_indices[real_module_type] = 0 self.objects[real_module_type] = [] diff --git a/compiler/tests/00_code_format_check_test.py b/compiler/tests/00_code_format_check_test.py index 6851f6a1..7fb5862d 100755 --- a/compiler/tests/00_code_format_check_test.py +++ b/compiler/tests/00_code_format_check_test.py @@ -10,7 +10,7 @@ import unittest from testutils import * import sys, os,re -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals import debug diff --git a/compiler/tests/01_library_test.py b/compiler/tests/01_library_test.py index 53151658..35d9eca2 100755 --- a/compiler/tests/01_library_test.py +++ b/compiler/tests/01_library_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os,re -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS import debug diff --git a/compiler/tests/03_contact_test.py b/compiler/tests/03_contact_test.py index c39c4c8b..34c96063 100755 --- a/compiler/tests/03_contact_test.py +++ b/compiler/tests/03_contact_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/03_path_test.py b/compiler/tests/03_path_test.py index c16794de..a08edad7 100755 --- a/compiler/tests/03_path_test.py +++ b/compiler/tests/03_path_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS import debug @@ -19,9 +19,9 @@ class path_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - import wire_path + from base import wire_path import tech - import design + from base import design min_space = 2 * tech.drc["minwidth_m1"] layer_stack = ("m1") @@ -32,8 +32,8 @@ class path_test(openram_test): [4 * min_space, 3 * min_space ], [0, 3 * min_space ], [0, 6 * min_space ]] - w = design.design("path_test0") - wire_path.wire_path(w,layer_stack, position_list) + w = design("path_test0") + wire_path(w,layer_stack, position_list) self.local_drc_check(w) @@ -49,8 +49,8 @@ class path_test(openram_test): [-1 * min_space, 4 * min_space], [-1 * min_space, 0]] position_list = [[x+min_space, y+min_space] for x,y in old_position_list] - w = design.design("path_test1") - wire_path.wire_path(w,layer_stack, position_list) + w = design("path_test1") + wire_path(w,layer_stack, position_list) self.local_drc_check(w) min_space = 2 * tech.drc["minwidth_m2"] @@ -65,8 +65,8 @@ class path_test(openram_test): [-1 * min_space, 4 * min_space], [-1 * min_space, 0]] position_list = [[x-min_space, y-min_space] for x,y in old_position_list] - w = design.design("path_test2") - wire_path.wire_path(w, layer_stack, position_list) + w = design("path_test2") + wire_path(w, layer_stack, position_list) self.local_drc_check(w) min_space = 2 * tech.drc["minwidth_m3"] @@ -82,8 +82,8 @@ class path_test(openram_test): [-1 * min_space, 0]] # run on the reverse list position_list.reverse() - w = design.design("path_test3") - wire_path.wire_path(w, layer_stack, position_list) + w = design("path_test3") + wire_path(w, layer_stack, position_list) self.local_drc_check(w) globals.end_openram() diff --git a/compiler/tests/03_ptx_1finger_nmos_test.py b/compiler/tests/03_ptx_1finger_nmos_test.py index 98cc1a5e..2ebf7d45 100755 --- a/compiler/tests/03_ptx_1finger_nmos_test.py +++ b/compiler/tests/03_ptx_1finger_nmos_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/03_ptx_1finger_pmos_test.py b/compiler/tests/03_ptx_1finger_pmos_test.py index 77bacea2..53922c9b 100755 --- a/compiler/tests/03_ptx_1finger_pmos_test.py +++ b/compiler/tests/03_ptx_1finger_pmos_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/03_ptx_3finger_nmos_test.py b/compiler/tests/03_ptx_3finger_nmos_test.py index e5ed6894..a4e18aa2 100755 --- a/compiler/tests/03_ptx_3finger_nmos_test.py +++ b/compiler/tests/03_ptx_3finger_nmos_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/03_ptx_3finger_pmos_test.py b/compiler/tests/03_ptx_3finger_pmos_test.py index 29e209e3..b4776456 100755 --- a/compiler/tests/03_ptx_3finger_pmos_test.py +++ b/compiler/tests/03_ptx_3finger_pmos_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/03_ptx_4finger_nmos_test.py b/compiler/tests/03_ptx_4finger_nmos_test.py index 1c8160e4..c1c2184b 100755 --- a/compiler/tests/03_ptx_4finger_nmos_test.py +++ b/compiler/tests/03_ptx_4finger_nmos_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/03_ptx_4finger_pmos_test.py b/compiler/tests/03_ptx_4finger_pmos_test.py index 408bffbc..fcc843bb 100755 --- a/compiler/tests/03_ptx_4finger_pmos_test.py +++ b/compiler/tests/03_ptx_4finger_pmos_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/03_ptx_no_contacts_test.py b/compiler/tests/03_ptx_no_contacts_test.py index 745e4f0b..36b53d8f 100755 --- a/compiler/tests/03_ptx_no_contacts_test.py +++ b/compiler/tests/03_ptx_no_contacts_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/03_wire_test.py b/compiler/tests/03_wire_test.py index 1de6a7d5..8906e1cf 100755 --- a/compiler/tests/03_wire_test.py +++ b/compiler/tests/03_wire_test.py @@ -10,7 +10,7 @@ import unittest from testutils import * import sys import os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals @@ -19,9 +19,9 @@ class wire_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - import wire + from base import wire import tech - import design + from base import design layer_stacks = [tech.poly_stack] + tech.beol_stacks @@ -46,8 +46,8 @@ class wire_test(openram_test): [-1 * min_space, 4 * min_space], [-1 * min_space, 0]] position_list = [[x - min_space, y - min_space] for x, y in position_list] - w = design.design("wire_test_{}".format("_".join(layer_stack))) - wire.wire(w, layer_stack, position_list) + w = design("wire_test_{}".format("_".join(layer_stack))) + wire(w, layer_stack, position_list) self.local_drc_check(w) globals.end_openram() diff --git a/compiler/tests/04_and2_dec_test.py b/compiler/tests/04_and2_dec_test.py index 69bdd676..93ad6d41 100755 --- a/compiler/tests/04_and2_dec_test.py +++ b/compiler/tests/04_and2_dec_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_and3_dec_test.py b/compiler/tests/04_and3_dec_test.py index bcf4e85b..6b6389e3 100755 --- a/compiler/tests/04_and3_dec_test.py +++ b/compiler/tests/04_and3_dec_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_and4_dec_test.py b/compiler/tests/04_and4_dec_test.py index 4dbb2613..c849e6d6 100755 --- a/compiler/tests/04_and4_dec_test.py +++ b/compiler/tests/04_and4_dec_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_column_mux_1rw_1r_test.py b/compiler/tests/04_column_mux_1rw_1r_test.py index 8e45d6c5..56b4301a 100755 --- a/compiler/tests/04_column_mux_1rw_1r_test.py +++ b/compiler/tests/04_column_mux_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_column_mux_pbitcell_test.py b/compiler/tests/04_column_mux_pbitcell_test.py index 8ee985d5..4ce02164 100755 --- a/compiler/tests/04_column_mux_pbitcell_test.py +++ b/compiler/tests/04_column_mux_pbitcell_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_column_mux_test.py b/compiler/tests/04_column_mux_test.py index 4254560a..78770b5b 100755 --- a/compiler/tests/04_column_mux_test.py +++ b/compiler/tests/04_column_mux_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_dff_buf_test.py b/compiler/tests/04_dff_buf_test.py index 5064e297..c8d2842e 100755 --- a/compiler/tests/04_dff_buf_test.py +++ b/compiler/tests/04_dff_buf_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_dummy_pbitcell_test.py b/compiler/tests/04_dummy_pbitcell_test.py index ad70820b..0d955283 100755 --- a/compiler/tests/04_dummy_pbitcell_test.py +++ b/compiler/tests/04_dummy_pbitcell_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -20,7 +20,7 @@ class replica_pbitcell_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - import dummy_pbitcell + from modules import dummy_pbitcell OPTS.bitcell = "pbitcell" OPTS.num_rw_ports = 1 @@ -29,7 +29,7 @@ class replica_pbitcell_test(openram_test): factory.reset() debug.info(2, "Checking dummy bitcell using pbitcell (small cell)") - tx = dummy_pbitcell.dummy_pbitcell(name="rpbc") + tx = dummy_pbitcell(name="rpbc") self.local_check(tx) OPTS.num_rw_ports = 1 @@ -38,7 +38,7 @@ class replica_pbitcell_test(openram_test): factory.reset() debug.info(2, "Checking dummy bitcell using pbitcell (large cell)") - tx = dummy_pbitcell.dummy_pbitcell(name="rpbc") + tx = dummy_pbitcell(name="rpbc") self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_pand2_test.py b/compiler/tests/04_pand2_test.py index de08a0e1..d1e9f6ff 100755 --- a/compiler/tests/04_pand2_test.py +++ b/compiler/tests/04_pand2_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS import debug @@ -23,10 +23,10 @@ class pand2_test(openram_test): global verify import verify - import pand2 + from modules import pand2 debug.info(2, "Testing pand2 gate 4x") - a = pand2.pand2(name="pand2x4", size=4) + a = pand2(name="pand2x4", size=4) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/04_pand3_test.py b/compiler/tests/04_pand3_test.py index e27c1050..3b49e3a1 100755 --- a/compiler/tests/04_pand3_test.py +++ b/compiler/tests/04_pand3_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS import debug @@ -23,10 +23,10 @@ class pand3_test(openram_test): global verify import verify - import pand3 + from modules import pand3 debug.info(2, "Testing pand3 gate 4x") - a = pand3.pand3(name="pand3x4", size=4) + a = pand3(name="pand3x4", size=4) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/04_pand4_test.py b/compiler/tests/04_pand4_test.py index cd1a4495..2c5f5878 100755 --- a/compiler/tests/04_pand4_test.py +++ b/compiler/tests/04_pand4_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS import debug @@ -23,10 +23,10 @@ class pand4_test(openram_test): global verify import verify - import pand4 + from modules import pand4 debug.info(2, "Testing pand4 gate 4x") - a = pand4.pand4(name="pand4x4", size=4) + a = pand4(name="pand4x4", size=4) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/04_pbitcell_test.py b/compiler/tests/04_pbitcell_test.py index fa9c05c1..119afc41 100755 --- a/compiler/tests/04_pbitcell_test.py +++ b/compiler/tests/04_pbitcell_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS import debug diff --git a/compiler/tests/04_pbuf_dec_8x_test.py b/compiler/tests/04_pbuf_dec_8x_test.py index c8086653..823f9bcc 100755 --- a/compiler/tests/04_pbuf_dec_8x_test.py +++ b/compiler/tests/04_pbuf_dec_8x_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_pbuf_test.py b/compiler/tests/04_pbuf_test.py index 1ee571b3..72a5f2ff 100755 --- a/compiler/tests/04_pbuf_test.py +++ b/compiler/tests/04_pbuf_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_pdriver_test.py b/compiler/tests/04_pdriver_test.py index fb95fb31..71ad80cd 100755 --- a/compiler/tests/04_pdriver_test.py +++ b/compiler/tests/04_pdriver_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_pinv_100x_test.py b/compiler/tests/04_pinv_100x_test.py index c9c23440..0d86e0a8 100755 --- a/compiler/tests/04_pinv_100x_test.py +++ b/compiler/tests/04_pinv_100x_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_pinv_10x_test.py b/compiler/tests/04_pinv_10x_test.py index 5b8ea70c..8151bf41 100755 --- a/compiler/tests/04_pinv_10x_test.py +++ b/compiler/tests/04_pinv_10x_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_pinv_1x_beta_test.py b/compiler/tests/04_pinv_1x_beta_test.py index a8cc1b46..9ecbc3aa 100755 --- a/compiler/tests/04_pinv_1x_beta_test.py +++ b/compiler/tests/04_pinv_1x_beta_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_pinv_1x_test.py b/compiler/tests/04_pinv_1x_test.py index d1a0abf3..f6f4ca04 100755 --- a/compiler/tests/04_pinv_1x_test.py +++ b/compiler/tests/04_pinv_1x_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_pinv_2x_test.py b/compiler/tests/04_pinv_2x_test.py index aed3bb6e..0ae30973 100755 --- a/compiler/tests/04_pinv_2x_test.py +++ b/compiler/tests/04_pinv_2x_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_pinv_dec_1x_test.py b/compiler/tests/04_pinv_dec_1x_test.py index 14f046cd..7aee5219 100755 --- a/compiler/tests/04_pinv_dec_1x_test.py +++ b/compiler/tests/04_pinv_dec_1x_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_pinvbuf_test.py b/compiler/tests/04_pinvbuf_test.py index 859eed61..4f227181 100755 --- a/compiler/tests/04_pinvbuf_test.py +++ b/compiler/tests/04_pinvbuf_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_pnand2_test.py b/compiler/tests/04_pnand2_test.py index 6a8b1f4c..053e343c 100755 --- a/compiler/tests/04_pnand2_test.py +++ b/compiler/tests/04_pnand2_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_pnand3_test.py b/compiler/tests/04_pnand3_test.py index a1142b55..a934f698 100755 --- a/compiler/tests/04_pnand3_test.py +++ b/compiler/tests/04_pnand3_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_pnand4_test.py b/compiler/tests/04_pnand4_test.py index a47ff7d2..bceff7f9 100755 --- a/compiler/tests/04_pnand4_test.py +++ b/compiler/tests/04_pnand4_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_pnor2_test.py b/compiler/tests/04_pnor2_test.py index 117044ce..a68a7190 100755 --- a/compiler/tests/04_pnor2_test.py +++ b/compiler/tests/04_pnor2_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_precharge_1rw_1r_test.py b/compiler/tests/04_precharge_1rw_1r_test.py index a5163e69..026deaee 100755 --- a/compiler/tests/04_precharge_1rw_1r_test.py +++ b/compiler/tests/04_precharge_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_precharge_pbitcell_test.py b/compiler/tests/04_precharge_pbitcell_test.py index 74e2fe54..ae9740fb 100755 --- a/compiler/tests/04_precharge_pbitcell_test.py +++ b/compiler/tests/04_precharge_pbitcell_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_precharge_test.py b/compiler/tests/04_precharge_test.py index 65b9a5f9..3d1d3832 100755 --- a/compiler/tests/04_precharge_test.py +++ b/compiler/tests/04_precharge_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_pwrite_driver_test.py b/compiler/tests/04_pwrite_driver_test.py index 4f7c6ca3..7d2d525b 100755 --- a/compiler/tests/04_pwrite_driver_test.py +++ b/compiler/tests/04_pwrite_driver_test.py @@ -10,7 +10,7 @@ import unittest from testutils import header, openram_test import sys import os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/04_replica_pbitcell_test.py b/compiler/tests/04_replica_pbitcell_test.py index 8e3ae17e..5b4e7271 100755 --- a/compiler/tests/04_replica_pbitcell_test.py +++ b/compiler/tests/04_replica_pbitcell_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -20,7 +20,7 @@ class replica_pbitcell_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - import replica_pbitcell + from modules import replica_pbitcell OPTS.bitcell = "pbitcell" OPTS.num_rw_ports = 1 @@ -29,7 +29,7 @@ class replica_pbitcell_test(openram_test): factory.reset() debug.info(2, "Checking replica bitcell using pbitcell (small cell)") - tx = replica_pbitcell.replica_pbitcell(name="rpbc") + tx = replica_pbitcell(name="rpbc") self.local_check(tx) OPTS.num_rw_ports = 1 @@ -38,7 +38,7 @@ class replica_pbitcell_test(openram_test): factory.reset() debug.info(2, "Checking replica bitcell using pbitcell (large cell)") - tx = replica_pbitcell.replica_pbitcell(name="rpbc") + tx = replica_pbitcell(name="rpbc") self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_wordline_driver_test.py b/compiler/tests/04_wordline_driver_test.py index 3713ff02..c71e3190 100755 --- a/compiler/tests/04_wordline_driver_test.py +++ b/compiler/tests/04_wordline_driver_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/05_bitcell_array_1rw_1r_test.py b/compiler/tests/05_bitcell_array_1rw_1r_test.py index 6216475d..3ae9a7d7 100755 --- a/compiler/tests/05_bitcell_array_1rw_1r_test.py +++ b/compiler/tests/05_bitcell_array_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/05_bitcell_array_test.py b/compiler/tests/05_bitcell_array_test.py index 916a4356..738a038e 100755 --- a/compiler/tests/05_bitcell_array_test.py +++ b/compiler/tests/05_bitcell_array_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/05_dummy_array_test.py b/compiler/tests/05_dummy_array_test.py index c6831b90..41eb7b0b 100755 --- a/compiler/tests/05_dummy_array_test.py +++ b/compiler/tests/05_dummy_array_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/05_pbitcell_array_test.py b/compiler/tests/05_pbitcell_array_test.py index ddefb588..8a05dcec 100755 --- a/compiler/tests/05_pbitcell_array_test.py +++ b/compiler/tests/05_pbitcell_array_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_column_decoder_16row_test.py b/compiler/tests/06_column_decoder_16row_test.py index 2823b647..d34d6879 100755 --- a/compiler/tests/06_column_decoder_16row_test.py +++ b/compiler/tests/06_column_decoder_16row_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_decoder_132row_1rw_1r_test.py b/compiler/tests/06_hierarchical_decoder_132row_1rw_1r_test.py index 3c4ee7ee..26aeb899 100755 --- a/compiler/tests/06_hierarchical_decoder_132row_1rw_1r_test.py +++ b/compiler/tests/06_hierarchical_decoder_132row_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_decoder_132row_test.py b/compiler/tests/06_hierarchical_decoder_132row_test.py index 3681fcbf..d1655a25 100755 --- a/compiler/tests/06_hierarchical_decoder_132row_test.py +++ b/compiler/tests/06_hierarchical_decoder_132row_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_decoder_16row_1rw_1r_test.py b/compiler/tests/06_hierarchical_decoder_16row_1rw_1r_test.py index ea50b36c..aad79dd4 100755 --- a/compiler/tests/06_hierarchical_decoder_16row_1rw_1r_test.py +++ b/compiler/tests/06_hierarchical_decoder_16row_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_decoder_16row_test.py b/compiler/tests/06_hierarchical_decoder_16row_test.py index b3dd35aa..fc379cc4 100755 --- a/compiler/tests/06_hierarchical_decoder_16row_test.py +++ b/compiler/tests/06_hierarchical_decoder_16row_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_decoder_17row_1rw_1r_test.py b/compiler/tests/06_hierarchical_decoder_17row_1rw_1r_test.py index 549ce54f..d81f6774 100755 --- a/compiler/tests/06_hierarchical_decoder_17row_1rw_1r_test.py +++ b/compiler/tests/06_hierarchical_decoder_17row_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_decoder_17row_test.py b/compiler/tests/06_hierarchical_decoder_17row_test.py index f4407baa..ff7d1662 100755 --- a/compiler/tests/06_hierarchical_decoder_17row_test.py +++ b/compiler/tests/06_hierarchical_decoder_17row_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_decoder_32row_1rw_1r_test.py b/compiler/tests/06_hierarchical_decoder_32row_1rw_1r_test.py index 6c2f6bd6..7ec03133 100755 --- a/compiler/tests/06_hierarchical_decoder_32row_1rw_1r_test.py +++ b/compiler/tests/06_hierarchical_decoder_32row_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_decoder_32row_test.py b/compiler/tests/06_hierarchical_decoder_32row_test.py index 26bcffad..895b63dc 100755 --- a/compiler/tests/06_hierarchical_decoder_32row_test.py +++ b/compiler/tests/06_hierarchical_decoder_32row_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_decoder_4096row_1rw_1r_test.py b/compiler/tests/06_hierarchical_decoder_4096row_1rw_1r_test.py index 201fc399..c0058da4 100755 --- a/compiler/tests/06_hierarchical_decoder_4096row_1rw_1r_test.py +++ b/compiler/tests/06_hierarchical_decoder_4096row_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_decoder_4096row_test.py b/compiler/tests/06_hierarchical_decoder_4096row_test.py index 50e9bcaa..14e3f113 100755 --- a/compiler/tests/06_hierarchical_decoder_4096row_test.py +++ b/compiler/tests/06_hierarchical_decoder_4096row_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_decoder_512row_1rw_1r_test.py b/compiler/tests/06_hierarchical_decoder_512row_1rw_1r_test.py index f53f4838..5982e930 100755 --- a/compiler/tests/06_hierarchical_decoder_512row_1rw_1r_test.py +++ b/compiler/tests/06_hierarchical_decoder_512row_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_decoder_512row_test.py b/compiler/tests/06_hierarchical_decoder_512row_test.py index 5bcfff11..6ad92d86 100755 --- a/compiler/tests/06_hierarchical_decoder_512row_test.py +++ b/compiler/tests/06_hierarchical_decoder_512row_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_decoder_64row_1rw_1r_test.py b/compiler/tests/06_hierarchical_decoder_64row_1rw_1r_test.py index af9fb4f4..6dd3b4de 100755 --- a/compiler/tests/06_hierarchical_decoder_64row_1rw_1r_test.py +++ b/compiler/tests/06_hierarchical_decoder_64row_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_decoder_64row_test.py b/compiler/tests/06_hierarchical_decoder_64row_test.py index 0ef767e9..37b97732 100755 --- a/compiler/tests/06_hierarchical_decoder_64row_test.py +++ b/compiler/tests/06_hierarchical_decoder_64row_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_decoder_pbitcell_test.py b/compiler/tests/06_hierarchical_decoder_pbitcell_test.py index 002317b4..2548e498 100755 --- a/compiler/tests/06_hierarchical_decoder_pbitcell_test.py +++ b/compiler/tests/06_hierarchical_decoder_pbitcell_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_predecode2x4_1rw_1r_test.py b/compiler/tests/06_hierarchical_predecode2x4_1rw_1r_test.py index 8a33451f..0cff264a 100755 --- a/compiler/tests/06_hierarchical_predecode2x4_1rw_1r_test.py +++ b/compiler/tests/06_hierarchical_predecode2x4_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_predecode2x4_pbitcell_test.py b/compiler/tests/06_hierarchical_predecode2x4_pbitcell_test.py index f634225e..bb9523a9 100755 --- a/compiler/tests/06_hierarchical_predecode2x4_pbitcell_test.py +++ b/compiler/tests/06_hierarchical_predecode2x4_pbitcell_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_predecode2x4_test.py b/compiler/tests/06_hierarchical_predecode2x4_test.py index ff982cc0..d8680f53 100755 --- a/compiler/tests/06_hierarchical_predecode2x4_test.py +++ b/compiler/tests/06_hierarchical_predecode2x4_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_predecode3x8_1rw_1r_test.py b/compiler/tests/06_hierarchical_predecode3x8_1rw_1r_test.py index 3c67fb68..d6580991 100755 --- a/compiler/tests/06_hierarchical_predecode3x8_1rw_1r_test.py +++ b/compiler/tests/06_hierarchical_predecode3x8_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_predecode3x8_pbitcell_test.py b/compiler/tests/06_hierarchical_predecode3x8_pbitcell_test.py index 9420fd72..1ddc91df 100755 --- a/compiler/tests/06_hierarchical_predecode3x8_pbitcell_test.py +++ b/compiler/tests/06_hierarchical_predecode3x8_pbitcell_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_predecode3x8_test.py b/compiler/tests/06_hierarchical_predecode3x8_test.py index eb139537..3ff4a252 100755 --- a/compiler/tests/06_hierarchical_predecode3x8_test.py +++ b/compiler/tests/06_hierarchical_predecode3x8_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/06_hierarchical_predecode4x16_test.py b/compiler/tests/06_hierarchical_predecode4x16_test.py index 8ebbb58a..ff855601 100755 --- a/compiler/tests/06_hierarchical_predecode4x16_test.py +++ b/compiler/tests/06_hierarchical_predecode4x16_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/07_column_mux_array_16mux_1rw_1r_test.py b/compiler/tests/07_column_mux_array_16mux_1rw_1r_test.py index 9ef7da3e..36d086a8 100755 --- a/compiler/tests/07_column_mux_array_16mux_1rw_1r_test.py +++ b/compiler/tests/07_column_mux_array_16mux_1rw_1r_test.py @@ -8,7 +8,7 @@ # from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/07_column_mux_array_16mux_test.py b/compiler/tests/07_column_mux_array_16mux_test.py index 67a7f9a4..51634eae 100755 --- a/compiler/tests/07_column_mux_array_16mux_test.py +++ b/compiler/tests/07_column_mux_array_16mux_test.py @@ -8,7 +8,7 @@ # from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/07_column_mux_array_2mux_1rw_1r_test.py b/compiler/tests/07_column_mux_array_2mux_1rw_1r_test.py index 10012e81..f217720e 100755 --- a/compiler/tests/07_column_mux_array_2mux_1rw_1r_test.py +++ b/compiler/tests/07_column_mux_array_2mux_1rw_1r_test.py @@ -8,7 +8,7 @@ # from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/07_column_mux_array_2mux_test.py b/compiler/tests/07_column_mux_array_2mux_test.py index e8303c45..ba5145a4 100755 --- a/compiler/tests/07_column_mux_array_2mux_test.py +++ b/compiler/tests/07_column_mux_array_2mux_test.py @@ -8,7 +8,7 @@ # from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/07_column_mux_array_4mux_1rw_1r_test.py b/compiler/tests/07_column_mux_array_4mux_1rw_1r_test.py index 96123cae..8f4fc364 100755 --- a/compiler/tests/07_column_mux_array_4mux_1rw_1r_test.py +++ b/compiler/tests/07_column_mux_array_4mux_1rw_1r_test.py @@ -8,7 +8,7 @@ # from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/07_column_mux_array_4mux_test.py b/compiler/tests/07_column_mux_array_4mux_test.py index 655bda54..0d637ef6 100755 --- a/compiler/tests/07_column_mux_array_4mux_test.py +++ b/compiler/tests/07_column_mux_array_4mux_test.py @@ -8,7 +8,7 @@ # from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/07_column_mux_array_8mux_1rw_1r_test.py b/compiler/tests/07_column_mux_array_8mux_1rw_1r_test.py index 9f85e3ac..7d2f248e 100755 --- a/compiler/tests/07_column_mux_array_8mux_1rw_1r_test.py +++ b/compiler/tests/07_column_mux_array_8mux_1rw_1r_test.py @@ -8,7 +8,7 @@ # from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/07_column_mux_array_8mux_test.py b/compiler/tests/07_column_mux_array_8mux_test.py index eab6560a..468d6507 100755 --- a/compiler/tests/07_column_mux_array_8mux_test.py +++ b/compiler/tests/07_column_mux_array_8mux_test.py @@ -8,7 +8,7 @@ # from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/07_column_mux_array_pbitcell_test.py b/compiler/tests/07_column_mux_array_pbitcell_test.py index 9e7365c0..bceba919 100755 --- a/compiler/tests/07_column_mux_array_pbitcell_test.py +++ b/compiler/tests/07_column_mux_array_pbitcell_test.py @@ -8,7 +8,7 @@ # from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/08_precharge_array_1rw_1r_test.py b/compiler/tests/08_precharge_array_1rw_1r_test.py index 71cd9673..1cb4d12c 100755 --- a/compiler/tests/08_precharge_array_1rw_1r_test.py +++ b/compiler/tests/08_precharge_array_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/08_precharge_array_test.py b/compiler/tests/08_precharge_array_test.py index 48bdc17b..39d87476 100755 --- a/compiler/tests/08_precharge_array_test.py +++ b/compiler/tests/08_precharge_array_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/08_wordline_buffer_array_test.py b/compiler/tests/08_wordline_buffer_array_test.py index 3152810d..6ae422c4 100755 --- a/compiler/tests/08_wordline_buffer_array_test.py +++ b/compiler/tests/08_wordline_buffer_array_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/08_wordline_driver_array_1rw_1r_test.py b/compiler/tests/08_wordline_driver_array_1rw_1r_test.py index b1daff3d..cbfa1825 100755 --- a/compiler/tests/08_wordline_driver_array_1rw_1r_test.py +++ b/compiler/tests/08_wordline_driver_array_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/08_wordline_driver_array_pbitcell_test.py b/compiler/tests/08_wordline_driver_array_pbitcell_test.py index 0e6cf594..f3398346 100755 --- a/compiler/tests/08_wordline_driver_array_pbitcell_test.py +++ b/compiler/tests/08_wordline_driver_array_pbitcell_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/08_wordline_driver_array_test.py b/compiler/tests/08_wordline_driver_array_test.py index 9436caf0..ea982005 100755 --- a/compiler/tests/08_wordline_driver_array_test.py +++ b/compiler/tests/08_wordline_driver_array_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/09_sense_amp_array_1rw_1r_test.py b/compiler/tests/09_sense_amp_array_1rw_1r_test.py index 48d3f744..8273a0ad 100755 --- a/compiler/tests/09_sense_amp_array_1rw_1r_test.py +++ b/compiler/tests/09_sense_amp_array_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/09_sense_amp_array_pbitcell_test.py b/compiler/tests/09_sense_amp_array_pbitcell_test.py index d65d8649..4dfd966d 100755 --- a/compiler/tests/09_sense_amp_array_pbitcell_test.py +++ b/compiler/tests/09_sense_amp_array_pbitcell_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys,os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/09_sense_amp_array_spare_cols_test.py b/compiler/tests/09_sense_amp_array_spare_cols_test.py index 8af08d77..57429d2b 100755 --- a/compiler/tests/09_sense_amp_array_spare_cols_test.py +++ b/compiler/tests/09_sense_amp_array_spare_cols_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/09_sense_amp_array_test.py b/compiler/tests/09_sense_amp_array_test.py index d0f38166..aa21f181 100755 --- a/compiler/tests/09_sense_amp_array_test.py +++ b/compiler/tests/09_sense_amp_array_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/10_write_driver_array_1rw_1r_test.py b/compiler/tests/10_write_driver_array_1rw_1r_test.py index 233d5c34..534d5904 100755 --- a/compiler/tests/10_write_driver_array_1rw_1r_test.py +++ b/compiler/tests/10_write_driver_array_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/10_write_driver_array_pbitcell_test.py b/compiler/tests/10_write_driver_array_pbitcell_test.py index e3b2ba2a..cd5601ce 100755 --- a/compiler/tests/10_write_driver_array_pbitcell_test.py +++ b/compiler/tests/10_write_driver_array_pbitcell_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/10_write_driver_array_spare_cols_test.py b/compiler/tests/10_write_driver_array_spare_cols_test.py index 3ee6e485..bacfbdd9 100755 --- a/compiler/tests/10_write_driver_array_spare_cols_test.py +++ b/compiler/tests/10_write_driver_array_spare_cols_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/10_write_driver_array_test.py b/compiler/tests/10_write_driver_array_test.py index 994e210a..fc17301e 100755 --- a/compiler/tests/10_write_driver_array_test.py +++ b/compiler/tests/10_write_driver_array_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/10_write_driver_array_wmask_pbitcell_test.py b/compiler/tests/10_write_driver_array_wmask_pbitcell_test.py index b2b29217..02c76300 100755 --- a/compiler/tests/10_write_driver_array_wmask_pbitcell_test.py +++ b/compiler/tests/10_write_driver_array_wmask_pbitcell_test.py @@ -10,7 +10,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/10_write_driver_array_wmask_spare_cols_test.py b/compiler/tests/10_write_driver_array_wmask_spare_cols_test.py index 266fc73a..e609ba43 100755 --- a/compiler/tests/10_write_driver_array_wmask_spare_cols_test.py +++ b/compiler/tests/10_write_driver_array_wmask_spare_cols_test.py @@ -10,7 +10,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/10_write_driver_array_wmask_test.py b/compiler/tests/10_write_driver_array_wmask_test.py index 843d1dc5..7c1fd7bc 100755 --- a/compiler/tests/10_write_driver_array_wmask_test.py +++ b/compiler/tests/10_write_driver_array_wmask_test.py @@ -10,7 +10,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/10_write_mask_and_array_1rw_1r_test.py b/compiler/tests/10_write_mask_and_array_1rw_1r_test.py index c59c4acd..806381b5 100755 --- a/compiler/tests/10_write_mask_and_array_1rw_1r_test.py +++ b/compiler/tests/10_write_mask_and_array_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/10_write_mask_and_array_pbitcell_test.py b/compiler/tests/10_write_mask_and_array_pbitcell_test.py index c389c879..fe43d0f2 100755 --- a/compiler/tests/10_write_mask_and_array_pbitcell_test.py +++ b/compiler/tests/10_write_mask_and_array_pbitcell_test.py @@ -10,7 +10,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/10_write_mask_and_array_test.py b/compiler/tests/10_write_mask_and_array_test.py index 8cc9b685..8a667145 100755 --- a/compiler/tests/10_write_mask_and_array_test.py +++ b/compiler/tests/10_write_mask_and_array_test.py @@ -10,7 +10,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/11_dff_array_test.py b/compiler/tests/11_dff_array_test.py index d5ee0607..7d4779eb 100755 --- a/compiler/tests/11_dff_array_test.py +++ b/compiler/tests/11_dff_array_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/11_dff_buf_array_test.py b/compiler/tests/11_dff_buf_array_test.py index 3e1d5eb3..e46a5f91 100755 --- a/compiler/tests/11_dff_buf_array_test.py +++ b/compiler/tests/11_dff_buf_array_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/12_tri_gate_array_test.py b/compiler/tests/12_tri_gate_array_test.py index 47724f89..354e5188 100755 --- a/compiler/tests/12_tri_gate_array_test.py +++ b/compiler/tests/12_tri_gate_array_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/13_delay_chain_test.py b/compiler/tests/13_delay_chain_test.py index af1229a3..b07dde74 100755 --- a/compiler/tests/13_delay_chain_test.py +++ b/compiler/tests/13_delay_chain_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/14_replica_bitcell_array_bothrbl_1rw_1r_test.py b/compiler/tests/14_replica_bitcell_array_bothrbl_1rw_1r_test.py index 8dad9f9b..0f905d75 100755 --- a/compiler/tests/14_replica_bitcell_array_bothrbl_1rw_1r_test.py +++ b/compiler/tests/14_replica_bitcell_array_bothrbl_1rw_1r_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_1r_test.py b/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_1r_test.py index 3137802b..a07318f0 100755 --- a/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_1r_test.py +++ b/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_1r_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/14_replica_bitcell_array_norbl_1rw_1r_test.py b/compiler/tests/14_replica_bitcell_array_norbl_1rw_1r_test.py index 7f7ee74c..920a3d3e 100755 --- a/compiler/tests/14_replica_bitcell_array_norbl_1rw_1r_test.py +++ b/compiler/tests/14_replica_bitcell_array_norbl_1rw_1r_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/14_replica_bitcell_array_test.py b/compiler/tests/14_replica_bitcell_array_test.py index 33ba6b8e..fc938bfb 100755 --- a/compiler/tests/14_replica_bitcell_array_test.py +++ b/compiler/tests/14_replica_bitcell_array_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/14_replica_column_1rw_1r_test.py b/compiler/tests/14_replica_column_1rw_1r_test.py index 82b6437a..10ee5983 100755 --- a/compiler/tests/14_replica_column_1rw_1r_test.py +++ b/compiler/tests/14_replica_column_1rw_1r_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/14_replica_column_test.py b/compiler/tests/14_replica_column_test.py index c8d50a53..73825e39 100755 --- a/compiler/tests/14_replica_column_test.py +++ b/compiler/tests/14_replica_column_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/14_replica_pbitcell_array_test.py b/compiler/tests/14_replica_pbitcell_array_test.py index b13bc56a..d72289a7 100755 --- a/compiler/tests/14_replica_pbitcell_array_test.py +++ b/compiler/tests/14_replica_pbitcell_array_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/15_global_bitcell_array_1rw_1r_test.py b/compiler/tests/15_global_bitcell_array_1rw_1r_test.py index 9dab6ddd..d7701539 100755 --- a/compiler/tests/15_global_bitcell_array_1rw_1r_test.py +++ b/compiler/tests/15_global_bitcell_array_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from sram_factory import factory import debug diff --git a/compiler/tests/15_global_bitcell_array_test.py b/compiler/tests/15_global_bitcell_array_test.py index 0f68227e..7f4b8154 100755 --- a/compiler/tests/15_global_bitcell_array_test.py +++ b/compiler/tests/15_global_bitcell_array_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from sram_factory import factory import debug diff --git a/compiler/tests/15_local_bitcell_array_1rw_1r_test.py b/compiler/tests/15_local_bitcell_array_1rw_1r_test.py index ae86f949..0826586c 100755 --- a/compiler/tests/15_local_bitcell_array_1rw_1r_test.py +++ b/compiler/tests/15_local_bitcell_array_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from sram_factory import factory import debug diff --git a/compiler/tests/15_local_bitcell_array_test.py b/compiler/tests/15_local_bitcell_array_test.py index ae6a4dc0..30c9c8e9 100755 --- a/compiler/tests/15_local_bitcell_array_test.py +++ b/compiler/tests/15_local_bitcell_array_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from sram_factory import factory import debug diff --git a/compiler/tests/16_control_logic_multiport_test.py b/compiler/tests/16_control_logic_multiport_test.py index c90b55de..ae6ce538 100755 --- a/compiler/tests/16_control_logic_multiport_test.py +++ b/compiler/tests/16_control_logic_multiport_test.py @@ -13,7 +13,7 @@ Run a regression test on a control_logic import unittest from testutils import header,openram_test import sys, os -sys.path.append(os.path.join(sys.path[0],"..")) + import globals from globals import OPTS from sram_factory import factory @@ -24,8 +24,6 @@ class control_logic_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - import control_logic - import tech # check control logic for multi-port OPTS.bitcell = "pbitcell" diff --git a/compiler/tests/16_control_logic_r_test.py b/compiler/tests/16_control_logic_r_test.py index 74d95189..67fa2635 100755 --- a/compiler/tests/16_control_logic_r_test.py +++ b/compiler/tests/16_control_logic_r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/16_control_logic_rw_test.py b/compiler/tests/16_control_logic_rw_test.py index a6b375e4..dd83f623 100755 --- a/compiler/tests/16_control_logic_rw_test.py +++ b/compiler/tests/16_control_logic_rw_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/16_control_logic_w_test.py b/compiler/tests/16_control_logic_w_test.py index bbdd0c09..4a828fdf 100755 --- a/compiler/tests/16_control_logic_w_test.py +++ b/compiler/tests/16_control_logic_w_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/18_port_address_16rows_1rw_1r_test.py b/compiler/tests/18_port_address_16rows_1rw_1r_test.py index ff39eeed..ffca57d3 100755 --- a/compiler/tests/18_port_address_16rows_1rw_1r_test.py +++ b/compiler/tests/18_port_address_16rows_1rw_1r_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/18_port_address_16rows_test.py b/compiler/tests/18_port_address_16rows_test.py index a60508de..36093297 100755 --- a/compiler/tests/18_port_address_16rows_test.py +++ b/compiler/tests/18_port_address_16rows_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/18_port_address_256rows_1rw_1r_test.py b/compiler/tests/18_port_address_256rows_1rw_1r_test.py index e9c11bd7..8fef71fc 100755 --- a/compiler/tests/18_port_address_256rows_1rw_1r_test.py +++ b/compiler/tests/18_port_address_256rows_1rw_1r_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/18_port_address_512rows_test.py b/compiler/tests/18_port_address_512rows_test.py index 120ec9be..03f8c455 100755 --- a/compiler/tests/18_port_address_512rows_test.py +++ b/compiler/tests/18_port_address_512rows_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory diff --git a/compiler/tests/18_port_data_16mux_1rw_1r_test.py b/compiler/tests/18_port_data_16mux_1rw_1r_test.py index 83a453d0..15ff8eee 100755 --- a/compiler/tests/18_port_data_16mux_1rw_1r_test.py +++ b/compiler/tests/18_port_data_16mux_1rw_1r_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -19,7 +19,7 @@ class port_data_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/18_port_data_16mux_test.py b/compiler/tests/18_port_data_16mux_test.py index de0f2394..3415711b 100755 --- a/compiler/tests/18_port_data_16mux_test.py +++ b/compiler/tests/18_port_data_16mux_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -19,7 +19,7 @@ class port_data_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/18_port_data_2mux_1rw_1r_test.py b/compiler/tests/18_port_data_2mux_1rw_1r_test.py index 70e5e7df..d907b50c 100755 --- a/compiler/tests/18_port_data_2mux_1rw_1r_test.py +++ b/compiler/tests/18_port_data_2mux_1rw_1r_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -19,7 +19,7 @@ class port_data_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/18_port_data_2mux_test.py b/compiler/tests/18_port_data_2mux_test.py index f9b8916c..4b72d046 100755 --- a/compiler/tests/18_port_data_2mux_test.py +++ b/compiler/tests/18_port_data_2mux_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -19,7 +19,7 @@ class port_data_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/18_port_data_4mux_1rw_1r_test.py b/compiler/tests/18_port_data_4mux_1rw_1r_test.py index ddca3075..c5d163cf 100755 --- a/compiler/tests/18_port_data_4mux_1rw_1r_test.py +++ b/compiler/tests/18_port_data_4mux_1rw_1r_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -19,7 +19,7 @@ class port_data_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/18_port_data_4mux_test.py b/compiler/tests/18_port_data_4mux_test.py index 82cbe5d1..84136361 100755 --- a/compiler/tests/18_port_data_4mux_test.py +++ b/compiler/tests/18_port_data_4mux_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -19,7 +19,7 @@ class port_data_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/18_port_data_8mux_1rw_1r_test.py b/compiler/tests/18_port_data_8mux_1rw_1r_test.py index cc67c810..17c98ace 100755 --- a/compiler/tests/18_port_data_8mux_1rw_1r_test.py +++ b/compiler/tests/18_port_data_8mux_1rw_1r_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -19,7 +19,7 @@ class port_data_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/18_port_data_8mux_test.py b/compiler/tests/18_port_data_8mux_test.py index ec669f02..781954cc 100755 --- a/compiler/tests/18_port_data_8mux_test.py +++ b/compiler/tests/18_port_data_8mux_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -19,7 +19,7 @@ class port_data_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/18_port_data_nomux_1rw_1r_test.py b/compiler/tests/18_port_data_nomux_1rw_1r_test.py index 67a6b6eb..1c1197ee 100755 --- a/compiler/tests/18_port_data_nomux_1rw_1r_test.py +++ b/compiler/tests/18_port_data_nomux_1rw_1r_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -19,7 +19,7 @@ class port_data_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/18_port_data_nomux_test.py b/compiler/tests/18_port_data_nomux_test.py index 34298d8b..7d775cd5 100755 --- a/compiler/tests/18_port_data_nomux_test.py +++ b/compiler/tests/18_port_data_nomux_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -19,7 +19,7 @@ class port_data_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/18_port_data_spare_cols_test.py b/compiler/tests/18_port_data_spare_cols_test.py index 392aef1a..f52e33d4 100755 --- a/compiler/tests/18_port_data_spare_cols_test.py +++ b/compiler/tests/18_port_data_spare_cols_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -19,7 +19,7 @@ class port_data_spare_cols_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=8, num_words=16, diff --git a/compiler/tests/18_port_data_wmask_1rw_1r_test.py b/compiler/tests/18_port_data_wmask_1rw_1r_test.py index 5d72cffc..5f58f670 100755 --- a/compiler/tests/18_port_data_wmask_1rw_1r_test.py +++ b/compiler/tests/18_port_data_wmask_1rw_1r_test.py @@ -7,7 +7,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -19,7 +19,7 @@ class port_data_wmask_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/18_port_data_wmask_test.py b/compiler/tests/18_port_data_wmask_test.py index 4f08400b..406b6822 100755 --- a/compiler/tests/18_port_data_wmask_test.py +++ b/compiler/tests/18_port_data_wmask_test.py @@ -8,7 +8,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -20,7 +20,7 @@ class port_data_wmask_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/19_bank_select_pbitcell_test.py b/compiler/tests/19_bank_select_pbitcell_test.py deleted file mode 100755 index 2f427a35..00000000 --- a/compiler/tests/19_bank_select_pbitcell_test.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python3 -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2021 Regents of the University of California and The Board -# of Regents for the Oklahoma Agricultural and Mechanical College -# (acting for and on behalf of Oklahoma State University) -# All rights reserved. -# -import unittest -from testutils import * -import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) -import globals -from globals import OPTS -from sram_factory import factory -import debug - -class bank_select_test(openram_test): - - def runTest(self): - config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) - globals.init_openram(config_file) - - OPTS.bitcell = "pbitcell" - debug.info(1, "No column mux, rw control logic") - a = factory.create(module_type="bank_select", port="rw") - self.local_check(a) - - OPTS.num_rw_ports = 0 - OPTS.num_w_ports = 1 - OPTS.num_r_ports = 1 - - debug.info(1, "No column mux, w control logic") - a = factory.create(module_type="bank_select", port="w") - self.local_check(a) - - debug.info(1, "No column mux, r control logic") - a = factory.create(module_type="bank_select", port="r") - self.local_check(a) - - globals.end_openram() - -# run the test from the command line -if __name__ == "__main__": - (OPTS, args) = globals.parse_args() - del sys.argv[1:] - header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/19_bank_select_test.py b/compiler/tests/19_bank_select_test.py deleted file mode 100755 index e3c7ece8..00000000 --- a/compiler/tests/19_bank_select_test.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python3 -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2021 Regents of the University of California and The Board -# of Regents for the Oklahoma Agricultural and Mechanical College -# (acting for and on behalf of Oklahoma State University) -# All rights reserved. -# -import unittest -from testutils import * -import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) -import globals -from globals import OPTS -from sram_factory import factory -import debug - -class bank_select_test(openram_test): - - def runTest(self): - config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) - globals.init_openram(config_file) - - debug.info(1, "No column mux, rw control logic") - a = factory.create(module_type="bank_select", port="rw") - self.local_check(a) - - globals.end_openram() - -# run the test from the command line -if __name__ == "__main__": - (OPTS, args) = globals.parse_args() - del sys.argv[1:] - header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/19_multi_bank_test.py b/compiler/tests/19_multi_bank_test.py index 46b75697..e73a97fc 100755 --- a/compiler/tests/19_multi_bank_test.py +++ b/compiler/tests/19_multi_bank_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class multi_bank_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=4, num_words=16) diff --git a/compiler/tests/19_pmulti_bank_test.py b/compiler/tests/19_pmulti_bank_test.py index 099a8214..be2ba0c0 100755 --- a/compiler/tests/19_pmulti_bank_test.py +++ b/compiler/tests/19_pmulti_bank_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class multi_bank_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.bitcell = "pbitcell" # testing layout of bank using pbitcell with 1 RW port (a 6T-cell equivalent) diff --git a/compiler/tests/19_psingle_bank_test.py b/compiler/tests/19_psingle_bank_test.py index 09be0b3f..8aec720c 100755 --- a/compiler/tests/19_psingle_bank_test.py +++ b/compiler/tests/19_psingle_bank_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class psingle_bank_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.bitcell = "pbitcell" OPTS.replica_bitcell="replica_pbitcell" diff --git a/compiler/tests/19_single_bank_16mux_1rw_1r_test.py b/compiler/tests/19_single_bank_16mux_1rw_1r_test.py index 6133ccad..adc5d33e 100755 --- a/compiler/tests/19_single_bank_16mux_1rw_1r_test.py +++ b/compiler/tests/19_single_bank_16mux_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class single_bank_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/19_single_bank_16mux_test.py b/compiler/tests/19_single_bank_16mux_test.py index 010703a9..8dd02db3 100755 --- a/compiler/tests/19_single_bank_16mux_test.py +++ b/compiler/tests/19_single_bank_16mux_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class single_bank_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/19_single_bank_1w_1r_test.py b/compiler/tests/19_single_bank_1w_1r_test.py index 6b6fe65c..31b8349b 100755 --- a/compiler/tests/19_single_bank_1w_1r_test.py +++ b/compiler/tests/19_single_bank_1w_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class single_bank_1w_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 0 OPTS.num_r_ports = 1 diff --git a/compiler/tests/19_single_bank_2mux_1rw_1r_test.py b/compiler/tests/19_single_bank_2mux_1rw_1r_test.py index 15664c81..dbed3cc6 100755 --- a/compiler/tests/19_single_bank_2mux_1rw_1r_test.py +++ b/compiler/tests/19_single_bank_2mux_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class single_bank_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/19_single_bank_2mux_test.py b/compiler/tests/19_single_bank_2mux_test.py index d29de4e6..f5efc231 100755 --- a/compiler/tests/19_single_bank_2mux_test.py +++ b/compiler/tests/19_single_bank_2mux_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class single_bank_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=4, num_words=16) diff --git a/compiler/tests/19_single_bank_4mux_1rw_1r_test.py b/compiler/tests/19_single_bank_4mux_1rw_1r_test.py index 9518373c..13387ac9 100755 --- a/compiler/tests/19_single_bank_4mux_1rw_1r_test.py +++ b/compiler/tests/19_single_bank_4mux_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class single_bank_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/19_single_bank_4mux_test.py b/compiler/tests/19_single_bank_4mux_test.py index 77459ff9..7a58b401 100755 --- a/compiler/tests/19_single_bank_4mux_test.py +++ b/compiler/tests/19_single_bank_4mux_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class single_bank_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=4, num_words=16) diff --git a/compiler/tests/19_single_bank_8mux_1rw_1r_test.py b/compiler/tests/19_single_bank_8mux_1rw_1r_test.py index 11b74350..f03aadc6 100755 --- a/compiler/tests/19_single_bank_8mux_1rw_1r_test.py +++ b/compiler/tests/19_single_bank_8mux_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class single_bank_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/19_single_bank_8mux_test.py b/compiler/tests/19_single_bank_8mux_test.py index 1317fd61..56a3c549 100755 --- a/compiler/tests/19_single_bank_8mux_test.py +++ b/compiler/tests/19_single_bank_8mux_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class single_bank_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/19_single_bank_global_bitline_test.py b/compiler/tests/19_single_bank_global_bitline_test.py index a99534c6..ead8decb 100755 --- a/compiler/tests/19_single_bank_global_bitline_test.py +++ b/compiler/tests/19_single_bank_global_bitline_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class single_bank_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/19_single_bank_nomux_1rw_1r_test.py b/compiler/tests/19_single_bank_nomux_1rw_1r_test.py index f165f991..afb1129b 100755 --- a/compiler/tests/19_single_bank_nomux_1rw_1r_test.py +++ b/compiler/tests/19_single_bank_nomux_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class single_bank_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/19_single_bank_nomux_test.py b/compiler/tests/19_single_bank_nomux_test.py index 1df7103d..6ae084ec 100755 --- a/compiler/tests/19_single_bank_nomux_test.py +++ b/compiler/tests/19_single_bank_nomux_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class single_bank_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/19_single_bank_spare_cols_test.py b/compiler/tests/19_single_bank_spare_cols_test.py index dd03b18e..97bcf5af 100755 --- a/compiler/tests/19_single_bank_spare_cols_test.py +++ b/compiler/tests/19_single_bank_spare_cols_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -20,7 +20,7 @@ class single_bank_spare_cols_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=4, num_words=16, diff --git a/compiler/tests/19_single_bank_wmask_1rw_1r_test.py b/compiler/tests/19_single_bank_wmask_1rw_1r_test.py index 9fae4bb6..77f7ba2e 100755 --- a/compiler/tests/19_single_bank_wmask_1rw_1r_test.py +++ b/compiler/tests/19_single_bank_wmask_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class single_bank_wmask_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/19_single_bank_wmask_test.py b/compiler/tests/19_single_bank_wmask_test.py index 9e17f105..08fe19f4 100755 --- a/compiler/tests/19_single_bank_wmask_test.py +++ b/compiler/tests/19_single_bank_wmask_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -20,7 +20,7 @@ class single_bank_wmask_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=8, diff --git a/compiler/tests/20_psram_1bank_2mux_1rw_1w_test.py b/compiler/tests/20_psram_1bank_2mux_1rw_1w_test.py index 05927d26..e1970b2f 100755 --- a/compiler/tests/20_psram_1bank_2mux_1rw_1w_test.py +++ b/compiler/tests/20_psram_1bank_2mux_1rw_1w_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class psram_1bank_2mux_1rw_1w_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.bitcell = "pbitcell" OPTS.num_rw_ports = 1 diff --git a/compiler/tests/20_psram_1bank_2mux_1rw_1w_wmask_test.py b/compiler/tests/20_psram_1bank_2mux_1rw_1w_wmask_test.py index 4a17bd05..a666f820 100755 --- a/compiler/tests/20_psram_1bank_2mux_1rw_1w_wmask_test.py +++ b/compiler/tests/20_psram_1bank_2mux_1rw_1w_wmask_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class psram_1bank_2mux_1rw_1w_wmask_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.bitcell = "pbitcell" OPTS.num_rw_ports = 1 diff --git a/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py b/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py index 683b786b..51be2cab 100755 --- a/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py +++ b/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class psram_1bank_2mux_1w_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.bitcell = "pbitcell" OPTS.num_rw_ports = 0 diff --git a/compiler/tests/20_psram_1bank_2mux_test.py b/compiler/tests/20_psram_1bank_2mux_test.py index 758d6b1c..133c81d1 100755 --- a/compiler/tests/20_psram_1bank_2mux_test.py +++ b/compiler/tests/20_psram_1bank_2mux_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class psram_1bank_2mux_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.bitcell = "pbitcell" OPTS.num_rw_ports = 1 diff --git a/compiler/tests/20_psram_1bank_4mux_1rw_1r_test.py b/compiler/tests/20_psram_1bank_4mux_1rw_1r_test.py index 345758ab..0995e49f 100755 --- a/compiler/tests/20_psram_1bank_4mux_1rw_1r_test.py +++ b/compiler/tests/20_psram_1bank_4mux_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class psram_1bank_4mux_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.bitcell = "pbitcell" OPTS.num_rw_ports = 1 diff --git a/compiler/tests/20_sram_1bank_16mux_1rw_1r_test.py b/compiler/tests/20_sram_1bank_16mux_1rw_1r_test.py index 072a3f8d..93736a53 100755 --- a/compiler/tests/20_sram_1bank_16mux_1rw_1r_test.py +++ b/compiler/tests/20_sram_1bank_16mux_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class sram_1bank_8mux_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/20_sram_1bank_16mux_test.py b/compiler/tests/20_sram_1bank_16mux_test.py index 61f469e4..6461c5a6 100755 --- a/compiler/tests/20_sram_1bank_16mux_test.py +++ b/compiler/tests/20_sram_1bank_16mux_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class sram_1bank_8mux_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/20_sram_1bank_2mux_1rw_1r_spare_cols_test.py b/compiler/tests/20_sram_1bank_2mux_1rw_1r_spare_cols_test.py index 82409479..08922ede 100755 --- a/compiler/tests/20_sram_1bank_2mux_1rw_1r_spare_cols_test.py +++ b/compiler/tests/20_sram_1bank_2mux_1rw_1r_spare_cols_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class sram_1bank_2mux_1rw_1r_spare_cols_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/20_sram_1bank_2mux_1rw_1r_test.py b/compiler/tests/20_sram_1bank_2mux_1rw_1r_test.py index af97d25a..b5d9d776 100755 --- a/compiler/tests/20_sram_1bank_2mux_1rw_1r_test.py +++ b/compiler/tests/20_sram_1bank_2mux_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class sram_1bank_2mux_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/20_sram_1bank_2mux_1w_1r_spare_cols_test.py b/compiler/tests/20_sram_1bank_2mux_1w_1r_spare_cols_test.py index b19cacc6..abbb2347 100755 --- a/compiler/tests/20_sram_1bank_2mux_1w_1r_spare_cols_test.py +++ b/compiler/tests/20_sram_1bank_2mux_1w_1r_spare_cols_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class sram_1bank_2mux_1w_1r_spare_cols_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 0 OPTS.num_w_ports = 1 diff --git a/compiler/tests/20_sram_1bank_2mux_1w_1r_test.py b/compiler/tests/20_sram_1bank_2mux_1w_1r_test.py index 890ad24a..5eabef8b 100755 --- a/compiler/tests/20_sram_1bank_2mux_1w_1r_test.py +++ b/compiler/tests/20_sram_1bank_2mux_1w_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class psram_1bank_2mux_1w_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 0 OPTS.num_w_ports = 1 diff --git a/compiler/tests/20_sram_1bank_2mux_global_test.py b/compiler/tests/20_sram_1bank_2mux_global_test.py index ec207564..fc4a32e8 100755 --- a/compiler/tests/20_sram_1bank_2mux_global_test.py +++ b/compiler/tests/20_sram_1bank_2mux_global_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class sram_1bank_2mux_global_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.local_array_size = 8 if OPTS.tech_name == "sky130": diff --git a/compiler/tests/20_sram_1bank_2mux_test.py b/compiler/tests/20_sram_1bank_2mux_test.py index 045eccec..85041348 100755 --- a/compiler/tests/20_sram_1bank_2mux_test.py +++ b/compiler/tests/20_sram_1bank_2mux_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class sram_1bank_2mux_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/20_sram_1bank_2mux_wmask_spare_cols_test.py b/compiler/tests/20_sram_1bank_2mux_wmask_spare_cols_test.py index 0472793c..d24fa62f 100755 --- a/compiler/tests/20_sram_1bank_2mux_wmask_spare_cols_test.py +++ b/compiler/tests/20_sram_1bank_2mux_wmask_spare_cols_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class sram_1bank_2mux_wmask_spare_cols_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/20_sram_1bank_2mux_wmask_test.py b/compiler/tests/20_sram_1bank_2mux_wmask_test.py index 65c0f399..84830d5c 100755 --- a/compiler/tests/20_sram_1bank_2mux_wmask_test.py +++ b/compiler/tests/20_sram_1bank_2mux_wmask_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class sram_1bank_2mux_wmask_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/20_sram_1bank_32b_1024_wmask_test.py b/compiler/tests/20_sram_1bank_32b_1024_wmask_test.py index 4a52c385..4df1bcca 100755 --- a/compiler/tests/20_sram_1bank_32b_1024_wmask_test.py +++ b/compiler/tests/20_sram_1bank_32b_1024_wmask_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -22,7 +22,7 @@ class sram_1bank_32b_1024_wmask_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/20_sram_1bank_4mux_1rw_1r_test.py b/compiler/tests/20_sram_1bank_4mux_1rw_1r_test.py index 8bcc0415..2e59670f 100755 --- a/compiler/tests/20_sram_1bank_4mux_1rw_1r_test.py +++ b/compiler/tests/20_sram_1bank_4mux_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class sram_1bank_4mux_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/20_sram_1bank_4mux_test.py b/compiler/tests/20_sram_1bank_4mux_test.py index 6f87fe44..0fdf883a 100755 --- a/compiler/tests/20_sram_1bank_4mux_test.py +++ b/compiler/tests/20_sram_1bank_4mux_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class sram_1bank_4mux_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/20_sram_1bank_8mux_1rw_1r_test.py b/compiler/tests/20_sram_1bank_8mux_1rw_1r_test.py index 33ef158f..bc1f824d 100755 --- a/compiler/tests/20_sram_1bank_8mux_1rw_1r_test.py +++ b/compiler/tests/20_sram_1bank_8mux_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class sram_1bank_8mux_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/20_sram_1bank_8mux_test.py b/compiler/tests/20_sram_1bank_8mux_test.py index dc4ad5ec..a670744a 100755 --- a/compiler/tests/20_sram_1bank_8mux_test.py +++ b/compiler/tests/20_sram_1bank_8mux_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class sram_1bank_8mux_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/20_sram_1bank_nomux_1rw_1r_spare_cols_test.py b/compiler/tests/20_sram_1bank_nomux_1rw_1r_spare_cols_test.py index 323678f7..561074a1 100755 --- a/compiler/tests/20_sram_1bank_nomux_1rw_1r_spare_cols_test.py +++ b/compiler/tests/20_sram_1bank_nomux_1rw_1r_spare_cols_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class sram_1bank_nomux_1rw_1r_spare_cols_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/20_sram_1bank_nomux_1rw_1r_test.py b/compiler/tests/20_sram_1bank_nomux_1rw_1r_test.py index 8b0a1b58..e8e18b7a 100755 --- a/compiler/tests/20_sram_1bank_nomux_1rw_1r_test.py +++ b/compiler/tests/20_sram_1bank_nomux_1rw_1r_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class sram_1bank_nomux_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/20_sram_1bank_nomux_spare_cols_test.py b/compiler/tests/20_sram_1bank_nomux_spare_cols_test.py index d2b5da52..99131037 100755 --- a/compiler/tests/20_sram_1bank_nomux_spare_cols_test.py +++ b/compiler/tests/20_sram_1bank_nomux_spare_cols_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class sram_1bank_nomux_spare_cols_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/20_sram_1bank_nomux_test.py b/compiler/tests/20_sram_1bank_nomux_test.py index 7a13b28b..59e309df 100755 --- a/compiler/tests/20_sram_1bank_nomux_test.py +++ b/compiler/tests/20_sram_1bank_nomux_test.py @@ -9,7 +9,6 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory @@ -21,7 +20,7 @@ class sram_1bank_nomux_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/20_sram_1bank_nomux_wmask_sparecols_test.py b/compiler/tests/20_sram_1bank_nomux_wmask_sparecols_test.py index f115a9b0..a7326df3 100755 --- a/compiler/tests/20_sram_1bank_nomux_wmask_sparecols_test.py +++ b/compiler/tests/20_sram_1bank_nomux_wmask_sparecols_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -22,7 +22,7 @@ class sram_1bank_nomux_wmask_sparecols_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/20_sram_1bank_nomux_wmask_test.py b/compiler/tests/20_sram_1bank_nomux_wmask_test.py index 8c012a60..5eb10212 100755 --- a/compiler/tests/20_sram_1bank_nomux_wmask_test.py +++ b/compiler/tests/20_sram_1bank_nomux_wmask_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -21,7 +21,7 @@ class sram_1bank_nomux_wmask_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/20_sram_1bank_ring_test.py b/compiler/tests/20_sram_1bank_ring_test.py index db2b5297..5010a3de 100755 --- a/compiler/tests/20_sram_1bank_ring_test.py +++ b/compiler/tests/20_sram_1bank_ring_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -22,7 +22,7 @@ class sram_1bank_nomux_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) OPTS.supply_pin_type = "ring" - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/20_sram_2bank_test.py b/compiler/tests/20_sram_2bank_test.py index da672801..e2d144bf 100755 --- a/compiler/tests/20_sram_2bank_test.py +++ b/compiler/tests/20_sram_2bank_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -22,7 +22,7 @@ class sram_2bank_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=16, num_words=32, num_banks=2) diff --git a/compiler/tests/21_hspice_delay_test.py b/compiler/tests/21_hspice_delay_test.py index 987fffa8..a5677a13 100755 --- a/compiler/tests/21_hspice_delay_test.py +++ b/compiler/tests/21_hspice_delay_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -30,7 +30,7 @@ class timing_sram_test(openram_test): import characterizer reload(characterizer) from characterizer import delay - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 num_spare_cols = 1 diff --git a/compiler/tests/21_hspice_setuphold_test.py b/compiler/tests/21_hspice_setuphold_test.py index 76f47d1a..0ebcb167 100755 --- a/compiler/tests/21_hspice_setuphold_test.py +++ b/compiler/tests/21_hspice_setuphold_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS diff --git a/compiler/tests/21_model_delay_test.py b/compiler/tests/21_model_delay_test.py index 71b002e1..ab6f3888 100755 --- a/compiler/tests/21_model_delay_test.py +++ b/compiler/tests/21_model_delay_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -31,8 +31,8 @@ class model_delay_test(openram_test): reload(characterizer) from characterizer import delay from characterizer import elmore - from sram import sram - from sram_config import sram_config + from modules import sram + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 num_spare_cols = 1 diff --git a/compiler/tests/21_ngspice_delay_extra_rows_test.py b/compiler/tests/21_ngspice_delay_extra_rows_test.py index f5bcc658..3935ac3d 100755 --- a/compiler/tests/21_ngspice_delay_extra_rows_test.py +++ b/compiler/tests/21_ngspice_delay_extra_rows_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -29,7 +29,7 @@ class timing_sram_test(openram_test): import characterizer reload(characterizer) from characterizer import delay - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=1, num_words=16, num_banks=1, diff --git a/compiler/tests/21_ngspice_delay_global_test.py b/compiler/tests/21_ngspice_delay_global_test.py index f826880c..94ed2aba 100755 --- a/compiler/tests/21_ngspice_delay_global_test.py +++ b/compiler/tests/21_ngspice_delay_global_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -31,7 +31,7 @@ class timing_sram_test(openram_test): import characterizer reload(characterizer) from characterizer import delay - from sram_config import sram_config + from modules import sram_config OPTS.local_array_size = 2 if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/21_ngspice_delay_test.py b/compiler/tests/21_ngspice_delay_test.py index e13eada8..d5b952ac 100755 --- a/compiler/tests/21_ngspice_delay_test.py +++ b/compiler/tests/21_ngspice_delay_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -29,7 +29,7 @@ class timing_sram_test(openram_test): import characterizer reload(characterizer) from characterizer import delay - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 num_spare_cols = 1 diff --git a/compiler/tests/21_ngspice_setuphold_test.py b/compiler/tests/21_ngspice_setuphold_test.py index 9bda2c2c..70adfaaa 100755 --- a/compiler/tests/21_ngspice_setuphold_test.py +++ b/compiler/tests/21_ngspice_setuphold_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS diff --git a/compiler/tests/21_regression_delay_test.py b/compiler/tests/21_regression_delay_test.py index c79f0218..dbebba0d 100755 --- a/compiler/tests/21_regression_delay_test.py +++ b/compiler/tests/21_regression_delay_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -31,8 +31,8 @@ class regression_model_test(openram_test): reload(characterizer) from characterizer import linear_regression from characterizer import neural_network - from sram import sram - from sram_config import sram_config + from modules import sram + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 num_spare_cols = 1 diff --git a/compiler/tests/21_xyce_delay_test.py b/compiler/tests/21_xyce_delay_test.py index 6592b50e..705f432e 100755 --- a/compiler/tests/21_xyce_delay_test.py +++ b/compiler/tests/21_xyce_delay_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -30,7 +30,7 @@ class timing_sram_test(openram_test): import characterizer reload(characterizer) from characterizer import delay - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 num_spare_cols = 1 diff --git a/compiler/tests/21_xyce_setuphold_test.py b/compiler/tests/21_xyce_setuphold_test.py index 3aabce06..c2962c48 100755 --- a/compiler/tests/21_xyce_setuphold_test.py +++ b/compiler/tests/21_xyce_setuphold_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS diff --git a/compiler/tests/22_psram_1bank_2mux_func_test.py b/compiler/tests/22_psram_1bank_2mux_func_test.py index f5f4cd8f..9d6d038e 100755 --- a/compiler/tests/22_psram_1bank_2mux_func_test.py +++ b/compiler/tests/22_psram_1bank_2mux_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -38,7 +38,7 @@ class psram_1bank_2mux_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=2, num_words=32, num_banks=1) diff --git a/compiler/tests/22_psram_1bank_4mux_func_test.py b/compiler/tests/22_psram_1bank_4mux_func_test.py index f422728b..30943de1 100755 --- a/compiler/tests/22_psram_1bank_4mux_func_test.py +++ b/compiler/tests/22_psram_1bank_4mux_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -39,7 +39,7 @@ class psram_1bank_4mux_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=2, num_words=256, num_banks=1) diff --git a/compiler/tests/22_psram_1bank_8mux_func_test.py b/compiler/tests/22_psram_1bank_8mux_func_test.py index f0247808..dd79e6b8 100755 --- a/compiler/tests/22_psram_1bank_8mux_func_test.py +++ b/compiler/tests/22_psram_1bank_8mux_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -39,7 +39,7 @@ class psram_1bank_8mux_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=4, num_words=256, num_banks=1) diff --git a/compiler/tests/22_psram_1bank_nomux_func_test.py b/compiler/tests/22_psram_1bank_nomux_func_test.py index 203fd0ac..e81cc87d 100755 --- a/compiler/tests/22_psram_1bank_nomux_func_test.py +++ b/compiler/tests/22_psram_1bank_nomux_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -38,7 +38,7 @@ class psram_1bank_nomux_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=2, num_words=32, num_banks=1) diff --git a/compiler/tests/22_sram_1bank_2mux_func_test.py b/compiler/tests/22_sram_1bank_2mux_func_test.py index dedbba0c..c7ac0d05 100755 --- a/compiler/tests/22_sram_1bank_2mux_func_test.py +++ b/compiler/tests/22_sram_1bank_2mux_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -31,7 +31,7 @@ class sram_1bank_2mux_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 num_spare_cols = 1 diff --git a/compiler/tests/22_sram_1bank_2mux_global_func_test.py b/compiler/tests/22_sram_1bank_2mux_global_func_test.py index 664815e7..dc4b1730 100755 --- a/compiler/tests/22_sram_1bank_2mux_global_func_test.py +++ b/compiler/tests/22_sram_1bank_2mux_global_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -31,7 +31,7 @@ class sram_1bank_2mux_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config OPTS.local_array_size = 8 if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/22_sram_1bank_2mux_sparecols_func_test.py b/compiler/tests/22_sram_1bank_2mux_sparecols_func_test.py index 0466af79..20570a6c 100755 --- a/compiler/tests/22_sram_1bank_2mux_sparecols_func_test.py +++ b/compiler/tests/22_sram_1bank_2mux_sparecols_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -31,7 +31,7 @@ class sram_1bank_2mux_sparecols_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 num_spare_cols = 1 diff --git a/compiler/tests/22_sram_1bank_4mux_func_test.py b/compiler/tests/22_sram_1bank_4mux_func_test.py index c08a4fef..7b397209 100755 --- a/compiler/tests/22_sram_1bank_4mux_func_test.py +++ b/compiler/tests/22_sram_1bank_4mux_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -31,7 +31,7 @@ class sram_1bank_4mux_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 num_spare_cols = 1 diff --git a/compiler/tests/22_sram_1bank_8mux_func_test.py b/compiler/tests/22_sram_1bank_8mux_func_test.py index 6e6190e4..fcc38091 100755 --- a/compiler/tests/22_sram_1bank_8mux_func_test.py +++ b/compiler/tests/22_sram_1bank_8mux_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -34,7 +34,7 @@ class sram_1bank_8mux_func_test(openram_test): if not OPTS.spice_exe: debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 num_spare_cols = 1 diff --git a/compiler/tests/22_sram_1bank_nomux_1rw_1r_func_test.py b/compiler/tests/22_sram_1bank_nomux_1rw_1r_func_test.py index c0518957..76116485 100755 --- a/compiler/tests/22_sram_1bank_nomux_1rw_1r_func_test.py +++ b/compiler/tests/22_sram_1bank_nomux_1rw_1r_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -35,7 +35,7 @@ class psram_1bank_nomux_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=4, num_words=32, num_banks=1) diff --git a/compiler/tests/22_sram_1bank_nomux_func_test.py b/compiler/tests/22_sram_1bank_nomux_func_test.py index c0e4e19a..5617b3fe 100755 --- a/compiler/tests/22_sram_1bank_nomux_func_test.py +++ b/compiler/tests/22_sram_1bank_nomux_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -31,7 +31,7 @@ class sram_1bank_nomux_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 num_spare_cols = 1 diff --git a/compiler/tests/22_sram_1bank_nomux_sparecols_func_test.py b/compiler/tests/22_sram_1bank_nomux_sparecols_func_test.py index 0116f444..5b3e0908 100755 --- a/compiler/tests/22_sram_1bank_nomux_sparecols_func_test.py +++ b/compiler/tests/22_sram_1bank_nomux_sparecols_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -31,7 +31,7 @@ class sram_1bank_nomux_sparecols_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 num_spare_cols = 1 diff --git a/compiler/tests/22_sram_1bank_wmask_1rw_1r_func_test.py b/compiler/tests/22_sram_1bank_wmask_1rw_1r_func_test.py index d2b62470..09b77170 100755 --- a/compiler/tests/22_sram_1bank_wmask_1rw_1r_func_test.py +++ b/compiler/tests/22_sram_1bank_wmask_1rw_1r_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -35,7 +35,7 @@ class sram_wmask_1w_1r_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 num_spare_cols = 1 diff --git a/compiler/tests/22_sram_wmask_func_test.py b/compiler/tests/22_sram_wmask_func_test.py index de10d9f6..570b515e 100755 --- a/compiler/tests/22_sram_wmask_func_test.py +++ b/compiler/tests/22_sram_wmask_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -31,7 +31,7 @@ class sram_wmask_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 num_spare_cols = 1 diff --git a/compiler/tests/23_lib_sram_linear_regression_test.py b/compiler/tests/23_lib_sram_linear_regression_test.py index 620b8f0e..642c3b51 100755 --- a/compiler/tests/23_lib_sram_linear_regression_test.py +++ b/compiler/tests/23_lib_sram_linear_regression_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os,re -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS import debug @@ -32,8 +32,8 @@ class lib_sram_linear_regression_test(openram_test): num_spare_cols = 0 from characterizer import lib - from sram import sram - from sram_config import sram_config + from modules import sram + from modules import sram_config c = sram_config(word_size=2, num_words=16, num_banks=1, diff --git a/compiler/tests/23_lib_sram_model_corners_test.py b/compiler/tests/23_lib_sram_model_corners_test.py index 1de09c2b..7a46aec5 100755 --- a/compiler/tests/23_lib_sram_model_corners_test.py +++ b/compiler/tests/23_lib_sram_model_corners_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os,re -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS import debug @@ -31,8 +31,8 @@ class lib_model_corners_lib_test(openram_test): num_spare_cols = 0 from characterizer import lib - from sram import sram - from sram_config import sram_config + from modules import sram + from modules import sram_config c = sram_config(word_size=2, num_words=16, num_banks=1, diff --git a/compiler/tests/23_lib_sram_model_test.py b/compiler/tests/23_lib_sram_model_test.py index e421235e..ec918b00 100755 --- a/compiler/tests/23_lib_sram_model_test.py +++ b/compiler/tests/23_lib_sram_model_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os,re -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS import debug @@ -31,8 +31,8 @@ class lib_sram_model_test(openram_test): num_spare_cols = 0 from characterizer import lib - from sram import sram - from sram_config import sram_config + from modules import sram + from modules import sram_config c = sram_config(word_size=2, num_words=16, num_banks=1, diff --git a/compiler/tests/23_lib_sram_prune_test.py b/compiler/tests/23_lib_sram_prune_test.py index ae9093f5..b509a1b9 100755 --- a/compiler/tests/23_lib_sram_prune_test.py +++ b/compiler/tests/23_lib_sram_prune_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os,re -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS import debug @@ -39,8 +39,8 @@ class lib_sram_prune_test(openram_test): num_spare_rows = 0 num_spare_cols = 0 - from sram import sram - from sram_config import sram_config + from modules import sram + from modules import sram_config c = sram_config(word_size=2, num_words=16, num_banks=1, diff --git a/compiler/tests/23_lib_sram_test.py b/compiler/tests/23_lib_sram_test.py index cf9cf801..34397ada 100755 --- a/compiler/tests/23_lib_sram_test.py +++ b/compiler/tests/23_lib_sram_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os,re -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS import debug @@ -37,8 +37,8 @@ class lib_test(openram_test): num_spare_rows = 0 num_spare_cols = 0 - from sram import sram - from sram_config import sram_config + from modules import sram + from modules import sram_config c = sram_config(word_size=2, num_words=16, num_banks=1, diff --git a/compiler/tests/24_lef_sram_test.py b/compiler/tests/24_lef_sram_test.py index 43638003..675daed8 100755 --- a/compiler/tests/24_lef_sram_test.py +++ b/compiler/tests/24_lef_sram_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS import debug @@ -23,8 +23,8 @@ class lef_test(openram_test): globals.init_openram(config_file) OPTS.route_supplies=False OPTS.check_lvsdrc=False - from sram import sram - from sram_config import sram_config + from modules import sram + from modules import sram_config c = sram_config(word_size=2, num_words=16, num_banks=1) diff --git a/compiler/tests/25_verilog_sram_test.py b/compiler/tests/25_verilog_sram_test.py index 63658d04..be2528b6 100755 --- a/compiler/tests/25_verilog_sram_test.py +++ b/compiler/tests/25_verilog_sram_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS import debug @@ -23,8 +23,8 @@ class verilog_test(openram_test): OPTS.route_supplies=False OPTS.check_lvsdrc=False OPTS.netlist_only=True - from sram import sram - from sram_config import sram_config + from modules import sram + from modules import sram_config c = sram_config(word_size=2, num_words=16, num_banks=1) diff --git a/compiler/tests/26_hspice_pex_pinv_test.py b/compiler/tests/26_hspice_pex_pinv_test.py index 3246913b..7dbd56a6 100755 --- a/compiler/tests/26_hspice_pex_pinv_test.py +++ b/compiler/tests/26_hspice_pex_pinv_test.py @@ -11,7 +11,7 @@ with HSPICE. import unittest from testutils import header, openram_test import sys, os -sys.path.append(os.path.join(sys.path[0],"..")) + import globals from globals import OPTS import debug diff --git a/compiler/tests/26_ngspice_pex_pinv_test.py b/compiler/tests/26_ngspice_pex_pinv_test.py index d53f2d2c..c2582237 100755 --- a/compiler/tests/26_ngspice_pex_pinv_test.py +++ b/compiler/tests/26_ngspice_pex_pinv_test.py @@ -11,7 +11,7 @@ with Ngspice. import unittest from testutils import header,openram_test import sys, os -sys.path.append(os.path.join(sys.path[0],"..")) + import globals from globals import OPTS import debug diff --git a/compiler/tests/26_sram_pex_test.py b/compiler/tests/26_sram_pex_test.py index 90dd46ee..c8b101cb 100755 --- a/compiler/tests/26_sram_pex_test.py +++ b/compiler/tests/26_sram_pex_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -30,7 +30,7 @@ class sram_pex_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=4, num_words=32, num_banks=1) diff --git a/compiler/tests/30_openram_back_end_test.py b/compiler/tests/30_openram_back_end_test.py index c67b8249..e0233ead 100755 --- a/compiler/tests/30_openram_back_end_test.py +++ b/compiler/tests/30_openram_back_end_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os, re, shutil -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS import debug diff --git a/compiler/tests/30_openram_front_end_test.py b/compiler/tests/30_openram_front_end_test.py index 87b280dc..489ea26c 100755 --- a/compiler/tests/30_openram_front_end_test.py +++ b/compiler/tests/30_openram_front_end_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os, re, shutil -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS import debug diff --git a/compiler/tests/50_riscv_1k_1rw1r_func_test.py b/compiler/tests/50_riscv_1k_1rw1r_func_test.py index 6cd494aa..2b770111 100755 --- a/compiler/tests/50_riscv_1k_1rw1r_func_test.py +++ b/compiler/tests/50_riscv_1k_1rw1r_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -37,7 +37,7 @@ class riscv_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=32, write_size=8, num_words=256, diff --git a/compiler/tests/50_riscv_1k_1rw_func_test.py b/compiler/tests/50_riscv_1k_1rw_func_test.py index a99fba03..9623f4af 100755 --- a/compiler/tests/50_riscv_1k_1rw_func_test.py +++ b/compiler/tests/50_riscv_1k_1rw_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -37,7 +37,7 @@ class riscv_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=32, write_size=8, num_words=256, diff --git a/compiler/tests/50_riscv_1rw1r_func_test.py b/compiler/tests/50_riscv_1rw1r_func_test.py index 19609159..4b864193 100755 --- a/compiler/tests/50_riscv_1rw1r_func_test.py +++ b/compiler/tests/50_riscv_1rw1r_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -36,7 +36,7 @@ class riscv_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=32, write_size=8, num_words=32, diff --git a/compiler/tests/50_riscv_1rw1r_phys_test.py b/compiler/tests/50_riscv_1rw1r_phys_test.py index 40ae942f..47774828 100755 --- a/compiler/tests/50_riscv_1rw1r_phys_test.py +++ b/compiler/tests/50_riscv_1rw1r_phys_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -22,7 +22,7 @@ class riscv_phys_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 diff --git a/compiler/tests/50_riscv_1rw_func_test.py b/compiler/tests/50_riscv_1rw_func_test.py index 0e7e79d7..ee157a44 100755 --- a/compiler/tests/50_riscv_1rw_func_test.py +++ b/compiler/tests/50_riscv_1rw_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -44,7 +44,7 @@ class riscv_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=32, write_size=8, num_words=64, diff --git a/compiler/tests/50_riscv_1rw_phys_test.py b/compiler/tests/50_riscv_1rw_phys_test.py index 4cf2def5..c4e574c1 100755 --- a/compiler/tests/50_riscv_1rw_phys_test.py +++ b/compiler/tests/50_riscv_1rw_phys_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -22,7 +22,7 @@ class riscv_phys_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - from sram_config import sram_config + from modules import sram_config if OPTS.tech_name == "sky130": num_spare_rows = 1 diff --git a/compiler/tests/50_riscv_2k_1rw1r_func_test.py b/compiler/tests/50_riscv_2k_1rw1r_func_test.py index 2fa1ec47..ffa7ca03 100755 --- a/compiler/tests/50_riscv_2k_1rw1r_func_test.py +++ b/compiler/tests/50_riscv_2k_1rw1r_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -37,7 +37,7 @@ class riscv_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=32, write_size=8, num_words=512, diff --git a/compiler/tests/50_riscv_2k_1rw_func_test.py b/compiler/tests/50_riscv_2k_1rw_func_test.py index 24ec2e3a..a48a03c0 100755 --- a/compiler/tests/50_riscv_2k_1rw_func_test.py +++ b/compiler/tests/50_riscv_2k_1rw_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -37,7 +37,7 @@ class riscv_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=32, write_size=8, num_words=512, diff --git a/compiler/tests/50_riscv_4k_1rw1r_func_test.py b/compiler/tests/50_riscv_4k_1rw1r_func_test.py index 6b4f336e..431b5390 100755 --- a/compiler/tests/50_riscv_4k_1rw1r_func_test.py +++ b/compiler/tests/50_riscv_4k_1rw1r_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -37,7 +37,7 @@ class riscv_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=32, write_size=8, num_words=1024, diff --git a/compiler/tests/50_riscv_4k_1rw_func_test.py b/compiler/tests/50_riscv_4k_1rw_func_test.py index 9f2dc2f6..45254ac4 100755 --- a/compiler/tests/50_riscv_4k_1rw_func_test.py +++ b/compiler/tests/50_riscv_4k_1rw_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -37,7 +37,7 @@ class riscv_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=32, write_size=8, num_words=1024, diff --git a/compiler/tests/50_riscv_512b_1rw1r_func_test.py b/compiler/tests/50_riscv_512b_1rw1r_func_test.py index 17b3f518..26682139 100755 --- a/compiler/tests/50_riscv_512b_1rw1r_func_test.py +++ b/compiler/tests/50_riscv_512b_1rw1r_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -37,7 +37,7 @@ class riscv_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=32, write_size=8, num_words=128, diff --git a/compiler/tests/50_riscv_512b_1rw_func_test.py b/compiler/tests/50_riscv_512b_1rw_func_test.py index 4cceefd8..0af228a9 100755 --- a/compiler/tests/50_riscv_512b_1rw_func_test.py +++ b/compiler/tests/50_riscv_512b_1rw_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -37,7 +37,7 @@ class riscv_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=32, write_size=8, num_words=128, diff --git a/compiler/tests/50_riscv_8k_1rw1r_func_test.py b/compiler/tests/50_riscv_8k_1rw1r_func_test.py index 0783823c..f2861bad 100755 --- a/compiler/tests/50_riscv_8k_1rw1r_func_test.py +++ b/compiler/tests/50_riscv_8k_1rw1r_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -37,7 +37,7 @@ class riscv_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=32, write_size=8, num_words=2048, diff --git a/compiler/tests/50_riscv_8k_1rw_func_test.py b/compiler/tests/50_riscv_8k_1rw_func_test.py index 7b948aad..22db186e 100755 --- a/compiler/tests/50_riscv_8k_1rw_func_test.py +++ b/compiler/tests/50_riscv_8k_1rw_func_test.py @@ -9,7 +9,7 @@ import unittest from testutils import * import sys, os -sys.path.append(os.getenv("OPENRAM_HOME")) + import globals from globals import OPTS from sram_factory import factory @@ -37,7 +37,7 @@ class riscv_func_test(openram_test): import characterizer reload(characterizer) from characterizer import functional - from sram_config import sram_config + from modules import sram_config c = sram_config(word_size=32, write_size=8, num_words=2048, diff --git a/compiler/tests/testutils.py b/compiler/tests/testutils.py index 67c08d2e..bd4a7aa2 100644 --- a/compiler/tests/testutils.py +++ b/compiler/tests/testutils.py @@ -7,7 +7,6 @@ # import unittest import sys, os, glob -sys.path.append(os.getenv("OPENRAM_HOME")) from globals import OPTS import debug import pdb @@ -140,8 +139,8 @@ class openram_test(unittest.TestCase): Reset everything after each test. """ # Reset the static duplicate name checker for unit tests. - import hierarchy_design - hierarchy_design.hierarchy_design.name_map=[] + from base import hierarchy_design + hierarchy_design.name_map=[] def check_golden_data(self, data, golden_data, error_tolerance=1e-2): """ diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index 53b2f167..0de27ba9 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -18,12 +18,10 @@ Calibre means pointing the code to the proper DRC and LVS rule files. import os -import shutil import re import debug -import utils from globals import OPTS -from run_script import run_script +from .run_script import run_script # Keep track of statistics num_drc_runs = 0 diff --git a/compiler/verify/klayout.py b/compiler/verify/klayout.py index ca19e79b..73cec474 100644 --- a/compiler/verify/klayout.py +++ b/compiler/verify/klayout.py @@ -16,7 +16,7 @@ import re import shutil import debug from globals import OPTS -from run_script import * +from .run_script import * # Keep track of statistics num_drc_runs = 0 diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 2b5727ed..e3cd8515 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -25,7 +25,7 @@ import re import shutil import debug from globals import OPTS -from run_script import * +from .run_script import * # Keep track of statistics num_drc_runs = 0 @@ -270,7 +270,7 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, out setup_file_object = open(output_path + "/setup.tcl", 'a') setup_file_object.write("# Increase the column sizes for ease of reading long names\n") - setup_file_object.write("::netgen::format 80\n") + setup_file_object.write("::netgen::format 120\n") else: setup_file = 'nosetup' diff --git a/openram.mk b/openram.mk index b0e57268..be987aaf 100644 --- a/openram.mk +++ b/openram.mk @@ -27,6 +27,7 @@ export DOCKER_CMD= docker run \ -e OPENRAM_HOME=/openram/compiler \ -e OPENRAM_TECH=/openram/technology \ -e OPENRAM_TMP=$(OPENRAM_DIR)/results/$*/tmp \ + -e PYTHONPATH=/openram/compiler \ -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \ --user $(UID):$(GID) \ vlsida/openram-ubuntu:latest @@ -41,6 +42,7 @@ mount: -e PDKPATH=/pdk/sky130A \ -e OPENRAM_HOME=/openram/compiler \ -e OPENRAM_TECH=/openram/technology \ + -e PYTHONPATH=/openram/compiler \ -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \ --user $(UID):$(GID) \ vlsida/openram-ubuntu:latest diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index 7c1ac84b..76522ff3 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -6,10 +6,11 @@ # All rights reserved. # import os -from design_rules import * -from module_type import * -from custom_cell_properties import cell_properties -from custom_layer_properties import layer_properties +import drc as d +#from drc.design_rules import design_rules +#from drc.module_type import module_type +#from drc.custom_cell_properties import cell_properties +#from drc.custom_layer_properties import layer_properties """ File containing the process technology parameters for FreePDK 45nm. @@ -24,18 +25,18 @@ File containing the process technology parameters for FreePDK 45nm. # Using tech_modules['cellname'] you can override each class by providing a custom # implementation in '$OPENRAM_TECHDIR/modules/' # For example: tech_modules['contact'] = 'contact_freepdk45' -tech_modules = module_type() +tech_modules = d.module_type() ################################################### # Custom cell properties ################################################### -cell_properties = cell_properties() +cell_properties = d.cell_properties() ################################################### # Custom cell properties ################################################### -layer_properties = layer_properties() +layer_properties = d.layer_properties() ################################################### # GDS file info @@ -185,7 +186,7 @@ parameter["6T_access_size"] = 0.135 drclvs_home=os.environ.get("DRCLVS_HOME") -drc = design_rules("freepdk45") +drc = d.design_rules("freepdk45") #grid size drc["grid"] = 0.0025 @@ -347,7 +348,7 @@ drc.add_layer("via2", # Minimum spacing of m3 wider than 1.5 & longer than 4.0=1.5 drc.add_layer("m3", width=0.07, - spacing=drc_lut({(0.00, 0.0): 0.07, + spacing=d.drc_lut({(0.00, 0.0): 0.07, (0.09, 0.3): 0.09, (0.27, 0.9): 0.27, (0.50, 1.8): 0.5, @@ -379,7 +380,7 @@ drc.add_layer("via3", # Minimum spacing of m4 wider than 1.5 & longer than 4.0=1.5 drc.add_layer("m4", width=0.14, - spacing=drc_lut({(0.00, 0.0): 0.14, + spacing=d.drc_lut({(0.00, 0.0): 0.14, (0.27, 0.9): 0.27, (0.50, 1.8): 0.5, (0.90, 2.7): 0.9, diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index 525736a8..e940ce29 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -6,10 +6,11 @@ # All rights reserved. # import os -from design_rules import * -from module_type import * -from custom_cell_properties import cell_properties -from custom_layer_properties import layer_properties +import drc as d +#from drc.design_rules import design_rules +#from drc.module_type import module_type +#from drc.custom_cell_properties import cell_properties +#from drc.custom_layer_properties import layer_properties """ File containing the process technology parameters for SCMOS 4m, 0.35um @@ -24,19 +25,19 @@ File containing the process technology parameters for SCMOS 4m, 0.35um # Using tech_modules['cellname'] you can override each class by providing a custom # implementation in '$OPENRAM_TECHDIR/modules/' # For example: tech_modules['contact'] = 'contact_scn4m' -tech_modules = module_type() +tech_modules = d.module_type() ################################################### # Custom cell properties ################################################### -cell_properties = cell_properties() +cell_properties = d.cell_properties() cell_properties.bitcell_1port.gnd_layer = "m2" cell_properties.bitcell_1port.gnd_dir = "V" ################################################### # Custom cell properties ################################################### -layer_properties = layer_properties() +layer_properties = d.layer_properties() ################################################### # GDS file info @@ -160,7 +161,7 @@ parameter["6T_access_size"] = 4*_lambda_ drclvs_home=os.environ.get("DRCLVS_HOME") -drc = design_rules("scn4me_sub") +drc = d.design_rules("scn4me_sub") #grid size is 1/2 a lambda drc["grid"]=0.5*_lambda_ diff --git a/technology/sky130/custom/__init__.py b/technology/sky130/custom/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/technology/sky130/modules/sky130_bitcell.py b/technology/sky130/custom/sky130_bitcell.py similarity index 94% rename from technology/sky130/modules/sky130_bitcell.py rename to technology/sky130/custom/sky130_bitcell.py index 90371a29..908ff45d 100644 --- a/technology/sky130/modules/sky130_bitcell.py +++ b/technology/sky130/custom/sky130_bitcell.py @@ -7,10 +7,10 @@ import debug from tech import cell_properties as props -import bitcell_base +from modules import bitcell_base -class sky130_bitcell(bitcell_base.bitcell_base): +class sky130_bitcell(bitcell_base): """ A single bit cell (6T, 8T, etc.) This module implements the single memory cell used in the design. It is a hand-made cell, so diff --git a/technology/sky130/modules/sky130_bitcell_array.py b/technology/sky130/custom/sky130_bitcell_array.py similarity index 97% rename from technology/sky130/modules/sky130_bitcell_array.py rename to technology/sky130/custom/sky130_bitcell_array.py index 9910cbd5..2c7f5cd5 100644 --- a/technology/sky130/modules/sky130_bitcell_array.py +++ b/technology/sky130/custom/sky130_bitcell_array.py @@ -6,8 +6,8 @@ # import debug -from bitcell_array import bitcell_array -from sky130_bitcell_base_array import sky130_bitcell_base_array +from modules import bitcell_array +from .sky130_bitcell_base_array import sky130_bitcell_base_array from globals import OPTS from sram_factory import factory diff --git a/technology/sky130/modules/sky130_bitcell_base_array.py b/technology/sky130/custom/sky130_bitcell_base_array.py similarity index 99% rename from technology/sky130/modules/sky130_bitcell_base_array.py rename to technology/sky130/custom/sky130_bitcell_base_array.py index adaf1304..1604fa02 100644 --- a/technology/sky130/modules/sky130_bitcell_base_array.py +++ b/technology/sky130/custom/sky130_bitcell_base_array.py @@ -6,9 +6,9 @@ # import debug -import geometry +from base import geometry from sram_factory import factory -from bitcell_base_array import bitcell_base_array +from modules import bitcell_base_array from globals import OPTS from tech import layer diff --git a/technology/sky130/modules/sky130_col_cap.py b/technology/sky130/custom/sky130_col_cap.py similarity index 96% rename from technology/sky130/modules/sky130_col_cap.py rename to technology/sky130/custom/sky130_col_cap.py index cd328754..eb2383e5 100644 --- a/technology/sky130/modules/sky130_col_cap.py +++ b/technology/sky130/custom/sky130_col_cap.py @@ -6,11 +6,11 @@ # import debug -import design +from base import design from tech import cell_properties as props -class sky130_col_cap(design.design): +class sky130_col_cap(design): def __init__(self, version, name=""): if version == "colend": diff --git a/technology/sky130/modules/sky130_col_cap_array.py b/technology/sky130/custom/sky130_col_cap_array.py similarity index 99% rename from technology/sky130/modules/sky130_col_cap_array.py rename to technology/sky130/custom/sky130_col_cap_array.py index 214a53a8..940296d3 100644 --- a/technology/sky130/modules/sky130_col_cap_array.py +++ b/technology/sky130/custom/sky130_col_cap_array.py @@ -6,9 +6,9 @@ # from sram_factory import factory -from sky130_bitcell_base_array import sky130_bitcell_base_array +from .sky130_bitcell_base_array import sky130_bitcell_base_array from globals import OPTS -import geometry +from base import geometry from tech import layer class sky130_col_cap_array(sky130_bitcell_base_array): diff --git a/technology/sky130/modules/sky130_corner.py b/technology/sky130/custom/sky130_corner.py similarity index 63% rename from technology/sky130/modules/sky130_corner.py rename to technology/sky130/custom/sky130_corner.py index 4c5594a2..858a0a4a 100644 --- a/technology/sky130/modules/sky130_corner.py +++ b/technology/sky130/custom/sky130_corner.py @@ -6,12 +6,12 @@ # import debug -import design -import utils +from base import design +from base import get_libcell_size from tech import layer, GDS -class sky130_corner(design.design): +class sky130_corner(design): def __init__(self, location, name=""): super().__init__(name) @@ -26,8 +26,8 @@ class sky130_corner(design.design): self.name = "sky130_fd_bd_sram__sram_sp_cornera" else: debug.error("Invalid sky130_corner location", -1) - design.design.__init__(self, name=self.name) - (self.width, self.height) = utils.get_libcell_size(self.name, - GDS["unit"], - layer["mem"]) - # pin_map = utils.get_libcell_pins(pin_names, self.name, GDS["unit"]) + design.__init__(self, name=self.name) + (self.width, self.height) = get_libcell_size(self.name, + GDS["unit"], + layer["mem"]) + # pin_map = get_libcell_pins(pin_names, self.name, GDS["unit"]) diff --git a/technology/sky130/modules/sky130_dummy_array.py b/technology/sky130/custom/sky130_dummy_array.py similarity index 98% rename from technology/sky130/modules/sky130_dummy_array.py rename to technology/sky130/custom/sky130_dummy_array.py index 246a7f86..bfdca620 100644 --- a/technology/sky130/modules/sky130_dummy_array.py +++ b/technology/sky130/custom/sky130_dummy_array.py @@ -5,10 +5,10 @@ # All rights reserved. # -from sky130_bitcell_base_array import sky130_bitcell_base_array +from .sky130_bitcell_base_array import sky130_bitcell_base_array from sram_factory import factory from globals import OPTS -import geometry +from base import geometry from tech import layer class sky130_dummy_array(sky130_bitcell_base_array): diff --git a/technology/sky130/modules/sky130_dummy_bitcell.py b/technology/sky130/custom/sky130_dummy_bitcell.py similarity index 91% rename from technology/sky130/modules/sky130_dummy_bitcell.py rename to technology/sky130/custom/sky130_dummy_bitcell.py index 044c2848..58ef8026 100644 --- a/technology/sky130/modules/sky130_dummy_bitcell.py +++ b/technology/sky130/custom/sky130_dummy_bitcell.py @@ -7,10 +7,10 @@ import debug from tech import cell_properties as props -import bitcell_base +from modules import bitcell_base -class sky130_dummy_bitcell(bitcell_base.bitcell_base): +class sky130_dummy_bitcell(bitcell_base): """ A single bit cell (6T, 8T, etc.) This module implements the single memory cell used in the design. It is a hand-made cell, so diff --git a/technology/sky130/modules/sky130_internal.py b/technology/sky130/custom/sky130_internal.py similarity index 64% rename from technology/sky130/modules/sky130_internal.py rename to technology/sky130/custom/sky130_internal.py index b8c0616f..10637384 100644 --- a/technology/sky130/modules/sky130_internal.py +++ b/technology/sky130/custom/sky130_internal.py @@ -6,12 +6,12 @@ # import debug -import design -import utils +from base import design +from base import get_libcell_size from tech import layer, GDS -class sky130_internal(design.design): +class sky130_internal(design): def __init__(self, version, name=""): super().__init__(name) @@ -26,8 +26,8 @@ class sky130_internal(design.design): self.name = "sky130_fd_bd_sram__sram_sp_wlstrapa_p" else: debug.error("Invalid version", -1) - design.design.__init__(self, name=self.name) - (self.width, self.height) = utils.get_libcell_size(self.name, - GDS["unit"], - layer["mem"]) - # pin_map = utils.get_libcell_pins(pin_names, self.name, GDS["unit"]) + design.__init__(self, name=self.name) + (self.width, self.height) = get_libcell_size(self.name, + GDS["unit"], + layer["mem"]) + # pin_map = get_libcell_pins(pin_names, self.name, GDS["unit"]) diff --git a/technology/sky130/modules/sky130_replica_bitcell.py b/technology/sky130/custom/sky130_replica_bitcell.py similarity index 90% rename from technology/sky130/modules/sky130_replica_bitcell.py rename to technology/sky130/custom/sky130_replica_bitcell.py index 8be40adc..2b30fb7a 100644 --- a/technology/sky130/modules/sky130_replica_bitcell.py +++ b/technology/sky130/custom/sky130_replica_bitcell.py @@ -6,13 +6,13 @@ # import debug -import bitcell_base +from modules import bitcell_base +from base import logical_effort from tech import parameter, drc from tech import cell_properties as props -import logical_effort -class sky130_replica_bitcell(bitcell_base.bitcell_base): +class sky130_replica_bitcell(bitcell_base): """ A single bit cell (6T, 8T, etc.) This module implements the single memory cell used in the design. It @@ -32,7 +32,7 @@ class sky130_replica_bitcell(bitcell_base.bitcell_base): size = 0.5 # This accounts for bitline being drained thought the access TX and internal node cin = 3 # Assumes always a minimum sizes inverter. Could be specified in the tech.py file. read_port_load = 0.5 # min size NMOS gate load - return logical_effort.logical_effort('bitline', size, cin, load + read_port_load, parasitic_delay, False) + return logical_effort('bitline', size, cin, load + read_port_load, parasitic_delay, False) def input_load(self): """Return the relative capacitance of the access transistor gates""" diff --git a/technology/sky130/modules/sky130_replica_bitcell_array.py b/technology/sky130/custom/sky130_replica_bitcell_array.py similarity index 99% rename from technology/sky130/modules/sky130_replica_bitcell_array.py rename to technology/sky130/custom/sky130_replica_bitcell_array.py index 09e00d4c..c7b3c609 100644 --- a/technology/sky130/modules/sky130_replica_bitcell_array.py +++ b/technology/sky130/custom/sky130_replica_bitcell_array.py @@ -6,10 +6,10 @@ # import debug -from replica_bitcell_array import replica_bitcell_array -from vector import vector -from sky130_bitcell_base_array import sky130_bitcell_base_array -from utils import round_to_grid +from modules import replica_bitcell_array +from base import vector +from .sky130_bitcell_base_array import sky130_bitcell_base_array +from base import round_to_grid from math import sqrt from tech import drc from tech import array_row_multiple diff --git a/technology/sky130/modules/sky130_replica_column.py b/technology/sky130/custom/sky130_replica_column.py similarity index 99% rename from technology/sky130/modules/sky130_replica_column.py rename to technology/sky130/custom/sky130_replica_column.py index f05f91b8..8997d4f2 100644 --- a/technology/sky130/modules/sky130_replica_column.py +++ b/technology/sky130/custom/sky130_replica_column.py @@ -6,10 +6,10 @@ # import debug -from sky130_bitcell_base_array import sky130_bitcell_base_array +from .sky130_bitcell_base_array import sky130_bitcell_base_array from sram_factory import factory from globals import OPTS -import geometry +from base import geometry from tech import layer diff --git a/technology/sky130/modules/sky130_row_cap.py b/technology/sky130/custom/sky130_row_cap.py similarity index 93% rename from technology/sky130/modules/sky130_row_cap.py rename to technology/sky130/custom/sky130_row_cap.py index bdd0aa95..1c81b8dd 100644 --- a/technology/sky130/modules/sky130_row_cap.py +++ b/technology/sky130/custom/sky130_row_cap.py @@ -6,11 +6,11 @@ # import debug -import design +from base import design from tech import cell_properties as props -class sky130_row_cap(design.design): +class sky130_row_cap(design): def __init__(self, version, name=""): diff --git a/technology/sky130/modules/sky130_row_cap_array.py b/technology/sky130/custom/sky130_row_cap_array.py similarity index 98% rename from technology/sky130/modules/sky130_row_cap_array.py rename to technology/sky130/custom/sky130_row_cap_array.py index e5721da2..45b63c77 100644 --- a/technology/sky130/modules/sky130_row_cap_array.py +++ b/technology/sky130/custom/sky130_row_cap_array.py @@ -6,7 +6,7 @@ # from sram_factory import factory -from sky130_bitcell_base_array import sky130_bitcell_base_array +from .sky130_bitcell_base_array import sky130_bitcell_base_array from globals import OPTS diff --git a/technology/sky130/tech/tech.py b/technology/sky130/tech/tech.py index 9eec156b..8eea88f1 100644 --- a/technology/sky130/tech/tech.py +++ b/technology/sky130/tech/tech.py @@ -7,10 +7,7 @@ import os -from design_rules import * -from module_type import * -from custom_cell_properties import cell_properties, cell -from custom_layer_properties import layer_properties +import drc as d """ File containing the process technology parameters for Skywater 130nm. @@ -25,7 +22,7 @@ File containing the process technology parameters for Skywater 130nm. # Using tech_modules['cellname'] you can override each class by providing a custom # implementation in '$OPENRAM_TECHDIR/modules/' # For example: tech_modules["contact"] = "contact_freepdk45" -tech_modules = module_type() +tech_modules = d.module_type() # These modules have been hand designed and provided in this repository. tech_modules["nand2_dec"] = "nand2_dec" @@ -68,7 +65,7 @@ tech_modules["and4_dec"] = "and4_dec" ################################################### # Custom cell properties ################################################### -cell_properties = cell_properties() +cell_properties = d.cell_properties() cell_properties.bitcell_power_pin_directions = ("H", "H") @@ -116,7 +113,7 @@ cell_properties.bitcell_2port.vdd_dir = "H" cell_properties.bitcell_2port.gnd_layer = "m2" cell_properties.bitcell_2port.gnd_dir = "H" -cell_properties.col_cap_1port_bitcell = cell(['bl', 'vdd', 'gnd', 'br', 'gate', 'vpb', 'vnb'], +cell_properties.col_cap_1port_bitcell = d.cell(['bl', 'vdd', 'gnd', 'br', 'gate', 'vpb', 'vnb'], ['INPUT', 'POWER', 'GROUND', 'INPUT', 'INPUT', 'BIAS', 'BIAS'], {'bl': 'bl', 'br': 'br', @@ -127,21 +124,21 @@ cell_properties.col_cap_1port_bitcell = cell(['bl', 'vdd', 'gnd', 'br', 'gate', 'vpb': 'vpb'}) cell_properties.col_cap_1port_bitcell.boundary_layer = "mem" -cell_properties.col_cap_1port_strap_power = cell(['vdd', 'vpb', 'vnb'], +cell_properties.col_cap_1port_strap_power = d.cell(['vdd', 'vpb', 'vnb'], ['POWER', 'BIAS', 'BIAS'], {'vnb': 'VNB', 'vpb': 'VPB', 'vdd': 'VPWR'}) cell_properties.col_cap_1port_strap_power.boundary_layer = "mem" -cell_properties.col_cap_1port_strap_ground = cell(['gnd', 'vpb', 'vnb'], +cell_properties.col_cap_1port_strap_ground = d.cell(['gnd', 'vpb', 'vnb'], ['GROUND', 'BIAS', 'BIAS'], {'vnb': 'VNB', 'vpb': 'VPB', 'gnd': 'VGND'}) cell_properties.col_cap_1port_strap_ground.boundary_layer = "mem" -cell_properties.row_cap_1port_cell = cell(['vdd', 'wl'], +cell_properties.row_cap_1port_cell = d.cell(['vdd', 'wl'], ['POWER', 'INPUT'], {'wl': 'WL', 'vdd': 'VPWR'}) @@ -235,10 +232,11 @@ cell_properties.names["write_driver"] = "sky130_fd_bd_sram__openram_write_driver array_row_multiple = 2 array_col_multiple = 2 + ################################################### # Custom layer properties ################################################### -layer_properties = layer_properties() +layer_properties = d.layer_properties() layer_properties.hierarchical_decoder.bus_layer = "m1" layer_properties.hierarchical_decoder.bus_directions = "nonpref" layer_properties.hierarchical_decoder.input_layer = "li" @@ -469,7 +467,7 @@ parameter["6T_inv_nmos_size"] = 0.205 parameter["6T_inv_pmos_size"] = 0.09 parameter["6T_access_size"] = 0.135 -drc = design_rules("sky130") +drc = d.design_rules("sky130") # grid size drc["grid"] = 0.005 From ff7ceaf92df9bd3083e9b16735b6e34864d7f98f Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 13 Jul 2022 17:19:09 -0700 Subject: [PATCH 227/229] Fix syntax error for module scope in row/col caps. --- compiler/modules/col_cap_bitcell_1port.py | 2 +- compiler/modules/col_cap_bitcell_2port.py | 2 +- compiler/modules/row_cap_bitcell_1port.py | 2 +- compiler/modules/row_cap_bitcell_2port.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/modules/col_cap_bitcell_1port.py b/compiler/modules/col_cap_bitcell_1port.py index b57cfa3f..da69c9b1 100644 --- a/compiler/modules/col_cap_bitcell_1port.py +++ b/compiler/modules/col_cap_bitcell_1port.py @@ -16,7 +16,7 @@ class col_cap_bitcell_1port(bitcell_base): """ def __init__(self, name="col_cap_bitcell_1port"): - bitcell_base.bitcell_base.__init__(self, name, prop=props.col_cap_1port) + bitcell_base.__init__(self, name, prop=props.col_cap_1port) debug.info(2, "Create col_cap bitcell 1 port object") self.no_instances = True diff --git a/compiler/modules/col_cap_bitcell_2port.py b/compiler/modules/col_cap_bitcell_2port.py index acc0e489..3b42ca9d 100644 --- a/compiler/modules/col_cap_bitcell_2port.py +++ b/compiler/modules/col_cap_bitcell_2port.py @@ -16,7 +16,7 @@ class col_cap_bitcell_2port(bitcell_base): """ def __init__(self, name="col_cap_bitcell_2port"): - bitcell_base.bitcell_base.__init__(self, name, prop=props.col_cap_2port) + bitcell_base.__init__(self, name, prop=props.col_cap_2port) debug.info(2, "Create col_cap bitcell 2 port object") self.no_instances = True diff --git a/compiler/modules/row_cap_bitcell_1port.py b/compiler/modules/row_cap_bitcell_1port.py index 82849000..a0eceeb3 100644 --- a/compiler/modules/row_cap_bitcell_1port.py +++ b/compiler/modules/row_cap_bitcell_1port.py @@ -16,7 +16,7 @@ class row_cap_bitcell_1port(bitcell_base): """ def __init__(self, name="row_cap_bitcell_1port"): - bitcell_base.bitcell_base.__init__(self, name, prop=props.row_cap_1port) + bitcell_base.__init__(self, name, prop=props.row_cap_1port) debug.info(2, "Create row_cap bitcell 1 port object") self.no_instances = True diff --git a/compiler/modules/row_cap_bitcell_2port.py b/compiler/modules/row_cap_bitcell_2port.py index 771e9043..9eabc80f 100644 --- a/compiler/modules/row_cap_bitcell_2port.py +++ b/compiler/modules/row_cap_bitcell_2port.py @@ -16,7 +16,7 @@ class row_cap_bitcell_2port(bitcell_base): """ def __init__(self, name="row_cap_bitcell_2port"): - bitcell_base.bitcell_base.__init__(self, name, prop=props.row_cap_2port) + bitcell_base.__init__(self, name, prop=props.row_cap_2port) debug.info(2, "Create row_cap bitcell 2 port object") self.no_instances = True From c406e2a9dac05752a6ee4ec7692adb8e7ac612d0 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 13 Jul 2022 17:19:25 -0700 Subject: [PATCH 228/229] Make macros use same DOCKER_CMD. --- macros/Makefile | 15 ++------------- openram.mk | 5 +++-- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/macros/Makefile b/macros/Makefile index f2b02466..630541c0 100644 --- a/macros/Makefile +++ b/macros/Makefile @@ -61,22 +61,11 @@ freepdk45: $(FREEPDK45_STAMPS) scn4m_subm: $(SCN4M_SUBM_STAMPS) .PHONY: scn4m_subm +OPENRAM_TMP=/openram/macros/$*/tmp %.ok: configs/%.py @echo "Building $*" @mkdir -p $* - @docker run -v $(TOP_DIR):/openram \ - -v $(FREEPDK45):/freepdk45 \ - -e FREEPDK45=/freepdk45 \ - -v $(PDK_ROOT):/pdk \ - -e PDK_ROOT=/pdk \ - -e PDKPATH=/pdk/sky130A \ - -e OPENRAM_HOME=/openram/compiler \ - -e OPENRAM_TECH=/openram/technology \ - -e OPENRAM_TMP=/openram/macros/$*/tmp \ - -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \ - --user $(UID):$(GID) \ - vlsida/openram-ubuntu:latest \ - python3 -u /openram/compiler/openram.py $(OPENRAM_OPTS) -o $* -p /openram/macros/$* /openram/macros/$< && touch $@ + @$(DOCKER_CMD) python3 -u /openram/compiler/openram.py $(OPENRAM_OPTS) -o $* -p /openram/macros/$* /openram/macros/$< && touch $@ .DELETE_ON_ERROR: $(STAMPS) diff --git a/openram.mk b/openram.mk index be987aaf..f169fa32 100644 --- a/openram.mk +++ b/openram.mk @@ -17,6 +17,7 @@ export PDK_ROOT UID = $(shell id -u) GID = $(shell id -g) +export OPENRAM_TMP=$(OPENRAM_DIR)/results/$*/tmp export DOCKER_CMD= docker run \ -v $(TOP_DIR):/openram \ -v $(FREEPDK45):/freepdk45 \ @@ -26,11 +27,11 @@ export DOCKER_CMD= docker run \ -e PDKPATH=/pdk/sky130A \ -e OPENRAM_HOME=/openram/compiler \ -e OPENRAM_TECH=/openram/technology \ - -e OPENRAM_TMP=$(OPENRAM_DIR)/results/$*/tmp \ + -e OPENRAM_TMP=$(OPENRAM_TMP)\ -e PYTHONPATH=/openram/compiler \ -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \ --user $(UID):$(GID) \ - vlsida/openram-ubuntu:latest + vlsida/openram-ubuntu:latest mount: @docker run -it \ From 3b0533c9c7fb5185e48f0bac30082169ac208d6a Mon Sep 17 00:00:00 2001 From: mrg Date: Sun, 17 Jul 2022 19:55:05 -0700 Subject: [PATCH 229/229] v1.2.0 --- compiler/globals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/globals.py b/compiler/globals.py index c216858e..4ff6332c 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -22,7 +22,7 @@ import getpass import subprocess -VERSION = "1.1.18" +VERSION = "1.2.0" NAME = "OpenRAM v{}".format(VERSION) USAGE = "openram.py [options] \nUse -h for help.\n"