Merge branch 'dev' into stable

This commit is contained in:
mrg 2022-07-21 09:37:24 -07:00
commit 0d616ae072
473 changed files with 11595 additions and 3032 deletions

View File

@ -1,56 +1,38 @@
name: ci name: ci
on: [push] on: [push]
jobs: jobs:
scn4me_subm: regress:
runs-on: self-hosted runs-on: self-hosted
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v1 uses: actions/checkout@v1
- name: SCMOS test - name: Docker build
run: |
cd ${{ github.workspace }}/docker
make build
- name: PDK Install
run: | run: |
. /home/github-runner/setup-paths.sh
export OPENRAM_HOME="${{ github.workspace }}/compiler" export OPENRAM_HOME="${{ github.workspace }}/compiler"
export OPENRAM_TECH="${{ github.workspace }}/technology:/software/PDKs/skywater-tech" export OPENRAM_TECH="${{ github.workspace }}/technology"
export OPENRAM_TMP="${{ github.workspace }}/scn4me_subm_temp" #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"
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 #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 clean
make -k -j 48
- name: Archive - name: Archive
if: ${{ failure() }} if: ${{ failure() }}
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: scn4me_subm Archives name: Regress Archives
path: ${{ github.workspace }}/*.zip 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/

160
Makefile
View File

@ -1,78 +1,111 @@
# -*- 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)))) TOP_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
include $(TOP_DIR)/openram.mk
.DEFAULT_GOAL := all .DEFAULT_GOAL := install
# Skywater PDK SRAM library # Skywater PDK SRAM library
#SRAM_LIBRARY ?= $(PDK_ROOT)/skywater-pdk/libraries/sky130_fd_bd_sram SRAM_LIB_DIR ?= $(PDK_ROOT)/sky130_fd_bd_sram
SRAM_GIT_REPO ?= git@github.com:google/skywater-pdk-libs-sky130_fd_bd_sram.git # Use this for release
SRAM_LIBRARY ?= $(TOP_DIR)/sky130_fd_bd_sram SRAM_LIB_GIT_REPO ?= https://github.com/vlsida/sky130_fd_bd_sram.git
# Open PDKs # Use this for development
OPEN_PDKS ?= $(PDK_ROOT)/sky130A #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 ?= a83b6468c48434d927b90058b22047843c58027b
# 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.311
#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 ?= f70d8ca46961ff92719d8870a18a076370b85f6c
# Create lists of all the files to copy/link # Create lists of all the files to copy/link
GDS_FILES := $(sort $(wildcard $(SRAM_LIBRARY)/cells/*/*.gds)) GDS_FILES := $(sort $(wildcard $(SRAM_LIB_DIR)/cells/*/*.gds))
MAG_FILES := $(sort $(wildcard $(SRAM_LIBRARY)/cells/*/*.mag)) 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 SPICE_SUFFIX := spice
SPICE_LVS_SUFFIX := lvs.$(SPICE_SUFFIX) SPICE_LVS_SUFFIX := lvs.$(SPICE_SUFFIX)
SPICE_CALIBRE_SUFFIX := lvs.calibre.$(SPICE_SUFFIX) SPICE_CALIBRE_SUFFIX := lvs.calibre.$(SPICE_SUFFIX)
SPICE_KLAYOUT_SUFFIX := lvs.klayout.$(SPICE_SUFFIX)
SPICE_BASE_SUFFIX := base.$(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)))
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_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) 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 maglef_lib
INSTALL_BASE := $(OPENRAM_HOME)/../technology/sky130 INSTALL_BASE := $(OPENRAM_HOME)/../technology/sky130
INSTALL_DIRS := $(addprefix $(INSTALL_BASE)/,$(INSTALL_BASE_DIRS)) INSTALL_DIRS := $(addprefix $(INSTALL_BASE)/,$(INSTALL_BASE_DIRS))
check-pdk-root:
ifndef PDK_ROOT
$(error PDK_ROOT is undefined, please export it before running make)
endif
install: $(INSTALL_DIRS) $(SKY130_PDKS_DIR): check-pdk-root
@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 libraries/sky130_fd_sc_hd/latest
$(SRAM_LIBRARY): $(OPEN_PDKS_DIR): $(SKY130_PDKS_DIR)
git clone $(SRAM_GIT_REPO) $(SRAM_LIBRARY) @echo "Cloning open_pdks..."
@[ -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)
.PHONY: $(SRAM_LIBRARY) $(INSTALL_DIRS) install $(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 && \
cd sky130 && \
make veryclean && \
make && \
make SHARED_PDKS_PATH=/pdk install"
all: $(SRAM_LIBRARY) $(SRAM_LIB_DIR): check-pdk-root
@echo "Cloning SRAM library..."
@[ -d $(SRAM_LIB_DIR) ] || (\
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) pdk
@[ -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 "Installing sky130 SRAM PDK..."
@echo "PDK_ROOT='$(PDK_ROOT)'" @echo "PDK_ROOT='$(PDK_ROOT)'"
@echo "SRAM_LIBRARY='$(SRAM_LIBRARY)'" @echo "SRAM_LIB_DIR='$(SRAM_LIB_DIR)'"
@echo "OPEN_PDKS='$(OPEN_PDKS)'" @echo "SKY130_PDK='$(SKY130_PDK)'"
make install @make $(INSTALL_DIRS)
.PHONY: install
pdk: $(SKY130_PDK)
@true @true
.PHONY: pdk
$(INSTALL_BASE)/gds_lib: $(GDS_FILES) $(INSTALL_BASE)/gds_lib: $(GDS_FILES)
@echo @echo
@echo "Setting up GDS cell library for OpenRAM." @echo "Setting up GDS cell library for OpenRAM."
@echo "==================================================================" @echo "=================================================================="
mkdir -p $@ mkdir -p $@
@cp -va $? $@ cp -va $? $@
@echo "==================================================================" @echo "=================================================================="
@echo @echo
@ -124,6 +157,18 @@ $(INSTALL_BASE)/calibre_lvs_lib: $(filter %.$(SPICE_CALIBRE_SUFFIX),$(ALL_SPICE_
@echo "==================================================================" @echo "=================================================================="
@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)) $(INSTALL_BASE)/sp_lib: $(filter-out %.$(SPICE_LVS_SUFFIX) %.$(SPICE_CALIBRE_SUFFIX),$(ALL_SPICE_FILES))
@echo @echo
@echo "Setting up spice simulation library for OpenRAM." @echo "Setting up spice simulation library for OpenRAM."
@ -140,10 +185,33 @@ $(INSTALL_BASE)/sp_lib: $(filter-out %.$(SPICE_LVS_SUFFIX) %.$(SPICE_CALIBRE_SUF
@echo "==================================================================" @echo "=================================================================="
@echo @echo
macros:
cd macros && make
.PHONY: macros
clean: clean:
rm -f $(SRAM_LIBRARY) @rm -f *.zip
rm -f $(INSTALL_BASE)/tech/.magicrc .PHONE: clean
rm -f $(INSTALL_BASE)/mag_lib/.magicrc
rm -f $(INSTALL_BASE)/lef_lib/.magicrc uninstall: clean
rm -f $(INSTALL_BASE)/maglef_lib/.magicrc @rm -f $(INSTALL_BASE)/tech/.magicrc
rm -rf $(INSTALL_DIRS) @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
@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_PDKS_DIR)
.PHONY: wipe

24
PORTING.md Normal file
View File

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

136
README.md
View File

@ -28,22 +28,31 @@ things that need to be fixed.
## Dependencies ## Dependencies
The OpenRAM compiler has very few dependencies: Please see the Dockerfile for the required versions of tools.
+ [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 In general, the OpenRAM compiler has very few dependencies:
+ Docker
+ Make
+ Python 3.6 or higher
+ Various Python packages (pip install -r requirements.txt) + Various Python packages (pip install -r requirements.txt)
+ [Git] + [Git]
If you want to perform DRC and LVS, you will need either: ## Docker
+ Calibre (for [FreePDK45])
+ [Magic] 8.3.130 or newer We have a [docker setup](./docker) to run OpenRAM. To use this, you should run:
+ [Netgen] 1.5.164 or newer ```
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: You must set two environment variables:
+ OPENRAM\_HOME should point to the compiler source directory. + OPENRAM\_HOME should point to the compiler source directory.
+ OPENERAM\_TECH should point to one or more root technology directories (colon separated). + OPENERAM\_TECH should point to one or more root technology directories (colon separated).
## Environment
For example add this to your .bashrc: For example add this to your .bashrc:
@ -52,25 +61,36 @@ For example add this to your .bashrc:
export OPENRAM_TECH="$HOME/openram/technology" 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. The We include the tech files necessary for [SCMOS] SCN4M_SUBM,
[SCMOS] spice models, however, are generic and should be replaced with [FreePDK45]. The [SCMOS] spice models, however, are
foundry models. If you are using [FreePDK45], you should also have generic and should be replaced with foundry models. You may get the
that set up and have the environment variable point to the PDK. For entire [FreePDK45 PDK here][FreePDK45].
example add this to your .bashrc:
```
export FREEPDK45="/bsoe/software/design-kits/FreePDK45"
```
You may get the entire [FreePDK45 PDK here][FreePDK45]. ### Sky130 Setup
If you are using [SCMOS], you should install [Magic] and [Netgen].
We have included the most recent SCN4M_SUBM design rules from [Qflow]. 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 # Basic Usage
@ -79,7 +99,6 @@ using a single configuration file written in Python.
For example, create a file called *myconfig.py* specifying the following For example, create a file called *myconfig.py* specifying the following
parameters for your memory: parameters for your memory:
``` ```
# Data word size # Data word size
word_size = 2 word_size = 2
@ -116,6 +135,12 @@ python3 $OPENRAM_HOME/openram.py myconfig
You can see all of the options for the configuration file in You can see all of the options for the configuration file in
$OPENRAM\_HOME/options.py $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 # Unit Tests
Regression testing performs a number of tests for all modules in OpenRAM. Regression testing performs a number of tests for all modules in OpenRAM.
@ -123,50 +148,39 @@ From the unit test directory ($OPENRAM\_HOME/tests),
use the following command to run all regression tests: use the following command to run all regression tests:
``` ```
python3 regress.py cd openram/compiler/tests
make -j 3
``` ```
To run a specific test: The -j can run with 3 threads. By default, this will run in all technologies.
To run a specific test in all technologies:
``` ```
python3 {unit test}.py cd openram/compiler/tests
make 05_bitcell_array_test
``` ```
The unit tests take the same arguments as openram.py itself. To run a specific technology:
To increase the verbosity of the test, add one (or more) -v options:
``` ```
python3 tests/00_code_format_check_test.py -v -t freepdk45 cd openram/compiler/tests
TECHS=scn4m_subm make 05_bitcell_array_test
``` ```
To specify a particular technology use "-t <techname>" such as
"-t freepdk45". The default for a unit test is scn4m_subm.
The default for openram.py is specified in the configuration file.
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
```
# Porting to a New Technology Unit test results are put in a directory:
```
If you want to support a new technology, you will need to create: openram/compiler/tests/results/<technology>/<test>
+ a setup script for each technology you want to use ```
+ a technology directory for each technology with the base cells 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.
We provide two technology examples for [SCMOS] and [FreePDK45]. Each You can view the .out file to see what the output of a test is in either case.
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 # Get Involved
+ [Port it](./PORTING.md) to a new technology.
+ Report bugs by submitting [Github issues]. + Report bugs by submitting [Github issues].
+ Develop new features (see [how to contribute](./CONTRIBUTING.md)) + 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]
@ -180,6 +194,7 @@ specific technology (e.g., [FreePDK45]) should be a subdirectory
+ [OpenRAM Slack Workspace][Slack] + [OpenRAM Slack Workspace][Slack]
+ [OpenRAM Users Group][user-group] ([subscribe here][user-group-subscribe]) + [OpenRAM Users Group][user-group] ([subscribe here][user-group-subscribe])
+ [OpenRAM Developers Group][dev-group] ([subscribe here][dev-group-subscribe]) + [OpenRAM Developers Group][dev-group] ([subscribe here][dev-group-subscribe])
+ <a rel="me" href="https://fosstodon.org/@mrg">@mrg@fostodon.org</a>
# License # License
@ -203,7 +218,7 @@ If I forgot to add you, please let me know!
[Github issues]: https://github.com/VLSIDA/OpenRAM/issues [Github issues]: https://github.com/VLSIDA/OpenRAM/issues
[Github pull request]: https://github.com/VLSIDA/OpenRAM/pulls [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 [documentation]: https://docs.google.com/presentation/d/10InGB33N51I6oBHnqpU7_w9DXlx-qe9zdrlco2Yc5co/edit?usp=sharing
[dev-group]: mailto:openram-dev-group@ucsc.edu [dev-group]: mailto:openram-dev-group@ucsc.edu
@ -211,6 +226,7 @@ If I forgot to add you, please let me know!
[dev-group-subscribe]: mailto:openram-dev-group+subscribe@ucsc.edu [dev-group-subscribe]: mailto:openram-dev-group+subscribe@ucsc.edu
[user-group-subscribe]: mailto:openram-user-group+subscribe@ucsc.edu [user-group-subscribe]: mailto:openram-user-group+subscribe@ucsc.edu
[Klayout]: https://www.klayout.de/
[Magic]: http://opencircuitdesign.com/magic/ [Magic]: http://opencircuitdesign.com/magic/
[Netgen]: http://opencircuitdesign.com/netgen/ [Netgen]: http://opencircuitdesign.com/netgen/
[Qflow]: http://opencircuitdesign.com/qflow/history.html [Qflow]: http://opencircuitdesign.com/qflow/history.html
@ -218,8 +234,10 @@ If I forgot to add you, please let me know!
[Xyce]: http://xyce.sandia.gov/ [Xyce]: http://xyce.sandia.gov/
[Git]: https://git-scm.com/ [Git]: https://git-scm.com/
[OSUPDK]: https://vlsiarch.ecen.okstate.edu/flow/
[FreePDK45]: https://www.eda.ncsu.edu/wiki/FreePDK45:Contents [FreePDK45]: https://www.eda.ncsu.edu/wiki/FreePDK45:Contents
[SCMOS]: https://www.mosis.com/files/scmos/scmos.pdf [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/zt-onim74ue-zlttW5XI30xvdBlJGJF6JA
[Slack]: https://join.slack.com/t/openram/shared_invite/enQtNDgxMjc3NzU5NTI1LWZiYWMwNjNkZThmYTdkODc3NDE1NDhjNzUxNDhmMDQ4ZTM3NDgwNWFlNjM5NWFiZDkyMzBlNzc1NTg3ZjllNTY

View File

@ -104,4 +104,3 @@ clean_model:
clean: clean:
find . -name \*.pyc -exec rm {} \; find . -name \*.pyc -exec rm {} \;
find . -name \*~ -exec rm {} \; find . -name \*~ -exec rm {} \;

21
compiler/base/__init__.py Normal file
View File

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

View File

@ -8,8 +8,8 @@
import collections import collections
import debug import debug
from tech import drc from tech import drc
from vector import vector from .vector import vector
import design from .design import design
class channel_net(): class channel_net():
@ -75,7 +75,7 @@ class channel_net():
return min_overlap or max_overlap return min_overlap or max_overlap
class channel_route(design.design): class channel_route(design):
unique_id = 0 unique_id = 0
@ -242,12 +242,12 @@ class channel_route(design.design):
if self.vertical: if self.vertical:
self.add_vertical_trunk_route(net.pins, self.add_vertical_trunk_route(net.pins,
current_offset, current_offset,
self.vertical_nonpref_pitch) self.horizontal_pitch)
current_offset = vector(current_offset.x, net.max_value + self.horizontal_nonpref_pitch) current_offset = vector(current_offset.x, net.max_value + self.horizontal_nonpref_pitch)
else: else:
self.add_horizontal_trunk_route(net.pins, self.add_horizontal_trunk_route(net.pins,
current_offset, current_offset,
self.horizontal_nonpref_pitch) self.vertical_pitch)
current_offset = vector(net.max_value + self.vertical_nonpref_pitch, current_offset.y) current_offset = vector(net.max_value + self.vertical_nonpref_pitch, current_offset.y)
# Remove the net from other constriants in the VCG # Remove the net from other constriants in the VCG

View File

@ -5,16 +5,14 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import hierarchy_design
import debug import debug
from tech import drc, layer from .hierarchy_design import hierarchy_design
import tech from .vector import vector
from vector import vector from tech import drc, layer, preferred_directions
from sram_factory import factory from tech import layer as tech_layers
import sys
class contact(hierarchy_design.hierarchy_design): class contact(hierarchy_design):
""" """
Object for a contact shape with its conductor enclosures. Creates Object for a contact shape with its conductor enclosures. Creates
a contact array minimum active or poly enclosure and metal1 a contact array minimum active or poly enclosure and metal1
@ -51,20 +49,20 @@ class contact(hierarchy_design.hierarchy_design):
# Non-preferred directions # Non-preferred directions
if directions == "nonpref": if directions == "nonpref":
first_dir = "H" if tech.preferred_directions[layer_stack[0]]=="V" else "V" first_dir = "H" if preferred_directions[layer_stack[0]]=="V" else "V"
second_dir = "H" if tech.preferred_directions[layer_stack[2]]=="V" else "V" second_dir = "H" if preferred_directions[layer_stack[2]]=="V" else "V"
self.directions = (first_dir, second_dir) self.directions = (first_dir, second_dir)
# Preferred directions # Preferred directions
elif directions == "pref": elif directions == "pref":
self.directions = (tech.preferred_directions[layer_stack[0]], self.directions = (preferred_directions[layer_stack[0]],
tech.preferred_directions[layer_stack[2]]) preferred_directions[layer_stack[2]])
# User directions # User directions
elif directions: elif directions:
self.directions = directions self.directions = directions
# Preferred directions # Preferred directions
else: else:
self.directions = (tech.preferred_directions[layer_stack[0]], self.directions = (preferred_directions[layer_stack[0]],
tech.preferred_directions[layer_stack[2]]) preferred_directions[layer_stack[2]])
self.offset = vector(0, 0) self.offset = vector(0, 0)
self.implant_type = implant_type self.implant_type = implant_type
self.well_type = well_type self.well_type = well_type
@ -101,7 +99,7 @@ class contact(hierarchy_design.hierarchy_design):
self.second_layer_name = second_layer self.second_layer_name = second_layer
# Contacts will have unique per first 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 self.via_layer_name = via_layer
elif via_layer == "contact": elif via_layer == "contact":
if first_layer in ("active", "poly"): if first_layer in ("active", "poly"):
@ -194,7 +192,7 @@ class contact(hierarchy_design.hierarchy_design):
def create_nitride_cut_enclosure(self): def create_nitride_cut_enclosure(self):
""" Special layer that encloses poly contacts in some processes """ """ Special layer that encloses poly contacts in some processes """
# Check if there is a special poly nitride cut layer # Check if there is a special poly nitride cut layer
if "npc" not in tech.layer: if "npc" not in tech_layers:
return return
npc_enclose_poly = drc("npc_enclose_poly") npc_enclose_poly = drc("npc_enclose_poly")
@ -256,7 +254,7 @@ class contact(hierarchy_design.hierarchy_design):
# Optionally implant well if layer exists # Optionally implant well if layer exists
well_layer = "{}well".format(self.well_type) 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) well_width_rule = drc("minwidth_" + well_layer)
self.well_enclose_active = drc(well_layer + "_enclose_active") self.well_enclose_active = drc(well_layer + "_enclose_active")
self.well_width = max(self.first_layer_width + 2 * self.well_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() 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)

View File

@ -5,15 +5,13 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
from hierarchy_design import hierarchy_design import debug
import utils
import contact
from tech import GDS, layer from tech import GDS, layer
from tech import preferred_directions from tech import preferred_directions
from tech import cell_properties as props from tech import cell_properties as props
from globals import OPTS from globals import OPTS
import re from . import utils
import debug from .hierarchy_design import hierarchy_design
class design(hierarchy_design): class design(hierarchy_design):
@ -68,207 +66,20 @@ class design(hierarchy_design):
self.setup_multiport_constants() 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): def check_pins(self):
for pin_name in self.pins: for pin_name in self.pins:
pins = self.get_pins(pin_name) pins = self.get_pins(pin_name)
for pin in pins: for pin in pins:
print(pin_name, pin) 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): def setup_multiport_constants(self):
""" """
These are contants and lists that aid multiport design. These are contants and lists that aid multiport design.
@ -316,6 +127,4 @@ class design(hierarchy_design):
total_module_power += inst.mod.analytical_power(corner, load) total_module_power += inst.mod.analytical_power(corner, load)
return total_module_power return total_module_power
design.setup_drc_constants()
design.setup_layer_constants()

View File

@ -9,13 +9,13 @@
This provides a set of useful generic types for the gdsMill interface. This provides a set of useful generic types for the gdsMill interface.
""" """
import debug import debug
from vector import vector from .vector import vector
import tech import tech
import math import math
import copy import copy
import numpy as np import numpy as np
from globals import OPTS from globals import OPTS
from utils import round_to_grid from .utils import round_to_grid
class geometry: class geometry:

View File

@ -5,13 +5,14 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import hierarchy_layout from .hierarchy_layout import layout
import hierarchy_spice from .hierarchy_spice import spice
import debug import debug
import os
from globals import OPTS 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. Design Class for all modules to inherit the base features.
Class consisting of a set of modules and instances of these modules Class consisting of a set of modules and instances of these modules
@ -22,8 +23,17 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
self.drc_errors = "skipped" self.drc_errors = "skipped"
self.lvs_errors = "skipped" self.lvs_errors = "skipped"
hierarchy_spice.spice.__init__(self, name, cell_name) # Flag for library cells which is recomputed in hierachy_layout
hierarchy_layout.layout.__init__(self, name, cell_name) 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 and not name.startswith(OPTS.output_name):
name = OPTS.output_name + "_" + name
cell_name = name
spice.__init__(self, name, cell_name)
layout.__init__(self, name, cell_name)
self.init_graph_params() self.init_graph_params()
def get_layout_pins(self, inst): def get_layout_pins(self, inst):

File diff suppressed because it is too large Load Diff

View File

@ -12,10 +12,11 @@ import math
import tech import tech
from globals import OPTS from globals import OPTS
from pprint import pformat from pprint import pformat
from delay_data import delay_data from .delay_data import delay_data
from wire_spice_model import wire_spice_model from .wire_spice_model import wire_spice_model
from power_data import power_data from .power_data import power_data
import logical_effort from .logical_effort import convert_relative_c_to_farad, convert_farad_to_relative_c
class spice(): class spice():
""" """
@ -36,19 +37,20 @@ class spice():
# If we have a separate lvs directory, then all the lvs files # If we have a separate lvs directory, then all the lvs files
# should be in there (all or nothing!) # should be in there (all or nothing!)
try: try:
lvs_subdir = tech.lvs_lib from tech import lvs_name
except AttributeError: lvs_dir = OPTS.openram_tech + lvs_name + "_lvs_lib/"
lvs_subdir = "lvs_lib" except ImportError:
lvs_dir = OPTS.openram_tech + lvs_subdir + "/" 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"
self.lvs_file = lvs_dir + cell_name + ".sp" if not os.path.exists(self.lvs_file):
else:
self.lvs_file = self.sp_file self.lvs_file = self.sp_file
self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "BIAS", "POWER", "GROUND"] self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "BIAS", "POWER", "GROUND"]
# Holds subckts/mods for this module # Holds subckts/mods for this module
self.mods = [] self.mods = set()
# Holds the pins for this module (in order) # Holds the pins for this module (in order)
self.pins = [] self.pins = []
# The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND # The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND
@ -187,10 +189,6 @@ class spice():
inout_list.append(pin) inout_list.append(pin)
return inout_list 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): def connect_inst(self, args, check=True):
""" """
Connects the pins of the last instance added Connects the pins of the last instance added
@ -281,7 +279,10 @@ class spice():
# parses line into ports and remove subckt # parses line into ports and remove subckt
lvs_pins = subckt_line.split(" ")[2:] lvs_pins = subckt_line.split(" ")[2:]
debug.check(lvs_pins == self.pins, 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): 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.""" """Checks if a net name exists in the current. Intended to be check nets in hand-made cells."""
@ -442,7 +443,7 @@ class spice():
# FIXME: Slew is not used in the model right now. # FIXME: Slew is not used in the model right now.
# Can be added heuristically as linear factor # 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) stage_effort = self.get_stage_effort(relative_cap)
# If it fails, then keep running with a valid object. # If it fails, then keep running with a valid object.
@ -510,7 +511,7 @@ class spice():
# Override this function within a module if a more accurate input capacitance is needed. # Override this function within a module if a more accurate input capacitance is needed.
# Input/outputs with differing capacitances is not implemented. # Input/outputs with differing capacitances is not implemented.
relative_cap = self.input_load() 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): def input_load(self):
"""Inform users undefined relative capacitance functions used for analytical delays.""" """Inform users undefined relative capacitance functions used for analytical delays."""

View File

@ -6,12 +6,12 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
from base import vector
from base import pin_layout
from tech import layer_names from tech import layer_names
import os import os
import shutil import shutil
from globals import OPTS from globals import OPTS
from vector import vector
from pin_layout import pin_layout
class lef: class lef:
@ -119,14 +119,13 @@ class lef:
old_blockages = list(self.blockages[pin.layer]) old_blockages = list(self.blockages[pin.layer])
for blockage in old_blockages: for blockage in old_blockages:
if blockage.overlaps(inflated_pin): 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 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 continue
# Remove the old blockage and add the new ones # Remove the old blockage and add the new ones
self.blockages[pin.layer].remove(blockage) self.blockages[pin.layer].remove(blockage)
intersection_pin = pin_layout("", intersection_shape, inflated_pin.layer)
new_blockages = blockage.cut(intersection_pin) new_blockages = blockage.cut(intersection_pin)
self.blockages[pin.layer].extend(new_blockages) self.blockages[pin.layer].extend(new_blockages)
# We split something so make another pass # We split something so make another pass

View File

@ -6,7 +6,7 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
from tech import drc, parameter, spice from tech import parameter
class logical_effort(): class logical_effort():
""" """

View File

@ -7,7 +7,7 @@
# #
import debug import debug
from tech import GDS, drc from tech import GDS, drc
from vector import vector from .vector import vector
from tech import layer, layer_indices from tech import layer, layer_indices
import math import math
@ -174,6 +174,10 @@ class pin_layout:
def intersection(self, other): def intersection(self, other):
""" Check if a shape overlaps with a rectangle """ """ Check if a shape overlaps with a rectangle """
if not self.overlaps(other):
return None
(ll, ur) = self.rect (ll, ur) = self.rect
(oll, our) = other.rect (oll, our) = other.rect
@ -182,7 +186,10 @@ class pin_layout:
min_y = max(ll.y, oll.y) min_y = max(ll.y, oll.y)
max_y = min(ur.y, our.y) max_y = min(ur.y, our.y)
return [vector(min_x, min_y), vector(max_x, max_y)] if max_x - min_x == 0 or max_y - min_y == 0:
return None
return pin_layout("", [vector(min_x, min_y), vector(max_x, max_y)], self.layer)
def xoverlaps(self, other): def xoverlaps(self, other):
""" Check if shape has x overlap """ """ Check if shape has x overlap """
@ -504,12 +511,19 @@ class pin_layout:
elif other.contains(self): elif other.contains(self):
return math.inf return math.inf
else: 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 # This is the common case where two pairs of edges overlap
# at two points, so just find the distance between those two points # at two points, so just find the distance between those two points
if len(intersections) == 2: if len(intersections) == 2:
(p1, p2) = intersections (p1, p2) = intersections
return math.sqrt(pow(p1[0]-p2[0], 2) + pow(p1[1]-p2[1], 2)) 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: else:
# This is where we had a corner intersection or none # This is where we had a corner intersection or none
return 0 return 0

View File

@ -5,12 +5,12 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
from tech import drc
import debug 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 itertools import tee
from vector import vector
from vector3d import vector3d
from sram_factory import factory from sram_factory import factory
class route(design): class route(design):

View File

@ -8,12 +8,12 @@
import os import os
import math import math
import gdsMill from gdsMill import gdsMill
import tech import tech
import globals import globals
import debug import debug
from vector import vector from .vector import vector
from pin_layout import pin_layout from .pin_layout import pin_layout
try: try:
from tech import special_purposes from tech import special_purposes
except ImportError: except ImportError:

View File

@ -51,6 +51,7 @@ class vector():
else: else:
self.x=float(value[0]) self.x=float(value[0])
self.y=float(value[1]) self.y=float(value[1])
self._hash = hash((self.x,self.y))
def __getitem__(self, index): def __getitem__(self, index):
""" """
@ -104,6 +105,7 @@ class vector():
def snap_to_grid(self): def snap_to_grid(self):
self.x = self.snap_offset_to_grid(self.x) self.x = self.snap_offset_to_grid(self.x)
self.y = self.snap_offset_to_grid(self.y) self.y = self.snap_offset_to_grid(self.y)
self._hash = hash((self.x,self.y))
return self return self
def snap_offset_to_grid(self, offset): def snap_offset_to_grid(self, offset):

View File

@ -94,12 +94,12 @@ class verilog:
self.vf.write("\n") 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: for port in self.all_ports:
self.register_inputs(port) 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: for port in self.all_ports:
if port in self.write_ports: if port in self.write_ports:
self.add_write_block(port) self.add_write_block(port)
@ -162,7 +162,7 @@ class verilog:
if port in self.read_ports: if port in self.read_ports:
self.vf.write(" #(T_HOLD) dout{0} = {1}'bx;\n".format(port, self.word_size)) self.vf.write(" #(T_HOLD) dout{0} = {1}'bx;\n".format(port, self.word_size))
if port in self.readwrite_ports: 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)) 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: elif port in self.read_ports:
self.vf.write(" if ( !csb{0}_reg && VERBOSE ) \n".format(port)) self.vf.write(" if ( !csb{0}_reg && VERBOSE ) \n".format(port))

View File

@ -6,8 +6,7 @@
# All rights reserved. # All rights reserved.
# #
from tech import drc from tech import drc
import contact from .wire_path import wire_path
from wire_path import wire_path
from sram_factory import factory from sram_factory import factory
@ -69,15 +68,24 @@ class wire(wire_path):
This is contact direction independent pitch, This is contact direction independent pitch,
i.e. we take the maximum contact dimension 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 (layer1, via, layer2) = layer_stack
if layer1 == "poly" or layer1 == "active": if layer1 == "poly" or layer1 == "active":
contact1 = getattr(contact, layer1 + "_contact") try:
contact1 = getattr(layout, layer1 + "_contact")
except AttributeError:
breakpoint()
else: else:
try: try:
contact1 = getattr(contact, layer1 + "_via") contact1 = getattr(layout, layer1 + "_via")
except AttributeError: except AttributeError:
contact1 = getattr(contact, layer2 + "_via") contact1 = getattr(layout, layer2 + "_via")
max_contact = max(contact1.width, contact1.height) max_contact = max(contact1.width, contact1.height)
layer1_space = drc("{0}_to_{0}".format(layer1)) layer1_space = drc("{0}_to_{0}".format(layer1))

View File

@ -5,11 +5,11 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
from .vector import vector
from .utils import snap_to_grid
from .design import design
from tech import drc from tech import drc
from tech import layer as techlayer from tech import layer as techlayer
import debug
from vector import vector
from utils import snap_to_grid
def create_rectilinear_route(my_list): def create_rectilinear_route(my_list):
""" Add intermediate nodes if it isn't rectilinear. Also skip """ Add intermediate nodes if it isn't rectilinear. Also skip

View File

@ -10,7 +10,7 @@ import math
import tech import tech
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
import timing_graph from base import timing_graph
class simulation(): class simulation():
@ -572,7 +572,7 @@ class simulation():
self.sram.graph_exclude_column_mux(self.bitline_column, port) self.sram.graph_exclude_column_mux(self.bitline_column, port)
# Generate new graph every analysis as edges might change depending on test bit # 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_instance_name = "X{}".format(self.sram.name)
self.sram.build_graph(self.graph, self.sram_instance_name, self.pins) self.sram.build_graph(self.graph, self.sram_instance_name, self.pins)

View File

@ -0,0 +1 @@
from .datasheet_gen import datasheet_gen

View File

@ -5,7 +5,7 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
from table_gen import * from .table_gen import *
import os import os
import base64 import base64
from globals import OPTS from globals import OPTS

View File

@ -19,8 +19,8 @@ from globals import OPTS
import os import os
import math import math
import csv import csv
import datasheet from .datasheet import datasheet
import table_gen from .table_gen import table_gen
# def process_name(corner): # def process_name(corner):
# """ # """
@ -400,7 +400,7 @@ def parse_characterizer_csv(f, pages):
if found == 0: if found == 0:
# if this is the first corner for this sram, run first time configuration and set up tables # 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) pages.append(new_sheet)
new_sheet.git_id = ORIGIN_ID 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, 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] 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( new_sheet.corners_table.add_row(
['Transistor Type', 'Power Supply', 'Temperature', 'Corner Name']) ['Transistor Type', 'Power Supply', 'Temperature', 'Corner Name'])
new_sheet.corners_table.add_row( new_sheet.corners_table.add_row(
[PROC, VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')]) [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") "operating_table")
new_sheet.operating_table.add_row( new_sheet.operating_table.add_row(
['Parameter', 'Min', 'Typ', 'Max', 'Units']) ['Parameter', 'Min', 'Typ', 'Max', 'Units'])
@ -432,10 +432,10 @@ def parse_characterizer_csv(f, pages):
# failed to provide non-zero MIN_PERIOD # failed to provide non-zero MIN_PERIOD
new_sheet.operating_table.add_row( new_sheet.operating_table.add_row(
['Operating Frequency (F)', '', '', "not available in netlist only", 'MHz']) ['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( new_sheet.power_table.add_row(
['Pins', 'Mode', 'Power', 'Units']) ['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( new_sheet.timing_table.add_row(
['Parameter', 'Min', 'Max', 'Units']) ['Parameter', 'Min', 'Max', 'Units'])
# parse initial timing information # parse initial timing information
@ -592,10 +592,10 @@ def parse_characterizer_csv(f, pages):
else: else:
break 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.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']) new_sheet.io_table.add_row(['Type', 'Value'])
if not OPTS.netlist_only: if not OPTS.netlist_only:

View File

@ -5,6 +5,8 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
class table_gen: class table_gen:
"""small library of functions to generate the html tables""" """small library of functions to generate the html tables"""

6
compiler/drc/__init__.py Normal file
View File

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

View File

@ -156,6 +156,16 @@ class bitcell(cell):
self.storage_nets = storage_nets 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(): class cell_properties():
""" """

View File

@ -6,8 +6,8 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
from drc_value import * from .drc_value import *
from drc_lut import * from .drc_lut import *
class design_rules(dict): class design_rules(dict):

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -22,7 +22,7 @@ import getpass
import subprocess import subprocess
VERSION = "1.1.19" VERSION = "1.2.0"
NAME = "OpenRAM v{}".format(VERSION) NAME = "OpenRAM v{}".format(VERSION)
USAGE = "openram.py [options] <config file>\nUse -h for help.\n" USAGE = "openram.py [options] <config file>\nUse -h for help.\n"
@ -252,7 +252,8 @@ def setup_bitcell():
# See if bitcell exists # See if bitcell exists
try: try:
__import__(OPTS.bitcell) c = importlib.import_module("modules." + OPTS.bitcell)
mod = getattr(c, OPTS.bitcell)
except ImportError: except ImportError:
# Use the pbitcell if we couldn't find a custom bitcell # Use the pbitcell if we couldn't find a custom bitcell
# or its custom replica bitcell # or its custom replica bitcell
@ -377,7 +378,6 @@ def read_config(config_file, is_unit_test=True):
ports, ports,
OPTS.tech_name) OPTS.tech_name)
def end_openram(): def end_openram():
""" Clean up openram for a proper exit """ """ Clean up openram for a proper exit """
cleanup_paths() cleanup_paths()
@ -431,19 +431,12 @@ def setup_paths():
OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME")) OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME"))
except: except:
debug.error("$OPENRAM_HOME is not properly defined.", 1) debug.error("$OPENRAM_HOME is not properly defined.", 1)
debug.check(os.path.isdir(OPENRAM_HOME), debug.check(os.path.isdir(OPENRAM_HOME),
"$OPENRAM_HOME does not exist: {0}".format(OPENRAM_HOME)) "$OPENRAM_HOME does not exist: {0}".format(OPENRAM_HOME))
# Add all of the subdirs to the python path if OPENRAM_HOME not in sys.path:
# These subdirs are modules and don't need debug.error("Please add OPENRAM_HOME to the PYTHONPATH.", -1)
# 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))
# Use a unique temp subdirectory if multithreaded # Use a unique temp subdirectory if multithreaded
if OPTS.num_threads > 1 or OPTS.openram_temp == "/tmp": if OPTS.num_threads > 1 or OPTS.openram_temp == "/tmp":
@ -570,18 +563,18 @@ def import_tech():
OPTS.openram_tech = os.path.dirname(tech_mod.__file__) + "/" 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 tech_path = OPTS.openram_tech
sys.path.append(tech_path) sys.path.insert(0, tech_path)
try: try:
import tech import tech
except ImportError: except ImportError:
debug.error("Could not load tech module.", -1) 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/") custom_mod_path = os.path.join(tech_path, "modules/")
if os.path.exists(custom_mod_path): 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): def print_time(name, now_time, last_time=None, indentation=2):

View File

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

View File

@ -6,20 +6,20 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
from vector import vector from base import vector
import design from base import design
from sram_factory import factory from sram_factory import factory
from globals import OPTS from globals import OPTS
from tech import layer from tech import layer
class and2_dec(design.design): class and2_dec(design):
""" """
This is an AND with configurable drive strength. This is an AND with configurable drive strength.
""" """
def __init__(self, name, size=1, height=None, add_wells=True): 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)) debug.info(1, "Creating and2_dec {}".format(name))
self.add_comment("size: {}".format(size)) self.add_comment("size: {}".format(size))
@ -43,9 +43,6 @@ class and2_dec(design.design):
height=self.height, height=self.height,
size=self.size) size=self.size)
self.add_mod(self.nand)
self.add_mod(self.inv)
def create_layout(self): def create_layout(self):
if "li" in layer: if "li" in layer:

View File

@ -6,19 +6,19 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
from vector import vector from base import design
import design from base import vector
from sram_factory import factory from sram_factory import factory
from globals import OPTS from globals import OPTS
from tech import layer from tech import layer
class and3_dec(design.design): class and3_dec(design):
""" """
This is an AND with configurable drive strength. This is an AND with configurable drive strength.
""" """
def __init__(self, name, size=1, height=None, add_wells=True): 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)) debug.info(1, "Creating and3_dec {}".format(name))
self.add_comment("size: {}".format(size)) self.add_comment("size: {}".format(size))
self.size = size self.size = size
@ -41,9 +41,6 @@ class and3_dec(design.design):
height=self.height, height=self.height,
size=self.size) size=self.size)
self.add_mod(self.nand)
self.add_mod(self.inv)
def create_layout(self): def create_layout(self):
if "li" in layer: if "li" in layer:
self.route_layer = "li" self.route_layer = "li"

View File

@ -6,20 +6,20 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
from vector import vector from base import design
import design from base import vector
from sram_factory import factory from sram_factory import factory
from globals import OPTS from globals import OPTS
from tech import layer from tech import layer
class and4_dec(design.design): class and4_dec(design):
""" """
This is an AND with configurable drive strength. This is an AND with configurable drive strength.
""" """
def __init__(self, name, size=1, height=None, add_wells=True): 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)) debug.info(1, "Creating and4_dec {}".format(name))
self.add_comment("size: {}".format(size)) self.add_comment("size: {}".format(size))
@ -43,9 +43,6 @@ class and4_dec(design.design):
height=self.height, height=self.height,
size=self.size) size=self.size)
self.add_mod(self.nand)
self.add_mod(self.inv)
def create_layout(self): def create_layout(self):
if "li" in layer: if "li" in layer:
self.route_layer = "li" self.route_layer = "li"
@ -129,4 +126,3 @@ class and4_dec(design.design):
offset=pin.center(), offset=pin.center(),
width=pin.width(), width=pin.width(),
height=pin.height()) height=pin.height())

View File

@ -6,16 +6,16 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import design from base import design
from base import vector
from sram_factory import factory from sram_factory import factory
from math import log, ceil, floor from math import log, ceil, floor
from tech import drc from tech import drc
from vector import vector
from globals import OPTS from globals import OPTS
from tech import layer_properties as layer_props from tech import layer_properties as layer_props
class bank(design.design): class bank(design):
""" """
Dynamically generated a single bank including bitcell array, Dynamically generated a single bank including bitcell array,
hierarchical_decoder, precharge, (optional column_mux and column decoder), hierarchical_decoder, precharge, (optional column_mux and column decoder),
@ -229,7 +229,7 @@ class bank(design.design):
# UPPER LEFT QUADRANT # UPPER LEFT QUADRANT
# To the left of the bitcell array above the predecoders and control logic # 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.port_address_offsets[port] = vector(-x_offset,
self.main_bitcell_array_bottom) self.main_bitcell_array_bottom)
@ -272,7 +272,7 @@ class bank(design.design):
# LOWER RIGHT QUADRANT # LOWER RIGHT QUADRANT
# To the right of the bitcell array # 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.port_address_offsets[port] = vector(x_offset,
self.main_bitcell_array_bottom) self.main_bitcell_array_bottom)
@ -364,9 +364,9 @@ class bank(design.design):
self.num_col_addr_lines = 0 self.num_col_addr_lines = 0
self.col_addr_bus_width = self.m2_pitch * self.num_col_addr_lines self.col_addr_bus_width = self.m2_pitch * self.num_col_addr_lines
# A space for wells or jogging m2 # Gap between decoder and array
self.m2_gap = max(2 * drc("pwell_to_nwell") + drc("nwell_enclose_active"), self.decoder_gap = max(2 * drc("pwell_to_nwell") + drc("nwell_enclose_active"),
3 * self.m2_pitch, 2 * self.m2_pitch,
drc("nwell_to_nwell")) drc("nwell_to_nwell"))
def add_modules(self): def add_modules(self):
@ -389,7 +389,6 @@ class bank(design.design):
self.bitcell_array = factory.create(module_type="replica_bitcell_array", self.bitcell_array = factory.create(module_type="replica_bitcell_array",
cols=self.num_cols + self.num_spare_cols, cols=self.num_cols + self.num_spare_cols,
rows=self.num_rows) rows=self.num_rows)
self.add_mod(self.bitcell_array)
self.port_address = [] self.port_address = []
for port in self.all_ports: for port in self.all_ports:
@ -397,21 +396,17 @@ class bank(design.design):
cols=self.num_cols + self.num_spare_cols, cols=self.num_cols + self.num_spare_cols,
rows=self.num_rows, rows=self.num_rows,
port=port)) port=port))
self.add_mod(self.port_address[port])
self.port_data = [] self.port_data = []
self.bit_offsets = self.get_column_offsets() self.bit_offsets = self.get_column_offsets()
for port in self.all_ports: for port in self.all_ports:
temp_pre = factory.create(module_type="port_data", self.port_data.append(factory.create(module_type="port_data",
sram_config=self.sram_config, sram_config=self.sram_config,
port=port, port=port,
bit_offsets=self.bit_offsets) bit_offsets=self.bit_offsets))
self.port_data.append(temp_pre)
self.add_mod(self.port_data[port])
if(self.num_banks > 1): if(self.num_banks > 1):
self.bank_select = factory.create(module_type="bank_select") self.bank_select = factory.create(module_type="bank_select")
self.add_mod(self.bank_select)
def create_bitcell_array(self): def create_bitcell_array(self):
""" Creating Bitcell Array """ """ Creating Bitcell Array """
@ -528,26 +523,9 @@ class bank(design.design):
if self.col_addr_size == 0: if self.col_addr_size == 0:
return 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: else:
# No error checking before? self.column_decoder = factory.create(module_type="column_decoder",
debug.error("Invalid column decoder?", -1) col_addr_size=self.col_addr_size)
self.add_mod(self.column_decoder)
self.column_decoder_inst = [None] * len(self.all_ports) self.column_decoder_inst = [None] * len(self.all_ports)
for port in self.all_ports: for port in self.all_ports:
@ -611,15 +589,22 @@ class bank(design.design):
def route_supplies(self): def route_supplies(self):
""" Propagate all vdd/gnd pins up to this level for all modules """ """ Propagate all vdd/gnd pins up to this level for all modules """
# Copy only the power pins already on the power layer # Copy only the power pins already on the power layer
# (this won't add vias to internal bitcell pins, for example) # (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) # This avoids getting copy errors on vias and other instances
self.copy_power_pins(inst, "gnd", add_vias=False) 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: 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']): 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. # If we use the pinvbuf as the decoder, we need to add power pins.
# Other decoders already have them. # Other decoders already have them.
@ -926,23 +911,14 @@ class bank(design.design):
stack = getattr(self, layer_props.bank.stack) stack = getattr(self, layer_props.bank.stack)
pitch = getattr(self, layer_props.bank.pitch) 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] for i in range(self.col_addr_size):
decode_names = ["Zb", "Z"] decoder_name = "in_{}".format(i)
addr_name = "addr{0}_{1}".format(port, i)
# The Address LSB self.copy_layout_pin(self.column_decoder_inst[port], decoder_name, addr_name)
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)
if port % 2: if port % 2:
offset = self.column_decoder_inst[port].ll() - vector((self.num_col_addr_lines + 1) * pitch, 0) offset = self.column_decoder_inst[port].ll() - vector((self.num_col_addr_lines + 1) * pitch, 0)

View File

@ -5,19 +5,16 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import sys from tech import drc
from tech import drc, parameter from base import design
import debug from base import vector
import design from pgates import pinv
import contact from pgates import pnand2
from pinv import pinv from pgates import pnor2
from pnand2 import pnand2
from pnor2 import pnor2
from vector import vector
from sram_factory import factory from sram_factory import factory
from globals import OPTS 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 """Create a bank select signal that is combined with an array of
NOR+INV gates to gate the control signals in case of multiple NOR+INV gates to gate the control signals in case of multiple
banks are created in upper level SRAM module banks are created in upper level SRAM module
@ -78,20 +75,15 @@ class bank_select(design.design):
# 1x Inverter # 1x Inverter
self.inv_sel = factory.create(module_type="pinv", height=height) self.inv_sel = factory.create(module_type="pinv", height=height)
self.add_mod(self.inv_sel)
# 4x Inverter # 4x Inverter
self.inv4x = factory.create(module_type="pinv", height=height, size=4) 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.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.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.nand2 = factory.create(module_type="pnand2", height=height)
self.add_mod(self.nand2)
def calculate_module_offsets(self): def calculate_module_offsets(self):

View File

@ -7,10 +7,10 @@
# #
import debug import debug
from tech import cell_properties as props 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 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 single memory cell used in the design. It is a hand-made cell, so

View File

@ -7,10 +7,10 @@
# #
import debug import debug
from tech import cell_properties as props 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 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 single memory cell used in the design. It is a hand-made cell, so

View File

@ -6,7 +6,7 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
from bitcell_base_array import bitcell_base_array from .bitcell_base_array import bitcell_base_array
from tech import drc, spice from tech import drc, spice
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
@ -46,6 +46,8 @@ class bitcell_array(bitcell_base_array):
self.add_layout_pins() self.add_layout_pins()
self.route_supplies()
self.add_boundary() self.add_boundary()
self.DRC_LVS() self.DRC_LVS()
@ -53,7 +55,6 @@ class bitcell_array(bitcell_base_array):
def add_modules(self): def add_modules(self):
""" Add the modules used in this design """ """ Add the modules used in this design """
self.cell = factory.create(module_type=OPTS.bitcell) self.cell = factory.create(module_type=OPTS.bitcell)
self.add_mod(self.cell)
def create_instances(self): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """

View File

@ -7,18 +7,18 @@
# #
import debug import debug
import design from base import design
from globals import OPTS from globals import OPTS
import logical_effort from base import logical_effort
from tech import parameter, drc, layer, spice from tech import parameter, drc, layer, spice
class bitcell_base(design.design): class bitcell_base(design):
""" """
Base bitcell parameters to be over-riden. Base bitcell parameters to be over-riden.
""" """
def __init__(self, name, cell_name=None, prop=None): 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 # Set the bitcell specific properties
if prop: if prop:
@ -37,12 +37,12 @@ class bitcell_base(design.design):
# min size NMOS gate load # min size NMOS gate load
read_port_load = 0.5 read_port_load = 0.5
return logical_effort.logical_effort('bitline', return logical_effort('bitline',
size, size,
cin, cin,
load + read_port_load, load + read_port_load,
parasitic_delay, parasitic_delay,
False) False)
def analytical_power(self, corner, load): def analytical_power(self, corner, load):
"""Bitcell power in nW. Only characterizes leakage.""" """Bitcell power in nW. Only characterizes leakage."""

View File

@ -6,12 +6,12 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import design from base import design
from sram_factory import factory from sram_factory import factory
from globals import OPTS from globals import OPTS
class bitcell_base_array(design.design): class bitcell_base_array(design):
""" """
Abstract base class for bitcell-arrays -- bitcell, dummy, replica Abstract base class for bitcell-arrays -- bitcell, dummy, replica
""" """
@ -43,11 +43,11 @@ class bitcell_base_array(design.design):
# Make a flat list too # Make a flat list too
self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl] 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: if row_size == None:
row_size = self.row_size 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: for port in self.all_ports:
self.wordline_names[port].append("wl_{0}_{1}".format(port, row)) self.wordline_names[port].append("wl_{0}_{1}".format(port, row))
@ -156,18 +156,15 @@ class bitcell_base_array(design.design):
width=self.width, width=self.width,
height=wl_pin.height()) height=wl_pin.height())
def add_supply_pins(self): def route_supplies(self):
for row in range(self.row_size): for inst in self.cell_inst.values():
for col in range(self.column_size): for pin_name in ["vdd", "gnd"]:
inst = self.cell_inst[row, col] self.copy_layout_pin(inst, pin_name)
for pin_name in ["vdd", "gnd"]:
self.copy_layout_pin(inst, pin_name)
def add_layout_pins(self): def add_layout_pins(self):
""" Add the layout pins """ """ Add the layout pins """
self.add_bitline_pins() self.add_bitline_pins()
self.add_wl_pins() self.add_wl_pins()
self.add_supply_pins()
def _adjust_x_offset(self, xoffset, col, col_offset): def _adjust_x_offset(self, xoffset, col, col_offset):
tempx = xoffset tempx = xoffset

View File

@ -3,7 +3,7 @@
# Copyright (c) 2016-2021 Regents of the University of California # Copyright (c) 2016-2021 Regents of the University of California
# All rights reserved. # 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 sram_factory import factory
from globals import OPTS from globals import OPTS
@ -49,7 +49,6 @@ class col_cap_array(bitcell_base_array):
def add_modules(self): def add_modules(self):
""" Add the modules used in this design """ """ Add the modules used in this design """
self.dummy_cell = factory.create(module_type="col_cap_{}".format(OPTS.bitcell)) self.dummy_cell = factory.create(module_type="col_cap_{}".format(OPTS.bitcell))
self.add_mod(self.dummy_cell)
def create_instances(self): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """
@ -100,5 +99,4 @@ class col_cap_array(bitcell_base_array):
inst = self.cell_inst[row, col] inst = self.cell_inst[row, col]
for pin_name in ["vdd", "gnd"]: for pin_name in ["vdd", "gnd"]:
for pin in inst.get_pins(pin_name): for pin in inst.get_pins(pin_name):
self.copy_power_pin(pin) self.copy_layout_pin(inst, pin_name)

View File

@ -7,16 +7,16 @@
# #
import debug import debug
from tech import cell_properties as props 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. Column end cap cell.
""" """
def __init__(self, name="col_cap_bitcell_1port"): 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") debug.info(2, "Create col_cap bitcell 1 port object")
self.no_instances = True self.no_instances = True

View File

@ -7,16 +7,16 @@
# #
import debug import debug
from tech import cell_properties as props 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. Column end cap cell.
""" """
def __init__(self, name="col_cap_bitcell_2port"): 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") debug.info(2, "Create col_cap bitcell 2 port object")
self.no_instances = True self.no_instances = True

View File

@ -0,0 +1,119 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2022 Regents of the University of California
# All rights reserved.
#
from tech import drc
import debug
from base import design
import math
from sram_factory import factory
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):
"""
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(2, col_addr_size)
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. """
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))
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 """
if self.col_addr_size == 1:
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",)
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)

View File

@ -5,16 +5,17 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import pgate from .pgate import *
import debug import debug
from tech import drc, layer from tech import drc, layer
from vector import vector from base import vector
from .pgate import *
from sram_factory import factory from sram_factory import factory
from tech import cell_properties as cell_props from tech import cell_properties as cell_props
from globals import OPTS from globals import OPTS
class column_mux(pgate.pgate): class column_mux(pgate):
""" """
This module implements the columnmux bitline cell used in the design. This module implements the columnmux bitline cell used in the design.
Creates a single column mux cell with the given integer size relative Creates a single column mux cell with the given integer size relative
@ -77,7 +78,6 @@ class column_mux(pgate.pgate):
self.ptx_width = self.tx_size * drc("minwidth_tx") self.ptx_width = self.tx_size * drc("minwidth_tx")
self.nmos = factory.create(module_type="ptx", self.nmos = factory.create(module_type="ptx",
width=self.ptx_width) width=self.ptx_width)
self.add_mod(self.nmos)
# Space it in the center # Space it in the center
self.nmos_lower = self.add_inst(name="mux_tx1", self.nmos_lower = self.add_inst(name="mux_tx1",
@ -241,10 +241,9 @@ class column_mux(pgate.pgate):
self.add_via_center(layers=self.col_mux_stack, self.add_via_center(layers=self.col_mux_stack,
offset=active_pos) offset=active_pos)
# Add the M1->..->power_grid_layer stack self.add_layout_pin_rect_center(text="gnd",
self.add_power_pin(name="gnd", layer="m1",
loc=active_pos, offset=active_pos)
start_layer="m1")
# Add well enclosure over all the tx and contact # Add well enclosure over all the tx and contact
if "pwell" in layer: if "pwell" in layer:

View File

@ -5,16 +5,16 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import design from base import design
import debug import debug
from tech import layer, preferred_directions from tech import layer, preferred_directions
from vector import vector from base import vector
from sram_factory import factory from sram_factory import factory
from globals import OPTS from globals import OPTS
from tech import layer_properties as layer_props from tech import layer_properties as layer_props
class column_mux_array(design.design): class column_mux_array(design):
""" """
Dynamically generated column mux array. Dynamically generated column mux array.
Array of column mux to read the bitlines through the 6T. Array of column mux to read the bitlines through the 6T.
@ -87,7 +87,6 @@ class column_mux_array(design.design):
self.mux = factory.create(module_type="column_mux", self.mux = factory.create(module_type="column_mux",
bitcell_bl=self.bitcell_bl, bitcell_bl=self.bitcell_bl,
bitcell_br=self.bitcell_br) bitcell_br=self.bitcell_br)
self.add_mod(self.mux)
self.cell = factory.create(module_type=OPTS.bitcell) self.cell = factory.create(module_type=OPTS.bitcell)
@ -148,13 +147,14 @@ class column_mux_array(design.design):
offset=offset, offset=offset,
height=self.height - offset.y) height=self.height - offset.y)
for inst in self.mux_inst: def route_supplies(self):
self.copy_layout_pin(inst, "gnd") self.route_horizontal_pins("gnd", self.insts)
def add_routing(self): def add_routing(self):
self.add_horizontal_input_rail() self.add_horizontal_input_rail()
self.add_vertical_poly_rail() self.add_vertical_poly_rail()
self.route_bitlines() self.route_bitlines()
self.route_supplies()
def add_horizontal_input_rail(self): def add_horizontal_input_rail(self):
""" Create address input rails below the mux transistors """ """ Create address input rails below the mux transistors """
@ -174,16 +174,17 @@ class column_mux_array(design.design):
sel_index = col % self.words_per_row sel_index = col % self.words_per_row
# Add the column x offset to find the right select bit # Add the column x offset to find the right select bit
gate_offset = self.mux_inst[col].get_pin("sel").bc() 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 # use the y offset from the sel pin and the x offset from the gate
offset = vector(gate_offset.x, offset = vector(gate_offset.x,
self.get_pin("sel_{}".format(sel_index)).cy()) self.get_pin("sel_{}".format(sel_index)).cy())
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", self.add_via_stack_center(from_layer="poly",
to_layer=self.sel_layer, to_layer=self.sel_layer,
offset=offset, offset=bl_offset,
directions=self.via_directions) directions=self.via_directions)
self.add_path("poly", [offset, gate_offset]) self.add_path("poly", [offset, gate_offset, bl_offset])
def route_bitlines(self): def route_bitlines(self):
""" Connect the output bit-lines to form the appropriate width mux """ """ Connect the output bit-lines to form the appropriate width mux """

View File

@ -5,16 +5,16 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import design from base import design
import debug import debug
from sram_factory import factory from sram_factory import factory
import math import math
from vector import vector from base import vector
from globals import OPTS 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. 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.num_words = num_rows * words_per_row
self.enable_delay_chain_resizing = False 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. # Determines how much larger the sen delay should be. Accounts for possible error in model.
# FIXME: This should be made a parameter # FIXME: This should be made a parameter
@ -91,17 +91,13 @@ class control_logic(design.design):
rows=self.num_control_signals, rows=self.num_control_signals,
columns=1) columns=1)
self.add_mod(self.ctrl_dff_array)
self.and2 = factory.create(module_type="pand2", self.and2 = factory.create(module_type="pand2",
size=12, size=12,
height=dff_height) height=dff_height)
self.add_mod(self.and2)
self.rbl_driver = factory.create(module_type="pbuf", self.rbl_driver = factory.create(module_type="pbuf",
size=self.num_cols, size=self.num_cols,
height=dff_height) height=dff_height)
self.add_mod(self.rbl_driver)
# clk_buf drives a flop for every address # clk_buf drives a flop for every address
addr_flops = math.log(self.num_words, 2) + math.log(self.words_per_row, 2) addr_flops = math.log(self.num_words, 2) + math.log(self.words_per_row, 2)
@ -114,8 +110,6 @@ class control_logic(design.design):
fanout=clock_fanout, fanout=clock_fanout,
height=dff_height) height=dff_height)
self.add_mod(self.clk_buf_driver)
# We will use the maximum since this same value is used to size the wl_en # We will use the maximum since this same value is used to size the wl_en
# and the p_en_bar drivers # and the p_en_bar drivers
# max_fanout = max(self.num_rows, self.num_cols) # max_fanout = max(self.num_rows, self.num_cols)
@ -126,25 +120,21 @@ class control_logic(design.design):
self.wl_en_driver = factory.create(module_type="pdriver", self.wl_en_driver = factory.create(module_type="pdriver",
size_list=size_list, size_list=size_list,
height=dff_height) height=dff_height)
self.add_mod(self.wl_en_driver)
# w_en drives every write driver # w_en drives every write driver
self.wen_and = factory.create(module_type="pand3", self.wen_and = factory.create(module_type="pand3",
size=self.word_size + 8, size=self.word_size + 8,
height=dff_height) height=dff_height)
self.add_mod(self.wen_and)
# s_en drives every sense amp # s_en drives every sense amp
self.sen_and3 = factory.create(module_type="pand3", self.sen_and3 = factory.create(module_type="pand3",
size=self.word_size + self.num_spare_cols, size=self.word_size + self.num_spare_cols,
height=dff_height) height=dff_height)
self.add_mod(self.sen_and3)
# used to generate inverted signals with low fanout # used to generate inverted signals with low fanout
self.inv = factory.create(module_type="pinv", self.inv = factory.create(module_type="pinv",
size=1, size=1,
height=dff_height) height=dff_height)
self.add_mod(self.inv)
# p_en_bar drives every column in the bitcell array # p_en_bar drives every column in the bitcell array
# but it is sized the same as the wl_en driver with # but it is sized the same as the wl_en driver with
@ -152,17 +142,14 @@ class control_logic(design.design):
self.p_en_bar_driver = factory.create(module_type="pdriver", self.p_en_bar_driver = factory.create(module_type="pdriver",
fanout=self.num_cols, fanout=self.num_cols,
height=dff_height) height=dff_height)
self.add_mod(self.p_en_bar_driver)
self.nand2 = factory.create(module_type="pnand2", self.nand2 = factory.create(module_type="pnand2",
height=dff_height) height=dff_height)
self.add_mod(self.nand2)
debug.check(OPTS.delay_chain_stages % 2, debug.check(OPTS.delay_chain_stages % 2,
"Must use odd number of delay chain stages for inverting delay chain.") "Must use odd number of delay chain stages for inverting delay chain.")
self.delay_chain=factory.create(module_type="delay_chain", self.delay_chain=factory.create(module_type="delay_chain",
fanout_list = OPTS.delay_chain_stages * [ OPTS.delay_chain_fanout_per_stage ]) fanout_list = OPTS.delay_chain_stages * [ OPTS.delay_chain_fanout_per_stage ])
self.add_mod(self.delay_chain)
def get_dynamic_delay_chain_size(self, previous_stages, previous_fanout): def get_dynamic_delay_chain_size(self, previous_stages, previous_fanout):
"""Determine the size of the delay chain used for the Sense Amp Enable using path delays""" """Determine the size of the delay chain used for the Sense Amp Enable using path delays"""
@ -293,7 +280,8 @@ class control_logic(design.design):
def route_rails(self): def route_rails(self):
""" Add the input signal inverted tracks """ """ Add the input signal inverted tracks """
height = self.control_logic_center.y - self.m2_pitch 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", self.input_bus = self.create_vertical_bus("m2",
offset, offset,
@ -325,7 +313,8 @@ class control_logic(design.design):
self.place_dffs() self.place_dffs()
# All of the control logic is placed to the right of the DFFs and bus # 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 row = 0
# Add the logic on the right of the bus # Add the logic on the right of the bus
@ -381,7 +370,7 @@ class control_logic(design.design):
self.route_clk_buf() self.route_clk_buf()
self.route_gated_clk_bar() self.route_gated_clk_bar()
self.route_gated_clk_buf() self.route_gated_clk_buf()
self.route_supply() self.route_supplies()
def create_delay(self): def create_delay(self):
""" Create the replica bitline """ """ Create the replica bitline """
@ -720,28 +709,74 @@ class control_logic(design.design):
start=out_pos, start=out_pos,
end=right_pos) end=right_pos)
def route_supply(self): def route_supplies(self):
""" Add vdd and gnd to the instance cells """ """ 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]
# 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]) 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: for inst in self.row_end_inst:
pins = inst.get_pins("vdd") pins = inst.get_pins("vdd")
for pin in pins: for pin in pins:
if pin.layer == supply_layer: if pin.layer == pin_layer:
row_loc = pin.rc() row_loc = pin.rc()
pin_loc = vector(max_row_x_loc, pin.rc().y) pin_loc = vector(max_row_x_loc, pin.rc().y)
self.add_power_pin("vdd", pin_loc, start_layer=pin.layer) vdd_pin_locs.append(pin_loc)
self.add_path(supply_layer, [row_loc, pin_loc]) 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") pins = inst.get_pins("gnd")
for pin in pins: for pin in pins:
if pin.layer == supply_layer: if pin.layer == pin_layer:
row_loc = pin.rc() row_loc = pin.rc()
pin_loc = vector(max_row_x_loc, pin.rc().y) pin_loc = vector(min_row_x_loc, pin.rc().y)
self.add_power_pin("gnd", pin_loc, start_layer=pin.layer) gnd_pin_locs.append(pin_loc)
self.add_path(supply_layer, [row_loc, pin_loc]) 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 - 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,
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 - 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,
width=via_width)
self.copy_layout_pin(self.delay_inst, "gnd") self.copy_layout_pin(self.delay_inst, "gnd")
self.copy_layout_pin(self.delay_inst, "vdd") self.copy_layout_pin(self.delay_inst, "vdd")
@ -794,7 +829,7 @@ class control_logic(design.design):
# Connect this at the bottom of the buffer # Connect this at the bottom of the buffer
out_pin = inst.get_pin("Z") out_pin = inst.get_pin("Z")
out_pos = out_pin.center() 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) mid2 = vector(self.input_bus[name].cx(), mid1.y)
bus_pos = self.input_bus[name].center() bus_pos = self.input_bus[name].center()
self.add_wire(self.m2_stack[::-1], [out_pos, mid1, mid2, bus_pos]) self.add_wire(self.m2_stack[::-1], [out_pos, mid1, mid2, bus_pos])

View File

@ -6,13 +6,13 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import design from base import design
from vector import vector from base import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory 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. Generate a delay chain with the given number of stages and fanout.
Input is a list contains the electrical effort (fanout) of each stage. Input is a list contains the electrical effort (fanout) of each stage.
@ -69,7 +69,6 @@ class delay_chain(design.design):
self.inv = factory.create(module_type="pinv", self.inv = factory.create(module_type="pinv",
height=dff_height) height=dff_height)
self.add_mod(self.inv)
def create_inverters(self): def create_inverters(self):
""" Create the inverters and connect them based on the stage list """ """ Create the inverters and connect them based on the stage list """
@ -173,20 +172,11 @@ class delay_chain(design.design):
self.add_path("m2", [z_pin.center(), mid1_point, mid2_point, next_a_pin.center()]) self.add_path("m2", [z_pin.center(), mid1_point, mid2_point, next_a_pin.center()])
def route_supplies(self): def route_supplies(self):
# Add power and ground to all the cells except: # These pins get routed in one cell from the left/right
# the fanout driver, the right-most load # because the input signal gets routed on M3 and can interfere with the delay input.
# The routing to connect the loads is over the first and last cells self.route_vertical_pins("vdd", self.driver_inst_list, xside="rx")
# We have an even number of drivers and must only do every other right_load_insts = [self.load_inst_map[x][-1] for x in self.driver_inst_list]
# supply rail self.route_vertical_pins("gnd", right_load_insts, xside="lx")
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))
def add_layout_pins(self): def add_layout_pins(self):
@ -213,4 +203,3 @@ class delay_chain(design.design):
self.add_layout_pin_rect_center(text="out", self.add_layout_pin_rect_center(text="out",
layer="m1", layer="m1",
offset=a_pin.center()) offset=a_pin.center())

View File

@ -5,12 +5,12 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import design from base import design
from tech import cell_properties as props from tech import cell_properties as props
from tech import spice from tech import spice
class dff(design.design): class dff(design):
""" """
Memory address flip-flop Memory address flip-flop
""" """

View File

@ -6,13 +6,13 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import design from base import design
from vector import vector from base import vector
from sram_factory import factory from sram_factory import factory
from globals import OPTS from globals import OPTS
class dff_array(design.design): class dff_array(design):
""" """
This is a simple row (or multiple rows) of flops. This is a simple row (or multiple rows) of flops.
Unlike the data flops, these are never spaced out. Unlike the data flops, these are never spaced out.
@ -42,13 +42,13 @@ class dff_array(design.design):
self.height = self.rows * self.dff.height self.height = self.rows * self.dff.height
self.place_dff_array() self.place_dff_array()
self.route_supplies()
self.add_layout_pins() self.add_layout_pins()
self.add_boundary() self.add_boundary()
self.DRC_LVS() self.DRC_LVS()
def add_modules(self): def add_modules(self):
self.dff = factory.create(module_type="dff") self.dff = factory.create(module_type="dff")
self.add_mod(self.dff)
def add_pins(self): def add_pins(self):
for row in range(self.rows): for row in range(self.rows):
@ -107,17 +107,26 @@ class dff_array(design.design):
return dout_name return dout_name
def route_supplies(self):
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:
# 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(), 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(), start_layer=gnd_pin.layer)
def add_layout_pins(self): 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 row in range(self.rows):
for col in range(self.columns): for col in range(self.columns):
din_pin = self.dff_insts[row, col].get_pin("D") din_pin = self.dff_insts[row, col].get_pin("D")

View File

@ -6,14 +6,14 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import design from base import design
from tech import layer from tech import layer
from vector import vector from base import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
class dff_buf(design.design): class dff_buf(design):
""" """
This is a simple buffered DFF. The output is buffered This is a simple buffered DFF. The output is buffered
with two inverters, of variable size, to provide q with two inverters, of variable size, to provide q
@ -58,17 +58,14 @@ class dff_buf(design.design):
def add_modules(self): def add_modules(self):
self.dff = factory.create(module_type="dff") self.dff = factory.create(module_type="dff")
self.add_mod(self.dff)
self.inv1 = factory.create(module_type="pinv", self.inv1 = factory.create(module_type="pinv",
size=self.inv1_size, size=self.inv1_size,
height=self.dff.height) height=self.dff.height)
self.add_mod(self.inv1)
self.inv2 = factory.create(module_type="pinv", self.inv2 = factory.create(module_type="pinv",
size=self.inv2_size, size=self.inv2_size,
height=self.dff.height) height=self.dff.height)
self.add_mod(self.inv2)
def add_pins(self): def add_pins(self):
self.add_pin_list(["D", "Q", "Qb", "clk", "vdd", "gnd"], self.add_pin_list(["D", "Q", "Qb", "clk", "vdd", "gnd"],

View File

@ -6,13 +6,13 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import design from base import design
from vector import vector from base import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory 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. This is a simple row (or multiple rows) of flops.
Unlike the data flops, these are never spaced out. Unlike the data flops, these are never spaced out.
@ -68,7 +68,6 @@ class dff_buf_array(design.design):
self.dff = factory.create(module_type="dff_buf", self.dff = factory.create(module_type="dff_buf",
inv1_size=self.inv1_size, inv1_size=self.inv1_size,
inv2_size=self.inv2_size) inv2_size=self.inv2_size)
self.add_mod(self.dff)
def create_dff_array(self): def create_dff_array(self):
self.dff_insts={} self.dff_insts={}
@ -155,15 +154,23 @@ class dff_buf_array(design.design):
gndn_pin=self.dff_insts[row, self.columns - 1].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()) self.add_path(gnd0_pin.layer, [gnd0_pin.lc(), gndn_pin.rc()], width=gnd0_pin.height())
for row in range(self.rows): if self.rows > 1:
for col in range(self.columns): # Vertical straps on ends if multiple rows
# Continous vdd rail along with label. left_dff_insts = [self.dff_insts[x, 0] for x in range(self.rows)]
vdd_pin=self.dff_insts[row, col].get_pin("vdd") right_dff_insts = [self.dff_insts[x, self.columns-1] for x in range(self.rows)]
self.copy_power_pin(vdd_pin, loc=vdd_pin.lc()) 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)
# 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): def add_layout_pins(self):

View File

@ -6,14 +6,13 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import design from base import design
from tech import drc from base import vector
from math import log
from vector import vector
from globals import OPTS from globals import OPTS
from pinv import pinv 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 This is a simple DFF with an inverted output. Some DFFs
do not have Qbar, so this will create it. do not have Qbar, so this will create it.
@ -66,12 +65,10 @@ class dff_inv(design.design):
def add_modules(self): def add_modules(self):
self.dff = dff_inv.dff_inv(self.inv_size) self.dff = dff_inv.dff_inv(self.inv_size)
self.add_mod(self.dff)
self.inv1 = factory.create(module_type="pinv", self.inv1 = factory.create(module_type="pinv",
size=self.inv_size, size=self.inv_size,
height=self.dff.height) height=self.dff.height)
self.add_mod(self.inv1)
def create_modules(self): def create_modules(self):
self.dff_inst=self.add_inst(name="dff_inv_dff", self.dff_inst=self.add_inst(name="dff_inv_dff",

View File

@ -6,13 +6,13 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import design from base import design
from vector import vector from base import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory 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. This is a simple row (or multiple rows) of flops.
Unlike the data flops, these are never spaced out. Unlike the data flops, these are never spaced out.
@ -53,7 +53,6 @@ class dff_inv_array(design.design):
def add_modules(self): def add_modules(self):
self.dff = factory.create(module_type="dff") self.dff = factory.create(module_type="dff")
self.add_mod(self.dff)
def add_pins(self): def add_pins(self):
for row in range(self.rows): for row in range(self.rows):
@ -129,11 +128,11 @@ class dff_inv_array(design.design):
for col in range(self.columns): for col in range(self.columns):
# Adds power pin on left of row # Adds power pin on left of row
vdd_pin=self.dff_insts[row,col].get_pin("vdd") 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 # Adds gnd pin on left of row
gnd_pin=self.dff_insts[row,col].get_pin("gnd") 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 row in range(self.rows):
for col in range(self.columns): for col in range(self.columns):

View File

@ -3,7 +3,7 @@
# Copyright (c) 2016-2021 Regents of the University of California # Copyright (c) 2016-2021 Regents of the University of California
# All rights reserved. # 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 sram_factory import factory
from globals import OPTS from globals import OPTS
@ -36,6 +36,8 @@ class dummy_array(bitcell_base_array):
self.add_layout_pins() self.add_layout_pins()
self.route_supplies()
self.add_boundary() self.add_boundary()
self.DRC_LVS() self.DRC_LVS()
@ -45,7 +47,6 @@ class dummy_array(bitcell_base_array):
self.dummy_cell = factory.create(module_type=OPTS.dummy_bitcell) self.dummy_cell = factory.create(module_type=OPTS.dummy_bitcell)
self.cell = factory.create(module_type=OPTS.bitcell) self.cell = factory.create(module_type=OPTS.bitcell)
self.add_mod(self.dummy_cell)
def create_instances(self): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """
@ -99,6 +100,8 @@ class dummy_array(bitcell_base_array):
width=self.width, width=self.width,
height=wl_pin.height()) height=wl_pin.height())
def route_supplies(self):
# Copy a vdd/gnd layout pin from every cell # Copy a vdd/gnd layout pin from every cell
for row in range(self.row_size): for row in range(self.row_size):
for col in range(self.column_size): for col in range(self.column_size):

View File

@ -7,10 +7,10 @@
# #
import debug import debug
from tech import cell_properties as props 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 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 single memory cell used in the design. It is a hand-made cell, so

View File

@ -7,10 +7,10 @@
# #
import debug import debug
from tech import cell_properties as props 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. A single bit cell which is forced to store a 0.
This module implements the single memory cell used in the design. It This module implements the single memory cell used in the design. It

View File

@ -6,13 +6,13 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import design from base import design
from vector import vector from base import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
class dummy_pbitcell(design.design): class dummy_pbitcell(design):
""" """
Creates a replica bitcell using pbitcell Creates a replica bitcell using pbitcell
""" """
@ -23,7 +23,7 @@ class dummy_pbitcell(design.design):
self.num_r_ports = OPTS.num_r_ports self.num_r_ports = OPTS.num_r_ports
self.total_ports = self.num_rw_ports + self.num_w_ports + self.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, 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_w_ports,
self.num_r_ports)) self.num_r_ports))
@ -56,7 +56,6 @@ class dummy_pbitcell(design.design):
def add_modules(self): def add_modules(self):
self.prbc = factory.create(module_type="pbitcell", self.prbc = factory.create(module_type="pbitcell",
dummy_bitcell=True) dummy_bitcell=True)
self.add_mod(self.prbc)
self.height = self.prbc.height self.height = self.prbc.height
self.width = self.prbc.width self.width = self.prbc.width

View File

@ -5,16 +5,16 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import bitcell_base_array from .bitcell_base_array import bitcell_base_array
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
from vector import vector from base import vector
import debug import debug
from numpy import cumsum from numpy import cumsum
from tech import layer_properties as layer_props 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. Creates a global bitcell array.
Rows is an integer number for all local arrays. Rows is an integer number for all local arrays.
@ -64,7 +64,6 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
rbl=self.rbl, rbl=self.rbl,
left_rbl=[0], left_rbl=[0],
right_rbl=[1] if len(self.all_ports) > 1 else []) right_rbl=[1] if len(self.all_ports) > 1 else [])
self.add_mod(la)
self.local_mods.append(la) self.local_mods.append(la)
return return
@ -90,7 +89,6 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
cols=cols, cols=cols,
rbl=self.rbl) rbl=self.rbl)
self.add_mod(la)
self.local_mods.append(la) self.local_mods.append(la)
def add_pins(self): 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""" """Exclude dffs from graph as they do not represent critical path"""
self.graph_inst_exclude.add(self.ctrl_dff_inst) self.graph_inst_exclude.add(self.ctrl_dff_inst)

View File

@ -6,17 +6,17 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import design from base import design
import math import math
from sram_factory import factory from sram_factory import factory
from vector import vector from base import vector
from globals import OPTS from globals import OPTS
from tech import layer_indices from tech import layer_indices
from tech import layer_stacks from tech import layer_stacks
from tech import layer_properties as layer_props from tech import layer_properties as layer_props
from tech import drc from tech import drc
class hierarchical_decoder(design.design): class hierarchical_decoder(design):
""" """
Dynamically generated hierarchical decoder. Dynamically generated hierarchical decoder.
""" """
@ -57,11 +57,12 @@ class hierarchical_decoder(design.design):
self.route_inputs() self.route_inputs()
self.route_outputs() self.route_outputs()
self.route_decoder_bus() self.route_decoder_bus()
self.route_vdd_gnd()
self.offset_x_coordinates() 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_supplies()
self.add_boundary() self.add_boundary()
self.DRC_LVS() self.DRC_LVS()
@ -69,14 +70,11 @@ class hierarchical_decoder(design.design):
def add_modules(self): def add_modules(self):
self.and2 = factory.create(module_type="and2_dec", self.and2 = factory.create(module_type="and2_dec",
height=self.cell_height) height=self.cell_height)
self.add_mod(self.and2)
self.and3 = factory.create(module_type="and3_dec", self.and3 = factory.create(module_type="and3_dec",
height=self.cell_height) height=self.cell_height)
self.add_mod(self.and3)
# TBD # TBD
# self.and4 = factory.create(module_type="and4_dec") # self.and4 = factory.create(module_type="and4_dec")
# self.add_mod(self.and4)
self.add_decoders() self.add_decoders()
@ -84,15 +82,12 @@ class hierarchical_decoder(design.design):
""" Create the decoders based on the number of pre-decodes """ """ Create the decoders based on the number of pre-decodes """
self.pre2_4 = factory.create(module_type="hierarchical_predecode2x4", self.pre2_4 = factory.create(module_type="hierarchical_predecode2x4",
height=self.cell_height) height=self.cell_height)
self.add_mod(self.pre2_4)
self.pre3_8 = factory.create(module_type="hierarchical_predecode3x8", self.pre3_8 = factory.create(module_type="hierarchical_predecode3x8",
height=self.cell_height) height=self.cell_height)
self.add_mod(self.pre3_8)
self.pre4_16 = factory.create(module_type="hierarchical_predecode4x16", self.pre4_16 = factory.create(module_type="hierarchical_predecode4x16",
height=self.cell_height) height=self.cell_height)
self.add_mod(self.pre4_16)
def determine_predecodes(self, num_inputs): def determine_predecodes(self, num_inputs):
""" """
@ -194,7 +189,7 @@ class hierarchical_decoder(design.design):
self.output_layer_pitch = getattr(self, self.output_layer + "_pitch") self.output_layer_pitch = getattr(self, self.output_layer + "_pitch")
# Two extra pitches between modules on left and right # 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 self.row_decoder_height = self.and2.height * self.num_outputs
# Extra bus space for supply contacts # Extra bus space for supply contacts
@ -501,11 +496,11 @@ class hierarchical_decoder(design.design):
if (self.num_inputs >= 4): if (self.num_inputs >= 4):
# This leaves an offset for the predecoder output jogs # 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)] 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, self.predecode_bus = self.create_vertical_bus(layer=self.bus_layer,
pitch=self.bus_pitch, pitch=self.bus_pitch,
offset=vector(self.bus_pitch, 0), offset=vector(self.bus_pitch, 0),
names=input_bus_names, names=input_bus_names,
length=self.height) length=self.height)
self.route_bus_to_decoder() self.route_bus_to_decoder()
self.route_predecodes_to_bus() self.route_predecodes_to_bus()
@ -593,44 +588,20 @@ class hierarchical_decoder(design.design):
output_index) output_index)
output_index = output_index + 1 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: # Leave these to route in the port_address
for n in ["vdd", "gnd"]: all_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst
pins = self.and_inst[0].get_pins(n) for inst in all_insts:
for pin in pins: self.copy_layout_pin(inst, "vdd")
self.add_rect(layer=pin.layer, self.copy_layout_pin(inst, "gnd")
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 self.route_vertical_pins("vdd", self.and_inst, xside="rx",)
# (except the last to keep them inside the boundary) self.route_vertical_pins("gnd", self.and_inst, xside="lx",)
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): def route_predecode_bus_outputs(self, rail_name, pin, row):
""" """
@ -698,7 +669,7 @@ class hierarchical_decoder(design.design):
drc_error = 0 drc_error = 0
for and_input in self.predecode_bus_rail_pos: for and_input in self.predecode_bus_rail_pos:
if and_input.x == rail_pos.x: 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 drc_error = 1
if drc_error == 0: if drc_error == 0:
break break

View File

@ -6,9 +6,9 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import design from base import design
import math import math
from vector import vector from base import vector
from sram_factory import factory from sram_factory import factory
from globals import OPTS from globals import OPTS
from tech import layer_properties as layer_props from tech import layer_properties as layer_props
@ -18,7 +18,7 @@ from tech import preferred_directions
from tech import drc from tech import drc
class hierarchical_predecode(design.design): class hierarchical_predecode(design):
""" """
Pre 2x4 and 3x8 and TBD 4x16 decoder shared code. Pre 2x4 and 3x8 and TBD 4x16 decoder shared code.
""" """
@ -59,13 +59,11 @@ class hierarchical_predecode(design.design):
inv_type = "inv_dec" inv_type = "inv_dec"
self.and_mod = factory.create(module_type=and_type, self.and_mod = factory.create(module_type=and_type,
height=self.cell_height) height=self.cell_height)
self.add_mod(self.and_mod)
# This uses the pinv_dec parameterized cell # This uses the pinv_dec parameterized cell
self.inv = factory.create(module_type=inv_type, self.inv = factory.create(module_type=inv_type,
height=self.cell_height, height=self.cell_height,
size=1) size=1)
self.add_mod(self.inv)
def create_layout(self): def create_layout(self):
""" The general organization is from left to right: """ The general organization is from left to right:
@ -191,7 +189,7 @@ class hierarchical_predecode(design.design):
self.route_output_inverters() self.route_output_inverters()
self.route_inputs_to_rails() self.route_inputs_to_rails()
self.route_output_ands() self.route_output_ands()
self.route_vdd_gnd() self.route_supplies()
def route_inputs_to_rails(self): def route_inputs_to_rails(self):
""" Route the uninverted inputs to the second set of rails """ """ Route the uninverted inputs to the second set of rails """
@ -380,10 +378,10 @@ class hierarchical_predecode(design.design):
offset=pin_pos, offset=pin_pos,
directions=direction) 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. """ """ 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: if layer_props.hierarchical_predecode.vertical_supply and not self.column_decoder:
for n in ["vdd", "gnd"]: for n in ["vdd", "gnd"]:
# This makes a wire from top to bottom for both inv and and gates # This makes a wire from top to bottom for both inv and and gates
@ -397,7 +395,7 @@ class hierarchical_predecode(design.design):
height=top_pin.uy() - self.bus_pitch) height=top_pin.uy() - self.bus_pitch)
# This adds power vias at the top of each cell # This adds power vias at the top of each cell
# (except the last to keep them inside the boundary) # (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) pins = i.get_pins(n)
for pin in pins: for pin in pins:
self.copy_power_pin(pin, loc=pin.uc()) self.copy_power_pin(pin, loc=pin.uc())
@ -405,8 +403,6 @@ class hierarchical_predecode(design.design):
# In other techs, we are using standard cell decoder cells with horizontal power # In other techs, we are using standard cell decoder cells with horizontal power
else: else:
for num in range(0, self.number_of_outputs): for num in range(0, self.number_of_outputs):
# Route both supplies
for n in ["vdd", "gnd"]: for n in ["vdd", "gnd"]:
and_pins = self.and_inst[num].get_pins(n) and_pins = self.and_inst[num].get_pins(n)
for and_pin in and_pins: for and_pin in and_pins:
@ -415,10 +411,9 @@ class hierarchical_predecode(design.design):
end=vector(self.width, and_pin.cy())) end=vector(self.width, and_pin.cy()))
# Add pins in two locations # Add pins in two locations
for xoffset in [self.inv_inst[0].lx() - self.bus_space, if n == "vdd":
self.and_inst[0].lx() - self.bus_space]: xoffset = self.and_inst[0].lx() - self.bus_space
pin_pos = vector(xoffset, and_pin.cy()) else:
self.copy_power_pin(and_pin, loc=pin_pos) xoffset = self.inv_inst[0].lx() - self.bus_space
pin_pos = vector(xoffset, and_pin.cy())
self.add_power_pin(n, pin_pos, start_layer=and_pin.layer)

View File

@ -5,7 +5,7 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
from hierarchical_predecode import hierarchical_predecode from .hierarchical_predecode import hierarchical_predecode
from globals import OPTS from globals import OPTS

View File

@ -5,7 +5,7 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
from hierarchical_predecode import hierarchical_predecode from .hierarchical_predecode import hierarchical_predecode
from globals import OPTS from globals import OPTS

View File

@ -5,7 +5,7 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
from hierarchical_predecode import hierarchical_predecode from .hierarchical_predecode import hierarchical_predecode
from globals import OPTS from globals import OPTS

View File

@ -5,13 +5,13 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import design from base import design
import logical_effort from base import logical_effort
from tech import cell_properties as props from tech import cell_properties as props
from tech import spice, parameter from tech import spice, parameter
class inv_dec(design.design): class inv_dec(design):
""" """
INV for address decoders. INV for address decoders.
""" """
@ -51,12 +51,12 @@ class inv_dec(design.design):
Input inverted by this stage. Input inverted by this stage.
""" """
parasitic_delay = 1 parasitic_delay = 1
return logical_effort.logical_effort(self.name, return logical_effort(self.name,
self.size, self.size,
self.input_load(), self.input_load(),
cout, cout,
parasitic_delay, parasitic_delay,
not inp_is_rise) not inp_is_rise)
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
""" """

View File

@ -5,15 +5,15 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import bitcell_base_array from .bitcell_base_array import bitcell_base_array
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
from vector import vector from base import vector
import debug import debug
from tech import layer_properties as layer_props 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. 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 This can either be a single aray on its own if there is no hierarchical WL
@ -73,12 +73,10 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
rbl=self.rbl, rbl=self.rbl,
left_rbl=self.left_rbl, left_rbl=self.left_rbl,
right_rbl=self.right_rbl) right_rbl=self.right_rbl)
self.add_mod(self.bitcell_array)
self.wl_array = factory.create(module_type="wordline_buffer_array", self.wl_array = factory.create(module_type="wordline_buffer_array",
rows=self.rows + 1, rows=self.rows + 1,
cols=self.cols) cols=self.cols)
self.add_mod(self.wl_array)
def add_pins(self): def add_pins(self):
# Outputs from the wordline driver (by port) # Outputs from the wordline driver (by port)
@ -161,17 +159,20 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
def place(self): def place(self):
""" Place the bitcelll array to the right of the wl driver. """ """ 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 driver_to_array_spacing = 3 * self.m3_pitch
self.wl_insts[0].place(vector(0, 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, bitcell_array_offset = vector(self.wl_insts[0].rx() + driver_to_array_spacing, 0)
0)) self.bitcell_array_inst.place(bitcell_array_offset)
if len(self.all_ports) > 1: 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, wl_offset = 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_bottom() + self.wl_array.height + self.cell.height)
self.wl_insts[1].place(wl_offset,
mirror="XY") mirror="XY")
self.height = self.bitcell_array.height self.height = self.bitcell_array.height

View File

@ -8,15 +8,14 @@
import sys import sys
from tech import drc, parameter from tech import drc, parameter
import debug import debug
import design from base import design
import math import math
from math import log,sqrt,ceil from math import log,sqrt,ceil
import contact from base import vector
from vector import vector
from sram_factory import factory from sram_factory import factory
from globals import OPTS from globals import OPTS
class multibank(design.design): class multibank(design):
""" """
Dynamically generated a single bank including bitcell array, Dynamically generated a single bank including bitcell array,
hierarchical_decoder, precharge, (optional column_mux and column decoder), hierarchical_decoder, precharge, (optional column_mux and column decoder),
@ -172,47 +171,36 @@ class multibank(design.design):
self.bitcell_array = self.mod_bitcell_array(cols=self.num_cols, self.bitcell_array = self.mod_bitcell_array(cols=self.num_cols,
rows=self.num_rows) rows=self.num_rows)
self.add_mod(self.bitcell_array)
self.precharge_array = self.mod_precharge_array(columns=self.num_cols) self.precharge_array = self.mod_precharge_array(columns=self.num_cols)
self.add_mod(self.precharge_array)
if self.col_addr_size > 0: if self.col_addr_size > 0:
self.column_mux_array = self.mod_column_mux_array(columns=self.num_cols, self.column_mux_array = self.mod_column_mux_array(columns=self.num_cols,
word_size=self.word_size) 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, self.sense_amp_array = self.mod_sense_amp_array(word_size=self.word_size,
words_per_row=self.words_per_row) words_per_row=self.words_per_row)
self.add_mod(self.sense_amp_array)
if self.write_size: if self.write_size:
self.write_mask_driver_array = self.mod_write_mask_driver_array(columns=self.num_cols, self.write_mask_driver_array = self.mod_write_mask_driver_array(columns=self.num_cols,
word_size=self.word_size, word_size=self.word_size,
write_size=self.write_size) write_size=self.write_size)
self.add_mod(self.write_mask_driver_array)
else: else:
self.write_driver_array = self.mod_write_driver_array(columns=self.num_cols, self.write_driver_array = self.mod_write_driver_array(columns=self.num_cols,
word_size=self.word_size) word_size=self.word_size)
self.add_mod(self.write_driver_array)
self.row_decoder = self.mod_decoder(rows=self.num_rows) 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, self.tri_gate_array = self.mod_tri_gate_array(columns=self.num_cols,
word_size=self.word_size) word_size=self.word_size)
self.add_mod(self.tri_gate_array)
self.wordline_driver = self.mod_wordline_driver(rows=self.num_rows) self.wordline_driver = self.mod_wordline_driver(rows=self.num_rows)
self.add_mod(self.wordline_driver)
self.inv = pinv() self.inv = pinv()
self.add_mod(self.inv)
if(self.num_banks > 1): if(self.num_banks > 1):
self.bank_select = self.mod_bank_select() self.bank_select = self.mod_bank_select()
self.add_mod(self.bank_select)
def add_bitcell_array(self): def add_bitcell_array(self):
@ -810,7 +798,7 @@ class multibank(design.design):
self.add_wire(("m3","via2","m2"),[in_pin, rail_pos, rail_pos - vector(0,self.m2_pitch)]) 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 # Bring it up to M2 for M2/M3 routing
self.add_via(layers=self.m1_stack, self.add_via(layers=self.m1_stack,
offset=in_pin + contact.m1_via.offset, offset=in_pin + self.m1_via.offset,
rotate=90) rotate=90)
self.add_via(layers=self.m2_stack, self.add_via(layers=self.m2_stack,
offset=in_pin + self.m2m3_via_offset, offset=in_pin + self.m2m3_via_offset,
@ -823,7 +811,7 @@ class multibank(design.design):
rail_pos = vector(self.rail_1_x_offsets[rail], in_pin.y) 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_wire(("m3","via2","m2"),[in_pin, rail_pos, rail_pos - vector(0,self.m2_pitch)])
self.add_via(layers=self.m1_stack, self.add_via(layers=self.m1_stack,
offset=in_pin + contact.m1_via.offset, offset=in_pin + self.m1_via.offset,
rotate=90) rotate=90)
self.add_via(layers=self.m2_stack, self.add_via(layers=self.m2_stack,
offset=in_pin + self.m2m3_via_offset, offset=in_pin + self.m2m3_via_offset,

View File

@ -5,13 +5,13 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import design from base import design
from tech import spice, parameter, drc from tech import spice, parameter, drc
from tech import cell_properties as props 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. 2-input NAND decoder for address decoders.
""" """
@ -56,12 +56,12 @@ class nand2_dec(design.design):
Input inverted by this stage. Input inverted by this stage.
""" """
parasitic_delay = 2 parasitic_delay = 2
return logical_effort.logical_effort(self.name, return logical_effort(self.name,
self.size, self.size,
self.input_load(), self.input_load(),
cout, cout,
parasitic_delay, parasitic_delay,
not inp_is_rise) not inp_is_rise)
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
""" """

View File

@ -5,13 +5,13 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import design from base import design
from tech import spice, parameter, drc from tech import spice, parameter, drc
from tech import cell_properties as props 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. 3-input NAND decoder for address decoders.
""" """
@ -56,12 +56,12 @@ class nand3_dec(design.design):
Input inverted by this stage. Input inverted by this stage.
""" """
parasitic_delay = 2 parasitic_delay = 2
return logical_effort.logical_effort(self.name, return logical_effort(self.name,
self.size, self.size,
self.input_load(), self.input_load(),
cout, cout,
parasitic_delay, parasitic_delay,
not inp_is_rise) not inp_is_rise)
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
""" """

View File

@ -5,13 +5,13 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import design from base import design
from tech import spice, parameter, drc from tech import spice, parameter, drc
from tech import cell_properties as props 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. 4-input NAND decoder for address decoders.
""" """
@ -56,12 +56,12 @@ class nand4_dec(design.design):
Input inverted by this stage. Input inverted by this stage.
""" """
parasitic_delay = 2 parasitic_delay = 2
return logical_effort.logical_effort(self.name, return logical_effort(self.name,
self.size, self.size,
self.input_load(), self.input_load(),
cout, cout,
parasitic_delay, parasitic_delay,
not inp_is_rise) not inp_is_rise)
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
""" """

View File

@ -5,7 +5,7 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # 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 tech import drc, spice
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
@ -47,7 +47,6 @@ class bitcell_array(bitcell_base_array):
def add_modules(self): def add_modules(self):
""" Add the modules used in this design """ """ Add the modules used in this design """
self.cell = factory.create(module_type=OPTS.bitcell) self.cell = factory.create(module_type=OPTS.bitcell)
self.add_mod(self.cell)
def create_instances(self): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """

View File

@ -6,12 +6,12 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
from vector import vector from base import vector
import pgate from .pgate import *
from sram_factory import factory from sram_factory import factory
class pand2(pgate.pgate): class pand2(pgate):
""" """
This is an AND (or NAND) with configurable drive strength. This is an AND (or NAND) with configurable drive strength.
""" """
@ -32,16 +32,13 @@ class pand2(pgate.pgate):
def create_modules(self): def create_modules(self):
self.nand = factory.create(module_type="pnand2", self.nand = factory.create(module_type="pnand2",
height=self.height, height=self.height,
add_wells=self.vertical) add_wells=False)
self.inv = factory.create(module_type="pdriver", self.inv = factory.create(module_type="pdriver",
size_list=[self.size], size_list=[self.size],
height=self.height, height=self.height,
add_wells=self.add_wells) add_wells=self.add_wells)
self.add_mod(self.nand)
self.add_mod(self.inv)
def create_layout(self): def create_layout(self):
if self.vertical: if self.vertical:
self.height = 2 * self.nand.height self.height = 2 * self.nand.height

View File

@ -6,12 +6,12 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
from vector import vector from base import vector
import pgate from .pgate import *
from sram_factory import factory from sram_factory import factory
class pand3(pgate.pgate): class pand3(pgate):
""" """
This is a simple buffer used for driving loads. This is a simple buffer used for driving loads.
""" """
@ -43,9 +43,6 @@ class pand3(pgate.pgate):
height=self.height, height=self.height,
add_wells=self.add_wells) add_wells=self.add_wells)
self.add_mod(self.nand)
self.add_mod(self.inv)
def create_layout(self): def create_layout(self):
if self.vertical: if self.vertical:
self.height = 2 * self.nand.height self.height = 2 * self.nand.height

View File

@ -6,12 +6,12 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
from vector import vector from base import vector
import pgate from .pgate import *
from sram_factory import factory from sram_factory import factory
class pand4(pgate.pgate): class pand4(pgate):
""" """
This is a simple buffer used for driving loads. This is a simple buffer used for driving loads.
""" """
@ -43,9 +43,6 @@ class pand4(pgate.pgate):
height=self.height, height=self.height,
add_wells=self.add_wells) add_wells=self.add_wells)
self.add_mod(self.nand)
self.add_mod(self.inv)
def create_layout(self): def create_layout(self):
if self.vertical: if self.vertical:
self.height = 2 * self.nand.height self.height = 2 * self.nand.height
@ -162,4 +159,3 @@ class pand4(pgate.pgate):
slew=nand_delay.slew, slew=nand_delay.slew,
load=load) load=load)
return nand_delay + inv_delay return nand_delay + inv_delay

View File

@ -5,18 +5,17 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import contact
import debug import debug
from base import logical_effort
from base import vector
from tech import drc, parameter, layer from tech import drc, parameter, layer
from tech import cell_properties as props from tech import cell_properties as props
from vector import vector
from ptx import ptx
from globals import OPTS from globals import OPTS
import logical_effort from .ptx import ptx
import bitcell_base 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, This module implements a parametrically sized multi-port bitcell,
with a variable number of read/write, write, and read ports with a variable number of read/write, write, and read ports
@ -33,7 +32,19 @@ class pbitcell(bitcell_base.bitcell_base):
self.mirror = props.bitcell_1port.mirror self.mirror = props.bitcell_1port.mirror
self.end_caps = props.bitcell_1port.end_caps self.end_caps = props.bitcell_1port.end_caps
bitcell_base.bitcell_base.__init__(self, name) 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.__init__(self, name)
fmt_str = "{0} rw ports, {1} w ports and {2} r ports" fmt_str = "{0} rw ports, {1} w ports and {2} r ports"
info_string = fmt_str.format(self.num_rw_ports, info_string = fmt_str.format(self.num_rw_ports,
self.num_w_ports, self.num_w_ports,
@ -87,7 +98,7 @@ class pbitcell(bitcell_base.bitcell_base):
self.route_wordlines() self.route_wordlines()
self.route_bitlines() self.route_bitlines()
self.route_supply() self.route_supplies()
if self.replica_bitcell: if self.replica_bitcell:
self.route_rbc_short() self.route_rbc_short()
@ -179,26 +190,21 @@ class pbitcell(bitcell_base.bitcell_base):
# create ptx for inverter transistors # create ptx for inverter transistors
self.inverter_nmos = ptx(width=inverter_nmos_width, self.inverter_nmos = ptx(width=inverter_nmos_width,
tx_type="nmos") tx_type="nmos")
self.add_mod(self.inverter_nmos)
self.inverter_pmos = ptx(width=inverter_pmos_width, self.inverter_pmos = ptx(width=inverter_pmos_width,
tx_type="pmos") tx_type="pmos")
self.add_mod(self.inverter_pmos)
# create ptx for readwrite transitors # create ptx for readwrite transitors
self.readwrite_nmos = ptx(width=readwrite_nmos_width, self.readwrite_nmos = ptx(width=readwrite_nmos_width,
tx_type="nmos") tx_type="nmos")
self.add_mod(self.readwrite_nmos)
# create ptx for write transitors # create ptx for write transitors
self.write_nmos = ptx(width=write_nmos_width, self.write_nmos = ptx(width=write_nmos_width,
tx_type="nmos") tx_type="nmos")
self.add_mod(self.write_nmos)
# create ptx for read transistors # create ptx for read transistors
self.read_nmos = ptx(width=read_nmos_width, self.read_nmos = ptx(width=read_nmos_width,
tx_type="nmos") tx_type="nmos")
self.add_mod(self.read_nmos)
def calculate_spacing(self): def calculate_spacing(self):
""" Calculate transistor spacings """ """ Calculate transistor spacings """
@ -215,20 +221,20 @@ class pbitcell(bitcell_base.bitcell_base):
# y-offset for the access transistor's gate contact # y-offset for the access transistor's gate contact
self.gate_contact_yoffset = max_contact_extension + self.m2_space \ 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 # 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 # y-position of inverter nmos
self.inverter_nmos_ypos = self.port_ypos self.inverter_nmos_ypos = self.port_ypos
# spacing between ports (same for read/write and write ports) # spacing between ports (same for read/write and write ports)
self.bitline_offset = -0.5 * self.readwrite_nmos.active_width \ 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 + self.m2_space + self.m2_width
m2_constraint = self.bitline_offset + self.m2_space \ 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 - 0.5 * self.readwrite_nmos.active_width
self.write_port_spacing = max(self.active_space, self.write_port_spacing = max(self.active_space,
self.m1_space, self.m1_space,
@ -236,7 +242,7 @@ class pbitcell(bitcell_base.bitcell_base):
self.read_port_spacing = self.bitline_offset + self.m2_space self.read_port_spacing = self.bitline_offset + self.m2_space
# spacing between cross coupled inverters # 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 # calculations related to inverter connections
inverter_pmos_contact_extension = 0.5 * \ inverter_pmos_contact_extension = 0.5 * \
@ -245,19 +251,19 @@ class pbitcell(bitcell_base.bitcell_base):
(self.inverter_nmos.active_contact.height - self.inverter_nmos.active_height) (self.inverter_nmos.active_contact.height - self.inverter_nmos.active_height)
self.inverter_gap = max(self.poly_to_active, self.inverter_gap = max(self.poly_to_active,
self.m1_space + inverter_nmos_contact_extension) \ 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.m1_space + inverter_pmos_contact_extension
self.cross_couple_lower_ypos = self.inverter_nmos_ypos \ self.cross_couple_lower_ypos = self.inverter_nmos_ypos \
+ self.inverter_nmos.active_height \ + self.inverter_nmos.active_height \
+ max(self.poly_to_active, + max(self.poly_to_active,
self.m1_space + inverter_nmos_contact_extension) \ 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.cross_couple_upper_ypos = self.inverter_nmos_ypos \
+ self.inverter_nmos.active_height \ + self.inverter_nmos.active_height \
+ max(self.poly_to_active, + max(self.poly_to_active,
self.m1_space + inverter_nmos_contact_extension) \ self.m1_space + inverter_nmos_contact_extension) \
+ self.poly_to_contact \ + self.poly_to_contact \
+ 1.5 * contact.poly_contact.width + 1.5 * self.poly_contact.width
# spacing between wordlines (and gnd) # spacing between wordlines (and gnd)
self.m1_offset = -0.5 * self.m1_width self.m1_offset = -0.5 * self.m1_width
@ -293,7 +299,7 @@ class pbitcell(bitcell_base.bitcell_base):
(self.write_nmos.active_width + self.write_port_spacing) \ (self.write_nmos.active_width + self.write_port_spacing) \
- self.num_r_ports * \ - self.num_r_ports * \
(self.read_port_width + self.read_port_spacing) \ (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.width = -2 * self.leftmost_xpos
self.height = self.topmost_ypos - self.botmost_ypos self.height = self.topmost_ypos - self.botmost_ypos
@ -383,14 +389,14 @@ class pbitcell(bitcell_base.bitcell_base):
# add contacts to connect gate poly to drain/source # add contacts to connect gate poly to drain/source
# metal1 (to connect Q to Q_bar) # metal1 (to connect Q to Q_bar)
contact_offset_left = vector(self.inverter_nmos_left.get_pin("D").rc().x \ 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.cross_couple_upper_ypos)
self.add_via_center(layers=self.poly_stack, self.add_via_center(layers=self.poly_stack,
offset=contact_offset_left, offset=contact_offset_left,
directions=("H", "H")) directions=("H", "H"))
contact_offset_right = vector(self.inverter_nmos_right.get_pin("S").lc().x \ 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.cross_couple_lower_ypos)
self.add_via_center(layers=self.poly_stack, self.add_via_center(layers=self.poly_stack,
offset=contact_offset_right, offset=contact_offset_right,
@ -407,24 +413,24 @@ class pbitcell(bitcell_base.bitcell_base):
if OPTS.use_pex: if OPTS.use_pex:
# add labels to cross couple inverter for extracted simulation # add labels to cross couple inverter for extracted simulation
contact_offset_left_output = vector(self.inverter_nmos_left.get_pin("D").rc().x \ 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) self.cross_couple_upper_ypos)
contact_offset_right_output = vector(self.inverter_nmos_right.get_pin("S").lc().x \ 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.cross_couple_lower_ypos)
self.add_pex_labels(contact_offset_left_output, contact_offset_right_output) self.add_pex_labels(contact_offset_left_output, contact_offset_right_output)
def route_rails(self): def route_rails(self):
""" Adds gnd and vdd rails and connects them to the inverters """ """ Adds gnd and vdd rails and connects them to the inverters """
# Add rails for vdd and gnd # Add rails for vdd and gnd
gnd_ypos = self.m1_offset - self.total_ports * self.m1_nonpref_pitch gnd_ypos = self.m1_offset - self.total_ports * self.m1_nonpref_pitch
self.gnd_position = vector(0, gnd_ypos) self.gnd_position = vector(0, gnd_ypos)
self.add_rect_center(layer="m1", self.add_layout_pin_rect_center(text="gnd",
offset=self.gnd_position, layer="m1",
width=self.width) offset=self.gnd_position,
self.add_power_pin("gnd", vector(0, gnd_ypos), directions=("H", "H")) width=self.width)
vdd_ypos = self.inverter_nmos_ypos \ vdd_ypos = self.inverter_nmos_ypos \
+ self.inverter_nmos.active_height \ + self.inverter_nmos.active_height \
@ -432,10 +438,10 @@ class pbitcell(bitcell_base.bitcell_base):
+ self.inverter_pmos.active_height \ + self.inverter_pmos.active_height \
+ self.vdd_offset + self.vdd_offset
self.vdd_position = vector(0, vdd_ypos) self.vdd_position = vector(0, vdd_ypos)
self.add_rect_center(layer="m1", self.add_layout_pin_rect_center(text="vdd",
offset=self.vdd_position, layer="m1",
width=self.width) offset=self.vdd_position,
self.add_power_pin("vdd", vector(0, vdd_ypos), directions=("H", "H")) width=self.width)
def create_readwrite_ports(self): def create_readwrite_ports(self):
""" """
@ -475,6 +481,7 @@ class pbitcell(bitcell_base.bitcell_base):
self.connect_inst([self.Q_bar, self.connect_inst([self.Q_bar,
self.rw_wl_names[k], br_name, "gnd"]) self.rw_wl_names[k], br_name, "gnd"])
def place_readwrite_ports(self): def place_readwrite_ports(self):
""" Places read/write ports in the bit cell """ """ Places read/write ports in the bit cell """
# define read/write transistor variables as empty arrays # define read/write transistor variables as empty arrays
@ -529,6 +536,21 @@ class pbitcell(bitcell_base.bitcell_base):
offset=self.rwbr_positions[k], offset=self.rwbr_positions[k],
height=self.height) 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 # update furthest left and right transistor edges
self.left_building_edge = left_readwrite_transistor_xpos self.left_building_edge = left_readwrite_transistor_xpos
self.right_building_edge = right_readwrite_transistor_xpos \ self.right_building_edge = right_readwrite_transistor_xpos \
@ -626,6 +648,20 @@ class pbitcell(bitcell_base.bitcell_base):
offset=self.wbr_positions[k], offset=self.wbr_positions[k],
height=self.height) 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 # update furthest left and right transistor edges
self.left_building_edge = left_write_transistor_xpos self.left_building_edge = left_write_transistor_xpos
self.right_building_edge = right_write_transistor_xpos \ self.right_building_edge = right_write_transistor_xpos \
@ -753,6 +789,20 @@ class pbitcell(bitcell_base.bitcell_base):
offset=self.rbr_positions[k], offset=self.rbr_positions[k],
height=self.height) 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): def route_wordlines(self):
""" Routes gate of transistors to their respective wordlines """ """ Routes gate of transistors to their respective wordlines """
port_transistors = [] port_transistors = []
@ -845,7 +895,7 @@ class pbitcell(bitcell_base.bitcell_base):
directions="nonpref") directions="nonpref")
self.add_path("m2", 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): for k in range(self.total_ports):
port_contact_offest = right_port_transistors[k].get_pin("D").center() port_contact_offest = right_port_transistors[k].get_pin("D").center()
@ -858,9 +908,9 @@ class pbitcell(bitcell_base.bitcell_base):
directions="nonpref") directions="nonpref")
self.add_path("m2", 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_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. Route inverter pmos to vdd. """
# route inverter nmos and read-access nmos to gnd # route inverter nmos and read-access nmos to gnd
nmos_contact_positions = [] nmos_contact_positions = []
@ -877,9 +927,9 @@ class pbitcell(bitcell_base.bitcell_base):
if position.x > 0: if position.x > 0:
contact_correct = 0.5 * contact.m1_via.height contact_correct = 0.5 * self.m1_via.height
else: else:
contact_correct = -0.5 * contact.m1_via.height contact_correct = -0.5 * self.m1_via.height
supply_offset = vector(position.x + contact_correct, supply_offset = vector(position.x + contact_correct,
self.gnd_position.y) self.gnd_position.y)
self.add_via_center(layers=self.m1_stack, self.add_via_center(layers=self.m1_stack,
@ -946,7 +996,7 @@ class pbitcell(bitcell_base.bitcell_base):
""" """
# add poly to metal1 contacts for gates of the inverters # add poly to metal1 contacts for gates of the inverters
left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x \ 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.cross_couple_upper_ypos)
self.add_via_center(layers=self.poly_stack, self.add_via_center(layers=self.poly_stack,
offset=left_storage_contact, offset=left_storage_contact,
@ -954,7 +1004,7 @@ class pbitcell(bitcell_base.bitcell_base):
right_storage_contact = vector(self.inverter_nmos_right.get_pin("G").rc().x \ 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.cross_couple_upper_ypos)
self.add_via_center(layers=self.poly_stack, self.add_via_center(layers=self.poly_stack,
offset=right_storage_contact, offset=right_storage_contact,
@ -1013,7 +1063,7 @@ class pbitcell(bitcell_base.bitcell_base):
well_height = max_nmos_well_height + self.port_ypos \ well_height = max_nmos_well_height + self.port_ypos \
- self.nwell_enclose_active - self.gnd_position.y - self.nwell_enclose_active - self.gnd_position.y
# FIXME fudge factor xpos # 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) offset = vector(self.leftmost_xpos - self.nwell_enclose_active, self.botmost_ypos)
self.add_rect(layer="pwell", self.add_rect(layer="pwell",
offset=offset, offset=offset,
@ -1141,12 +1191,12 @@ class pbitcell(bitcell_base.bitcell_base):
# min size NMOS gate load # min size NMOS gate load
read_port_load = self.num_r_ports / 2 read_port_load = self.num_r_ports / 2
total_load = load + read_port_load + write_port_load total_load = load + read_port_load + write_port_load
return logical_effort.logical_effort('bitline', return logical_effort('bitline',
size, size,
cin, cin,
load + read_port_load, load + read_port_load,
parasitic_delay, parasitic_delay,
False) False)
def input_load(self): def input_load(self):
""" Return the relative capacitance of the access transistor gates """ """ Return the relative capacitance of the access transistor gates """
@ -1172,4 +1222,3 @@ class pbitcell(bitcell_base.bitcell_base):
for wl, bl, br in pin_zip: 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[bl], self)
graph.add_edge(pin_dict[wl], pin_dict[br], self) graph.add_edge(pin_dict[wl], pin_dict[br], self)

View File

@ -6,12 +6,12 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
from vector import vector from base import vector
import pgate from .pgate import *
from sram_factory import factory from sram_factory import factory
class pbuf(pgate.pgate): class pbuf(pgate):
""" """
This is a simple buffer used for driving loads. This is a simple buffer used for driving loads.
""" """
@ -52,13 +52,11 @@ class pbuf(pgate.pgate):
self.inv1 = factory.create(module_type="pinv", self.inv1 = factory.create(module_type="pinv",
size=input_size, size=input_size,
height=self.height) height=self.height)
self.add_mod(self.inv1)
self.inv2 = factory.create(module_type="pinv", self.inv2 = factory.create(module_type="pinv",
size=self.size, size=self.size,
height=self.height, height=self.height,
add_wells=False) add_wells=False)
self.add_mod(self.inv2)
def create_insts(self): def create_insts(self):
self.inv1_inst = self.add_inst(name="buf_inv1", self.inv1_inst = self.add_inst(name="buf_inv1",
@ -96,4 +94,3 @@ class pbuf(pgate.pgate):
offset=a_pin.center(), offset=a_pin.center(),
width=a_pin.width(), width=a_pin.width(),
height=a_pin.height()) height=a_pin.height())

View File

@ -6,12 +6,12 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
from vector import vector from base import vector
import pgate from .pgate import *
from sram_factory import factory from sram_factory import factory
class pbuf_dec(pgate.pgate): class pbuf_dec(pgate):
""" """
This is a simple buffer used for driving wordlines. This is a simple buffer used for driving wordlines.
""" """
@ -25,7 +25,7 @@ class pbuf_dec(pgate.pgate):
self.height = height self.height = height
# Creates the netlist and layout # Creates the netlist and layout
pgate.pgate.__init__(self, name, height) pgate.__init__(self, name, height)
def create_netlist(self): def create_netlist(self):
self.add_pins() self.add_pins()
@ -52,12 +52,10 @@ class pbuf_dec(pgate.pgate):
self.inv1 = factory.create(module_type="pinv_dec", self.inv1 = factory.create(module_type="pinv_dec",
size=input_size, size=input_size,
height=self.height) height=self.height)
self.add_mod(self.inv1)
self.inv2 = factory.create(module_type="pinv_dec", self.inv2 = factory.create(module_type="pinv_dec",
size=self.size, size=self.size,
height=self.height) height=self.height)
self.add_mod(self.inv2)
def create_insts(self): def create_insts(self):
self.inv1_inst = self.add_inst(name="buf_inv1", self.inv1_inst = self.add_inst(name="buf_inv1",

View File

@ -6,12 +6,12 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import pgate from .pgate import *
from vector import vector from base import vector
from sram_factory import factory from sram_factory import factory
class pdriver(pgate.pgate): class pdriver(pgate):
""" """
This instantiates an even or odd number of inverters This instantiates an even or odd number of inverters
sized for driving a load. sized for driving a load.
@ -93,7 +93,6 @@ class pdriver(pgate.pgate):
height=self.height, height=self.height,
add_wells=self.add_wells) add_wells=self.add_wells)
self.inv_list.append(temp_inv) self.inv_list.append(temp_inv)
self.add_mod(temp_inv)
def create_insts(self): def create_insts(self):
self.inv_inst_list = [] self.inv_inst_list = []

View File

@ -5,20 +5,20 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import contact from base import design
import design from base import vector
import debug import debug
import math import math
from bisect import bisect_left from bisect import bisect_left
from tech import layer, drc from tech import layer, drc
from vector import vector
from globals import OPTS from globals import OPTS
from tech import cell_properties as cell_props from tech import cell_properties as cell_props
if cell_props.ptx.bin_spice_models: if cell_props.ptx.bin_spice_models:
from tech import nmos_bins, pmos_bins from tech import nmos_bins, pmos_bins
class pgate(design.design): class pgate(design):
""" """
This is a module that implements some shared This is a module that implements some shared
functions for parameterized gates. functions for parameterized gates.
@ -113,14 +113,14 @@ class pgate(design.design):
left_gate_offset = vector(nmos_gate_pin.lx(), ypos) left_gate_offset = vector(nmos_gate_pin.lx(), ypos)
# Center is completely symmetric. # Center is completely symmetric.
contact_width = contact.poly_contact.width contact_width = self.poly_contact.width
if position == "center": if position == "center":
contact_offset = left_gate_offset \ contact_offset = left_gate_offset \
+ vector(0.5 * self.poly_width, 0) + vector(0.5 * self.poly_width, 0)
elif position == "farleft": elif position == "farleft":
contact_offset = left_gate_offset \ contact_offset = left_gate_offset \
- vector(0.5 * contact.poly_contact.width, 0) - vector(0.5 * self.poly_contact.width, 0)
elif position == "left": elif position == "left":
contact_offset = left_gate_offset \ contact_offset = left_gate_offset \
- vector(0.5 * contact_width - 0.5 * self.poly_width, 0) - 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) + left_gate_offset.scale(0.5, 0)
self.add_rect_center(layer="poly", self.add_rect_center(layer="poly",
offset=mid_point, 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) width=left_gate_offset.x - contact_offset.x)
return via return via
@ -208,12 +208,15 @@ class pgate(design.design):
# from the top of the well # from the top of the well
# OR align the active with the top of PMOS active. # OR align the active with the top of PMOS active.
max_y_offset = self.height + 0.5 * self.m1_width 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, contact_yoffset = min(self.height - 0.5 * self.implant_width,
max_y_offset - pmos.active_contact.first_layer_height / 2 - self.nwell_enclose_active) self.get_tx_insts("pmos")[0].uy()) \
- pmos.active_contact.first_layer_height \
- self.implant_enclose_active
contact_offset = vector(contact_xoffset, contact_yoffset) contact_offset = vector(contact_xoffset, contact_yoffset)
# Offset by half a contact in x and y # Offset by half a contact in x and y
contact_offset += vector(0.5 * pmos.active_contact.first_layer_width, contact_offset += vector(0.5 * pmos.active_contact.first_layer_width,
0.5 * pmos.active_contact.first_layer_height) 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, self.nwell_contact = self.add_via_center(layers=layer_stack,
offset=contact_offset, offset=contact_offset,
implant_type="n", implant_type="n",
@ -276,24 +279,34 @@ class pgate(design.design):
rightx=rightx, rightx=rightx,
topy=self.height) topy=self.height)
try: self.add_rect(layer="pimplant",
ntap_insts = [self.nwell_contact] offset=vector(0, self.height - 0.5 * self.implant_width),
self.add_enclosure(ntap_insts, width=self.width,
layer="nimplant", height=self.implant_width)
extend=self.implant_enclose_active, self.add_rect(layer="nimplant",
rightx=self.width, offset=vector(0, -0.5 * self.implant_width),
topy=self.height) width=self.width,
except AttributeError: height=self.implant_width)
pass
try:
ptap_insts = [self.pwell_contact] # try:
self.add_enclosure(ptap_insts, # ntap_insts = [self.nwell_contact]
layer="pimplant", # self.add_enclosure(ntap_insts,
extend=self.implant_enclose_active, # layer="nimplant",
rightx=self.width, # extend=self.implant_enclose_active,
boty=0) # rightx=self.width,
except AttributeError: # topy=self.height)
pass # 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): def add_pwell_contact(self, nmos, nmos_pos):
""" Add an pwell contact next to the given nmos device. """ """ Add an pwell contact next to the given nmos device. """
@ -303,11 +316,9 @@ class pgate(design.design):
# To the right a spacing away from the nmos right active edge # To the right a spacing away from the nmos right active edge
contact_xoffset = nmos_pos.x + nmos.active_width \ contact_xoffset = nmos_pos.x + nmos.active_width \
+ self.active_space + self.active_space
# Must be at least an well enclosure of active up # Allow an nimplant below it under the rail
# from the bottom of the well contact_yoffset = max(0.5 * self.implant_width + self.implant_enclose_active,
contact_yoffset = max(nmos_pos.y, self.get_tx_insts("nmos")[0].by())
self.nwell_enclose_active \
- nmos.active_contact.first_layer_height / 2)
contact_offset = vector(contact_xoffset, contact_yoffset) contact_offset = vector(contact_xoffset, contact_yoffset)
# Offset by half a contact # Offset by half a contact
@ -362,7 +373,7 @@ class pgate(design.design):
# It was already set or is left as default (minimum) # 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 # Width is determined by well contact and spacing and allowing a supply via between each cell
if self.add_wells: 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. # Height is an input parameter, so it is not recomputed.
else: else:
max_active_xoffset = self.find_highest_layer_coords("active").x max_active_xoffset = self.find_highest_layer_coords("active").x

View File

@ -5,22 +5,21 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import contact
import pgate
import debug 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 import operator
from tech import drc, parameter, spice from tech import drc, parameter, spice
from vector import vector
from math import ceil from math import ceil
from globals import OPTS from globals import OPTS
from utils import round_to_grid
import logical_effort
from sram_factory import factory from sram_factory import factory
from errors import drc_error
from tech import cell_properties as cell_props from tech import cell_properties as cell_props
class pinv(pgate.pgate): class pinv(pgate):
""" """
Pinv generates gds of a parametrically sized inverter. The Pinv generates gds of a parametrically sized inverter. The
size is specified as the drive size (relative to minimum NMOS) and 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.nmos_width = self.nmos_size * drc("minwidth_tx")
self.pmos_width = self.pmos_size * drc("minwidth_tx") self.pmos_width = self.pmos_size * drc("minwidth_tx")
if cell_props.ptx.bin_spice_models: if cell_props.ptx.bin_spice_models:
(self.nmos_width, self.tx_mults) = pgate.pgate.best_bin("nmos", self.nmos_width) (self.nmos_width, self.tx_mults) = pgate.best_bin("nmos", self.nmos_width)
(self.pmos_width, self.tx_mults) = pgate.pgate.best_bin("pmos", self.pmos_width) (self.pmos_width, self.tx_mults) = pgate.best_bin("pmos", self.pmos_width)
return return
# Do a quick sanity check and bail if unlikely feasible height # Do a quick sanity check and bail if unlikely feasible height
@ -106,8 +105,8 @@ class pinv(pgate.pgate):
tx_type="pmos") tx_type="pmos")
tx_height = nmos.poly_height + pmos.poly_height tx_height = nmos.poly_height + pmos.poly_height
# rotated m1 pitch or poly to active spacing # rotated m1 pitch or poly to active spacing
min_channel = max(contact.poly_contact.width + self.m1_space, min_channel = max(self.poly_contact.width + self.m1_space,
contact.poly_contact.width + 2 * self.poly_to_active) self.poly_contact.width + 2 * self.poly_to_active)
total_height = tx_height + min_channel + 2 * self.top_bottom_space total_height = tx_height + min_channel + 2 * self.top_bottom_space
# debug.check(self.height > total_height, # debug.check(self.height > total_height,
@ -207,7 +206,6 @@ class pinv(pgate.pgate):
add_drain_contact=self.route_layer, add_drain_contact=self.route_layer,
connect_poly=True, connect_poly=True,
connect_drain_active=True) connect_drain_active=True)
self.add_mod(self.nmos)
self.pmos = factory.create(module_type="ptx", self.pmos = factory.create(module_type="ptx",
width=self.pmos_width, width=self.pmos_width,
@ -217,7 +215,6 @@ class pinv(pgate.pgate):
add_drain_contact=self.route_layer, add_drain_contact=self.route_layer,
connect_poly=True, connect_poly=True,
connect_drain_active=True) connect_drain_active=True)
self.add_mod(self.pmos)
def create_ptx(self): def create_ptx(self):
""" """
@ -324,12 +321,12 @@ class pinv(pgate.pgate):
Input inverted by this stage. Input inverted by this stage.
""" """
parasitic_delay = 1 parasitic_delay = 1
return logical_effort.logical_effort(self.name, return logical_effort(self.name,
self.size, self.size,
self.input_load(), self.input_load(),
cout, cout,
parasitic_delay, parasitic_delay,
not inp_is_rise) not inp_is_rise)
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
""" """
@ -340,7 +337,6 @@ class pinv(pgate.pgate):
def is_non_inverting(self): def is_non_inverting(self):
"""Return input to output polarity for module""" """Return input to output polarity for module"""
return False return False
def get_on_resistance(self): def get_on_resistance(self):

View File

@ -5,17 +5,16 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import contact
import pinv
import debug import debug
from base import vector
from .pinv import pinv
from tech import drc, parameter, layer from tech import drc, parameter, layer
from vector import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
from tech import cell_properties as cell_props 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. This is another version of pinv but with layout for the decoder.
Other stuff is the same (netlist, sizes, etc.) 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]) self.add_path("poly", [nmos_gate_pos, pmos_gate_pos])
# Center is completely symmetric. # Center is completely symmetric.
contact_width = contact.poly_contact.width contact_width = self.poly_contact.width
contact_offset = nmos_gate_pin.lc() \ contact_offset = nmos_gate_pin.lc() \
- vector(self.poly_extend_active + 0.5 * contact_width, 0) - vector(self.poly_extend_active + 0.5 * contact_width, 0)
via = self.add_via_stack_center(from_layer="poly", 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 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 # 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_pos = vector(x_offset, y_offset)
self.nmos_inst.place(self.nmos_pos, self.nmos_inst.place(self.nmos_pos,
rotate=270) rotate=270)
@ -192,20 +191,20 @@ class pinv_dec(pinv.pinv):
source_pos = self.pmos_inst.get_pin("S").center() source_pos = self.pmos_inst.get_pin("S").center()
contact_pos = vector(source_pos.x, self.height) contact_pos = vector(source_pos.x, self.height)
self.nwell_contact = self.add_via_center(layers=self.active_stack, self.add_via_center(layers=self.active_stack,
offset=contact_pos, offset=contact_pos,
implant_type="n", implant_type="n",
well_type="n") well_type="n")
self.add_via_stack_center(offset=contact_pos, self.add_via_stack_center(offset=contact_pos,
from_layer=self.active_stack[2], from_layer=self.active_stack[2],
to_layer=self.supply_layer) to_layer=self.supply_layer)
source_pos = self.nmos_inst.get_pin("S").center() source_pos = self.nmos_inst.get_pin("S").center()
contact_pos = vector(source_pos.x, self.height) contact_pos = vector(source_pos.x, self.height)
self.pwell_contact= self.add_via_center(layers=self.active_stack, self.add_via_center(layers=self.active_stack,
offset=contact_pos, offset=contact_pos,
implant_type="p", implant_type="p",
well_type="p") well_type="p")
self.add_via_stack_center(offset=contact_pos, self.add_via_stack_center(offset=contact_pos,
from_layer=self.active_stack[2], from_layer=self.active_stack[2],
to_layer=self.supply_layer) to_layer=self.supply_layer)

View File

@ -6,12 +6,12 @@
# All rights reserved. # All rights reserved.
# #
import debug import debug
import pgate from .pgate import *
from vector import vector from base import vector
from sram_factory import factory from sram_factory import factory
from tech import layer from tech import layer
class pinvbuf(pgate.pgate): class pinvbuf(pgate):
""" """
This is a simple inverter/buffer used for driving loads. It is 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. used in the column decoder for 1:2 decoding and as the clock buffer.
@ -65,17 +65,14 @@ class pinvbuf(pgate.pgate):
self.inv = factory.create(module_type="pinv", self.inv = factory.create(module_type="pinv",
size=input_size, size=input_size,
height=self.row_height) height=self.row_height)
self.add_mod(self.inv)
self.inv1 = factory.create(module_type="pinv", self.inv1 = factory.create(module_type="pinv",
size=self.predriver_size, size=self.predriver_size,
height=self.row_height) height=self.row_height)
self.add_mod(self.inv1)
self.inv2 = factory.create(module_type="pinv", self.inv2 = factory.create(module_type="pinv",
size=self.size, size=self.size,
height=self.row_height) height=self.row_height)
self.add_mod(self.inv2)
def create_insts(self): def create_insts(self):
# Create INV1 (capacitance shield) # Create INV1 (capacitance shield)

View File

@ -5,17 +5,16 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import pgate from .pgate import *
import debug import debug
from tech import drc, parameter, spice from tech import drc, parameter, spice
from vector import vector from base import vector
import logical_effort from base import logical_effort
from sram_factory import factory from sram_factory import factory
import contact
from tech import cell_properties as cell_props 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 module generates gds of a parametrically sized 2-input nand.
This model use ptx to generate a 2-input nand within a cetrain height. This model use ptx to generate a 2-input nand within a cetrain height.
@ -79,7 +78,6 @@ class pnand2(pgate.pgate):
tx_type="nmos", tx_type="nmos",
add_source_contact=self.route_layer, add_source_contact=self.route_layer,
add_drain_contact="active") add_drain_contact="active")
self.add_mod(self.nmos_left)
self.nmos_right = factory.create(module_type="ptx", self.nmos_right = factory.create(module_type="ptx",
width=self.nmos_width, width=self.nmos_width,
@ -87,7 +85,6 @@ class pnand2(pgate.pgate):
tx_type="nmos", tx_type="nmos",
add_source_contact="active", add_source_contact="active",
add_drain_contact=self.route_layer) add_drain_contact=self.route_layer)
self.add_mod(self.nmos_right)
self.pmos_left = factory.create(module_type="ptx", self.pmos_left = factory.create(module_type="ptx",
width=self.pmos_width, width=self.pmos_width,
@ -95,7 +92,6 @@ class pnand2(pgate.pgate):
tx_type="pmos", tx_type="pmos",
add_source_contact=self.route_layer, add_source_contact=self.route_layer,
add_drain_contact=self.route_layer) add_drain_contact=self.route_layer)
self.add_mod(self.pmos_left)
self.pmos_right = factory.create(module_type="ptx", self.pmos_right = factory.create(module_type="ptx",
width=self.pmos_width, width=self.pmos_width,
@ -103,7 +99,6 @@ class pnand2(pgate.pgate):
tx_type="pmos", tx_type="pmos",
add_source_contact=self.route_layer, add_source_contact=self.route_layer,
add_drain_contact=self.route_layer) add_drain_contact=self.route_layer)
self.add_mod(self.pmos_right)
def setup_layout_constants(self): def setup_layout_constants(self):
""" Pre-compute some handy layout parameters. """ """ Pre-compute some handy layout parameters. """
@ -179,11 +174,11 @@ class pnand2(pgate.pgate):
# Top of NMOS drain # Top of NMOS drain
bottom_pin = self.nmos1_inst.get_pin("D") bottom_pin = self.nmos1_inst.get_pin("D")
# active contact metal to poly contact metal spacing # 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 # active diffusion to poly contact spacing
# doesn't use nmos uy because that is calculated using offset + poly height # 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_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 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, self.inputA_yoffset = max(active_contact_to_poly_contact,
active_to_poly_contact, active_to_poly_contact,
@ -197,9 +192,9 @@ class pnand2(pgate.pgate):
self.inputB_yoffset = self.inputA_yoffset + 2 * self.m3_pitch self.inputB_yoffset = self.inputA_yoffset + 2 * self.m3_pitch
# # active contact metal to poly contact metal spacing # # 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_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 # 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, # self.inputB_yoffset = min(active_contact_to_poly_contact,
# active_to_poly_contact, # active_to_poly_contact,
@ -219,7 +214,7 @@ class pnand2(pgate.pgate):
""" Route the Z output """ """ Route the Z output """
# One routing track layer below the PMOS contacts # 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 self.output_yoffset = self.pmos1_inst.get_pin("D").by() - route_layer_offset
@ -301,12 +296,12 @@ class pnand2(pgate.pgate):
Input inverted by this stage. Input inverted by this stage.
""" """
parasitic_delay = 2 parasitic_delay = 2
return logical_effort.logical_effort(self.name, return logical_effort(self.name,
self.size, self.size,
self.input_load(), self.input_load(),
cout, cout,
parasitic_delay, parasitic_delay,
not inp_is_rise) not inp_is_rise)
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
""" """
@ -317,7 +312,6 @@ class pnand2(pgate.pgate):
def is_non_inverting(self): def is_non_inverting(self):
"""Return input to output polarity for module""" """Return input to output polarity for module"""
return False return False
def get_on_resistance(self): def get_on_resistance(self):
@ -341,4 +335,3 @@ class pnand2(pgate.pgate):
1, 1,
self.tx_mults) self.tx_mults)
return nmos_drain_c + pmos_drain_c return nmos_drain_c + pmos_drain_c

View File

@ -5,17 +5,16 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import pgate from .pgate import *
import debug import debug
from tech import drc, parameter, spice from tech import drc, parameter, spice
from vector import vector from base import vector
import logical_effort from base import logical_effort
from sram_factory import factory from sram_factory import factory
import contact
from tech import cell_properties as cell_props 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 module generates gds of a parametrically sized 2-input nand.
This model use ptx to generate a 2-input nand within a cetrain height. This model use ptx to generate a 2-input nand within a cetrain height.
@ -82,7 +81,6 @@ class pnand3(pgate.pgate):
tx_type="nmos", tx_type="nmos",
add_source_contact="active", add_source_contact="active",
add_drain_contact="active") add_drain_contact="active")
self.add_mod(self.nmos_center)
self.nmos_right = factory.create(module_type="ptx", self.nmos_right = factory.create(module_type="ptx",
width=self.nmos_width, width=self.nmos_width,
@ -90,7 +88,6 @@ class pnand3(pgate.pgate):
tx_type="nmos", tx_type="nmos",
add_source_contact="active", add_source_contact="active",
add_drain_contact=self.route_layer) add_drain_contact=self.route_layer)
self.add_mod(self.nmos_right)
self.nmos_left = factory.create(module_type="ptx", self.nmos_left = factory.create(module_type="ptx",
width=self.nmos_width, width=self.nmos_width,
@ -98,7 +95,6 @@ class pnand3(pgate.pgate):
tx_type="nmos", tx_type="nmos",
add_source_contact=self.route_layer, add_source_contact=self.route_layer,
add_drain_contact="active") add_drain_contact="active")
self.add_mod(self.nmos_left)
self.pmos_left = factory.create(module_type="ptx", self.pmos_left = factory.create(module_type="ptx",
width=self.pmos_width, width=self.pmos_width,
@ -106,7 +102,6 @@ class pnand3(pgate.pgate):
tx_type="pmos", tx_type="pmos",
add_source_contact=self.route_layer, add_source_contact=self.route_layer,
add_drain_contact=self.route_layer) add_drain_contact=self.route_layer)
self.add_mod(self.pmos_left)
self.pmos_center = factory.create(module_type="ptx", self.pmos_center = factory.create(module_type="ptx",
width=self.pmos_width, width=self.pmos_width,
@ -114,7 +109,6 @@ class pnand3(pgate.pgate):
tx_type="pmos", tx_type="pmos",
add_source_contact=self.route_layer, add_source_contact=self.route_layer,
add_drain_contact=self.route_layer) add_drain_contact=self.route_layer)
self.add_mod(self.pmos_center)
self.pmos_right = factory.create(module_type="ptx", self.pmos_right = factory.create(module_type="ptx",
width=self.pmos_width, width=self.pmos_width,
@ -122,7 +116,6 @@ class pnand3(pgate.pgate):
tx_type="pmos", tx_type="pmos",
add_source_contact=self.route_layer, add_source_contact=self.route_layer,
add_drain_contact=self.route_layer) add_drain_contact=self.route_layer)
self.add_mod(self.pmos_right)
def setup_layout_constants(self): def setup_layout_constants(self):
""" Pre-compute some handy layout parameters. """ """ Pre-compute some handy layout parameters. """
@ -210,17 +203,17 @@ class pnand3(pgate.pgate):
""" Route the A and B and C inputs """ """ Route the A and B and C inputs """
# We can use this pitch because the contacts and overlap won't be adjacent # 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() 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 self.output_yoffset = pmos_drain_bottom - 0.5 * self.route_layer_width - self.route_layer_space
bottom_pin = self.nmos1_inst.get_pin("D") bottom_pin = self.nmos1_inst.get_pin("D")
# active contact metal to poly contact metal spacing # 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 # active diffusion to poly contact spacing
# doesn't use nmos uy because that is calculated using offset + poly height # 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_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 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, self.inputA_yoffset = max(active_contact_to_poly_contact,
active_to_poly_contact, active_to_poly_contact,
@ -334,12 +327,12 @@ class pnand3(pgate.pgate):
Input inverted by this stage. Input inverted by this stage.
""" """
parasitic_delay = 3 parasitic_delay = 3
return logical_effort.logical_effort(self.name, return logical_effort(self.name,
self.size, self.size,
self.input_load(), self.input_load(),
cout, cout,
parasitic_delay, parasitic_delay,
not inp_is_rise) not inp_is_rise)
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
""" """
@ -350,7 +343,6 @@ class pnand3(pgate.pgate):
def is_non_inverting(self): def is_non_inverting(self):
"""Return input to output polarity for module""" """Return input to output polarity for module"""
return False return False
def get_on_resistance(self): def get_on_resistance(self):

View File

@ -5,17 +5,16 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import pgate from .pgate import *
import debug import debug
from tech import drc, parameter, spice from tech import drc, parameter, spice
from vector import vector from base import vector
import logical_effort from base import logical_effort
from sram_factory import factory from sram_factory import factory
import contact
from tech import cell_properties as cell_props 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 module generates gds of a parametrically sized 4-input nand.
This model use ptx to generate a 4-input nand within a cetrain height. This model use ptx to generate a 4-input nand within a cetrain height.
@ -82,7 +81,6 @@ class pnand4(pgate.pgate):
tx_type="nmos", tx_type="nmos",
add_source_contact="active", add_source_contact="active",
add_drain_contact="active") add_drain_contact="active")
self.add_mod(self.nmos_center)
self.nmos_right = factory.create(module_type="ptx", self.nmos_right = factory.create(module_type="ptx",
width=self.nmos_width, width=self.nmos_width,
@ -90,7 +88,6 @@ class pnand4(pgate.pgate):
tx_type="nmos", tx_type="nmos",
add_source_contact="active", add_source_contact="active",
add_drain_contact=self.route_layer) add_drain_contact=self.route_layer)
self.add_mod(self.nmos_right)
self.nmos_left = factory.create(module_type="ptx", self.nmos_left = factory.create(module_type="ptx",
width=self.nmos_width, width=self.nmos_width,
@ -98,7 +95,6 @@ class pnand4(pgate.pgate):
tx_type="nmos", tx_type="nmos",
add_source_contact=self.route_layer, add_source_contact=self.route_layer,
add_drain_contact="active") add_drain_contact="active")
self.add_mod(self.nmos_left)
self.pmos_left = factory.create(module_type="ptx", self.pmos_left = factory.create(module_type="ptx",
width=self.pmos_width, width=self.pmos_width,
@ -106,7 +102,6 @@ class pnand4(pgate.pgate):
tx_type="pmos", tx_type="pmos",
add_source_contact=self.route_layer, add_source_contact=self.route_layer,
add_drain_contact=self.route_layer) add_drain_contact=self.route_layer)
self.add_mod(self.pmos_left)
self.pmos_center = factory.create(module_type="ptx", self.pmos_center = factory.create(module_type="ptx",
width=self.pmos_width, width=self.pmos_width,
@ -114,7 +109,6 @@ class pnand4(pgate.pgate):
tx_type="pmos", tx_type="pmos",
add_source_contact=self.route_layer, add_source_contact=self.route_layer,
add_drain_contact=self.route_layer) add_drain_contact=self.route_layer)
self.add_mod(self.pmos_center)
self.pmos_right = factory.create(module_type="ptx", self.pmos_right = factory.create(module_type="ptx",
width=self.pmos_width, width=self.pmos_width,
@ -122,7 +116,6 @@ class pnand4(pgate.pgate):
tx_type="pmos", tx_type="pmos",
add_source_contact=self.route_layer, add_source_contact=self.route_layer,
add_drain_contact=self.route_layer) add_drain_contact=self.route_layer)
self.add_mod(self.pmos_right)
def setup_layout_constants(self): def setup_layout_constants(self):
""" Pre-compute some handy layout parameters. """ """ Pre-compute some handy layout parameters. """
@ -231,11 +224,11 @@ class pnand4(pgate.pgate):
bottom_pin = self.nmos1_inst.get_pin("D") bottom_pin = self.nmos1_inst.get_pin("D")
# active contact metal to poly contact metal spacing # 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 # active diffusion to poly contact spacing
# doesn't use nmos uy because that is calculated using offset + poly height # 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_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 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, self.inputA_yoffset = max(active_contact_to_poly_contact,
active_to_poly_contact, active_to_poly_contact,
@ -356,12 +349,12 @@ class pnand4(pgate.pgate):
Input inverted by this stage. Input inverted by this stage.
""" """
parasitic_delay = 3 parasitic_delay = 3
return logical_effort.logical_effort(self.name, return logical_effort(self.name,
self.size, self.size,
self.input_load(), self.input_load(),
cout, cout,
parasitic_delay, parasitic_delay,
not inp_is_rise) not inp_is_rise)
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
""" """

View File

@ -5,15 +5,15 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import pgate from .pgate import *
import debug import debug
from tech import drc, parameter, spice from tech import drc, parameter, spice
from vector import vector from base import vector
from sram_factory import factory from sram_factory import factory
from tech import cell_properties as cell_props 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 module generates gds of a parametrically sized 2-input nor.
This model use ptx to generate a 2-input nor within a cetrain height. This model use ptx to generate a 2-input nor within a cetrain height.
@ -77,7 +77,6 @@ class pnor2(pgate.pgate):
tx_type="nmos", tx_type="nmos",
add_source_contact=self.route_layer, add_source_contact=self.route_layer,
add_drain_contact=self.route_layer) add_drain_contact=self.route_layer)
self.add_mod(self.nmos_left)
self.nmos_right = factory.create(module_type="ptx", self.nmos_right = factory.create(module_type="ptx",
width=self.nmos_width, width=self.nmos_width,
@ -85,7 +84,6 @@ class pnor2(pgate.pgate):
tx_type="nmos", tx_type="nmos",
add_source_contact=self.route_layer, add_source_contact=self.route_layer,
add_drain_contact=self.route_layer) add_drain_contact=self.route_layer)
self.add_mod(self.nmos_right)
self.pmos_left = factory.create(module_type="ptx", self.pmos_left = factory.create(module_type="ptx",
width=self.pmos_width, width=self.pmos_width,
@ -93,7 +91,6 @@ class pnor2(pgate.pgate):
tx_type="pmos", tx_type="pmos",
add_source_contact=self.route_layer, add_source_contact=self.route_layer,
add_drain_contact="active") add_drain_contact="active")
self.add_mod(self.pmos_left)
self.pmos_right = factory.create(module_type="ptx", self.pmos_right = factory.create(module_type="ptx",
width=self.pmos_width, width=self.pmos_width,
@ -101,7 +98,6 @@ class pnor2(pgate.pgate):
tx_type="pmos", tx_type="pmos",
add_source_contact="active", add_source_contact="active",
add_drain_contact=self.route_layer) add_drain_contact=self.route_layer)
self.add_mod(self.pmos_right)
def setup_layout_constants(self): def setup_layout_constants(self):
""" Pre-compute some handy layout parameters. """ """ Pre-compute some handy layout parameters. """

View File

@ -5,15 +5,15 @@
# #
from math import log, ceil from math import log, ceil
import debug import debug
import design from base import design
from sram_factory import factory from sram_factory import factory
from vector import vector from base import vector
from tech import layer, drc from tech import layer, drc
from globals import OPTS from globals import OPTS
from tech import layer_properties as layer_props 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).. Create the address port (row decoder and wordline driver)..
""" """
@ -76,15 +76,18 @@ class port_address(design.design):
def route_supplies(self): def route_supplies(self):
""" Propagate all vdd/gnd pins up to this level for all modules """ """ Propagate all vdd/gnd pins up to this level for all modules """
for inst in [self.wordline_driver_array_inst, self.row_decoder_inst]: if layer_props.wordline_driver.vertical_supply:
self.copy_power_pins(inst, "vdd") self.copy_layout_pin(self.rbl_driver_inst, "vdd")
self.copy_power_pins(inst, "gnd") 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()])
for rbl_vdd_pin in self.rbl_driver_inst.get_pins("vdd"): self.copy_layout_pin(self.wordline_driver_array_inst, "vdd")
if layer_props.port_address.supply_offset: self.copy_layout_pin(self.wordline_driver_array_inst, "gnd")
self.copy_power_pin(rbl_vdd_pin)
else: self.copy_layout_pin(self.row_decoder_inst, "vdd")
self.copy_power_pin(rbl_vdd_pin, loc=rbl_vdd_pin.lc()) self.copy_layout_pin(self.row_decoder_inst, "gnd")
# Also connect the B input of the RBL and_dec to vdd # Also connect the B input of the RBL and_dec to vdd
if OPTS.local_array_size == 0: if OPTS.local_array_size == 0:
@ -145,12 +148,10 @@ class port_address(design.design):
self.row_decoder = factory.create(module_type="decoder", self.row_decoder = factory.create(module_type="decoder",
num_outputs=self.num_rows) num_outputs=self.num_rows)
self.add_mod(self.row_decoder)
self.wordline_driver_array = factory.create(module_type="wordline_driver_array", self.wordline_driver_array = factory.create(module_type="wordline_driver_array",
rows=self.num_rows, rows=self.num_rows,
cols=self.num_cols) cols=self.num_cols)
self.add_mod(self.wordline_driver_array)
local_array_size = OPTS.local_array_size local_array_size = OPTS.local_array_size
if local_array_size > 0: if local_array_size > 0:
@ -174,8 +175,6 @@ class port_address(design.design):
size=driver_size, size=driver_size,
height=b.height) height=b.height)
self.add_mod(self.rbl_driver)
def create_row_decoder(self): def create_row_decoder(self):
""" Create the hierarchical row decoder """ """ Create the hierarchical row decoder """
@ -232,17 +231,15 @@ class port_address(design.design):
wordline_driver_array_offset = vector(self.row_decoder_inst.rx(), 0) wordline_driver_array_offset = vector(self.row_decoder_inst.rx(), 0)
self.wordline_driver_array_inst.place(wordline_driver_array_offset) 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 # This m4_pitch corresponds to the offset space for jog routing in the
well_gap = 2 * drc("pwell_to_nwell") + drc("nwell_enclose_active") # wordline_driver_array
x_offset = self.wordline_driver_array_inst.rx() - well_gap - self.rbl_driver.width rbl_driver_offset = wordline_driver_array_offset + vector(2 * self.m4_pitch, 0)
if self.port == 0: if self.port == 0:
rbl_driver_offset = vector(x_offset,
0)
self.rbl_driver_inst.place(rbl_driver_offset, "MX") self.rbl_driver_inst.place(rbl_driver_offset, "MX")
else: else:
rbl_driver_offset = vector(x_offset, rbl_driver_offset += vector(0,
self.wordline_driver_array.height) self.wordline_driver_array.height)
self.rbl_driver_inst.place(rbl_driver_offset) self.rbl_driver_inst.place(rbl_driver_offset)
# Pass this up # Pass this up

View File

@ -5,17 +5,17 @@
# #
from tech import drc from tech import drc
import debug import debug
import design from base import design
import math import math
from sram_factory import factory from sram_factory import factory
from collections import namedtuple from collections import namedtuple
from vector import vector from base import vector
from globals import OPTS from globals import OPTS
from tech import cell_properties from tech import cell_properties
from tech import layer_properties as layer_props 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. 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. Port 0 always has the RBL on the left while port 1 is on the right.
@ -215,7 +215,6 @@ class port_data(design.design):
bitcell_bl=self.bl_names[self.port], bitcell_bl=self.bl_names[self.port],
bitcell_br=self.br_names[self.port], bitcell_br=self.br_names[self.port],
column_offset=self.port - 1) column_offset=self.port - 1)
self.add_mod(self.precharge_array)
if self.port in self.read_ports: if self.port in self.read_ports:
# RBLs don't get a sense amp # RBLs don't get a sense amp
@ -224,7 +223,6 @@ class port_data(design.design):
offsets=self.bit_offsets, offsets=self.bit_offsets,
words_per_row=self.words_per_row, words_per_row=self.words_per_row,
num_spare_cols=self.num_spare_cols) num_spare_cols=self.num_spare_cols)
self.add_mod(self.sense_amp_array)
else: else:
self.sense_amp_array = None self.sense_amp_array = None
@ -236,7 +234,6 @@ class port_data(design.design):
offsets=self.bit_offsets, offsets=self.bit_offsets,
bitcell_bl=self.bl_names[self.port], bitcell_bl=self.bl_names[self.port],
bitcell_br=self.br_names[self.port]) bitcell_br=self.br_names[self.port])
self.add_mod(self.column_mux_array)
else: else:
self.column_mux_array = None self.column_mux_array = None
@ -248,7 +245,6 @@ class port_data(design.design):
offsets=self.bit_offsets, offsets=self.bit_offsets,
write_size=self.write_size, write_size=self.write_size,
num_spare_cols=self.num_spare_cols) num_spare_cols=self.num_spare_cols)
self.add_mod(self.write_driver_array)
if self.write_size is not None: if self.write_size is not None:
# RBLs don't get a write mask # RBLs don't get a write mask
self.write_mask_and_array = factory.create(module_type="write_mask_and_array", 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, offsets=self.bit_offsets,
word_size=self.word_size, word_size=self.word_size,
write_size=self.write_size) write_size=self.write_size)
self.add_mod(self.write_mask_and_array)
else: else:
self.write_mask_and_array = None self.write_mask_and_array = None
@ -516,9 +511,6 @@ class port_data(design.design):
wdriver_inst = self.write_driver_array_inst wdriver_inst = self.write_driver_array_inst
for bit in range(self.num_wmasks): 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)) wmask_out_pin = wmask_inst.get_pin("wmask_out_{0}".format(bit))
wdriver_en_pin = wdriver_inst.get_pin("en_{0}".format(bit)) wdriver_en_pin = wdriver_inst.get_pin("en_{0}".format(bit))

View File

@ -5,18 +5,17 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import contact from base import design
import design
import debug import debug
from pgate import pgate from .pgate import *
from tech import parameter, drc from tech import parameter, drc
from vector import vector from base import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
from tech import cell_properties as cell_props from tech import cell_properties as cell_props
class precharge(design.design): class precharge(design):
""" """
Creates a single precharge cell Creates a single precharge cell
This module implements the precharge bitline cell used in the design. This module implements the precharge bitline cell used in the design.
@ -71,7 +70,7 @@ class precharge(design.design):
self.connect_poly() self.connect_poly()
self.route_en() self.route_en()
self.place_nwell_and_contact() self.place_nwell_and_contact()
self.route_vdd_rail() self.route_supplies()
self.route_bitlines() self.route_bitlines()
self.connect_to_bitlines() self.connect_to_bitlines()
self.add_boundary() self.add_boundary()
@ -90,35 +89,19 @@ class precharge(design.design):
width=self.ptx_width, width=self.ptx_width,
mults=self.ptx_mults, mults=self.ptx_mults,
tx_type="pmos") tx_type="pmos")
self.add_mod(self.pmos)
def route_vdd_rail(self): def route_supplies(self):
""" """
Adds a vdd rail at the top of the cell 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") 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])
# center of vdd rail self.add_layout_pin_rect_center(text="vdd",
pmos_vdd_pos = vector(pmos_pin.cx(), vdd_position.y) layer=pmos_pin.layer,
self.add_path(self.en_layer, [pmos_pin.center(), pmos_vdd_pos]) offset=self.well_contact_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): def create_ptx(self):
""" """
@ -194,7 +177,7 @@ class precharge(design.design):
pin_offset = self.lower_pmos_inst.get_pin("G").lr() pin_offset = self.lower_pmos_inst.get_pin("G").lr()
# This is an extra space down for some techs with contact to active spacing # This is an extra space down for some techs with contact to active spacing
contact_space = max(self.poly_space, 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) offset = pin_offset - vector(0, contact_space)
self.add_via_stack_center(from_layer="poly", self.add_via_stack_center(from_layer="poly",
to_layer=self.en_layer, to_layer=self.en_layer,
@ -214,7 +197,7 @@ class precharge(design.design):
# adds the contact from active to metal1 # adds the contact from active to metal1
offset_height = self.upper_pmos1_inst.uy() + \ offset_height = self.upper_pmos1_inst.uy() + \
contact.active_contact.height + \ self.active_contact.height + \
self.nwell_extend_active self.nwell_extend_active
self.well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1, 0) + \ self.well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1, 0) + \
vector(0, offset_height) vector(0, offset_height)
@ -226,7 +209,7 @@ class precharge(design.design):
to_layer=self.bitline_layer, to_layer=self.bitline_layer,
offset=self.well_contact_pos) 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 # nwell should span the whole design since it is pmos only
self.add_rect(layer="nwell", self.add_rect(layer="nwell",
@ -305,4 +288,3 @@ class precharge(design.design):
self.add_path(self.bitline_layer, self.add_path(self.bitline_layer,
[left_pos, right_pos], [left_pos, right_pos],
width=pmos_pin.height()) width=pmos_pin.height())

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