Merge branch 'dev' into delay_ctrl

This commit is contained in:
Sam Crow 2023-06-05 16:24:48 -07:00
commit 2f5d3b6faf
690 changed files with 347277 additions and 7674 deletions

27
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,27 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**Version**
Which commit are you using?
**To Reproduce**
What did you do to demonstrate the bug?
Please include your configuration file used.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Logs**
If applicable, add logs or output to help explain your problem.
**Additional context**
Add any other context about the problem here.

108
.github/workflows/README.md vendored Normal file
View File

@ -0,0 +1,108 @@
# How do the workflows work?
1. When there is a push to the private repo's 'dev' branch (private/dev),
`regress` workflow runs the regression tests if the commit is not versioned.
`sync` workflow runs and makes sure that the versioned commit has a tag if it is
versioned. See [important notes](#important-notes) to see what "versioned
commit" means.
1. If `regress` workflow fails on 'private/dev', `sync` workflow gets triggered
and it pushes the latest changes to the public repo's 'dev' branch (public/dev).
1. If `regress` workflow successfully passes on 'private/dev', `version`
workflow gets triggered. It creates a new version commit and tag, and pushes to
'private/dev', 'public/dev', and 'public/stable'.
1. When there is a push with new version to the 'public/stable' branch, `deploy`
workflow runs. It deploys the PyPI package of OpenRAM and creates a new GitHub
release on that repo.
## Important Notes
1. Workflows understand that the latest commit is versioned with the following
commit message syntax.
```
Bump version: <any message>
```
Automatically generated version commits have the following syntax:
```
Bump version: a.b.c -> a.b.d
```
1. `version` workflow only increments the right-most version digit. Other digits
in the version number must be updated manually, following the syntax above. Just
following this syntax is enough for workflows to create a new version
automatically. That means, you don't have to tag that commit manually.
1. `regress` workflow doesn't run if the push has a new version. We assume that
this commit was automatically generated after a previous commit passed `regress`
workflow or was manually generated with caution.
1. `regress` workflow doesn't run on the public repo.
1. `deploy` workflow only runs on branches named 'stable'.
1. `version` workflow is only triggered from branches named 'dev' if they pass
`regress` workflow.
1. `sync` workflow only runs on the private repo.
1. `sync_tag` workflow only runs on the private repo.
1. Merging pull requests on the private repo should be safe in any case. They
are treated the same as commit pushes.
> **Warning**: `regress` workflow is currently disabled on the public repo
> manually. This was done because of a security risk on our private server.
> Enabling it on GitHub will run `regress` workflow on the public repo.
## Flowchart
```mermaid
flowchart TD
start((Start));
privatedev[(PrivateRAM/dev)];
publicdev[(OpenRAM/dev)];
publicstable[(OpenRAM/stable)];
regressprivate{{regress}};
regresspublic{{regress}};
syncnover{{sync}};
synctag{{sync_tag}};
deploy{{deploy}};
versionprivate{{version}};
versionpublic{{version}};
privateif1(Is versioned?);
privateif2(Has version tag?);
privateif3(Did tests pass?);
publicif1(Is versioned?);
publicif2(Is versioned?);
publicif3(Did tests pass?)
start-- Push commit -->privatedev
privatedev-->privateif1
privateif1-- Yes -->privateif2
privateif2-- No -->synctag
privateif1-- No -->regressprivate
regressprivate-->privateif3
privateif3-- Yes -->versionprivate
privateif3-- No -->syncnover
start-- Push commit / Merge PR -->publicdev
publicdev-->publicif1
publicif1-- No -->regresspublic
regresspublic-->publicif3
publicif3-- Yes -->versionpublic
start-- "Push commit (from workflows)" -->publicstable
publicstable-->publicif2
publicif2-- Yes -->deploy
```

View File

@ -1,38 +0,0 @@
name: ci
on: [push]
jobs:
regress:
runs-on: self-hosted
steps:
- name: Checkout code
uses: actions/checkout@v1
- name: Docker build
run: |
cd ${{ github.workspace }}/docker
make build
- name: PDK Install
run: |
export OPENRAM_HOME="${{ github.workspace }}/compiler"
export OPENRAM_TECH="${{ github.workspace }}/technology"
#cd $OPENRAM_HOME/tests
#export PDK_ROOT="${{ github.workspace }}/pdk"
#make pdk
#make install
- name: Regress
run: |
export OPENRAM_HOME="${{ github.workspace }}/compiler"
export OPENRAM_TECH="${{ github.workspace }}/technology"
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
#$OPENRAM_HOME/tests/regress.py -j 24 -t scn4m_subm
cd $OPENRAM_HOME/tests
make clean
make -k -j 48
- name: Archive
if: ${{ failure() }}
uses: actions/upload-artifact@v2
with:
name: Regress Archives
path: ${{ github.workspace }}/compiler/tests/results/*

54
.github/workflows/deploy.yml vendored Normal file
View File

@ -0,0 +1,54 @@
name: deploy
on:
push:
branches:
- stable
jobs:
# This job upload the Python library to PyPI
deploy_pip:
if: ${{ startsWith(github.event.head_commit.message, 'Bump version:') }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v1
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: '3.8'
- name: Install dependencies
run: |
python3 -m pip install virtualenv
- name: Build Python package
run: |
make build_library
- name: Upload package to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
# This job creates a new GitHub release
github_release:
if: ${{ startsWith(github.event.head_commit.message, 'Bump version:') }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 0
token: ${{ secrets.WORKFLOW_ACCESS_TOKEN }}
- name: Create a release
run: |
# Find the last two commits
export LATEST_TAG="$(git describe --tags --abbrev=0)"
export PREVIOUS_TAG="$(git describe --tags --abbrev=0 $(git rev-list --tags --skip=1 --max-count=1))"
# Write release notes to a file
touch release_notes.txt
printf "## Install\nPython package is available at [PyPI](https://pypi.org/project/openram/).\n" >> release_notes.txt
printf "## Documentation\nDocumentation is available [here](https://github.com/VLSIDA/OpenRAM/blob/stable/docs/source/index.md).\n" >> release_notes.txt
printf "## Changes\n" >> release_notes.txt
printf "Full changelog: https://github.com/VLSIDA/OpenRAM/compare/${PREVIOUS_TAG}...${LATEST_TAG}\n" >> release_notes.txt
printf "## Contributors\n" >> release_notes.txt
printf "$(git log --pretty='format:+ %an' ${LATEST_TAG}...${PREVIOUS_TAG} | sort -u)\n" >> release_notes.txt
# Create the release via GitHub CLI
gh release create ${LATEST_TAG} --verify-tag -F release_notes.txt
env:
GITHUB_TOKEN: ${{ secrets.WORKFLOW_ACCESS_TOKEN }}

63
.github/workflows/regress.yml vendored Normal file
View File

@ -0,0 +1,63 @@
name: regress
on:
push:
branches-ignore:
- stable
jobs:
# All tests should be run from this job
regression_test:
# This job runs on pull requests or any push that doesn't have a new version
if: ${{ startsWith(github.event.head_commit.message, 'Bump version:') == false }}
runs-on: self-hosted
steps:
- name: Checkout code
uses: actions/checkout@v1
- name: Library build
run: |
rm -rf ~/.local/lib/python3.8/site-packages/openram*
make library
- name: Build conda
run: |
./install_conda.sh
- name: PDK Install
run: |
export OPENRAM_HOME="${{ github.workspace }}/compiler"
export OPENRAM_TECH="${{ github.workspace }}/technology"
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 PDK_ROOT="${{ github.workspace }}/pdk"
export FREEPDK45="~/FreePDK45"
# KLAYOUT_PATH breaks klayout installation. Unset it for now...
unset KLAYOUT_PATH
#cd $OPENRAM_HOME/.. && make pdk && make install
#export OPENRAM_TMP="${{ github.workspace }}/scn4me_subm_temp"
#python3-coverage run -p $OPENRAM_HOME/tests/regress.py -j 12 -t scn4m_subm
#$OPENRAM_HOME/tests/regress.py -j 24 -t scn4m_subm
cd $OPENRAM_HOME/tests
make clean
make -k -j 48
- name: Archive
if: ${{ failure() }}
uses: actions/upload-artifact@v2
with:
name: Regress Archives
path: ${{ github.workspace }}/compiler/tests/results/*
# This job triggers sync.yml workflow
sync_trigger:
if: ${{ always() && github.ref_name == 'dev' && github.repository == 'VLSIDA/PrivateRAM' && needs.regression_test.result == 'failure' }}
needs: regression_test
uses: ./.github/workflows/sync.yml
secrets:
WORKFLOW_ACCESS_TOKEN: ${{ secrets.WORKFLOW_ACCESS_TOKEN }}
# This job triggers version.yml workflow
version_trigger:
if: ${{ github.ref_name == 'dev' }}
needs: regression_test
uses: ./.github/workflows/version.yml
secrets:
WORKFLOW_ACCESS_TOKEN: ${{ secrets.WORKFLOW_ACCESS_TOKEN }}

27
.github/workflows/sync.yml vendored Normal file
View File

@ -0,0 +1,27 @@
name: sync
on:
workflow_call:
secrets:
WORKFLOW_ACCESS_TOKEN:
required: true
jobs:
# This job synchronizes the 'dev' branch of OpenRAM repo with the current branch
sync_dev_no_version:
if: ${{ github.repository == 'VLSIDA/PrivateRAM' }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 0
token: ${{ secrets.WORKFLOW_ACCESS_TOKEN }}
- name: Synchronize OpenRAM repo
run: |
# Configure pusher account
git config --global user.name "vlsida-bot"
git config --global user.email "mrg+vlsidabot@ucsc.edu"
# Add remote repo
git remote add public-repo https://${{ secrets.WORKFLOW_ACCESS_TOKEN }}@github.com/VLSIDA/OpenRAM.git
git pull public-repo dev
# Push the latest changes
git push -u public-repo HEAD:dev

42
.github/workflows/sync_tag.yml vendored Normal file
View File

@ -0,0 +1,42 @@
name: sync_tag
on:
push:
branches:
- dev
jobs:
# This job makes sure that a version commit has a tag (manually bumped versions might have tags missing)
sync_dev_tag_check:
if: ${{ github.repository == 'VLSIDA/PrivateRAM' && startsWith(github.event.head_commit.message, 'Bump version:') }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 0
token: ${{ secrets.WORKFLOW_ACCESS_TOKEN }}
- name: Compare version and tag
run: |
# Configure pusher account
git config --global user.name "vlsida-bot"
git config --global user.email "mrg+vlsidabot@ucsc.edu"
# Add both repos
git remote add private-repo https://${{ secrets.WORKFLOW_ACCESS_TOKEN }}@github.com/VLSIDA/PrivateRAM.git
git remote add public-repo https://${{ secrets.WORKFLOW_ACCESS_TOKEN }}@github.com/VLSIDA/OpenRAM.git
# Read the version file
echo "LATEST_VERSION=v$(cat VERSION)" >> $GITHUB_ENV
# Read the tag name of the last commit
echo "HEAD_TAG=$(git describe --tags HEAD)" >> $GITHUB_ENV
- name: Make a new tag and push
if: ${{ env.LATEST_VERSION != env.HEAD_TAG }}
run: |
# Tag the commit
git tag ${{ env.LATEST_VERSION }} HEAD
# Push to private/dev
git pull private-repo dev
git push private-repo HEAD:dev ${{ env.LATEST_VERSION }}
# Push to public-repo/dev
git pull public-repo dev
git push public-repo HEAD:dev ${{ env.LATEST_VERSION }}
# Push to public/stable
git pull public-repo stable
git push public-repo HEAD:stable ${{ env.LATEST_VERSION }}

46
.github/workflows/version.yml vendored Normal file
View File

@ -0,0 +1,46 @@
name: version
on:
workflow_call:
secrets:
WORKFLOW_ACCESS_TOKEN:
required: true
jobs:
make_version:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 0
token: ${{ secrets.WORKFLOW_ACCESS_TOKEN }}
- name: Configure git
run: |
# Configure the committer
git config --global user.name "vlsida-bot"
git config --global user.email "mrg+vlsidabot@ucsc.edu"
# Set remote repos
git remote add private-repo https://${{ secrets.WORKFLOW_ACCESS_TOKEN }}@github.com/VLSIDA/PrivateRAM.git
git remote add public-repo https://${{ secrets.WORKFLOW_ACCESS_TOKEN }}@github.com/VLSIDA/OpenRAM.git
- name: Make new version number
run: |
# Read the current version number
export CURRENT_VERSION="$(cat VERSION)"
# Increment the version number
export NEXT_VERSION="$(echo ${CURRENT_VERSION} | awk -F. -v OFS=. '{$NF += 1 ; print}')"
echo "${NEXT_VERSION}" > VERSION
# Commit the change and tag the commit
git commit -a -m "Bump version: ${CURRENT_VERSION} -> ${NEXT_VERSION}"
git tag "v${NEXT_VERSION}" HEAD
- name: Push changes
run: |
# Read next tag
export NEXT_TAG="v$(cat VERSION)"
# Push to private/dev
git pull private-repo dev
git push private-repo HEAD:dev ${NEXT_TAG}
# Push to public/dev
git pull public-repo dev
git push public-repo HEAD:dev ${NEXT_TAG}
# Push to public/stable
git pull public-repo stable
git push public-repo HEAD:stable ${NEXT_TAG}

10
.gitignore vendored
View File

@ -1,4 +1,5 @@
.DS_Store .DS_Store
.coverage*
*~ *~
*.orig *.orig
*.rej *.rej
@ -13,3 +14,12 @@ technology/freepdk45/ncsu_basekit
technology/sky130/*_lib technology/sky130/*_lib
technology/sky130/tech/.magicrc technology/sky130/tech/.magicrc
.idea .idea
compiler/tests/results/
open_pdks/
dist/
openram.egg-info/
miniconda/
sky130A/
sky130B/
skywater-pdk/
sky130_fd_bd_sram/

117
HINTS.md
View File

@ -1,117 +0,0 @@
# Debugging
When OpenRAM runs, it puts files in a temporary directory that is
shown in the banner at the top. Like:
```
/tmp/openram_mrg_18128_temp/
```
This is where simulations and DRC/LVS get run so there is no network
traffic. The directory name is unique for each person and run of
OpenRAM to not clobber any files and allow simultaneous runs. If it
passes, the files are deleted. If it fails, you will see these files:
+ temp.gds is the layout (.mag files too if using SCMOS)
+ temp.sp is the netlist
+ test1.drc.err is the std err output of the DRC command
+ test1.drc.out is the standard output of the DRC command
+ test1.drc.results is the DRC results file
+ test1.lvs.err is the std err output of the LVS command
+ test1.lvs.out is the standard output of the LVS command
+ test1.lvs.results is the DRC results file
Depending on your DRC/LVS tools, there will also be:
+ \_calibreDRC.rul\_ is the DRC rule file (Calibre)
+ dc_runset is the command file (Calibre)
+ extracted.sp (Calibre)
+ run_lvs.sh is a Netgen script for LVS (Netgen)
+ run_drc.sh is a Magic script for DRC (Magic)
+ <topcell>.spice (Magic)
If DRC/LVS fails, the first thing is to check if it ran in the .out and
.err file. This shows the standard output and error output from
running DRC/LVS. If there is a setup problem it will be shown here.
If DRC/LVS runs, but doesn't pass, you then should look at the .results
file. If the DRC fails, it will typically show you the command that was used
to run Calibre or Magic+Netgen.
To debug, you will need a layout viewer. I prefer to use Glade
on my Mac, but you can also use Calibre, Magic, etc.
1. Klayout
You can view the designs in [Klayout](https://www.klayout.de/) with the configuration
file provided in the tech directories. For example,
```
klayout temp.gds -l /home/vagrant/openram/technology/freepdk45/tf/FreePDK45.lyp
```
2. Calibre
Start the Calibre DESIGNrev viewer in the temp directory and load your GDS file:
```
calibredrv temp.gds
```
Select Verification->Start RVE and select the results database file in
the new form (e.g., test1.drc.db). This will start the RVE (results
viewer). Scroll through the check pane and find the DRC check with an
error. Select it and it will open some numbers to the right. Double
click on any of the errors in the result browser. These will be
labelled as numbers "1 2 3 4" for example will be 4 DRC errors.
In the viewer ">" opens the layout down a level.
3. Glade
You can view errors in [Glade](http://www.peardrop.co.uk/glade/) as well.
To remote display over X windows, you need to disable OpenGL acceleration or use vnc
or something. You can disable by adding this to your .bashrc in bash:
```
export GLADE_USE_OPENGL=no
```
or in .cshrc/.tcshrc in csh/tcsh:
```
setenv GLADE_USE_OPENGAL no
```
To use this with the FreePDK45 or SCMOS layer views you should use the
tech files. Then create a .glade.py file in your user directory with
these commands to load the technology layers:
```
ui().importCds("default",
"/Users/mrg/techfiles/freepdk45/display.drf",
"/Users/mrg/techfiles/freepdk45/FreePDK45.tf", 1000, 1,
"/Users/mrg/techfiles/freepdk45/layers.map")
```
Obviously, edit the paths to point to your directory. To switch
between processes, you have to change the importCds command (or you
can manually run the command each time you start glade).
To load the errors, you simply do Verify->Import Calibre Errors select
the .results file from Calibre.
4. Magic
Magic is only supported in SCMOS. You will need to install the MOSIS SCMOS rules
and [Magic](http://opencircuitdesign.com/)
When running DRC or extraction, OpenRAM will load the GDS file, save
the .ext/.mag files, and export an extracted netlist (.spice).
5. It is possible to use other viewers as well, such as:
* [LayoutEditor](http://www.layouteditor.net/)
# Example to output/input .gds layout files from/to Cadence
1. To create your component layouts, you should stream them to
individual gds files using our provided layermap and flatten
cells. For example,
```
strmout -layerMap layers.map -library sram -topCell $i -view layout -flattenVias -flattenPcells -strmFile ../gds_lib/$i.gds
```
2. To stream a layout back into Cadence, do this:
```
strmin -layerMap layers.map -attachTechFileOfLib NCSU\_TechLib\_FreePDK45 -library sram_4_32 -strmFile sram_4_32.gds
```
When you import a gds file, make sure to attach the correct tech lib
or you will get incorrect layers in the resulting library.

26
MANIFEST.in Normal file
View File

@ -0,0 +1,26 @@
include Makefile
include openram.mk
include setpaths.sh
include requirements.txt
include install_conda.sh
include docker/*
recursive-include compiler *
recursive-include technology *
include VERSION
exclude .DS_Store
exclude .idea
exclude **/model_data
exclude technology/sky130/*_lib
exclude technology/sky130/tech/.magicrc
exclude compiler/gen_stimulus.py
exclude compiler/model_data_util.py
exclude compiler/printGDS.py
exclude compiler/processGDS.py
exclude compiler/uniquifyGDS.py
exclude compiler/view_profile.py
exclude compiler/run_profile.sh
recursive-exclude open_pdks *
recursive-exclude compiler/tests/results *
recursive-exclude technology/freepdk45/ncsu_basekit *
recursive-exclude outputs *
global-exclude *.pyc *~ *.orig *.rej *.aux *.out *.toc *.synctex.gz

View File

@ -49,6 +49,9 @@ INSTALL_BASE_DIRS := gds_lib mag_lib sp_lib lvs_lib calibre_lvs_lib klayout_lvs_
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))
# If conda is installed, we will use Magic from there
CONDA_DIR := $(wildcard $(TOP_DIR)/miniconda)
check-pdk-root: check-pdk-root:
ifndef PDK_ROOT ifndef PDK_ROOT
$(error PDK_ROOT is undefined, please export it before running make) $(error PDK_ROOT is undefined, please export it before running make)
@ -58,33 +61,42 @@ $(SKY130_PDKS_DIR): check-pdk-root
@echo "Cloning skywater PDK..." @echo "Cloning skywater PDK..."
@[ -d $(PDK_ROOT)/skywater-pdk ] || \ @[ -d $(PDK_ROOT)/skywater-pdk ] || \
git clone https://github.com/google/skywater-pdk.git $(PDK_ROOT)/skywater-pdk git clone https://github.com/google/skywater-pdk.git $(PDK_ROOT)/skywater-pdk
@cd $(SKY130_PDKS_DIR) && \ @git -C $(SKY130_PDKS_DIR) checkout $(SKY130_PDKS_GIT_COMMIT) && \
git checkout main && git pull && \ git -C $(SKY130_PDKS_DIR) submodule update --init libraries/sky130_fd_pr/latest libraries/sky130_fd_sc_hd/latest
git checkout -qf $(SKY130_PDKS_GIT_COMMIT) && \
git submodule update --init libraries/sky130_fd_pr/latest libraries/sky130_fd_sc_hd/latest
$(OPEN_PDKS_DIR): $(SKY130_PDKS_DIR) $(OPEN_PDKS_DIR): $(SKY130_PDKS_DIR)
@echo "Cloning open_pdks..." @echo "Cloning open_pdks..."
@[ -d $(OPEN_PDKS_DIR) ] || \ @[ -d $(OPEN_PDKS_DIR) ] || \
git clone $(OPEN_PDKS_GIT_REPO) $(OPEN_PDKS_DIR) git clone $(OPEN_PDKS_GIT_REPO) $(OPEN_PDKS_DIR)
@cd $(OPEN_PDKS_DIR) && git pull && git checkout $(OPEN_PDKS_GIT_COMMIT) @git -C $(OPEN_PDKS_DIR) checkout $(OPEN_PDKS_GIT_COMMIT)
$(SKY130_PDK): $(OPEN_PDKS_DIR) $(SKY130_PDKS_DIR) $(SKY130_PDK): $(OPEN_PDKS_DIR) $(SKY130_PDKS_DIR)
@echo "Installing open_pdks..." @echo "Installing open_pdks..."
$(DOCKER_CMD) sh -c ". /home/cad-user/.bashrc && cd /pdk/open_pdks && \ ifeq ($(CONDA_DIR),"")
./configure --enable-sky130-pdk=/pdk/skywater-pdk/libraries --with-sky130-local-path=/pdk && \ @cd $(PDK_ROOT)/open_pdks && \
cd sky130 && \ ./configure --enable-sky130-pdk=$(PDK_ROOT)/skywater-pdk/libraries --with-sky130-local-path=$(PDK_ROOT) && \
make veryclean && \ cd sky130 && \
make && \ make veryclean && \
make SHARED_PDKS_PATH=/pdk install" make && \
make SHARED_PDKS_PATH=$(PDK_ROOT) install
else
@source $(TOP_DIR)/miniconda/bin/activate && \
cd $(PDK_ROOT)/open_pdks && \
./configure --enable-sky130-pdk=$(PDK_ROOT)/skywater-pdk/libraries --with-sky130-local-path=$(PDK_ROOT) && \
cd sky130 && \
make veryclean && \
make && \
make SHARED_PDKS_PATH=$(PDK_ROOT) install && \
conda deactivate
endif
$(SRAM_LIB_DIR): check-pdk-root $(SRAM_LIB_DIR): check-pdk-root
@echo "Cloning SRAM library..." @echo "Cloning SRAM library..."
@[ -d $(SRAM_LIB_DIR) ] || (\ @[ -d $(SRAM_LIB_DIR) ] || \
git clone $(SRAM_LIB_GIT_REPO) $(SRAM_LIB_DIR) && \ git clone $(SRAM_LIB_GIT_REPO) $(SRAM_LIB_DIR)
cd $(SRAM_LIB_DIR) && git pull && git checkout $(SRAM_LIB_GIT_COMMIT)) @git -C $(SRAM_LIB_DIR) checkout $(SRAM_LIB_GIT_COMMIT)
install: $(SRAM_LIB_DIR) pdk install: $(SRAM_LIB_DIR)
@[ -d $(PDK_ROOT)/sky130A ] || \ @[ -d $(PDK_ROOT)/sky130A ] || \
(echo "Warning: $(PDK_ROOT)/sky130A not found!! Run make pdk first." && false) (echo "Warning: $(PDK_ROOT)/sky130A not found!! Run make pdk first." && false)
@[ -d $(PDK_ROOT)/skywater-pdk ] || \ @[ -d $(PDK_ROOT)/skywater-pdk ] || \
@ -215,3 +227,16 @@ wipe: uninstall
@rm -rf $(OPEN_PDKS_DIR) @rm -rf $(OPEN_PDKS_DIR)
@rm -rf $(SKY130_PDKS_DIR) @rm -rf $(SKY130_PDKS_DIR)
.PHONY: wipe .PHONY: wipe
# Build the openram library
build_library:
@rm -rf dist
@rm -rf openram.egg-info
@python3 -m pip install --upgrade build
@python3 -m build
.PHONY: build_library
# Build and install the openram library
library: build_library
@python3 -m pip install --force dist/openram*.whl
.PHONY: library

View File

@ -6,19 +6,24 @@ If you want to support a new technology, you will need to create:
We provide two technology examples for [SCMOS] and [FreePDK45]. Each We provide two technology examples for [SCMOS] and [FreePDK45]. Each
specific technology (e.g., [FreePDK45]) should be a subdirectory specific technology (e.g., [FreePDK45]) should be a subdirectory
(e.g., $OPENRAM_TECH/freepdk45) and include certain folders and files: (e.g., `$OPENRAM_TECH/freepdk45`) and include certain folders and files:
* gds_lib folder with all the .gds (premade) library cells: * `gds_lib` folder with all the `.gds` (premade) library cells:
* dff.gds * `dff.gds`
* sense_amp.gds * `sense_amp.gds`
* write_driver.gds * `write_driver.gds`
* cell_1rw.gds * `cell_1rw.gds`
* replica\_cell\_1rw.gds * `replica\_cell\_1rw.gds`
* dummy\_cell\_1rw.gds * `dummy\_cell\_1rw.gds`
* sp_lib folder with all the .sp (premade) library netlists for the above cells. * `sp_lib` folder with all the `.sp` (premade) library netlists for the above cells.
* layers.map * `layers.map`
* A valid tech Python module (tech directory with \_\_init\_\_.py and tech.py) with: * A valid tech Python module (tech directory with `__init__.py` and `tech.py`) with:
* References in tech.py to spice models * References in tech.py to spice models
* DRC/LVS rules needed for dynamic cells and routing * DRC/LVS rules needed for dynamic cells and routing
* Layer information * Layer information
* Spice and supply information * Spice and supply information
* etc. * etc.
[FreePDK45]: https://www.eda.ncsu.edu/wiki/FreePDK45:Contents
[SCMOS]: https://www.mosis.com/files/scmos/scmos.pdf

204
README.md
View File

@ -1,15 +1,17 @@
![](./images/OpenRAM_logo_yellow_transparent.svg) ![](https://raw.githubusercontent.com/VLSIDA/OpenRAM/stable/images/OpenRAM_logo_yellow_transparent.svg)
# OpenRAM # OpenRAM
[![Python 3.5](https://img.shields.io/badge/Python-3.5-green.svg)](https://www.python.org/) [![Python 3.5](https://img.shields.io/badge/Python-3.5-green.svg)](https://www.python.org/)
[![License: BSD 3-clause](./images/license_badge.svg)](./LICENSE) [![License: BSD 3-clause](https://raw.githubusercontent.com/VLSIDA/OpenRAM/stable/images/license_badge.svg)](./LICENSE)
[![Download](./images/download-stable-blue.svg)](https://github.com/VLSIDA/OpenRAM/archive/stable.zip) [![PyPI - Downloads](https://img.shields.io/pypi/dm/openram?color=brightgreen&label=PyPI)](https://pypi.org/project/openram/)
[![Download](./images/download-unstable-blue.svg)](https://github.com/VLSIDA/OpenRAM/archive/dev.zip) [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://githubtocolab.com/sfmth/openram-playground/blob/main/OpenRAM.ipynb)
An open-source static random access memory (SRAM) compiler. An open-source static random access memory (SRAM) compiler.
# What is OpenRAM? # What is OpenRAM?
<img align="right" width="25%" src="images/SCMOS_16kb_sram.jpg"> <img align="right" width="25%" src="https://raw.githubusercontent.com/VLSIDA/OpenRAM/stable/images/SCMOS_16kb_sram.jpg">
OpenRAM is an award winning open-source Python framework to create the layout, OpenRAM is an award winning open-source Python framework to create the layout,
netlists, timing and power models, placement and routing models, and netlists, timing and power models, placement and routing models, and
@ -17,185 +19,53 @@ other views necessary to use SRAMs in ASIC design. OpenRAM supports
integration in both commercial and open-source flows with both integration in both commercial and open-source flows with both
predictive and fabricable technologies. predictive and fabricable technologies.
# Documentation # Documentation
Please take a look at our presentation We have created a detailed Please see our [documentation][documentation] and let us know if anything needs
presentation that serves as our [documentation][documentation]. updating.
This is the most up-to-date information, so please let us know if you see
things that need to be fixed.
# Basic Setup
## Dependencies
Please see the Dockerfile for the required versions of tools.
In general, the OpenRAM compiler has very few dependencies:
+ Docker
+ Make
+ Python 3.6 or higher
+ Various Python packages (pip install -r requirements.txt)
+ [Git]
## Docker
We have a [docker setup](./docker) to run OpenRAM. To use this, you should run:
```
cd openram/docker
make build
```
This must be run once and will take a while to build all the tools.
## Environment
You must set two environment variables:
+ OPENRAM\_HOME should point to the compiler source directory.
+ OPENERAM\_TECH should point to one or more root technology directories (colon separated).
You should also add OPENRAM\_HOME to your PYTHONPATH.
For example add this to your .bashrc:
```
export OPENRAM_HOME="$HOME/openram/compiler"
export OPENRAM_TECH="$HOME/openram/technology"
export PYTHONPATH=$OPENRAM_HOME
```
Note that if you want symbols to resolve in your editor, you may also want to add the specific technology
directory that you use and any custom technology modules as well. For example:
```
export PYTHONPATH="$OPENRAM_HOME:$OPENRAM_TECH/sky130:$OPENRAM_TECH/sky130/custom"
```
We include the tech files necessary for [SCMOS] SCN4M_SUBM,
[FreePDK45]. The [SCMOS] spice models, however, are
generic and should be replaced with foundry models. You may get the
entire [FreePDK45 PDK here][FreePDK45].
### Sky130 Setup
To install [Sky130], you must have the open_pdks files installed in $PDK_ROOT.
To install this automatically, you can run:
cd $HOME/openram
make pdk
Then you must also install the [Sky130] SRAM build space and the appropriate cell views
by running:
cd $HOME/openram
make install
# Basic Usage
Once you have defined the environment, you can run OpenRAM from the command line
using a single configuration file written in Python.
For example, create a file called *myconfig.py* specifying the following
parameters for your memory:
```
# Data word size
word_size = 2
# Number of words in the memory
num_words = 16
# Technology to use in $OPENRAM_TECH
tech_name = "scn4m_subm"
# You can use the technology nominal corner only
nominal_corner_only = True
# Or you can specify particular corners
# Process corners to characterize
# process_corners = ["SS", "TT", "FF"]
# Voltage corners to characterize
# supply_voltages = [ 3.0, 3.3, 3.5 ]
# Temperature corners to characterize
# temperatures = [ 0, 25 100]
# Output directory for the results
output_path = "temp"
# Output file base name
output_name = "sram_{0}_{1}_{2}".format(word_size,num_words,tech_name)
# Disable analytical models for full characterization (WARNING: slow!)
# analytical_delay = False
```
You can then run OpenRAM by executing:
```
python3 $OPENRAM_HOME/openram.py myconfig
```
You can see all of the options for the configuration file in
$OPENRAM\_HOME/options.py
To run designs in Docker, it is suggested to use, for example:
```
cd openram/macros
make example_config_scn4m_subm
```
# Unit Tests
Regression testing performs a number of tests for all modules in OpenRAM.
From the unit test directory ($OPENRAM\_HOME/tests),
use the following command to run all regression tests:
```
cd openram/compiler/tests
make -j 3
```
The -j can run with 3 threads. By default, this will run in all technologies.
To run a specific test in all technologies:
```
cd openram/compiler/tests
make 05_bitcell_array_test
```
To run a specific technology:
```
cd openram/compiler/tests
TECHS=scn4m_subm make 05_bitcell_array_test
```
To increase the verbosity of the test, add one (or more) -v options and
pass it as an argument to OpenRAM:
```
ARGS="-v" make 05_bitcell_array_test
```
Unit test results are put in a directory:
```
openram/compiler/tests/results/<technology>/<test>
```
If the test fails, there will be a tmp directory with intermediate results.
If the test passes, this directory will be deleted to save space.
You can view the .out file to see what the output of a test is in either case.
# Get Involved # Get Involved
+ [Port it](./PORTING.md) to a new technology. + [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]
+ Follow our [project][Github project]. + Follow our [project][Github project]
+ Read and cite our [ICCAD paper][OpenRAMpaper] + Read and cite our [ICCAD paper][OpenRAMpaper]
# Further Help # Further Help
+ [Additional hints](./HINTS.md)
+ [Documentation][documentation] + [Documentation][documentation]
+ [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
OpenRAM is licensed under the [BSD 3-clause License](./LICENSE). OpenRAM is licensed under the [BSD 3-Clause License](./LICENSE).
# Publications
+ [M. R. Guthaus, J. E. Stine, S. Ataei, B. Chen, B. Wu, M. Sarwar, "OpenRAM: An Open-Source Memory Compiler," Proceedings of the 35th International Conference on Computer-Aided Design (ICCAD), 2016.](https://escholarship.org/content/qt8x19c778/qt8x19c778_noSplash_b2b3fbbb57f1269f86d0de77865b0691.pdf)
+ [S. Ataei, J. Stine, M. Guthaus, “A 64 kb differential single-port 12T SRAM design with a bit-interleaving scheme for low-voltage operation in 32 nm SOI CMOS,” International Conference on Computer Design (ICCD), 2016, pp. 499-506.](https://escholarship.org/uc/item/99f6q9c9)
+ [E. Ebrahimi, M. Guthaus, J. Renau, “Timing Speculative SRAM”, IEEE International Symposium on Circuits and Systems (ISCAS), 2017.](https://escholarship.org/content/qt7nn0j5x3/qt7nn0j5x3_noSplash_172457455e1aceba20694c3d7aa489b4.pdf)
+ [B. Wu, J.E. Stine, M.R. Guthaus, "Fast and Area-Efficient Word-Line Optimization", IEEE International Symposium on Circuits and Systems (ISCAS), 2019.](https://escholarship.org/content/qt98s4c1hp/qt98s4c1hp_noSplash_753dcc3e218f60aafff98ef77fb56384.pdf)
+ [B. Wu, M. Guthaus, "Bottom Up Approach for High Speed SRAM Word-line Buffer Insertion Optimization", IFIP/IEEE International Conference on Very Large Scale Integration (VLSI-SoC), 2019.](https://ieeexplore.ieee.org/document/8920325)
+ [H. Nichols, M. Grimes, J. Sowash, J. Cirimelli-Low, M. Guthaus "Automated Synthesis of Multi-Port Memories and Control", IFIP/IEEE International Conference on Very Large Scale Integration (VLSI-SoC), 2019.](https://escholarship.org/content/qt7047n3k0/qt7047n3k0.pdf?t=q4gcij)
+ [H. Nichols, "Statistical Modeling of SRAMs", M.S. Thesis, UCSC, 2022.](https://escholarship.org/content/qt7vx9n089/qt7vx9n089_noSplash_cfc4ba479d8eb1b6ec25d7c92357bc18.pdf?t=ra9wzr)
+ [M. Guthaus, H. Nichols, J. Cirimelli-Low, J. Kunzler, B. Wu, "Enabling Design Technology Co-Optimization of SRAMs though Open-Source Software", IEEE International Electron Devices Meeting (IEDM), 2020.](https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=9372047)
# Contributors & Acknowledgment # Contributors & Acknowledgment
@ -205,7 +75,7 @@ OpenRAM is licensed under the [BSD 3-clause License](./LICENSE).
If I forgot to add you, please let me know! If I forgot to add you, please let me know!
* * *
[Matthew Guthaus]: https://users.soe.ucsc.edu/~mrg [Matthew Guthaus]: https://users.soe.ucsc.edu/~mrg
[James Stine]: https://ece.okstate.edu/content/stine-james-e-jr-phd [James Stine]: https://ece.okstate.edu/content/stine-james-e-jr-phd
@ -215,9 +85,9 @@ 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]: docs/source/index.md
[dev-group]: mailto:openram-dev-group@ucsc.edu [dev-group]: mailto:openram-dev-group@ucsc.edu
[user-group]: mailto:openram-user-group@ucsc.edu [user-group]: mailto:openram-user-group@ucsc.edu
[dev-group-subscribe]: mailto:openram-dev-group+subscribe@ucsc.edu [dev-group-subscribe]: mailto:openram-dev-group+subscribe@ucsc.edu

1
VERSION Normal file
View File

@ -0,0 +1 @@
1.2.15

91
__init__.py Normal file
View File

@ -0,0 +1,91 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import os
# Attempt to add the source code to the PYTHONPATH here before running globals.init_openram()
try:
OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME"))
except:
OPENRAM_HOME = os.path.dirname(os.path.abspath(__file__)) + "/compiler"
if not os.path.isdir(OPENRAM_HOME):
assert False
# Make sure that OPENRAM_HOME is an environment variable just in case
if "OPENRAM_HOME" not in os.environ.keys():
os.environ["OPENRAM_HOME"] = OPENRAM_HOME
# Prepend $OPENRAM_HOME to __path__ so that openram will use those modules
__path__.insert(0, OPENRAM_HOME)
# Find the conda installer script
if os.path.exists(OPENRAM_HOME + "/install_conda.sh"):
CONDA_INSTALLER = OPENRAM_HOME + "/install_conda.sh"
CONDA_HOME = OPENRAM_HOME + "/miniconda"
elif os.path.exists(OPENRAM_HOME + "/../install_conda.sh"):
CONDA_INSTALLER = OPENRAM_HOME + "/../install_conda.sh"
CONDA_HOME = os.path.abspath(OPENRAM_HOME + "/../miniconda")
# Override CONDA_HOME if it's set as an environment variable
if "CONDA_HOME" in os.environ.keys():
CONDA_HOME = os.environ["CONDA_HOME"]
# Add CONDA_HOME to environment variables just in case
try:
os.environ["CONDA_HOME"] = CONDA_HOME
except:
from openram import debug
debug.warning("Couldn't find conda setup directory.")
# Import everything in globals.py
from .globals import *
# Import classes in the "openram" namespace
from .sram_config import *
from .sram import *
from .rom_config import *
from .rom import *
# Add a meta path finder for custom modules
from importlib.abc import MetaPathFinder
class custom_module_finder(MetaPathFinder):
"""
This class is a 'hook' in Python's import system. If it encounters a module
that can be customized, it checks if there is a custom module specified in
the configuration file. If there is a custom module, it is imported instead
of the default one.
"""
def find_spec(self, fullname, path, target=None):
# Get package and module names
package_name = fullname.split(".")[0]
module_name = fullname.split(".")[-1]
# Skip if the package is not openram
if package_name != "openram":
return None
# Search for the module name in customizable modules
from openram import OPTS
for k, v in OPTS.__dict__.items():
if module_name == v:
break
else:
return None
# Search for the custom module
import sys
# Try to find the module in sys.path
for path in sys.path:
# Skip this path if not directory
if not os.path.isdir(path):
continue
for file in os.listdir(path):
# If there is a script matching the custom module name,
# import it with the default module name
if file == (module_name + ".py"):
from importlib.util import spec_from_file_location
return spec_from_file_location(module_name, "{0}/{1}.py".format(path, module_name))
return None
# Python calls meta path finders and asks them to handle the module import if
# they can
sys.meta_path.insert(0, custom_module_finder())

31
common.py Normal file
View File

@ -0,0 +1,31 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
"""
Common functions for top-level scripts
"""
import sys
import os
def make_openram_package():
""" Make sure that OpenRAM can be used as a Python package. """
import importlib.util
# Find the package loader from python/site-packages
openram_loader = importlib.util.find_spec("openram")
# If openram library isn't found as a python package, import it from
# the $OPENRAM_HOME path.
if openram_loader is None:
OPENRAM_HOME = os.getenv("OPENRAM_HOME")
# Import using spec since the directory can be named something other
# than "openram".
spec = importlib.util.spec_from_file_location("openram", "{}/../__init__.py".format(OPENRAM_HOME))
module = importlib.util.module_from_spec(spec)
sys.modules["openram"] = module
spec.loader.exec_module(module)

View File

@ -95,7 +95,7 @@ model: $(STAMPS)
$(eval bname=$(basename $(notdir $@))) $(eval bname=$(basename $(notdir $@)))
$(eval config_path=$(CONFIG_DIR)/$(addsuffix .py, $(notdir $(basename $@)))) $(eval config_path=$(CONFIG_DIR)/$(addsuffix .py, $(notdir $(basename $@))))
mkdir -p $(SIM_DIR)/$(bname) mkdir -p $(SIM_DIR)/$(bname)
-python3 $(OPENRAM_HOME)/openram.py $(OPTS) -p $(SIM_DIR)/$(bname) -o $(bname) -t $(TECH) $(config_path) 2>&1 > /dev/null -python3 $(OPENRAM_HOME)/../sram_compiler.py $(OPTS) -p $(SIM_DIR)/$(bname) -o $(bname) -t $(TECH) $(config_path) 2>&1 > /dev/null
touch $@ touch $@
clean_model: clean_model:

View File

@ -1,3 +1,8 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .channel_route import * from .channel_route import *
from .contact import * from .contact import *
from .delay_data import * from .delay_data import *

View File

@ -1,13 +1,13 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 collections import collections
import debug from openram import debug
from tech import drc from openram.tech import drc
from .vector import vector from .vector import vector
from .design import design from .design import design
@ -405,4 +405,3 @@ class channel_route(design):
to_layer=self.horizontal_layer, to_layer=self.horizontal_layer,
offset=pin_pos) offset=pin_pos)

View File

@ -1,15 +1,15 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 debug from openram import debug
from openram.tech import drc, layer, preferred_directions
from openram.tech import layer as tech_layers
from .hierarchy_design import hierarchy_design from .hierarchy_design import hierarchy_design
from .vector import vector from .vector import vector
from tech import drc, layer, preferred_directions
from tech import layer as tech_layers
class contact(hierarchy_design): class contact(hierarchy_design):

View File

@ -1,12 +1,11 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 delay_data(): class delay_data():
""" """
This is the delay class to represent the delay information This is the delay class to represent the delay information
@ -38,7 +37,3 @@ class delay_data():
assert isinstance(other, delay_data) assert isinstance(other, delay_data)
return delay_data(other.delay + self.delay, return delay_data(other.delay + self.delay,
self.slew) self.slew)

View File

@ -1,15 +1,15 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 debug from openram import debug
from tech import GDS, layer from openram.tech import GDS, layer
from tech import preferred_directions from openram.tech import preferred_directions
from tech import cell_properties as props from openram.tech import cell_properties as props
from globals import OPTS from openram import OPTS
from . import utils from . import utils
from .hierarchy_design import hierarchy_design from .hierarchy_design import hierarchy_design
@ -67,7 +67,7 @@ class design(hierarchy_design):
self.setup_multiport_constants() self.setup_multiport_constants()
try: try:
from tech import power_grid from openram.tech import power_grid
self.supply_stack = power_grid self.supply_stack = power_grid
except ImportError: except ImportError:
# if no power_grid is specified by tech we use sensible defaults # if no power_grid is specified by tech we use sensible defaults
@ -78,7 +78,7 @@ class design(hierarchy_design):
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) debug.info(0, "{0} {1}".format(pin_name, pin))
def setup_multiport_constants(self): def setup_multiport_constants(self):
""" """

View File

@ -1,4 +1,8 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
class drc_error(Exception): class drc_error(Exception):
"""Exception raised for DRC errors. """Exception raised for DRC errors.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -8,14 +8,14 @@
""" """
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
from .vector import vector
import tech
import math import math
import copy import copy
import numpy as np import numpy as np
from globals import OPTS from openram import debug
from openram import tech
from openram import OPTS
from .utils import round_to_grid from .utils import round_to_grid
from .vector import vector
class geometry: class geometry:
@ -249,7 +249,6 @@ class instance(geometry):
""" Return an absolute pin that is offset and transformed based on """ Return an absolute pin that is offset and transformed based on
this instance location. Index will return one of several pins.""" this instance location. Index will return one of several pins."""
import copy
if index == -1: if index == -1:
pin = copy.deepcopy(self.mod.get_pin(name)) pin = copy.deepcopy(self.mod.get_pin(name))
pin.transform(self.offset, self.mirror, self.rotate) pin.transform(self.offset, self.mirror, self.rotate)
@ -267,7 +266,6 @@ class instance(geometry):
""" Return an absolute pin that is offset and transformed based on """ Return an absolute pin that is offset and transformed based on
this instance location. """ this instance location. """
import copy
pin = copy.deepcopy(self.mod.get_pins(name)) pin = copy.deepcopy(self.mod.get_pins(name))
new_pins = [] new_pins = []

View File

@ -1,15 +1,15 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 os
from openram import debug
from openram import OPTS
from .hierarchy_layout import layout from .hierarchy_layout import layout
from .hierarchy_spice import spice from .hierarchy_spice import spice
import debug
import os
from globals import OPTS
class hierarchy_design(spice, layout): class hierarchy_design(spice, layout):
@ -49,7 +49,7 @@ class hierarchy_design(spice, layout):
def DRC_LVS(self, final_verification=False, force_check=False): def DRC_LVS(self, final_verification=False, force_check=False):
"""Checks both DRC and LVS for a module""" """Checks both DRC and LVS for a module"""
import verify from openram import verify
# No layout to check # No layout to check
if OPTS.netlist_only: if OPTS.netlist_only:
@ -82,7 +82,7 @@ class hierarchy_design(spice, layout):
def DRC(self, final_verification=False): def DRC(self, final_verification=False):
"""Checks DRC for a module""" """Checks DRC for a module"""
import verify from openram import verify
# Unit tests will check themselves. # Unit tests will check themselves.
# Do not run if disabled in options. # Do not run if disabled in options.
@ -102,7 +102,7 @@ class hierarchy_design(spice, layout):
def LVS(self, final_verification=False): def LVS(self, final_verification=False):
"""Checks LVS for a module""" """Checks LVS for a module"""
import verify from openram import verify
# Unit tests will check themselves. # Unit tests will check themselves.
# Do not run if disabled in options. # Do not run if disabled in options.

View File

@ -1,32 +1,32 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 os
import sys import sys
import os
import re import re
from math import sqrt from math import sqrt
import debug from openram import debug
from gdsMill import gdsMill from openram.gdsMill import gdsMill
import tech from openram import tech
from tech import drc, GDS from openram.tech import drc, GDS
from tech import layer as tech_layer from openram.tech import layer as tech_layer
from tech import layer_indices as tech_layer_indices from openram.tech import layer_indices as tech_layer_indices
from tech import preferred_directions from openram.tech import preferred_directions
from tech import layer_stacks as tech_layer_stacks from openram.tech import layer_stacks as tech_layer_stacks
from tech import active_stack as tech_active_stack from openram.tech import active_stack as tech_active_stack
from sram_factory import factory from openram.sram_factory import factory
from globals import OPTS from openram import OPTS
from .vector import vector from .vector import vector
from .pin_layout import pin_layout from .pin_layout import pin_layout
from .utils import round_to_grid from .utils import round_to_grid
from . import geometry from . import geometry
try: try:
from tech import special_purposes from openram.tech import special_purposes
except ImportError: except ImportError:
special_purposes = {} special_purposes = {}
@ -141,30 +141,28 @@ class layout():
layout.active_space) layout.active_space)
# These are for debugging previous manual rules # These are for debugging previous manual rules
if False: level=99
print("poly_width", layout.poly_width) debug.info(level, "poly_width".format(layout.poly_width))
print("poly_space", layout.poly_space) debug.info(level, "poly_space".format(layout.poly_space))
print("m1_width", layout.m1_width) debug.info(level, "m1_width".format(layout.m1_width))
print("m1_space", layout.m1_space) debug.info(level, "m1_space".format(layout.m1_space))
print("m2_width", layout.m2_width) debug.info(level, "m2_width".format(layout.m2_width))
print("m2_space", layout.m2_space) debug.info(level, "m2_space".format(layout.m2_space))
print("m3_width", layout.m3_width) debug.info(level, "m3_width".format(layout.m3_width))
print("m3_space", layout.m3_space) debug.info(level, "m3_space".format(layout.m3_space))
print("m4_width", layout.m4_width) debug.info(level, "m4_width".format(layout.m4_width))
print("m4_space", layout.m4_space) debug.info(level, "m4_space".format(layout.m4_space))
print("active_width", layout.active_width) debug.info(level, "active_width".format(layout.active_width))
print("active_space", layout.active_space) debug.info(level, "active_space".format(layout.active_space))
print("contact_width", layout.contact_width) debug.info(level, "contact_width".format(layout.contact_width))
print("poly_to_active", layout.poly_to_active) debug.info(level, "poly_to_active".format(layout.poly_to_active))
print("poly_extend_active", layout.poly_extend_active) debug.info(level, "poly_extend_active".format(layout.poly_extend_active))
print("poly_to_contact", layout.poly_to_contact) debug.info(level, "poly_to_contact".format(layout.poly_to_contact))
print("active_contact_to_gate", layout.active_contact_to_gate) debug.info(level, "active_contact_to_gate".format(layout.active_contact_to_gate))
print("poly_contact_to_gate", layout.poly_contact_to_gate) debug.info(level, "poly_contact_to_gate".format(layout.poly_contact_to_gate))
print("well_enclose_active", layout.well_enclose_active) debug.info(level, "well_enclose_active".format(layout.well_enclose_active))
print("implant_enclose_active", layout.implant_enclose_active) debug.info(level, "implant_enclose_active".format(layout.implant_enclose_active))
print("implant_space", layout.implant_space) debug.info(level, "implant_space".format(layout.implant_space))
import sys
sys.exit(1)
@classmethod @classmethod
def setup_layer_constants(layout): def setup_layer_constants(layout):
@ -173,7 +171,7 @@ class layout():
in many places in the compiler. in many places in the compiler.
""" """
try: try:
from tech import power_grid from openram.tech import power_grid
layout.pwr_grid_layers = [power_grid[0], power_grid[2]] layout.pwr_grid_layers = [power_grid[0], power_grid[2]]
except ImportError: except ImportError:
layout.pwr_grid_layers = ["m3", "m4"] layout.pwr_grid_layers = ["m3", "m4"]
@ -202,21 +200,19 @@ class layout():
"{}_nonpref_pitch".format(layer_id), "{}_nonpref_pitch".format(layer_id),
layout.compute_pitch(layer_id, False)) layout.compute_pitch(layer_id, False))
if False: level=99
for name in tech_layer_indices: for name in tech_layer_indices:
if name == "active": if name == "active":
continue continue
try: try:
print("{0} width {1} space {2}".format(name, debug.info(level, "{0} width {1} space {2}".format(name,
getattr(layout, "{}_width".format(name)), getattr(layout, "{}_width".format(name)),
getattr(layout, "{}_space".format(name)))) getattr(layout, "{}_space".format(name))))
print("pitch {0} nonpref {1}".format(getattr(layout, "{}_pitch".format(name)), debug.info(level, "pitch {0} nonpref {1}".format(getattr(layout, "{}_pitch".format(name)),
getattr(layout, "{}_nonpref_pitch".format(name)))) getattr(layout, "{}_nonpref_pitch".format(name))))
except AttributeError: except AttributeError:
pass pass
import sys
sys.exit(1)
@staticmethod @staticmethod
def compute_pitch(layer, preferred=True): def compute_pitch(layer, preferred=True):
@ -635,10 +631,11 @@ class layout():
""" """
return self.pins return self.pins
def copy_layout_pin(self, instance, pin_name, new_name=""): def copy_layout_pin(self, instance, pin_name, new_name="", relative_offset=vector(0, 0)):
""" """
Create a copied version of the layout pin at the current level. Create a copied version of the layout pin at the current level.
You can optionally rename the pin to a new name. You can optionally rename the pin to a new name.
You can optionally add an offset vector by which to move the pin.
""" """
pins = instance.get_pins(pin_name) pins = instance.get_pins(pin_name)
@ -650,7 +647,7 @@ class layout():
new_name = pin_name new_name = pin_name
self.add_layout_pin(new_name, self.add_layout_pin(new_name,
pin.layer, pin.layer,
pin.ll(), pin.ll() + relative_offset,
pin.width(), pin.width(),
pin.height()) pin.height())
@ -699,13 +696,15 @@ class layout():
start=left_pos, start=left_pos,
end=right_pos) end=right_pos)
def connect_row_pins(self, layer, pins, name=None, full=False): def connect_row_pins(self, layer, pins, name=None, full=False, round=False):
""" """
Connects left/right rows that are aligned. Connects left/right rows that are aligned.
""" """
bins = {} bins = {}
for pin in pins: for pin in pins:
y = pin.cy() y = pin.cy()
if round:
y = round_to_grid(y)
try: try:
bins[y].append(pin) bins[y].append(pin)
except KeyError: except KeyError:
@ -788,13 +787,15 @@ class layout():
end=bot_pos) end=bot_pos)
def connect_col_pins(self, layer, pins, name=None, full=False): def connect_col_pins(self, layer, pins, name=None, full=False, round=False, directions="pref"):
""" """
Connects top/bot columns that are aligned. Connects top/bot columns that are aligned.
""" """
bins = {} bins = {}
for pin in pins: for pin in pins:
x = pin.cx() x = pin.cx()
if round:
x = round_to_grid(x)
try: try:
bins[x].append(pin) bins[x].append(pin)
except KeyError: except KeyError:
@ -820,7 +821,8 @@ class layout():
self.add_via_stack_center(from_layer=pin.layer, self.add_via_stack_center(from_layer=pin.layer,
to_layer=layer, to_layer=layer,
offset=pin.center(), offset=pin.center(),
min_area=True) min_area=True,
directions=directions)
if name: if name:
self.add_layout_pin_segment_center(text=name, self.add_layout_pin_segment_center(text=name,
@ -1257,7 +1259,6 @@ class layout():
def add_via(self, layers, offset, size=[1, 1], directions=None, implant_type=None, well_type=None): def add_via(self, layers, offset, size=[1, 1], directions=None, implant_type=None, well_type=None):
""" Add a three layer via structure. """ """ Add a three layer via structure. """
from sram_factory import factory
via = factory.create(module_type="contact", via = factory.create(module_type="contact",
layer_stack=layers, layer_stack=layers,
dimensions=size, dimensions=size,
@ -1276,7 +1277,6 @@ class layout():
Add a three layer via structure by the center coordinate Add a three layer via structure by the center coordinate
accounting for mirroring and rotation. accounting for mirroring and rotation.
""" """
from sram_factory import factory
via = factory.create(module_type="contact", via = factory.create(module_type="contact",
layer_stack=layers, layer_stack=layers,
dimensions=size, dimensions=size,
@ -1383,10 +1383,10 @@ class layout():
def add_ptx(self, offset, mirror="R0", rotate=0, width=1, mults=1, tx_type="nmos"): def add_ptx(self, offset, mirror="R0", rotate=0, width=1, mults=1, tx_type="nmos"):
"""Adds a ptx module to the design.""" """Adds a ptx module to the design."""
import ptx from openram.modules import ptx
mos = ptx.ptx(width=width, mos = ptx(width=width,
mults=mults, mults=mults,
tx_type=tx_type) tx_type=tx_type)
inst = self.add_inst(name=mos.name, inst = self.add_inst(name=mos.name,
mod=mos, mod=mos,
offset=offset, offset=offset,
@ -1897,7 +1897,7 @@ class layout():
elif add_vias: elif add_vias:
self.copy_power_pin(pin, new_name=new_name) self.copy_power_pin(pin, new_name=new_name)
def add_io_pin(self, instance, pin_name, new_name, start_layer=None): def add_io_pin(self, instance, pin_name, new_name, start_layer=None, directions=None):
""" """
Add a signle input or output pin up to metal 3. Add a signle input or output pin up to metal 3.
""" """
@ -1907,7 +1907,7 @@ class layout():
start_layer = pin.layer start_layer = pin.layer
# Just use the power pin function for now to save code # Just use the power pin function for now to save code
self.add_power_pin(new_name, pin.center(), start_layer=start_layer) self.add_power_pin(new_name, pin.center(), start_layer=start_layer, directions=directions)
def add_power_pin(self, name, loc, directions=None, start_layer="m1"): def add_power_pin(self, name, loc, directions=None, start_layer="m1"):
# Hack for min area # Hack for min area
@ -2180,7 +2180,6 @@ class layout():
# Find the number of vias for this pitch # Find the number of vias for this pitch
supply_vias = 1 supply_vias = 1
from sram_factory import factory
while True: while True:
c = factory.create(module_type="contact", c = factory.create(module_type="contact",
layer_stack=self.m1_stack, layer_stack=self.m1_stack,
@ -2293,7 +2292,6 @@ class layout():
# Find the number of vias for this pitch # Find the number of vias for this pitch
self.supply_vias = 1 self.supply_vias = 1
from sram_factory import factory
while True: while True:
c = factory.create(module_type="contact", c = factory.create(module_type="contact",
layer_stack=self.m1_stack, layer_stack=self.m1_stack,

View File

@ -1,17 +1,18 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 debug
import re
import os import os
import re
import math import math
import tech import textwrap as tr
from globals import OPTS
from pprint import pformat from pprint import pformat
from openram import debug
from openram import tech
from openram import OPTS
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
@ -37,7 +38,7 @@ 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:
from tech import lvs_name from openram.tech import lvs_name
lvs_dir = OPTS.openram_tech + lvs_name + "_lvs_lib/" lvs_dir = OPTS.openram_tech + lvs_name + "_lvs_lib/"
except ImportError: except ImportError:
lvs_dir = OPTS.openram_tech + "lvs_lib/" lvs_dir = OPTS.openram_tech + "lvs_lib/"
@ -338,19 +339,21 @@ class spice():
return return
# write out the first spice line (the subcircuit) # write out the first spice line (the subcircuit)
sp.write("\n.SUBCKT {0} {1}\n".format(self.cell_name, wrapped_pins = "\n+ ".join(tr.wrap(" ".join(self.pins)))
" ".join(self.pins))) sp.write("\n.SUBCKT {0}\n+ {1}\n".format(self.cell_name,
wrapped_pins))
# write a PININFO line # write a PININFO line
pin_info = "*.PININFO" if False:
for pin in self.pins: pin_info = "*.PININFO"
if self.pin_type[pin] == "INPUT": for pin in self.pins:
pin_info += " {0}:I".format(pin) if self.pin_type[pin] == "INPUT":
elif self.pin_type[pin] == "OUTPUT": pin_info += " {0}:I".format(pin)
pin_info += " {0}:O".format(pin) elif self.pin_type[pin] == "OUTPUT":
else: pin_info += " {0}:O".format(pin)
pin_info += " {0}:B".format(pin) else:
sp.write(pin_info + "\n") pin_info += " {0}:B".format(pin)
sp.write(pin_info + "\n")
# Also write pins as comments # Also write pins as comments
for pin in self.pins: for pin in self.pins:
@ -391,9 +394,11 @@ class spice():
" ".join(self.conns[i]))) " ".join(self.conns[i])))
sp.write("\n") sp.write("\n")
else: else:
sp.write("X{0} {1} {2}\n".format(self.insts[i].name, wrapped_connections = "\n+ ".join(tr.wrap(" ".join(self.conns[i])))
" ".join(self.conns[i]),
self.insts[i].mod.cell_name)) sp.write("X{0}\n+ {1}\n+ {2}\n".format(self.insts[i].name,
wrapped_connections,
self.insts[i].mod.cell_name))
sp.write(".ENDS {0}\n".format(self.cell_name)) sp.write(".ENDS {0}\n".format(self.cell_name))
@ -409,6 +414,7 @@ class spice():
sp.write("\n") sp.write("\n")
def sp_write(self, spname, lvs=False, trim=False): def sp_write(self, spname, lvs=False, trim=False):
"""Writes the spice to files""" """Writes the spice to files"""
debug.info(3, "Writing to {0}".format(spname)) debug.info(3, "Writing to {0}".format(spname))

View File

@ -1,17 +1,17 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 debug
from base import vector
from base import pin_layout
from tech import layer_names
import os import os
import shutil import shutil
from globals import OPTS from openram import debug
from openram.base import vector
from openram.base import pin_layout
from openram.tech import layer_names
from openram import OPTS
class lef: class lef:
@ -64,7 +64,7 @@ class lef:
f.write('puts "Finished writing LEF cell {}"\n'.format(self.name)) f.write('puts "Finished writing LEF cell {}"\n'.format(self.name))
f.close() f.close()
os.system("chmod u+x {}".format(run_file)) os.system("chmod u+x {}".format(run_file))
from run_script import run_script from openram.verify.run_script import run_script
(outfile, errfile, resultsfile) = run_script(self.name, "lef") (outfile, errfile, resultsfile) = run_script(self.name, "lef")
def lef_write(self, lef_name): def lef_write(self, lef_name):
@ -220,4 +220,3 @@ class lef:
round(item[1], round(item[1],
self.round_grid))) self.round_grid)))
self.lef.write(" ;\n") self.lef.write(" ;\n")

View File

@ -1,12 +1,13 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 debug from openram import debug
from tech import parameter from openram.tech import parameter
class logical_effort(): class logical_effort():
""" """

View File

@ -1,15 +1,15 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 debug
from tech import GDS, drc
from .vector import vector
from tech import layer, layer_indices
import math import math
from openram import debug
from openram.tech import GDS, drc
from openram.tech import layer, layer_indices
from .vector import vector
class pin_layout: class pin_layout:
@ -48,8 +48,8 @@ class pin_layout:
else: else:
try: try:
from tech import layer_override from openram.tech import layer_override
from tech import layer_override_name from openram.tech import layer_override_name
if layer_override[name]: if layer_override[name]:
self.lpp = layer_override[name] self.lpp = layer_override[name]
self.layer = "pwellp" self.layer = "pwellp"
@ -406,15 +406,15 @@ class pin_layout:
# Try to use a global pin purpose if it exists, # Try to use a global pin purpose if it exists,
# otherwise, use the regular purpose # otherwise, use the regular purpose
try: try:
from tech import pin_purpose as global_pin_purpose from openram.tech import pin_purpose as global_pin_purpose
pin_purpose = global_pin_purpose pin_purpose = global_pin_purpose
except ImportError: except ImportError:
pass pass
try: try:
from tech import label_purpose from openram.tech import label_purpose
try: try:
from tech import layer_override_purpose from openram.tech import layer_override_purpose
if pin_layer_num in layer_override_purpose: if pin_layer_num in layer_override_purpose:
layer_num = layer_override_purpose[pin_layer_num][0] layer_num = layer_override_purpose[pin_layer_num][0]
label_purpose = layer_override_purpose[pin_layer_num][1] label_purpose = layer_override_purpose[pin_layer_num][1]

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,17 +1,18 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 debug from itertools import tee
from openram import debug
from openram.sram_factory import factory
from openram.tech import drc
from .design import design from .design import design
from .vector import vector from .vector import vector
from .vector3d import vector3d from .vector3d import vector3d
from tech import drc
from itertools import tee
from sram_factory import factory
class route(design): class route(design):
""" """

View File

@ -1,6 +1,11 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
import copy import copy
from collections import defaultdict from collections import defaultdict
import debug from openram import debug
class timing_graph(): class timing_graph():
@ -153,4 +158,3 @@ class timing_graph():
""" override print function output """ """ override print function output """
return str(self) return str(self)

View File

@ -1,24 +1,22 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 os import os
import math import math
from openram import debug
from gdsMill import gdsMill from openram import tech
import tech from openram.gdsMill import gdsMill
import globals from openram import OPTS
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 openram.tech import special_purposes
except ImportError: except ImportError:
special_purposes = {} special_purposes = {}
OPTS = globals.OPTS
def ceil(decimal): def ceil(decimal):
@ -159,7 +157,7 @@ def get_gds_pins(pin_names, name, gds_filename, units):
# may have must-connect pins # may have must-connect pins
if isinstance(lpp[1], list): if isinstance(lpp[1], list):
try: try:
from tech import layer_override from openram.tech import layer_override
if layer_override[pin_name]: if layer_override[pin_name]:
lpp = layer_override[pin_name.textString] lpp = layer_override[pin_name.textString]
except: except:

View File

@ -1,13 +1,12 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 math import math
import tech from openram import tech
class vector(): class vector():

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,12 +1,12 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 math import math
from tech import spice from openram.tech import spice
class verilog: class verilog:
@ -24,7 +24,7 @@ class verilog:
self.vf.write("// OpenRAM SRAM model\n") self.vf.write("// OpenRAM SRAM model\n")
self.vf.write("// Words: {0}\n".format(self.num_words)) self.vf.write("// Words: {0}\n".format(self.num_words))
self.vf.write("// Word size: {0}\n".format(self.word_size)) self.vf.write("// Word size: {0}\n".format(self.word_size))
if self.write_size: if self.write_size != self.word_size:
self.vf.write("// Write size: {0}\n\n".format(self.write_size)) self.vf.write("// Write size: {0}\n\n".format(self.write_size))
else: else:
self.vf.write("\n") self.vf.write("\n")
@ -38,7 +38,10 @@ class verilog:
except KeyError: except KeyError:
self.gnd_name = "gnd" self.gnd_name = "gnd"
self.vf.write("module {0}(\n".format(self.name)) if self.num_banks > 1:
self.vf.write("module {0}(\n".format(self.name))
else:
self.vf.write("module {0}(\n".format(self.name))
self.vf.write("`ifdef USE_POWER_PINS\n") self.vf.write("`ifdef USE_POWER_PINS\n")
self.vf.write(" {},\n".format(self.vdd_name)) self.vf.write(" {},\n".format(self.vdd_name))
self.vf.write(" {},\n".format(self.gnd_name)) self.vf.write(" {},\n".format(self.gnd_name))
@ -53,14 +56,14 @@ class verilog:
self.vf.write("// Port {0}: W\n".format(port)) self.vf.write("// Port {0}: W\n".format(port))
if port in self.readwrite_ports: if port in self.readwrite_ports:
self.vf.write(" clk{0},csb{0},web{0},".format(port)) self.vf.write(" clk{0},csb{0},web{0},".format(port))
if self.write_size: if self.write_size != self.word_size:
self.vf.write("wmask{},".format(port)) self.vf.write("wmask{},".format(port))
if self.num_spare_cols > 0: if self.num_spare_cols > 0:
self.vf.write("spare_wen{0},".format(port)) self.vf.write("spare_wen{0},".format(port))
self.vf.write("addr{0},din{0},dout{0}".format(port)) self.vf.write("addr{0},din{0},dout{0}".format(port))
elif port in self.write_ports: elif port in self.write_ports:
self.vf.write(" clk{0},csb{0},".format(port)) self.vf.write(" clk{0},csb{0},".format(port))
if self.write_size: if self.write_size != self.word_size:
self.vf.write("wmask{},".format(port)) self.vf.write("wmask{},".format(port))
if self.num_spare_cols > 0: if self.num_spare_cols > 0:
self.vf.write("spare_wen{0},".format(port)) self.vf.write("spare_wen{0},".format(port))
@ -72,11 +75,11 @@ class verilog:
self.vf.write(",\n") self.vf.write(",\n")
self.vf.write("\n );\n\n") self.vf.write("\n );\n\n")
if self.write_size: if self.write_size != self.word_size:
self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
self.vf.write(" parameter NUM_WMASKS = {0} ;\n".format(self.num_wmasks)) self.vf.write(" parameter NUM_WMASKS = {0} ;\n".format(self.num_wmasks))
self.vf.write(" parameter DATA_WIDTH = {0} ;\n".format(self.word_size + self.num_spare_cols)) self.vf.write(" parameter DATA_WIDTH = {0} ;\n".format(self.word_size + self.num_spare_cols))
self.vf.write(" parameter ADDR_WIDTH = {0} ;\n".format(self.addr_size)) self.vf.write(" parameter ADDR_WIDTH = {0} ;\n".format(self.bank_addr_size))
self.vf.write(" parameter RAM_DEPTH = 1 << ADDR_WIDTH;\n") self.vf.write(" parameter RAM_DEPTH = 1 << ADDR_WIDTH;\n")
self.vf.write(" // FIXME: This delay is arbitrary.\n") self.vf.write(" // FIXME: This delay is arbitrary.\n")
self.vf.write(" parameter DELAY = 3 ;\n") self.vf.write(" parameter DELAY = 3 ;\n")
@ -125,7 +128,7 @@ class verilog:
if port in self.readwrite_ports: if port in self.readwrite_ports:
self.vf.write(" reg web{0}_reg;\n".format(port)) self.vf.write(" reg web{0}_reg;\n".format(port))
if port in self.write_ports: if port in self.write_ports:
if self.write_size: if self.write_size != self.word_size:
self.vf.write(" reg [NUM_WMASKS-1:0] wmask{0}_reg;\n".format(port)) self.vf.write(" reg [NUM_WMASKS-1:0] wmask{0}_reg;\n".format(port))
if self.num_spare_cols > 1: if self.num_spare_cols > 1:
self.vf.write(" reg [{1}:0] spare_wen{0}_reg;".format(port, self.num_spare_cols - 1)) self.vf.write(" reg [{1}:0] spare_wen{0}_reg;".format(port, self.num_spare_cols - 1))
@ -149,7 +152,7 @@ class verilog:
if port in self.readwrite_ports: if port in self.readwrite_ports:
self.vf.write(" web{0}_reg = web{0};\n".format(port)) self.vf.write(" web{0}_reg = web{0};\n".format(port))
if port in self.write_ports: if port in self.write_ports:
if self.write_size: if self.write_size != self.word_size:
self.vf.write(" wmask{0}_reg = wmask{0};\n".format(port)) self.vf.write(" wmask{0}_reg = wmask{0};\n".format(port))
if self.num_spare_cols: if self.num_spare_cols:
self.vf.write(" spare_wen{0}_reg = spare_wen{0};\n".format(port)) self.vf.write(" spare_wen{0}_reg = spare_wen{0};\n".format(port))
@ -169,13 +172,13 @@ class verilog:
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))
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))
if self.write_size: if self.write_size != self.word_size:
self.vf.write(" $display($time,\" Writing %m addr{0}=%b din{0}=%b wmask{0}=%b\",addr{0}_reg,din{0}_reg,wmask{0}_reg);\n".format(port)) self.vf.write(" $display($time,\" Writing %m addr{0}=%b din{0}=%b wmask{0}=%b\",addr{0}_reg,din{0}_reg,wmask{0}_reg);\n".format(port))
else: else:
self.vf.write(" $display($time,\" Writing %m addr{0}=%b din{0}=%b\",addr{0}_reg,din{0}_reg);\n".format(port)) self.vf.write(" $display($time,\" Writing %m addr{0}=%b din{0}=%b\",addr{0}_reg,din{0}_reg);\n".format(port))
elif port in self.write_ports: elif port in self.write_ports:
self.vf.write(" if ( !csb{0}_reg && VERBOSE )\n".format(port)) self.vf.write(" if ( !csb{0}_reg && VERBOSE )\n".format(port))
if self.write_size: if self.write_size != self.word_size:
self.vf.write(" $display($time,\" Writing %m addr{0}=%b din{0}=%b wmask{0}=%b\",addr{0}_reg,din{0}_reg,wmask{0}_reg);\n".format(port)) self.vf.write(" $display($time,\" Writing %m addr{0}=%b din{0}=%b wmask{0}=%b\",addr{0}_reg,din{0}_reg,wmask{0}_reg);\n".format(port))
else: else:
self.vf.write(" $display($time,\" Writing %m addr{0}=%b din{0}=%b\",addr{0}_reg,din{0}_reg);\n".format(port)) self.vf.write(" $display($time,\" Writing %m addr{0}=%b din{0}=%b\",addr{0}_reg,din{0}_reg);\n".format(port))
@ -193,7 +196,7 @@ class verilog:
self.vf.write(" input [ADDR_WIDTH-1:0] addr{0};\n".format(port)) self.vf.write(" input [ADDR_WIDTH-1:0] addr{0};\n".format(port))
if port in self.write_ports: if port in self.write_ports:
if self.write_size: if self.write_size != self.word_size:
self.vf.write(" input [NUM_WMASKS-1:0] wmask{0}; // write mask\n".format(port)) self.vf.write(" input [NUM_WMASKS-1:0] wmask{0}; // write mask\n".format(port))
if self.num_spare_cols == 1: if self.num_spare_cols == 1:
self.vf.write(" input spare_wen{0}; // spare mask\n".format(port)) self.vf.write(" input spare_wen{0}; // spare mask\n".format(port))
@ -218,7 +221,7 @@ class verilog:
else: else:
self.vf.write(" if (!csb{0}_reg) begin\n".format(port)) self.vf.write(" if (!csb{0}_reg) begin\n".format(port))
if self.write_size: if self.write_size != self.word_size:
for mask in range(0, self.num_wmasks): for mask in range(0, self.num_wmasks):
lower = mask * self.write_size lower = mask * self.write_size
upper = lower + self.write_size - 1 upper = lower + self.write_size - 1

View File

@ -1,13 +1,13 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 from openram.tech import drc
from openram.sram_factory import factory
from .wire_path import wire_path from .wire_path import wire_path
from sram_factory import factory
class wire(wire_path): class wire(wire_path):
@ -71,7 +71,7 @@ class wire(wire_path):
# This is here for the unit tests which may not have # This is here for the unit tests which may not have
# initialized the static parts of the layout class yet. # initialized the static parts of the layout class yet.
from base import layout from openram.base import layout
layout("fake", "fake") layout("fake", "fake")
(layer1, via, layer2) = layer_stack (layer1, via, layer2) = layer_stack

View File

@ -1,15 +1,16 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 openram.tech import drc
from .utils import snap_to_grid from openram.tech import layer as techlayer
from .design import design from .design import design
from tech import drc from .utils import snap_to_grid
from tech import layer as techlayer from .vector import vector
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

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -16,14 +16,14 @@ class wire_spice_model():
self.wire_r = self.cal_wire_r(wire_length, wire_width) # r in each segment self.wire_r = self.cal_wire_r(wire_length, wire_width) # r in each segment
def cal_wire_c(self, wire_length, wire_width): def cal_wire_c(self, wire_length, wire_width):
from tech import spice from openram.tech import spice
# Convert the F/um^2 to fF/um^2 then multiple by width and length # Convert the F/um^2 to fF/um^2 then multiple by width and length
total_c = (spice["wire_unit_c"]*1e12) * wire_length * wire_width total_c = (spice["wire_unit_c"]*1e12) * wire_length * wire_width
wire_c = total_c / self.lump_num wire_c = total_c / self.lump_num
return wire_c return wire_c
def cal_wire_r(self, wire_length, wire_width): def cal_wire_r(self, wire_length, wire_width):
from tech import spice from openram.tech import spice
total_r = spice["wire_unit_r"] * wire_length / wire_width total_r = spice["wire_unit_r"] * wire_length / wire_width
wire_r = total_r / self.lump_num wire_r = total_r / self.lump_num
return wire_r return wire_r

View File

@ -1,13 +1,13 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 os import os
import debug from openram import debug
from globals import OPTS, find_exe, get_tool from openram import OPTS, find_exe, get_tool
from .lib import * from .lib import *
from .delay import * from .delay import *
from .elmore import * from .elmore import *
@ -56,4 +56,3 @@ if not OPTS.analytical_delay:
else: else:
debug.info(1, "Analytical model enabled.") debug.info(1, "Analytical model enabled.")

View File

@ -1,16 +1,16 @@
# See LICENSE for licensing information.
# #
# Copyright (c) 2016-2019 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 os
import debug
import csv import csv
import math import math
import numpy as np import numpy as np
import os from openram import debug
process_transform = {'SS':0.0, 'TT': 0.5, 'FF':1.0} process_transform = {'SS':0.0, 'TT': 0.5, 'FF':1.0}

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,17 +1,16 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2019 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 .simulation import simulation
from globals import OPTS
import debug
import tech
import math import math
from openram import debug
from openram import tech
from openram import OPTS
from .simulation import simulation
class cacti(simulation): class cacti(simulation):
""" """
@ -24,7 +23,7 @@ class cacti(simulation):
# self.targ_read_ports = [] # self.targ_read_ports = []
# self.targ_write_ports = [] # self.targ_write_ports = []
# self.period = 0 # self.period = 0
# if self.write_size: # if self.write_size != self.word_size:
# self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) # self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
# else: # else:
# self.num_wmasks = 0 # self.num_wmasks = 0
@ -51,7 +50,7 @@ class cacti(simulation):
debug.warning("In analytical mode, all ports have the timing of the first read port.") debug.warning("In analytical mode, all ports have the timing of the first read port.")
# Probe set to 0th bit, does not matter for analytical delay. # Probe set to 0th bit, does not matter for analytical delay.
self.set_probe('0' * self.addr_size, 0) self.set_probe('0' * self.bank_addr_size, 0)
self.create_graph() self.create_graph()
self.set_internal_spice_names() self.set_internal_spice_names()
self.create_measurement_names() self.create_measurement_names()
@ -118,5 +117,3 @@ class cacti(simulation):
debug.info(1, "Dynamic Power: {0} mW".format(power.dynamic)) debug.info(1, "Dynamic Power: {0} mW".format(power.dynamic))
debug.info(1, "Leakage Power: {0} mW".format(power.leakage)) debug.info(1, "Leakage Power: {0} mW".format(power.leakage))
return power return power

View File

@ -1,14 +1,14 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 os import os
import re import re
import debug from openram import debug
from globals import OPTS from openram import OPTS
def relative_compare(value1, value2, error_tolerance=0.001): def relative_compare(value1, value2, error_tolerance=0.001):

View File

@ -1,20 +1,20 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 shutil
import debug
import tech
import math import math
import shutil
from openram import debug
from openram import tech
from openram import OPTS
from .stimuli import * from .stimuli import *
from .trim_spice import * from .trim_spice import *
from .charutils import * from .charutils import *
from .sram_op import * from .sram_op import *
from .bit_polarity import * from .bit_polarity import *
from globals import OPTS
from .simulation import simulation from .simulation import simulation
from .measurements import * from .measurements import *
@ -43,7 +43,7 @@ class delay(simulation):
self.targ_read_ports = [] self.targ_read_ports = []
self.targ_write_ports = [] self.targ_write_ports = []
self.period = 0 self.period = 0
if self.write_size: if self.write_size != self.word_size:
self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
else: else:
self.num_wmasks = 0 self.num_wmasks = 0
@ -342,7 +342,7 @@ class delay(simulation):
except ValueError: except ValueError:
debug.error("Probe Address is not of binary form: {0}".format(self.probe_address), 1) debug.error("Probe Address is not of binary form: {0}".format(self.probe_address), 1)
if len(self.probe_address) != self.addr_size: if len(self.probe_address) != self.bank_addr_size:
debug.error("Probe Address's number of bits does not correspond to given SRAM", 1) debug.error("Probe Address's number of bits does not correspond to given SRAM", 1)
if not isinstance(self.probe_data, int) or self.probe_data>self.word_size or self.probe_data<0: if not isinstance(self.probe_data, int) or self.probe_data>self.word_size or self.probe_data<0:
@ -455,7 +455,7 @@ class delay(simulation):
self.stim.gen_constant(sig_name="{0}{1}_{2} ".format(self.din_name, write_port, i), self.stim.gen_constant(sig_name="{0}{1}_{2} ".format(self.din_name, write_port, i),
v_val=0) v_val=0)
for port in self.all_ports: for port in self.all_ports:
for i in range(self.addr_size): for i in range(self.bank_addr_size):
self.stim.gen_constant(sig_name="{0}{1}_{2}".format(self.addr_name, port, i), self.stim.gen_constant(sig_name="{0}{1}_{2}".format(self.addr_name, port, i),
v_val=0) v_val=0)
@ -1391,7 +1391,7 @@ class delay(simulation):
""" """
for port in self.all_ports: for port in self.all_ports:
for i in range(self.addr_size): for i in range(self.bank_addr_size):
sig_name = "{0}{1}_{2}".format(self.addr_name, port, i) sig_name = "{0}{1}_{2}".format(self.addr_name, port, i)
self.stim.gen_pwl(sig_name, self.cycle_times, self.addr_values[port][i], self.period, self.slew, 0.05) self.stim.gen_pwl(sig_name, self.cycle_times, self.addr_values[port][i], self.period, self.slew, 0.05)

View File

@ -1,14 +1,14 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2019 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 openram import debug
from openram import OPTS
from .simulation import simulation from .simulation import simulation
from globals import OPTS
import debug
class elmore(simulation): class elmore(simulation):
""" """
@ -21,7 +21,7 @@ class elmore(simulation):
# self.targ_read_ports = [] # self.targ_read_ports = []
# self.targ_write_ports = [] # self.targ_write_ports = []
# self.period = 0 # self.period = 0
# if self.write_size: # if self.write_size != self.word_size:
# self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) # self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
# else: # else:
# self.num_wmasks = 0 # self.num_wmasks = 0
@ -45,7 +45,7 @@ class elmore(simulation):
debug.warning("In analytical mode, all ports have the timing of the first read port.") debug.warning("In analytical mode, all ports have the timing of the first read port.")
# Probe set to 0th bit, does not matter for analytical delay. # Probe set to 0th bit, does not matter for analytical delay.
self.set_probe('0' * self.addr_size, 0) self.set_probe('0' * self.bank_addr_size, 0)
self.create_graph() self.create_graph()
self.set_internal_spice_names() self.set_internal_spice_names()
self.create_measurement_names() self.create_measurement_names()

View File

@ -1,18 +1,18 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 collections
import debug
import random
import math import math
import random
import collections
from numpy import binary_repr from numpy import binary_repr
from openram import debug
from openram import OPTS
from .stimuli import * from .stimuli import *
from .charutils import * from .charutils import *
from globals import OPTS
from .simulation import simulation from .simulation import simulation
@ -44,7 +44,7 @@ class functional(simulation):
else: else:
self.output_path = output_path self.output_path = output_path
if self.write_size: if self.write_size != self.word_size:
self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
else: else:
self.num_wmasks = 0 self.num_wmasks = 0
@ -60,7 +60,7 @@ class functional(simulation):
self.addr_spare_index = -int(math.log(self.words_per_row) / math.log(2)) self.addr_spare_index = -int(math.log(self.words_per_row) / math.log(2))
else: else:
# This will select the entire address when one word per row # This will select the entire address when one word per row
self.addr_spare_index = self.addr_size self.addr_spare_index = self.bank_addr_size
# If trim is set, specify the valid addresses # If trim is set, specify the valid addresses
self.valid_addresses = set() self.valid_addresses = set()
self.max_address = self.num_rows * self.words_per_row - 1 self.max_address = self.num_rows * self.words_per_row - 1
@ -68,7 +68,7 @@ class functional(simulation):
for i in range(self.words_per_row): for i in range(self.words_per_row):
self.valid_addresses.add(i) self.valid_addresses.add(i)
self.valid_addresses.add(self.max_address - i - 1) self.valid_addresses.add(self.max_address - i - 1)
self.probe_address, self.probe_data = '0' * self.addr_size, 0 self.probe_address, self.probe_data = '0' * self.bank_addr_size, 0
self.set_corner(corner) self.set_corner(corner)
self.set_spice_constants() self.set_spice_constants()
self.set_stimulus_variables() self.set_stimulus_variables()
@ -133,7 +133,7 @@ class functional(simulation):
def create_random_memory_sequence(self): def create_random_memory_sequence(self):
# Select randomly, but have 3x more reads to increase probability # Select randomly, but have 3x more reads to increase probability
if self.write_size: if self.write_size != self.word_size:
rw_ops = ["noop", "write", "partial_write", "read", "read"] rw_ops = ["noop", "write", "partial_write", "read", "read"]
w_ops = ["noop", "write", "partial_write"] w_ops = ["noop", "write", "partial_write"]
else: else:
@ -142,7 +142,7 @@ class functional(simulation):
r_ops = ["noop", "read"] r_ops = ["noop", "read"]
# First cycle idle is always an idle cycle # First cycle idle is always an idle cycle
comment = self.gen_cycle_comment("noop", "0" * self.word_size, "0" * self.addr_size, "0" * self.num_wmasks, 0, self.t_current) comment = self.gen_cycle_comment("noop", "0" * self.word_size, "0" * self.bank_addr_size, "0" * self.num_wmasks, 0, self.t_current)
self.add_noop_all_ports(comment) self.add_noop_all_ports(comment)
@ -244,7 +244,7 @@ class functional(simulation):
self.t_current += self.period self.t_current += self.period
# Last cycle idle needed to correctly measure the value on the second to last clock edge # Last cycle idle needed to correctly measure the value on the second to last clock edge
comment = self.gen_cycle_comment("noop", "0" * self.word_size, "0" * self.addr_size, "0" * self.num_wmasks, 0, self.t_current) comment = self.gen_cycle_comment("noop", "0" * self.word_size, "0" * self.bank_addr_size, "0" * self.num_wmasks, 0, self.t_current)
self.add_noop_all_ports(comment) self.add_noop_all_ports(comment)
def gen_masked_data(self, old_word, word, wmask): def gen_masked_data(self, old_word, word, wmask):
@ -363,10 +363,10 @@ class functional(simulation):
def gen_addr(self): def gen_addr(self):
""" Generates a random address value to write to. """ """ Generates a random address value to write to. """
if self.valid_addresses: if self.valid_addresses:
random_value = random.sample(self.valid_addresses, 1)[0] random_value = random.sample(list(self.valid_addresses), 1)[0]
else: else:
random_value = random.randint(0, self.max_address) random_value = random.randint(0, self.max_address)
addr_bits = binary_repr(random_value, self.addr_size) addr_bits = binary_repr(random_value, self.bank_addr_size)
return addr_bits return addr_bits
def get_data(self): def get_data(self):
@ -426,7 +426,7 @@ class functional(simulation):
# Generate address bits # Generate address bits
for port in self.all_ports: for port in self.all_ports:
for bit in range(self.addr_size): for bit in range(self.bank_addr_size):
sig_name="{0}{1}_{2} ".format(self.addr_name, port, bit) sig_name="{0}{1}_{2} ".format(self.addr_name, port, bit)
self.stim.gen_pwl(sig_name, self.cycle_times, self.addr_values[port][bit], self.period, self.slew, 0.05) self.stim.gen_pwl(sig_name, self.cycle_times, self.addr_values[port][bit], self.period, self.slew, 0.05)
@ -440,7 +440,7 @@ class functional(simulation):
# Generate wmask bits # Generate wmask bits
for port in self.write_ports: for port in self.write_ports:
if self.write_size: if self.write_size != self.word_size:
self.sf.write("\n* Generation of wmask signals\n") self.sf.write("\n* Generation of wmask signals\n")
for bit in range(self.num_wmasks): for bit in range(self.num_wmasks):
sig_name = "WMASK{0}_{1} ".format(port, bit) sig_name = "WMASK{0}_{1} ".format(port, bit)

View File

@ -1,21 +1,21 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 os,sys,re import os, sys, re
import time import time
import debug
import datetime import datetime
import numpy as np
from openram import debug
from openram import tech
from openram.tech import spice
from openram import OPTS
from .setup_hold import * from .setup_hold import *
from .delay import * from .delay import *
from .charutils import * from .charutils import *
import tech
import numpy as np
from globals import OPTS
from tech import spice
class lib: class lib:
@ -183,7 +183,8 @@ class lib:
# set the read and write port as inputs. # set the read and write port as inputs.
self.write_data_bus(port) self.write_data_bus(port)
self.write_addr_bus(port) self.write_addr_bus(port)
if self.sram.write_size and port in self.write_ports: if self.sram.write_size != self.sram.word_size and \
port in self.write_ports:
self.write_wmask_bus(port) self.write_wmask_bus(port)
# need to split this into sram and port control signals # need to split this into sram and port control signals
self.write_control_pins(port) self.write_control_pins(port)
@ -193,8 +194,8 @@ class lib:
def write_footer(self): def write_footer(self):
""" Write the footer """ """ Write the footer """
self.lib.write(" }\n") #Closing brace for the cell self.lib.write(" }\n") # Closing brace for the cell
self.lib.write("}\n") #Closing brace for the library self.lib.write("}\n") # Closing brace for the library
def write_header(self): def write_header(self):
""" Write the header information """ """ Write the header information """
@ -378,7 +379,7 @@ class lib:
self.lib.write(" bit_to : 0;\n") self.lib.write(" bit_to : 0;\n")
self.lib.write(" }\n\n") self.lib.write(" }\n\n")
if self.sram.write_size: if self.sram.write_size != self.sram.word_size:
self.lib.write(" type (wmask){\n") self.lib.write(" type (wmask){\n")
self.lib.write(" base_type : array;\n") self.lib.write(" base_type : array;\n")
self.lib.write(" data_type : bit;\n") self.lib.write(" data_type : bit;\n")

View File

@ -1,17 +1,15 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2019 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 .regression_model import regression_model
from sklearn.linear_model import Ridge from sklearn.linear_model import Ridge
from globals import OPTS
import debug
from sklearn.linear_model import LinearRegression from sklearn.linear_model import LinearRegression
from openram import debug
from openram import OPTS
from .regression_model import regression_model
class linear_regression(regression_model): class linear_regression(regression_model):
@ -40,4 +38,3 @@ class linear_regression(regression_model):
pred = model.predict(features) pred = model.predict(features)
return pred return pred

View File

@ -1,16 +1,17 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 debug
from tech import drc, parameter, spice
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from openram import debug
from openram.tech import drc, parameter, spice
from .stimuli import * from .stimuli import *
from .charutils import * from .charutils import *
class spice_measurement(ABC): class spice_measurement(ABC):
"""Base class for spice stimulus measurements.""" """Base class for spice stimulus measurements."""
def __init__(self, measure_name, measure_scale=None, has_port=True): def __init__(self, measure_name, measure_scale=None, has_port=True):
@ -211,4 +212,3 @@ class voltage_at_measure(spice_measurement):
meas_name = self.name meas_name = self.name
targ_name = self.targ_name_no_port targ_name = self.targ_name_no_port
return (meas_name, targ_name, time_at) return (meas_name, targ_name, time_at)

View File

@ -1,16 +1,16 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 debug from openram import debug
import tech from openram import tech
from openram import OPTS
from .stimuli import * from .stimuli import *
from .trim_spice import * from .trim_spice import *
from .charutils import * from .charutils import *
from globals import OPTS
from .delay import delay from .delay import delay
from .measurements import * from .measurements import *
@ -448,6 +448,3 @@ class model_check(delay):
name_dict[self.sae_model_name] = name_dict["sae_measures"] name_dict[self.sae_model_name] = name_dict["sae_measures"]
return name_dict return name_dict

View File

@ -1,15 +1,14 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2019 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 .regression_model import regression_model
from globals import OPTS
import debug
from sklearn.neural_network import MLPRegressor from sklearn.neural_network import MLPRegressor
from openram import debug
from openram import OPTS
from .regression_model import regression_model
class neural_network(regression_model): class neural_network(regression_model):
@ -41,4 +40,3 @@ class neural_network(regression_model):
pred = model.predict(features) pred = model.predict(features)
reshape_pred = np.reshape(pred, (len(pred),1)) reshape_pred = np.reshape(pred, (len(pred),1))
return reshape_pred return reshape_pred

View File

@ -1,17 +1,16 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2019 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 math
from openram import debug
from openram import OPTS
from .analytical_util import * from .analytical_util import *
from .simulation import simulation from .simulation import simulation
from globals import OPTS
import debug
import math
relative_data_path = "sim_data" relative_data_path = "sim_data"
data_file = "sim_data.csv" data_file = "sim_data.csv"
@ -205,4 +204,3 @@ class regression_model(simulation):
OPTS.model_dict[model_name+"_coef"] = list(model.coef_[0]) OPTS.model_dict[model_name+"_coef"] = list(model.coef_[0])
debug.info(1,"Coefs of {}:{}".format(model_name,OPTS.model_dict[model_name+"_coef"])) debug.info(1,"Coefs of {}:{}".format(model_name,OPTS.model_dict[model_name+"_coef"]))
OPTS.model_dict[model_name+"_intercept"] = float(model.intercept_) OPTS.model_dict[model_name+"_intercept"] = float(model.intercept_)

View File

@ -1,16 +1,16 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 tech from openram import debug
from openram.sram_factory import factory
from openram import tech
from openram import OPTS
from .stimuli import * from .stimuli import *
import debug
from .charutils import * from .charutils import *
from globals import OPTS
from sram_factory import factory
class setup_hold(): class setup_hold():

View File

@ -1,16 +1,16 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 debug
import math import math
import tech from openram import debug
from globals import OPTS from openram.base import timing_graph
from sram_factory import factory from openram.sram_factory import factory
from base import timing_graph from openram import tech
from openram import OPTS
class simulation(): class simulation():
@ -20,7 +20,7 @@ class simulation():
self.name = self.sram.name self.name = self.sram.name
self.word_size = self.sram.word_size self.word_size = self.sram.word_size
self.addr_size = self.sram.addr_size self.bank_addr_size = self.sram.bank_addr_size
self.write_size = self.sram.write_size self.write_size = self.sram.write_size
self.num_spare_rows = self.sram.num_spare_rows self.num_spare_rows = self.sram.num_spare_rows
if not self.sram.num_spare_cols: if not self.sram.num_spare_cols:
@ -39,7 +39,7 @@ class simulation():
self.words_per_row = self.sram.words_per_row self.words_per_row = self.sram.words_per_row
self.num_rows = self.sram.num_rows self.num_rows = self.sram.num_rows
self.num_cols = self.sram.num_cols self.num_cols = self.sram.num_cols
if self.write_size: if self.write_size != self.word_size:
self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
else: else:
self.num_wmasks = 0 self.num_wmasks = 0
@ -80,7 +80,7 @@ class simulation():
self.dout_name = "dout" self.dout_name = "dout"
self.pins = self.gen_pin_names(port_signal_names=(self.addr_name, self.din_name, self.dout_name), self.pins = self.gen_pin_names(port_signal_names=(self.addr_name, self.din_name, self.dout_name),
port_info=(len(self.all_ports), self.write_ports, self.read_ports), port_info=(len(self.all_ports), self.write_ports, self.read_ports),
abits=self.addr_size, abits=self.bank_addr_size,
dbits=self.word_size + self.num_spare_cols) dbits=self.word_size + self.num_spare_cols)
debug.check(len(self.sram.pins) == len(self.pins), debug.check(len(self.sram.pins) == len(self.pins),
"Number of pins generated for characterization \ "Number of pins generated for characterization \
@ -103,7 +103,7 @@ class simulation():
self.spare_wen_value = {port: [] for port in self.write_ports} self.spare_wen_value = {port: [] for port in self.write_ports}
# Three dimensional list to handle each addr and data bits for each port over the number of checks # Three dimensional list to handle each addr and data bits for each port over the number of checks
self.addr_values = {port: [[] for bit in range(self.addr_size)] for port in self.all_ports} self.addr_values = {port: [[] for bit in range(self.bank_addr_size)] for port in self.all_ports}
self.data_values = {port: [[] for bit in range(self.word_size + self.num_spare_cols)] for port in self.write_ports} self.data_values = {port: [[] for bit in range(self.word_size + self.num_spare_cols)] for port in self.write_ports}
self.wmask_values = {port: [[] for bit in range(self.num_wmasks)] for port in self.write_ports} self.wmask_values = {port: [[] for bit in range(self.num_wmasks)] for port in self.write_ports}
self.spare_wen_values = {port: [[] for bit in range(self.num_spare_cols)] for port in self.write_ports} self.spare_wen_values = {port: [[] for bit in range(self.num_spare_cols)] for port in self.write_ports}
@ -174,10 +174,10 @@ class simulation():
def add_address(self, address, port): def add_address(self, address, port):
""" Add the array of address values """ """ Add the array of address values """
debug.check(len(address)==self.addr_size, "Invalid address size.") debug.check(len(address)==self.bank_addr_size, "Invalid address size.")
self.addr_value[port].append(address) self.addr_value[port].append(address)
bit = self.addr_size - 1 bit = self.bank_addr_size - 1
for c in address: for c in address:
if c=="0": if c=="0":
self.addr_values[port][bit].append(0) self.addr_values[port][bit].append(0)
@ -330,7 +330,7 @@ class simulation():
try: try:
self.add_address(self.addr_value[port][-1], port) self.add_address(self.addr_value[port][-1], port)
except: except:
self.add_address("0" * self.addr_size, port) self.add_address("0" * self.bank_addr_size, port)
# If the port is also a readwrite then add # If the port is also a readwrite then add
# the same value as previous cycle # the same value as previous cycle
@ -464,7 +464,7 @@ class simulation():
for port in range(total_ports): for port in range(total_ports):
pin_names.append("{0}{1}".format("clk", port)) pin_names.append("{0}{1}".format("clk", port))
if self.write_size: if self.write_size != self.word_size:
for port in write_index: for port in write_index:
for bit in range(self.num_wmasks): for bit in range(self.num_wmasks):
pin_names.append("WMASK{0}_{1}".format(port, bit)) pin_names.append("WMASK{0}_{1}".format(port, bit))

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -11,12 +11,12 @@ various functions that can be be used to generate stimulus for other
simulations as well. simulations as well.
""" """
import tech
import debug
import subprocess
import os import os
import subprocess
import numpy as np import numpy as np
from globals import OPTS from openram import debug
from openram import tech
from openram import OPTS
class stimuli(): class stimuli():
@ -405,6 +405,11 @@ class stimuli():
spice_stdout = open("{0}spice_stdout.log".format(OPTS.openram_temp), 'w') spice_stdout = open("{0}spice_stdout.log".format(OPTS.openram_temp), 'w')
spice_stderr = open("{0}spice_stderr.log".format(OPTS.openram_temp), 'w') spice_stderr = open("{0}spice_stderr.log".format(OPTS.openram_temp), 'w')
# Wrap the command with conda activate & conda deactivate
# FIXME: Should use verify/run_script.py here but run_script doesn't return
# the return code of the subprocess. File names might also mismatch.
from openram import CONDA_HOME
cmd = "source {0}/bin/activate && {1} && conda deactivate".format(CONDA_HOME, cmd)
debug.info(2, cmd) debug.info(2, cmd)
retcode = subprocess.call(cmd, stdout=spice_stdout, stderr=spice_stderr, shell=True) retcode = subprocess.call(cmd, stdout=spice_stdout, stderr=spice_stderr, shell=True)

View File

@ -1,13 +1,13 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 debug
from math import log,ceil
import re import re
from math import log, ceil
from openram import debug
class trim_spice(): class trim_spice():

View File

@ -1 +1,6 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .datasheet_gen import datasheet_gen from .datasheet_gen import datasheet_gen

View File

@ -1,14 +1,15 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 pathlib import Path
import glob
import os
import sys import sys
import os
import glob
from pathlib import Path
# This is the path to the directory you would like to search # This is the path to the directory you would like to search
# This directory is searched recursively for .html files # This directory is searched recursively for .html files

View File

@ -1,14 +1,14 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 *
import os import os
import base64 import base64
from globals import OPTS from openram import OPTS
from .table_gen import *
class datasheet(): class datasheet():

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -15,10 +15,10 @@ a web friendly html datasheet.
# Improve css # Improve css
from globals import OPTS
import os import os
import math import math
import csv import csv
from openram import OPTS
from .datasheet import datasheet from .datasheet import datasheet
from .table_gen import table_gen from .table_gen import table_gen

View File

@ -1,12 +1,11 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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"""

View File

@ -1,15 +1,15 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 os
import inspect
import globals
import sys import sys
import os
import pdb import pdb
import inspect
from openram import globals
# the debug levels: # the debug levels:
# 0 = minimum output (default) # 0 = minimum output (default)
@ -96,7 +96,11 @@ log.create_file = True
def info(lev, str): def info(lev, str):
from globals import OPTS from openram.globals import OPTS
# 99 is a special never print level
if lev == 99:
return
if (OPTS.verbose_level >= lev): if (OPTS.verbose_level >= lev):
frm = inspect.stack()[1] frm = inspect.stack()[1]
mod = inspect.getmodule(frm[0]) mod = inspect.getmodule(frm[0])
@ -110,7 +114,7 @@ def info(lev, str):
def archive(): def archive():
from globals import OPTS from openram.globals import OPTS
try: try:
OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME")) OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME"))
except: except:
@ -127,11 +131,10 @@ def bp():
An empty function so you can set soft breakpoints in pdb. An empty function so you can set soft breakpoints in pdb.
Usage: Usage:
1) Add a breakpoint anywhere in your code with "import debug; debug.bp()". 1) Add a breakpoint anywhere in your code with "import debug; debug.bp()".
2) Run "python3 -m pdb openram.py config.py" or "python3 -m pdb 05_bitcell_array.test" (for example) 2) Run "python3 -m pdb sram_compiler.py config.py" or "python3 -m pdb 05_bitcell_array.test" (for example)
3) When pdb starts, run "break debug.bp" to set a SOFT breakpoint. (Or you can add this to your ~/.pdbrc) 3) When pdb starts, run "break debug.bp" to set a SOFT breakpoint. (Or you can add this to your ~/.pdbrc)
4) Then run "cont" to continue. 4) Then run "cont" to continue.
5) You can now set additional breakpoints or display commands 5) You can now set additional breakpoints or display commands
and whenever you encounter the debug.bp() they won't be "reset". and whenever you encounter the debug.bp() they won't be "reset".
""" """
pass pass

View File

@ -1,3 +1,8 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .custom_cell_properties import * from .custom_cell_properties import *
from .custom_layer_properties import * from .custom_layer_properties import *
from .design_rules import * from .design_rules import *

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2020 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -186,12 +186,15 @@ class cell_properties():
self.names["col_cap_bitcell_2port"] = "col_cap_cell_2rw" self.names["col_cap_bitcell_2port"] = "col_cap_cell_2rw"
self.names["row_cap_bitcell_1port"] = "row_cap_cell_1rw" self.names["row_cap_bitcell_1port"] = "row_cap_cell_1rw"
self.names["row_cap_bitcell_2port"] = "row_cap_cell_2rw" self.names["row_cap_bitcell_2port"] = "row_cap_cell_2rw"
self.names["internal"] = "internal"
self.use_strap = False self.use_strap = False
self._ptx = _ptx(model_is_subckt=False, self._ptx = _ptx(model_is_subckt=False,
bin_spice_models=False) bin_spice_models=False)
self._pgate = _pgate(add_implants=False) self._pgate = _pgate(add_implants=False)
self._inv_dec = cell(["A", "Z", "vdd", "gnd"], self._inv_dec = cell(["A", "Z", "vdd", "gnd"],
["INPUT", "OUTPUT", "POWER", "GROUND"]) ["INPUT", "OUTPUT", "POWER", "GROUND"])
@ -231,6 +234,12 @@ class cell_properties():
self._row_cap_2port = bitcell(["wl0", "wl1", "gnd"], self._row_cap_2port = bitcell(["wl0", "wl1", "gnd"],
["INPUT", "INPUT", "POWER", "GROUND"]) ["INPUT", "INPUT", "POWER", "GROUND"])
self._internal = cell([],[])
@property
def internal(self):
return self._internal
@property @property
def ptx(self): def ptx(self):
return self._ptx return self._ptx
@ -290,4 +299,3 @@ class cell_properties():
@property @property
def row_cap_2port(self): def row_cap_2port(self):
return self._row_cap_2port return self._row_cap_2port

View File

@ -1,12 +1,11 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2020 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 _bank: class _bank:
def __init__(self, stack, pitch): def __init__(self, stack, pitch):
# bank # bank

View File

@ -1,11 +1,11 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 debug from openram import debug
from .drc_value import * from .drc_value import *
from .drc_lut import * from .drc_lut import *

View File

@ -1,11 +1,11 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 debug from openram import debug
class drc_lut(): class drc_lut():

View File

@ -1,12 +1,11 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (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 drc_value(): class drc_value():
""" """
A single DRC value. A single DRC value.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,8 +1,8 @@
import pyx
import math import math
from numpy import matrix
from gdsPrimitives import *
import random import random
from numpy import matrix
from openram.gdsMill import pyx
from .gdsPrimitives import *
class pdfLayout: class pdfLayout:
"""Class representing a view for a layout as a PDF""" """Class representing a view for a layout as a PDF"""

View File

@ -1,8 +1,8 @@
from .gdsPrimitives import * import math
from datetime import * from datetime import *
import numpy as np import numpy as np
import math from openram import debug
import debug from .gdsPrimitives import *
class VlsiLayout: class VlsiLayout:
@ -774,7 +774,7 @@ class VlsiLayout:
else: else:
label_text = label.textString label_text = label.textString
try: try:
from tech import layer_override from openram.tech import layer_override
if layer_override[label_text]: if layer_override[label_text]:
shapes = self.getAllShapes((layer_override[label_text][0], None)) shapes = self.getAllShapes((layer_override[label_text][0], None))
if not shapes: if not shapes:

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.

View File

@ -1,6 +1,6 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2021 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
@ -9,48 +9,45 @@
This is called globals.py, but it actually parses all the arguments This is called globals.py, but it actually parses all the arguments
and performs the global OpenRAM setup as well. and performs the global OpenRAM setup as well.
""" """
import sys
import os import os
import debug import re
import shutil import shutil
import optparse import optparse
import options
import sys
import re
import copy import copy
import importlib import importlib
import getpass import getpass
import subprocess import subprocess
from openram import debug
from openram import options
VERSION = "1.1.18" from openram import OPENRAM_HOME
VERSION = open(OPENRAM_HOME + "/../VERSION").read().rstrip()
NAME = "OpenRAM v{}".format(VERSION) NAME = "OpenRAM v{}".format(VERSION)
USAGE = "openram.py [options] <config file>\nUse -h for help.\n" USAGE = "sram_compiler.py [options] <config file>\nUse -h for help.\n"
OPTS = options.options() OPTS = options.options()
CHECKPOINT_OPTS = None
def parse_args(): def parse_args():
""" Parse the optional arguments for OpenRAM """ """ Parse the optional arguments for OpenRAM. """
global OPTS global OPTS
option_list = { option_list = {
optparse.make_option("-b", optparse.make_option("-b", "--backannotated",
"--backannotated",
action="store_true", action="store_true",
dest="use_pex", dest="use_pex",
help="Back annotate simulation"), help="Back annotate simulation"),
optparse.make_option("-o", optparse.make_option("-o", "--output",
"--output",
dest="output_name", dest="output_name",
help="Base output file name(s) prefix", help="Base output file name(s) prefix",
metavar="FILE"), metavar="FILE"),
optparse.make_option("-p", "--outpath", optparse.make_option("-p", "--outpath",
dest="output_path", dest="output_path",
help="Output file(s) location"), help="Output file(s) location"),
optparse.make_option("-i", optparse.make_option("-i", "--inlinecheck",
"--inlinecheck",
action="store_true", action="store_true",
help="Enable inline LVS/DRC checks", help="Enable inline LVS/DRC checks",
dest="inline_lvsdrc"), dest="inline_lvsdrc"),
@ -68,36 +65,29 @@ def parse_args():
type="int", type="int",
help="Specify the number of spice simulation threads (default: 3)", help="Specify the number of spice simulation threads (default: 3)",
dest="num_sim_threads"), dest="num_sim_threads"),
optparse.make_option("-v", optparse.make_option("-v", "--verbose",
"--verbose",
action="count", action="count",
dest="verbose_level", dest="verbose_level",
help="Increase the verbosity level"), help="Increase the verbosity level"),
optparse.make_option("-t", optparse.make_option("-t", "--tech",
"--tech",
dest="tech_name", dest="tech_name",
help="Technology name"), help="Technology name"),
optparse.make_option("-s", optparse.make_option("-s", "--spice",
"--spice",
dest="spice_name", dest="spice_name",
help="Spice simulator executable name"), help="Spice simulator executable name"),
optparse.make_option("-r", optparse.make_option("-r", "--remove_netlist_trimming",
"--remove_netlist_trimming",
action="store_false", action="store_false",
dest="trim_netlist", dest="trim_netlist",
help="Disable removal of noncritical memory cells during characterization"), help="Disable removal of noncritical memory cells during characterization"),
optparse.make_option("-c", optparse.make_option("-c", "--characterize",
"--characterize",
action="store_false", action="store_false",
dest="analytical_delay", dest="analytical_delay",
help="Perform characterization to calculate delays (default is analytical models)"), help="Perform characterization to calculate delays (default is analytical models)"),
optparse.make_option("-k", optparse.make_option("-k", "--keeptemp",
"--keeptemp",
action="store_true", action="store_true",
dest="keep_temp", dest="keep_temp",
help="Keep the contents of the temp directory after a successful run"), help="Keep the contents of the temp directory after a successful run"),
optparse.make_option("-d", optparse.make_option("-d", "--debug",
"--debug",
action="store_true", action="store_true",
dest="debug", dest="debug",
help="Run in debug mode to drop to pdb on failure") help="Run in debug mode to drop to pdb on failure")
@ -125,7 +115,7 @@ def parse_args():
def print_banner(): def print_banner():
""" Conditionally print the banner to stdout """ """ Conditionally print the banner to stdout. """
global OPTS global OPTS
if OPTS.is_unit_test: if OPTS.is_unit_test:
return return
@ -141,9 +131,6 @@ def print_banner():
debug.print_raw("|=========" + user_info.center(60) + "=========|") debug.print_raw("|=========" + user_info.center(60) + "=========|")
dev_info = "Development help: openram-dev-group@ucsc.edu" dev_info = "Development help: openram-dev-group@ucsc.edu"
debug.print_raw("|=========" + dev_info.center(60) + "=========|") debug.print_raw("|=========" + dev_info.center(60) + "=========|")
if OPTS.openram_temp:
temp_info = "Temp dir: {}".format(OPTS.openram_temp)
debug.print_raw("|=========" + temp_info.center(60) + "=========|")
debug.print_raw("|=========" + "See LICENSE for license info".center(60) + "=========|") debug.print_raw("|=========" + "See LICENSE for license info".center(60) + "=========|")
debug.print_raw("|==============================================================================|") debug.print_raw("|==============================================================================|")
@ -163,8 +150,7 @@ def check_versions():
try: try:
subprocess.check_output(["git", "--version"]) subprocess.check_output(["git", "--version"])
except: except:
debug.error("Git is required. Please install git.") debug.error("Git is required. Please install git.", -1)
sys.exit(1)
# FIXME: Check versions of other tools here?? # FIXME: Check versions of other tools here??
# or, this could be done in each module (e.g. verify, characterizer, etc.) # or, this could be done in each module (e.g. verify, characterizer, etc.)
@ -188,7 +174,7 @@ def check_versions():
OPTS.coverage = 0 OPTS.coverage = 0
def init_openram(config_file, is_unit_test=True): def init_openram(config_file, is_unit_test=False):
""" Initialize the technology, paths, simulators, etc. """ """ Initialize the technology, paths, simulators, etc. """
check_versions() check_versions()
@ -199,38 +185,38 @@ def init_openram(config_file, is_unit_test=True):
read_config(config_file, is_unit_test) read_config(config_file, is_unit_test)
install_conda()
import_tech() import_tech()
set_default_corner() set_default_corner()
init_paths() init_paths()
from sram_factory import factory from openram.sram_factory import factory
factory.reset() factory.reset()
global OPTS global OPTS
global CHECKPOINT_OPTS
# This is a hack. If we are running a unit test and have checkpointed
# the options, load them rather than reading the config file.
# This way, the configuration is reloaded at the start of every unit test.
# If a unit test fails,
# we don't have to worry about restoring the old config values
# that may have been tested.
if is_unit_test and CHECKPOINT_OPTS:
OPTS.__dict__ = CHECKPOINT_OPTS.__dict__.copy()
return
# Setup correct bitcell names # Setup correct bitcell names
setup_bitcell() setup_bitcell()
# Import these to find the executables for checkpointing # Import these to find the executables for checkpointing
import characterizer from openram import characterizer
import verify from openram import verify
# Make a checkpoint of the options so we can restore
# after each unit test
if not CHECKPOINT_OPTS: def install_conda():
CHECKPOINT_OPTS = copy.copy(OPTS) """ Setup conda for default tools. """
# Don't setup conda if not used
if not OPTS.use_conda or OPTS.is_unit_test:
return
debug.info(1, "Creating conda setup...");
from openram import CONDA_INSTALLER
subprocess.call(CONDA_INSTALLER)
def setup_bitcell(): def setup_bitcell():
@ -252,7 +238,7 @@ def setup_bitcell():
# See if bitcell exists # See if bitcell exists
try: try:
c = importlib.import_module("modules." + OPTS.bitcell) c = importlib.import_module("openram.modules." + OPTS.bitcell)
mod = getattr(c, 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
@ -283,21 +269,20 @@ def get_tool(tool_type, preferences, default_name=None):
2) 2)
else: else:
debug.info(1, "Using {0}: {1}".format(tool_type, exe_name)) debug.info(1, "Using {0}: {1}".format(tool_type, exe_name))
return(default_name, exe_name) return (default_name, exe_name)
else: else:
for name in preferences: for name in preferences:
exe_name = find_exe(name) exe_name = find_exe(name)
if exe_name != None: if exe_name != None:
debug.info(1, "Using {0}: {1}".format(tool_type, exe_name)) debug.info(1, "Using {0}: {1}".format(tool_type, exe_name))
return(name, exe_name) return (name, exe_name)
else: else:
debug.info(1, debug.info(1, "Could not find {0}, trying next {1} tool.".format(name, tool_type))
"Could not find {0}, trying next {1} tool.".format(name, tool_type))
else: else:
return(None, "") return (None, "")
def read_config(config_file, is_unit_test=True): def read_config(config_file, is_unit_test=False):
""" """
Read the configuration file that defines a few parameters. The Read the configuration file that defines a few parameters. The
config file is just a Python file that defines some config config file is just a Python file that defines some config
@ -378,12 +363,17 @@ def read_config(config_file, is_unit_test=True):
ports, ports,
OPTS.tech_name) OPTS.tech_name)
# If write size is not defined, set it equal to word size
if OPTS.write_size is None:
OPTS.write_size = OPTS.word_size
def end_openram(): def end_openram():
""" Clean up openram for a proper exit """ """ Clean up openram for a proper exit. """
cleanup_paths() cleanup_paths()
if OPTS.check_lvsdrc: if OPTS.check_lvsdrc:
import verify from openram import verify
verify.print_drc_stats() verify.print_drc_stats()
verify.print_lvs_stats() verify.print_lvs_stats()
verify.print_pex_stats() verify.print_pex_stats()
@ -391,8 +381,7 @@ def end_openram():
def purge_temp(): def purge_temp():
""" Remove the temp directory. """ """ Remove the temp directory. """
debug.info(1, debug.info(1, "Purging temp directory: {}".format(OPTS.openram_temp))
"Purging temp directory: {}".format(OPTS.openram_temp))
#import inspect #import inspect
#s = inspect.stack() #s = inspect.stack()
#print("Purge {0} in dir {1}".format(s[3].filename, OPTS.openram_temp)) #print("Purge {0} in dir {1}".format(s[3].filename, OPTS.openram_temp))
@ -414,8 +403,7 @@ def cleanup_paths():
""" """
global OPTS global OPTS
if OPTS.keep_temp: if OPTS.keep_temp:
debug.info(0, debug.info(0, "Preserving temp directory: {}".format(OPTS.openram_temp))
"Preserving temp directory: {}".format(OPTS.openram_temp))
return return
elif os.path.exists(OPTS.openram_temp): elif os.path.exists(OPTS.openram_temp):
purge_temp() purge_temp()
@ -427,20 +415,11 @@ def setup_paths():
global OPTS global OPTS
try: from openram import OPENRAM_HOME
OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME")) debug.info(1, "OpenRAM source code found in {}".format(OPENRAM_HOME))
except:
debug.error("$OPENRAM_HOME is not properly defined.", 1)
debug.check(os.path.isdir(OPENRAM_HOME),
"$OPENRAM_HOME does not exist: {0}".format(OPENRAM_HOME))
if OPENRAM_HOME not in sys.path:
debug.error("Please add OPENRAM_HOME to the PYTHONPATH.", -1)
# 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":
# Make a unique subdir # Make a unique subdir
tempdir = "/openram_{0}_{1}_temp".format(getpass.getuser(), tempdir = "/openram_{0}_{1}_temp".format(getpass.getuser(),
os.getpid()) os.getpid())
@ -455,16 +434,26 @@ def setup_paths():
def is_exe(fpath): def is_exe(fpath):
""" Return true if the given is an executable file that exists. """ """ Return true if the given is an executable file that exists. """
return os.path.exists(fpath) and os.access(fpath, os.X_OK) return os.path.exists(fpath) and os.access(fpath, os.X_OK)
def find_exe(check_exe): def find_exe(check_exe):
""" """
Check if the binary exists in any path dir Check if the binary exists in any path dir and return the full path.
and return the full path.
""" """
# Search for conda setup if used
if OPTS.use_conda:
from openram import CONDA_HOME
search_path = "{0}/bin{1}{2}".format(CONDA_HOME,
os.pathsep,
os.environ["PATH"])
else:
search_path = os.environ["PATH"]
# Check if the preferred spice option exists in the path # Check if the preferred spice option exists in the path
for path in os.environ["PATH"].split(os.pathsep): for path in search_path.split(os.pathsep):
exe = os.path.join(path, check_exe) exe = os.path.join(path, check_exe)
# if it is found, then break and use first version # if it is found, then break and use first version
if is_exe(exe): if is_exe(exe):
@ -473,18 +462,20 @@ def find_exe(check_exe):
def init_paths(): def init_paths():
""" Create the temp and output directory if it doesn't exist """ """ Create the temp and output directory if it doesn't exist. """
if os.path.exists(OPTS.openram_temp): if os.path.exists(OPTS.openram_temp):
purge_temp() purge_temp()
else: else:
# make the directory if it doesn't exist # Make the directory if it doesn't exist
try: try:
debug.info(1, debug.info(1, "Creating temp directory: {}".format(OPTS.openram_temp))
"Creating temp directory: {}".format(OPTS.openram_temp))
os.makedirs(OPTS.openram_temp, 0o750) os.makedirs(OPTS.openram_temp, 0o750)
except OSError as e: except OSError as e:
if e.errno == 17: # errno.EEXIST if e.errno == 17: # errno.EEXIST
os.chmod(OPTS.openram_temp, 0o750) os.chmod(OPTS.openram_temp, 0o750)
else:
debug.error("Unable to make temp directory: {}".format(OPTS.openram_temp), -1)
#import inspect #import inspect
#s = inspect.stack() #s = inspect.stack()
#from pprint import pprint #from pprint import pprint
@ -497,16 +488,16 @@ def init_paths():
try: try:
os.makedirs(OPTS.output_path, 0o750) os.makedirs(OPTS.output_path, 0o750)
except OSError as e: except OSError as e:
if e.errno == 17: # errno.EEXIST if e.errno == 17: # errno.EEXIST
os.chmod(OPTS.output_path, 0o750) os.chmod(OPTS.output_path, 0o750)
except: else:
debug.error("Unable to make output directory.", -1) debug.error("Unable to make output directory: {}".format(OPTS.output_path), -1)
def set_default_corner(): def set_default_corner():
""" Set the default corner. """ """ Set the default corner. """
import tech from openram import tech
# Set some default options now based on the technology... # Set some default options now based on the technology...
if (OPTS.process_corners == ""): if (OPTS.process_corners == ""):
if OPTS.nominal_corner_only: if OPTS.nominal_corner_only:
@ -539,19 +530,38 @@ def import_tech():
""" Dynamically adds the tech directory to the path and imports it. """ """ Dynamically adds the tech directory to the path and imports it. """
global OPTS global OPTS
debug.info(2, debug.info(2, "Importing technology: " + OPTS.tech_name)
"Importing technology: " + OPTS.tech_name)
# environment variable should point to the technology dir OPENRAM_TECH = ""
# Check if $OPENRAM_TECH is defined
try: try:
OPENRAM_TECH = os.path.abspath(os.environ.get("OPENRAM_TECH")) OPENRAM_TECH = os.path.abspath(os.environ.get("OPENRAM_TECH"))
except: except:
debug.error("$OPENRAM_TECH environment variable is not defined.", 1) debug.info(2,
"$OPENRAM_TECH environment variable is not defined. "
"Only the default technology modules will be considered if installed.")
# Point to the default technology modules that are part of the openram package
try:
import openram
if OPENRAM_TECH != "":
OPENRAM_TECH += ":"
OPENRAM_TECH += os.path.dirname(openram.__file__) + "/technology"
except:
if OPENRAM_TECH == "":
debug.warning("Couldn't find a tech directory. "
"Install openram library or set $OPENRAM_TECH.")
debug.info(1, "Tech directory found in {}".format(OPENRAM_TECH))
# Add this environment variable to os.environ and openram namespace
os.environ["OPENRAM_TECH"] = OPENRAM_TECH
openram.OPENRAM_TECH = OPENRAM_TECH
# Add all of the paths # Add all of the paths
for tech_path in OPENRAM_TECH.split(":"): for tech_path in OPENRAM_TECH.split(":"):
debug.check(os.path.isdir(tech_path), debug.check(os.path.isdir(tech_path),
"$OPENRAM_TECH does not exist: {0}".format(tech_path)) "$OPENRAM_TECH does not exist: {}".format(tech_path))
sys.path.append(tech_path) sys.path.append(tech_path)
debug.info(1, "Adding technology path: {}".format(tech_path)) debug.info(1, "Adding technology path: {}".format(tech_path))
@ -559,22 +569,27 @@ def import_tech():
try: try:
tech_mod = __import__(OPTS.tech_name) tech_mod = __import__(OPTS.tech_name)
except ImportError: except ImportError:
debug.error("Nonexistent technology module: {0}".format(OPTS.tech_name), -1) debug.error("Nonexistent technology module: {}".format(OPTS.tech_name), -1)
OPTS.openram_tech = os.path.dirname(tech_mod.__file__) + "/" OPTS.openram_tech = os.path.dirname(tech_mod.__file__) + "/"
# Prepend the tech directory so it is sourced FIRST # Append tech_path to openram.__path__ to import it from openram
tech_path = OPTS.openram_tech tech_path = OPTS.openram_tech
sys.path.insert(0, tech_path) openram.__path__.append(tech_path)
try: try:
import tech from openram import tech
except ImportError: except ImportError:
debug.error("Could not load tech module.", -1) debug.error("Could not load tech module.", -1)
# Prepend custom modules of the technology to the path, if they exist # Remove OPENRAM_TECH from sys.path because we should be done with those
custom_mod_path = os.path.join(tech_path, "modules/") for tech_path in OPENRAM_TECH.split(":"):
sys.path.remove(tech_path)
# Add the custom modules to "tech"
custom_mod_path = os.path.join(tech_path, "custom/")
if os.path.exists(custom_mod_path): if os.path.exists(custom_mod_path):
sys.path.insert(0, custom_mod_path) from openram import tech
tech.__path__.append(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):
@ -623,7 +638,7 @@ def report_status():
total_size = OPTS.word_size*OPTS.num_words*OPTS.num_banks total_size = OPTS.word_size*OPTS.num_words*OPTS.num_banks
debug.print_raw("Total size: {} bits".format(total_size)) debug.print_raw("Total size: {} bits".format(total_size))
if total_size >= 2**14 and not OPTS.analytical_delay: if total_size >= 2**14 and not OPTS.analytical_delay:
debug.warning("Characterizing large memories ({0}) will have a large run-time. ".format(total_size)) debug.warning("Characterizing large memories ({0}) will have a large run-time.".format(total_size))
debug.print_raw("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size, debug.print_raw("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size,
OPTS.num_words, OPTS.num_words,
OPTS.num_banks)) OPTS.num_banks))

View File

@ -1 +1,6 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
model_name = "cacti" model_name = "cacti"

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 10 word_size = 10
num_words = 64 num_words = 64
words_per_row = 4 words_per_row = 4

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 128 word_size = 128
num_words = 1024 num_words = 1024

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 12 word_size = 12
num_words = 128 num_words = 128
words_per_row = 4 words_per_row = 4

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 12 word_size = 12
num_words = 16 num_words = 16
words_per_row = 1 words_per_row = 1

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 12 word_size = 12
num_words = 256 num_words = 256
words_per_row = 16 words_per_row = 16

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 12 word_size = 12
num_words = 256 num_words = 256
words_per_row = 8 words_per_row = 8

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 14 word_size = 14
num_words = 32 num_words = 32
words_per_row = 2 words_per_row = 2

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 15 word_size = 15
num_words = 512 num_words = 512
words_per_row = 8 words_per_row = 8

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 16 word_size = 16
num_words = 1024 num_words = 1024
words_per_row = 16 words_per_row = 16

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 17 word_size = 17
num_words = 1024 num_words = 1024
words_per_row = 16 words_per_row = 16

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 17 word_size = 17
num_words = 256 num_words = 256
words_per_row = 16 words_per_row = 16

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 18 word_size = 18
num_words = 128 num_words = 128
words_per_row = 2 words_per_row = 2

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 18 word_size = 18
num_words = 32 num_words = 32
words_per_row = 1 words_per_row = 1

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 21 word_size = 21
num_words = 1024 num_words = 1024
words_per_row = 4 words_per_row = 4

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 22 word_size = 22
num_words = 512 num_words = 512
words_per_row = 16 words_per_row = 16

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 23 word_size = 23
num_words = 1024 num_words = 1024
words_per_row = 16 words_per_row = 16

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 26 word_size = 26
num_words = 64 num_words = 64
words_per_row = 4 words_per_row = 4

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 27 word_size = 27
num_words = 1024 num_words = 1024
words_per_row = 4 words_per_row = 4

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 27 word_size = 27
num_words = 256 num_words = 256
words_per_row = 8 words_per_row = 8

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 27 word_size = 27
num_words = 512 num_words = 512
words_per_row = 4 words_per_row = 4

View File

@ -1,3 +1,8 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from shared_config import * from shared_config import *
word_size = 32 word_size = 32
num_words = 1024 num_words = 1024

View File

@ -1,4 +1,9 @@
from shared_config import * # See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
from .shared_config import *
word_size = 32 word_size = 32
num_words = 2048 num_words = 2048

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