merge dev into datasheet_gen; fixed merge conflict in hierarchy_design.py

This commit is contained in:
Jesse Cirimelli-Low 2018-11-15 10:45:33 -08:00
commit 59c0421804
24 changed files with 1014 additions and 634 deletions

View File

@ -7,6 +7,26 @@ list at openram-dev-group@ucsc.edu. We are happy to give insights into
the best way to implement a change to ensure your contribution will be the best way to implement a change to ensure your contribution will be
accepted and help other OpenRAM users. accepted and help other OpenRAM users.
# Directory Structure
* compiler - openram compiler itself (pointed to by OPENRAM_HOME)
* compiler/base - base data structure modules
* compiler/pgates - parameterized cells (e.g. logic gates)
* compiler/bitcells - various bitcell styles
* compiler/modules - high-level modules (e.g. decoders, etc.)
* compiler/verify - DRC and LVS verification wrappers
* compiler/characterizer - timing characterization code
* compiler/gdsMill - GDSII reader/writer
* compiler/router - router for signals and power supplies
* compiler/tests - unit tests
* technology - openram technology directory (pointed to by OPENRAM_TECH)
* technology/freepdk45 - example configuration library for [FreePDK45 technology node
* technology/scn4m_subm - example configuration library [SCMOS] technology node
* technology/scn3me_subm - unsupported configuration (not enough metal layers)
* technology/setup_scripts - setup scripts to customize your PDKs and OpenRAM technologies
* docs - LaTeX manual (outdated)
* lib - IP library of pregenerated memories
# Code Style # Code Style
Our code may not be the best and we acknowledge that. We welcome Our code may not be the best and we acknowledge that. We welcome

110
HINTS.md Normal file
View File

@ -0,0 +1,110 @@
# 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. 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.
2. Glade
You can view errors in Glade as well. I like this because it is on my laptop.
You can get it from: http://www.peardrop.co.uk/glade/
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.
3. Magic
Magic is only supported in SCMOS. You will need to install the MOSIS SCMOS rules
and Magic from: 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).
4. 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.

336
README.md
View File

@ -1,238 +1,214 @@
# BASIC SETUP # OpenRAM
[![pipeline status](https://scone.soe.ucsc.edu:8888/mrg/PrivateRAM/badges/dev/pipeline.svg?private_token=ynB6rSFLzvKUseoBPcwV)](https://github.com/VLSIDA/PrivateRAM/commits)
[![Download](images/download.svg)](https://github.com/VLSIDA/PrivateRAM/archive/dev.zip)
[![License: BSD 3-clause](./images/license_badge.svg)](./LICENSE)
Please look at the OpenRAM ICCAD paper and presentation in the repository: An open-source static random access memory (SRAM) compiler.
https://github.com/mguthaus/OpenRAM/blob/master/OpenRAM_ICCAD_2016_paper.pdf
https://github.com/mguthaus/OpenRAM/blob/master/OpenRAM_ICCAD_2016_presentation.pdf # What is OpenRAM?
<img align="right" width="25%" src="images/SCMOS_16kb_sram.jpg">
OpenRAM is an open-source Python framework to create the layout,
netlists, timing and power models, placement and routing models, and
other views necessary to use SRAMs in ASIC design. OpenRAM supports
integration in both commercial and open-source flows with both
predictive and fabricable technologies.
# Basic Setup
The OpenRAM compiler has very few dependencies: The OpenRAM compiler has very few dependencies:
* ngspice-26 (or later) or HSpice I-2013.12-1 (or later) or CustomSim 2017 (or later) + [Ngspice] 26 (or later) or HSpice I-2013.12-1 (or later) or CustomSim 2017 (or later)
* Python 3.5 and higher + Python 3.5 or higher
* Python numpy (pip3 install numpy to install) + Python numpy (pip3 install numpy to install)
* flask_table (pip3 install flask to install) + flask_table (pip3 install flask to install)
* a setup script for each technology you want to use
* a technology directory for each technology with the base cells
If you want to perform DRC and LVS, you will need either: If you want to perform DRC and LVS, you will need either:
* Calibre (for FreePDK45 or SCMOS) + Calibre (for [FreePDK45])
* Magic + Netgen (for SCMOS only) + [Magic] + [Netgen] (for [SCMOS])
You must set two environment variables:
+ OPENRAM\_HOME should point to the compiler source directory.
+ OPENERAM\_TECH should point to a root technology directory.
For example add this to your .bashrc:
You must set two environment variables: OPENRAM_HOME should point to
the compiler source directory. OPENERAM_TECH should point to a root
technology directory that contains subdirs of all other technologies.
For example, in bash, add to your .bashrc:
``` ```
export OPENRAM_HOME="$HOME/openram/compiler" export OPENRAM_HOME="$HOME/openram/compiler"
export OPENRAM_TECH="$HOME/openram/technology" export OPENRAM_TECH="$HOME/openram/technology"
``` ```
For example, in csh/tcsh, add to your .cshrc/.tcshrc:
```
setenv OPENRAM_HOME "$HOME/openram/compiler"
setenv OPENRAM_TECH "$HOME/openram/technology"
```
We include the tech files necessary for FreePDK and SCMOS. The SCMOS We include the tech files necessary for [FreePDK45] and [SCMOS]
spice models, however, are generic and should be replaced with foundry SCN4M_SUBM. The [SCMOS] spice models, however, are generic and should
models. be replaced with foundry models. If you are using [FreePDK45], you
If you are using FreePDK, you should also have that set up and have the should also have that set up and have the environment variable point
environment variable point to the PDK. to the PDK. For example add this to your .bashrc:
For example, in bash, add to your .bashrc:
``` ```
export FREEPDK45="/bsoe/software/design-kits/FreePDK45" export FREEPDK45="/bsoe/software/design-kits/FreePDK45"
``` ```
For example, in csh/tcsh, add to your .tcshrc:
You may get the entire [FreePDK45 PDK here][FreePDK45].
If you are using [SCMOS], you should install [Magic] and [Netgen].
We have included the most recent SCN4M_SUBM design rules from [Qflow].
# Basic Usage
Once you have defined the environment, you can run OpenRAM from the command line
using a single configuration file written in Python. You may wish to add
$OPENRAM\_HOME to your $PYTHONPATH.
For example, create a file called *myconfig.py* specifying the following
parameters for your memory:
``` ```
setenv FREEPDK45 "/bsoe/software/design-kits/FreePDK45" # 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"
# Process corners to characterize
process_corners = ["TT"]
# Voltage corners to characterize
supply_voltages = [ 3.3 ]
# Temperature corners to characterize
temperatures = [ 25 ]
# 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
``` ```
We do not distribute the PDK, but you may get it from:
https://www.eda.ncsu.edu/wiki/FreePDK45:Contents
If you are using SCMOS, you should install Magic and netgen from: You can then run OpenRAM by executing:
http://opencircuitdesign.com/magic/ ```
http://opencircuitdesign.com/netgen/ python3 $OPENRAM\_HOME/openram.py myconfig
We have included the SCN4M design rules from QFlow: ```
http://opencircuitdesign.com/qflow/ You can see all of the options for the configuration file in
$OPENRAM\_HOME/options.py
# DIRECTORY STRUCTURE
* compiler - openram compiler itself (pointed to by OPENRAM_HOME)
* compiler/base - base data structure modules
* compiler/pgates - parameterized cells (e.g. logic gates)
* compiler/bitcells - various bitcell styles
* compiler/modules - high-level modules (e.g. decoders, etc.)
* compiler/verify - DRC and LVS verification wrappers
* compiler/characterizer - timing characterization code
* compiler/gdsMill - GDSII reader/writer
* compiler/router - router for signals and power supplies
* compiler/tests - unit tests
* technology - openram technology directory (pointed to by OPENRAM_TECH)
* technology/freepdk45 - example configuration library for freepdk45 technology node
* technology/scn4m_subm - example configuration library SCMOS technology node
* technology/scn3me_subm - unsupported configuration (not enough metal layers)
* technology/setup_scripts - setup scripts to customize your PDKs and OpenRAM technologies
* docs - LaTeX manual (outdated)
* lib - IP library of pregenerated memories
# UNIT TESTS # Unit Tests
Regression testing performs a number of tests for all modules in OpenRAM. Regression testing performs a number of tests for all modules in OpenRAM.
From the unit test directory ($OPENRAM\_HOME/tests),
use the following command to run all regression tests:
Use the command:
``` ```
python regress.py python3 regress.py
``` ```
To run a specific test: To run a specific test:
``` ```
python {unit test}.py python3 {unit test}.py
``` ```
The unit tests take the same arguments as openram.py itself. The unit tests take the same arguments as openram.py itself.
To increase the verbosity of the test, add one (or more) -v options: To increase the verbosity of the test, add one (or more) -v options:
``` ```
python tests/00_code_format_check_test.py -v -t freepdk45 python3 tests/00_code_format_check_test.py -v -t freepdk45
``` ```
To specify a particular technology use "-t <techname>" such as To specify a particular technology use "-t <techname>" such as
"-t freepdk45" or "-t scn4m_subm". The default for a unit test is scn4m_subm. "-t freepdk45" or "-t scn4m\_subm". The default for a unit test is scn4m_subm.
The default for openram.py is specified in the configuration file. The default for openram.py is specified in the configuration file.
# CREATING CUSTOM TECHNOLOGIES # Porting to a New Technology
All setup scripts should be in the setup_scripts directory under the If you want to support a enw technology, you will need to create:
$OPENRAM_TECH directory. Please look at the following file for an + a setup script for each technology you want to use
+ a technology directory for each technology with the base cells
All setup scripts should be in the setup\_scripts directory under the
$OPENRAM\_TECH directory. We provide two technology examples for
[SCMOS] and [FreePDK45]. Please look at the following file for an
example of what is needed for OpenRAM: example of what is needed for OpenRAM:
``` ```
$OPENRAM_TECH/setup_scripts/setup_openram_freepdk45.py $OPENRAM_TECH/setup_scripts/setup_openram_freepdk45.py
``` ```
Each setup script should be named as: setup_openram_{tech name}.py.
Each specific technology (e.g., freepdk45) should be a subdirectory Each setup script should be named as: setup\_openram\_{tech name}.py.
Each 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:
1. gds_lib folder with all the .gds (premade) library cells. At a * gds_lib folder with all the .gds (premade) library cells:
minimum this includes: * dff.gds
* ms_flop.gds * sense_amp.gds
* sense_amp.gds * write_driver.gds
* write_driver.gds * cell_6t.gds
* cell_6t.gds * replica\_cell\_6t.gds
* replica_cell_6t.gds * sp_lib folder with all the .sp (premade) library netlists for the above cells.
* tri_gate.gds * layers.map
2. sp_lib folder with all the .sp (premade) library netlists for the above cells. * A valid tech Python module (tech directory with __init__.py and tech.py) with:
3. layers.map * References in tech.py to spice models
4. A valid tech Python module (tech directory with __init__.py and tech.py) with: * DRC/LVS rules needed for dynamic cells and routing
* References in tech.py to spice models * Layer information
* DRC/LVS rules needed for dynamic cells and routing * Spice and supply information
* Layer information * etc.
* etc.
# DEBUGGING # Get Involved
When OpenRAM runs, it puts files in a temporary directory that is + Report bugs by submitting [Github issues].
shown in the banner at the top. Like: + Develop new features (see [how to contribute](./CONTRIBUTING.md))
``` + Submit code/fixes using a [Github pull request]
/tmp/openram_mrg_18128_temp/ + Follow our [project][Github projects].
``` + Read and cite our [ICCAD paper][OpenRAMpaper]
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 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: # Further Help
* _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 + [Additional hints](./HINTS.md)
.err file. This shows the standard output and error output from + [OpenRAM Slack Workspace][Slack]
running DRC/LVS. If there is a setup problem it will be shown here. + [OpenRAM Users Group][user-group] ([subscribe here][user-group-subscribe])
+ [OpenRAM Developers Group][dev-group] ([subscribe here][dev-group-subscribe])
If DRC/LVS runs, but doesn't pass, you then should look at the .results # License
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 OpenRAM is licensed under the [BSD 3-clause License](./LICENSE).
on my Mac, but you can also use Calibre, Magic, etc.
1. Calibre # Contributors & Acknowledgment
Start the Calibre DESIGNrev viewer in the temp directory and load your GDS file: - [Matthew Guthaus] from [VLSIDA] created the OpenRAM project and is the lead architect.
``` - [James Stine] from [VLSIARCH] co-founded the project.
calibredrv temp.gds - Hunter Nichols maintains and updates the timing characterization.
``` - Michael Grims created and maintains the multiport netlist code.
Select Verification->Start RVE and select the results database file in - Jennifer Sowash is creating the OpenRAM IP library.
the new form (e.g., test1.drc.db). This will start the RVE (results - Jesse Cirimelli-Low created the datasheet generation.
viewer). Scroll through the check pane and find the DRC check with an - Samira Ataei created early multi-bank layouts and control logic.
error. Select it and it will open some numbers to the right. Double - Bin Wu created early parameterized cells.
click on any of the errors in the result browser. These will be - Yusu Wang is porting parameterized cells to new technologies.
labelled as numbers "1 2 3 4" for example will be 4 DRC errors. - Brian Chen created early prototypes of the timing characterizer.
- Jeff Butera created early prototypes of the bank layout.
In the viewer ">" opens the layout down a level. * * *
2. Glade [Matthew Guthaus]: https://users.soe.ucsc.edu/~mrg
[James Stine]: https://ece.okstate.edu/content/stine-james-e-jr-phd
[VLSIDA]: https://vlsida.soe.ucsc.edu
[VLSIARCH]: https://vlsiarch.ecen.okstate.edu/
[OpenRAMpaper]: https://ieeexplore.ieee.org/document/7827670/
You can view errors in Glade as well. I like this because it is on my laptop. [Github issues]: https://github.com/PrivateRAM/PrivateRAM/issues
You can get it from: http://www.peardrop.co.uk/glade/ [Github pull request]: https://github.com/PrivateRAM/PrivateRAM/pulls
[Github projects]: https://github.com/PrivateRAM/PrivateRAM/projects
To remote display over X windows, you need to disable OpenGL acceleration or use vnc [email me]: mailto:mrg+openram@ucsc.edu
or something. You can disable by adding this to your .bashrc in bash: [dev-group]: mailto:openram-dev-group@ucsc.edu
``` [user-group]: mailto:openram-user-group@ucsc.edu
export GLADE_USE_OPENGL=no [dev-group-subscribe]: mailto:openram-dev-group+subscribe@ucsc.edu
``` [user-group-subscribe]: mailto:openram-user-group+subscribe@ucsc.edu
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 [Magic]: http://opencircuitdesign.com/magic/
the .results file from Calibre. [Netgen]: http://opencircuitdesign.com/netgen/
[Qflow]: http://opencircuitdesign.com/qflow/history.html
[Ngspice]: http://ngspice.sourceforge.net/
3. Magic [OSUPDK]: https://vlsiarch.ecen.okstate.edu/flow/
[FreePDK45]: https://www.eda.ncsu.edu/wiki/FreePDK45:Contents
Magic is only supported in SCMOS. You will need to install the MOSIS SCMOS rules [SCMOS]: https://www.mosis.com/files/scmos/scmos.pdf
and Magic from: 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).
4. 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.
[Slack]: https://join.slack.com/t/openram/shared_invite/enQtNDgxMjc3NzU5NTI1LTE4ODMyM2I0Mzk2ZmFiMjgwYTYyMTQ4NTgwMmUwMDhiM2E1MDViNDRjYzU1NjJhZTQxNWZjMzE3M2FlODBmZjA

View File

@ -70,40 +70,47 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
"""Checks both DRC and LVS for a module""" """Checks both DRC and LVS for a module"""
# Unit tests will check themselves. # Unit tests will check themselves.
# Do not run if disabled in options. # Do not run if disabled in options.
if not OPTS.is_unit_test and OPTS.check_lvsdrc:
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
global total_drc_errors global total_drc_errors
global total_lvs_errors global total_lvs_errors
tempspice = OPTS.openram_temp + "/temp.sp" tempspice = OPTS.openram_temp + "/temp.sp"
tempgds = OPTS.openram_temp + "/temp.gds" tempgds = OPTS.openram_temp + "/temp.gds"
self.sp_write(tempspice) self.sp_write(tempspice)
self.gds_write(tempgds) self.gds_write(tempgds)
num_drc_errors = verify.run_drc(self.name, tempgds)
num_drc_errors = verify.run_drc(self.name, tempgds, final_verification)
num_lvs_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification) num_lvs_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification)
debug.check(num_drc_errors == 0,"DRC failed for {0} with {1} error(s)".format(self.name,num_drc_errors)) debug.check(num_drc_errors == 0,"DRC failed for {0} with {1} error(s)".format(self.name,num_drc_errors))
debug.check(num_lvs_errors == 0,"LVS failed for {0} with {1} errors(s)".format(self.name,num_lvs_errors)) debug.check(num_lvs_errors == 0,"LVS failed for {0} with {1} errors(s)".format(self.name,num_lvs_errors))
total_drc_errors += num_drc_errors total_drc_errors += num_drc_errors
total_lvs_errors += num_lvs_errors total_lvs_errors += num_lvs_errors
os.remove(tempspice) os.remove(tempspice)
os.remove(tempgds) os.remove(tempgds)
def DRC(self): def DRC(self, final_verification=False):
"""Checks DRC for a module""" """Checks DRC for a module"""
# Unit tests will check themselves. # Unit tests will check themselves.
# Do not run if disabled in options. # Do not run if disabled in options.
if not OPTS.is_unit_test and OPTS.check_lvsdrc:
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
global total_drc_errors global total_drc_errors
tempgds = OPTS.openram_temp + "/temp.gds" tempgds = OPTS.openram_temp + "/temp.gds"
self.gds_write(tempgds) self.gds_write(tempgds)
num_errors = verify.run_drc(self.name, tempgds) num_errors = verify.run_drc(self.name, tempgds, final_verification)
total_drc_errors += num_errors total_drc_errors += num_errors
debug.check(num_errors == 0,"DRC failed for {0} with {1} error(s)".format(self.name,num_error)) debug.check(num_errors == 0,"DRC failed for {0} with {1} error(s)".format(self.name,num_error))
os.remove(tempgds) os.remove(tempgds)
def LVS(self, final_verification=False): def LVS(self, final_verification=False):
"""Checks LVS for a module""" """Checks LVS for a module"""
# Unit tests will check themselves. # Unit tests will check themselves.
# Do not run if disabled in options. # Do not run if disabled in options.
if not OPTS.is_unit_test and OPTS.check_lvsdrc:
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
global total_lvs_errors global total_lvs_errors
tempspice = OPTS.openram_temp + "/temp.sp" tempspice = OPTS.openram_temp + "/temp.sp"
tempgds = OPTS.openram_temp + "/temp.gds" tempgds = OPTS.openram_temp + "/temp.gds"

View File

@ -30,8 +30,10 @@ def parse_args():
help="Base output file name(s) prefix", metavar="FILE"), help="Base output file name(s) prefix", metavar="FILE"),
optparse.make_option("-p", "--outpath", dest="output_path", optparse.make_option("-p", "--outpath", dest="output_path",
help="Output file(s) location"), help="Output file(s) location"),
optparse.make_option("-i", "--inlinecheck", action="store_true",
help="Enable inline LVS/DRC checks", dest="inline_lvsdrc"),
optparse.make_option("-n", "--nocheck", action="store_false", optparse.make_option("-n", "--nocheck", action="store_false",
help="Disable inline LVS/DRC checks", dest="check_lvsdrc"), help="Disable all LVS/DRC checks", dest="check_lvsdrc"),
optparse.make_option("-v", "--verbose", action="count", dest="debug_level", optparse.make_option("-v", "--verbose", action="count", dest="debug_level",
help="Increase the verbosity level"), help="Increase the verbosity level"),
optparse.make_option("-t", "--tech", dest="tech_name", optparse.make_option("-t", "--tech", dest="tech_name",
@ -388,10 +390,10 @@ def import_tech():
def print_time(name, now_time, last_time=None): def print_time(name, now_time, last_time=None):
""" Print a statement about the time delta. """ """ Print a statement about the time delta. """
if last_time: if last_time:
time = round((now_time-last_time).total_seconds(),1) time = str(round((now_time-last_time).total_seconds(),1)) + " seconds"
else: else:
time = now_time time = now_time.strftime('%m/%d/%Y %H:%M:%S')
print("** {0}: {1} seconds".format(name,time)) print("** {0}: {1}".format(name,time))
def report_status(): def report_status():
@ -414,6 +416,9 @@ def report_status():
if OPTS.netlist_only: if OPTS.netlist_only:
print("Netlist only mode (no physical design is being done).") print("Netlist only mode (no physical design is being done).")
if not OPTS.check_lvsdrc: if not OPTS.inline_lvsdrc:
print("DRC/LVS/PEX checking is disabled.") print("DRC/LVS/PEX is only run on the top-level design.")
if not OPTS.check_lvsdrc:
print("DRC/LVS/PEX is completely disabled.")

File diff suppressed because it is too large Load Diff

View File

@ -27,12 +27,12 @@ class bank_select(design.design):
def create_netlist(self): def create_netlist(self):
self.add_pins() self.add_pins()
self.add_modules() self.add_modules()
self.create_modules() self.create_instances()
def create_layout(self): def create_layout(self):
self.calculate_module_offsets() self.calculate_module_offsets()
self.place_modules() self.place_instances()
self.route_modules() self.route_instances()
self.DRC_LVS() self.DRC_LVS()
@ -99,7 +99,7 @@ class bank_select(design.design):
self.height = self.yoffset_maxpoint + 2*self.m1_pitch self.height = self.yoffset_maxpoint + 2*self.m1_pitch
self.width = self.xoffset_inv + self.inv4x.width self.width = self.xoffset_inv + self.inv4x.width
def create_modules(self): def create_instances(self):
self.bank_sel_inv=self.add_inst(name="bank_sel_inv", self.bank_sel_inv=self.add_inst(name="bank_sel_inv",
mod=self.inv_sel) mod=self.inv_sel)
@ -152,7 +152,7 @@ class bank_select(design.design):
"vdd", "vdd",
"gnd"]) "gnd"])
def place_modules(self): def place_instances(self):
# bank select inverter # bank select inverter
self.bank_select_inv_position = vector(self.xoffset_bank_sel_inv, 0) self.bank_select_inv_position = vector(self.xoffset_bank_sel_inv, 0)
@ -195,7 +195,7 @@ class bank_select(design.design):
mirror=mirror) mirror=mirror)
def route_modules(self): def route_instances(self):
# bank_sel is vertical wire # bank_sel is vertical wire
bank_sel_inv_pin = self.bank_sel_inv.get_pin("A") bank_sel_inv_pin = self.bank_sel_inv.get_pin("A")

View File

@ -34,7 +34,7 @@ class bitcell_array(design.design):
""" Create and connect the netlist """ """ Create and connect the netlist """
self.add_modules() self.add_modules()
self.add_pins() self.add_pins()
self.create_modules() self.create_instances()
def create_layout(self): def create_layout(self):
@ -85,7 +85,7 @@ class bitcell_array(design.design):
self.cell = self.mod_bitcell() self.cell = self.mod_bitcell()
self.add_mod(self.cell) self.add_mod(self.cell)
def create_modules(self): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """
self.cell_inst = {} self.cell_inst = {}
for col in range(self.column_size): for col in range(self.column_size):

View File

@ -41,12 +41,12 @@ class control_logic(design.design):
self.setup_signal_busses() self.setup_signal_busses()
self.add_pins() self.add_pins()
self.add_modules() self.add_modules()
self.create_modules() self.create_instances()
def create_layout(self): def create_layout(self):
""" Create layout and route between modules """ """ Create layout and route between modules """
self.route_rails() self.route_rails()
self.place_modules() self.place_instances()
self.route_all() self.route_all()
#self.add_lvs_correspondence_points() #self.add_lvs_correspondence_points()
@ -155,8 +155,8 @@ class control_logic(design.design):
self.rail_offsets = self.create_vertical_bus("metal2", self.m2_pitch, offset, self.internal_bus_list, height) self.rail_offsets = self.create_vertical_bus("metal2", self.m2_pitch, offset, self.internal_bus_list, height)
def create_modules(self): def create_instances(self):
""" Create all the modules """ """ Create all the instances """
self.create_dffs() self.create_dffs()
self.create_clk_row() self.create_clk_row()
if (self.port_type == "rw") or (self.port_type == "w"): if (self.port_type == "rw") or (self.port_type == "w"):
@ -167,8 +167,8 @@ class control_logic(design.design):
self.create_rbl() self.create_rbl()
def place_modules(self): def place_instances(self):
""" Place all the modules """ """ Place all the instances """
# Keep track of all right-most instances to determine row boundary # Keep track of all right-most instances to determine row boundary
# and add the vdd/gnd pins # and add the vdd/gnd pins
self.row_end_inst = [] self.row_end_inst = []

View File

@ -36,13 +36,13 @@ class dff_buf(design.design):
def create_netlist(self): def create_netlist(self):
self.add_modules() self.add_modules()
self.add_pins() self.add_pins()
self.create_modules() self.create_instances()
def create_layout(self): def create_layout(self):
self.width = self.dff.width + self.inv1.width + self.inv2.width self.width = self.dff.width + self.inv1.width + self.inv2.width
self.height = self.dff.height self.height = self.dff.height
self.place_modules() self.place_instances()
self.route_wires() self.route_wires()
self.add_layout_pins() self.add_layout_pins()
self.DRC_LVS() self.DRC_LVS()
@ -70,7 +70,7 @@ class dff_buf(design.design):
self.add_pin("vdd") self.add_pin("vdd")
self.add_pin("gnd") self.add_pin("gnd")
def create_modules(self): def create_instances(self):
self.dff_inst=self.add_inst(name="dff_buf_dff", self.dff_inst=self.add_inst(name="dff_buf_dff",
mod=self.dff) mod=self.dff)
self.connect_inst(["D", "qint", "clk", "vdd", "gnd"]) self.connect_inst(["D", "qint", "clk", "vdd", "gnd"])
@ -83,7 +83,7 @@ class dff_buf(design.design):
mod=self.inv2) mod=self.inv2)
self.connect_inst(["Qb", "Q", "vdd", "gnd"]) self.connect_inst(["Qb", "Q", "vdd", "gnd"])
def place_modules(self): def place_instances(self):
# Add the DFF # Add the DFF
self.dff_inst.place(vector(0,0)) self.dff_inst.place(vector(0,0))

View File

@ -31,8 +31,8 @@ class hierarchical_predecode(design.design):
self.add_pin("vdd") self.add_pin("vdd")
self.add_pin("gnd") self.add_pin("gnd")
def create_modules(self): def add_modules(self):
""" Create the INV and NAND gate """ """ Add the INV and NAND gate modules """
self.inv = pinv() self.inv = pinv()
self.add_mod(self.inv) self.add_mod(self.inv)

View File

@ -18,7 +18,7 @@ class hierarchical_predecode2x4(hierarchical_predecode):
def create_netlist(self): def create_netlist(self):
self.add_pins() self.add_pins()
self.create_modules() self.add_modules()
self.create_input_inverters() self.create_input_inverters()
self.create_output_inverters() self.create_output_inverters()
connections =[["inbar_0", "inbar_1", "Z_0", "vdd", "gnd"], connections =[["inbar_0", "inbar_1", "Z_0", "vdd", "gnd"],

View File

@ -18,7 +18,7 @@ class hierarchical_predecode3x8(hierarchical_predecode):
def create_netlist(self): def create_netlist(self):
self.add_pins() self.add_pins()
self.create_modules() self.add_modules()
self.create_input_inverters() self.create_input_inverters()
self.create_output_inverters() self.create_output_inverters()
connections=[["inbar_0", "inbar_1", "inbar_2", "Z_0", "vdd", "gnd"], connections=[["inbar_0", "inbar_1", "inbar_2", "Z_0", "vdd", "gnd"],

View File

@ -54,8 +54,8 @@ class multibank(design.design):
self.compute_sizes() self.compute_sizes()
self.add_pins() self.add_pins()
self.create_modules()
self.add_modules() self.add_modules()
self.create_instances()
self.setup_layout_constraints() self.setup_layout_constraints()
# FIXME: Move this to the add modules function # FIXME: Move this to the add modules function
@ -111,7 +111,7 @@ class multibank(design.design):
self.route_supplies() self.route_supplies()
def add_modules(self): def create_instances(self):
""" Add modules. The order should not matter! """ """ Add modules. The order should not matter! """
# Above the bitcell array # Above the bitcell array
@ -175,8 +175,8 @@ class multibank(design.design):
def create_modules(self): def add_modules(self):
""" Create all the modules using the class loader """ """ Add all the modules using the class loader """
self.tri = self.mod_tri_gate() self.tri = self.mod_tri_gate()
self.bitcell = self.mod_bitcell() self.bitcell = self.mod_bitcell()

View File

@ -29,11 +29,11 @@ class replica_bitline(design.design):
def create_netlist(self): def create_netlist(self):
self.add_modules() self.add_modules()
self.add_pins() self.add_pins()
self.create_modules() self.create_instances()
def create_layout(self): def create_layout(self):
self.calculate_module_offsets() self.calculate_module_offsets()
self.place_modules() self.place_instances()
self.route() self.route()
self.add_layout_pins() self.add_layout_pins()
@ -104,7 +104,7 @@ class replica_bitline(design.design):
self.access_tx = ptx(tx_type="pmos") self.access_tx = ptx(tx_type="pmos")
self.add_mod(self.access_tx) self.add_mod(self.access_tx)
def create_modules(self): def create_instances(self):
""" Create all of the module instances in the logical netlist """ """ Create all of the module instances in the logical netlist """
# This is the threshold detect inverter on the output of the RBL # This is the threshold detect inverter on the output of the RBL
@ -152,7 +152,7 @@ class replica_bitline(design.design):
self.wl_list = self.rbl.cell.list_all_wl_names() self.wl_list = self.rbl.cell.list_all_wl_names()
self.bl_list = self.rbl.cell.list_all_bl_names() self.bl_list = self.rbl.cell.list_all_bl_names()
def place_modules(self): def place_instances(self):
""" Add all of the module instances in the logical netlist """ """ Add all of the module instances in the logical netlist """
# This is the threshold detect inverter on the output of the RBL # This is the threshold detect inverter on the output of the RBL

View File

@ -129,16 +129,15 @@ class wordline_driver(design.design):
nand2_xoffset = inv1_xoffset + self.inv.width nand2_xoffset = inv1_xoffset + self.inv.width
inv2_xoffset = nand2_xoffset + self.nand2.width inv2_xoffset = nand2_xoffset + self.nand2.width
self.width = inv2_xoffset + self.inv.height self.width = inv2_xoffset + self.inv.width
driver_height = self.inv.height
self.height = self.inv.height * self.rows self.height = self.inv.height * self.rows
for row in range(self.rows): for row in range(self.rows):
if (row % 2): if (row % 2):
y_offset = driver_height*(row + 1) y_offset = self.inv.height*(row + 1)
inst_mirror = "MX" inst_mirror = "MX"
else: else:
y_offset = driver_height*row y_offset = self.inv.height*row
inst_mirror = "R0" inst_mirror = "R0"
inv1_offset = [inv1_xoffset, y_offset] inv1_offset = [inv1_xoffset, y_offset]

View File

@ -20,8 +20,10 @@ class options(optparse.Values):
debug_level = 0 debug_level = 0
# When enabled, layout is not generated (and no DRC or LVS are performed) # When enabled, layout is not generated (and no DRC or LVS are performed)
netlist_only = False netlist_only = False
# This determines whether LVS and DRC is checked for each submodule. # This determines whether LVS and DRC is checked at all.
check_lvsdrc = True check_lvsdrc = True
# This determines whether LVS and DRC is checked for every submodule.
inline_lvsdrc = False
# Variable to select the variant of spice # Variable to select the variant of spice
spice_name = "" spice_name = ""
# The spice executable being used which is derived from the user PATH. # The spice executable being used which is derived from the user PATH.

View File

@ -653,63 +653,32 @@ class router(router_tech):
debug.info(2,"Analyzing pin groups for {}.".format(pin_name)) debug.info(2,"Analyzing pin groups for {}.".format(pin_name))
pin_set = self.pins[pin_name] pin_set = self.pins[pin_name]
local_debug = False
# Put each pin in an equivalence class of it's own # Put each pin in an equivalence class of it's own
equiv_classes = [set([x]) for x in pin_set] equiv_classes = [set([x]) for x in pin_set]
if local_debug:
debug.info(0,"INITIAL\n",equiv_classes)
def compare_classes(class1, class2):
"""
Determine if two classes should be combined and if so return
the combined set. Otherwise, return None.
"""
if local_debug:
debug.info(0,"CLASS1:\n",class1)
debug.info(0,"CLASS2:\n",class2)
# Compare each pin in each class,
# and if any overlap, return the combined the class
for p1 in class1:
for p2 in class2:
if p1.overlaps(p2):
combined_class = class1 | class2
if local_debug:
debug.info(0,"COMBINE:",pformat(combined_class))
return combined_class
if local_debug:
debug.info(0,"NO COMBINE")
return None
def combine_classes(equiv_classes): def combine_classes(equiv_classes):
""" Recursive function to combine classes. """
local_debug = False
if local_debug:
debug.info(0,"\nRECURSE:\n",pformat(equiv_classes))
if len(equiv_classes)==1:
return(equiv_classes)
for class1 in equiv_classes: for class1 in equiv_classes:
for class2 in equiv_classes: for class2 in equiv_classes:
if class1 == class2: if class1 == class2:
continue continue
class3 = compare_classes(class1, class2) # Compare each pin in each class,
if class3: # and if any overlap, update equiv_classes to include the combined the class
new_classes = equiv_classes for p1 in class1:
new_classes.remove(class1) for p2 in class2:
new_classes.remove(class2) if p1.overlaps(p2):
new_classes.append(class3) combined_class = class1 | class2
return(combine_classes(new_classes)) equiv_classes.remove(class1)
else: equiv_classes.remove(class2)
return(equiv_classes) equiv_classes.append(combined_class)
return(equiv_classes)
return(equiv_classes)
reduced_classes = combine_classes(equiv_classes) old_length = math.inf
if local_debug: while (len(equiv_classes)<old_length):
debug.info(0,"FINAL ",reduced_classes) old_length = len(equiv_classes)
self.pin_groups[pin_name] = [pin_group(name=pin_name, pin_set=x, router=self) for x in reduced_classes] equiv_classes = combine_classes(equiv_classes)
self.pin_groups[pin_name] = [pin_group(name=pin_name, pin_set=x, router=self) for x in equiv_classes]
def convert_pins(self, pin_name): def convert_pins(self, pin_name):
""" """

View File

@ -34,14 +34,14 @@ class sram_1bank(sram_base):
self.bank_inst=self.create_bank(0) self.bank_inst=self.create_bank(0)
self.control_logic_inst = self.create_control_logic() self.control_logic_insts = self.create_control_logic()
self.row_addr_dff_inst = self.create_row_addr_dff() self.row_addr_dff_insts = self.create_row_addr_dff()
if self.col_addr_dff: if self.col_addr_dff:
self.col_addr_dff_inst = self.create_col_addr_dff() self.col_addr_dff_insts = self.create_col_addr_dff()
self.data_dff_inst = self.create_data_dff() self.data_dff_insts = self.create_data_dff()
def place_modules(self): def place_modules(self):
""" """
@ -58,14 +58,14 @@ class sram_1bank(sram_base):
# The x-coordinate is placed to allow a single clock wire (plus an extra pitch) # The x-coordinate is placed to allow a single clock wire (plus an extra pitch)
# up to the row address DFFs. # up to the row address DFFs.
for port in self.all_ports: for port in self.all_ports:
control_pos = vector(-self.control_logic.width - 2*self.m2_pitch, control_pos = vector(-self.control_logic_rw.width - 2*self.m2_pitch,
self.bank.bank_center.y - self.control_logic.control_logic_center.y) self.bank.bank_center.y - self.control_logic_rw.control_logic_center.y)
self.control_logic_inst[port].place(control_pos) self.control_logic_insts[port].place(control_pos)
# The row address bits are placed above the control logic aligned on the right. # The row address bits are placed above the control logic aligned on the right.
row_addr_pos = vector(self.control_logic_inst[0].rx() - self.row_addr_dff.width, row_addr_pos = vector(self.control_logic_insts[0].rx() - self.row_addr_dff.width,
self.control_logic_inst[0].uy()) self.control_logic_insts[0].uy())
self.row_addr_dff_inst[port].place(row_addr_pos) self.row_addr_dff_insts[port].place(row_addr_pos)
# This is M2 pitch even though it is on M1 to help stem via spacings on the trunk # This is M2 pitch even though it is on M1 to help stem via spacings on the trunk
data_gap = -self.m2_pitch*(self.word_size+1) data_gap = -self.m2_pitch*(self.word_size+1)
@ -75,7 +75,7 @@ class sram_1bank(sram_base):
if self.col_addr_dff: if self.col_addr_dff:
col_addr_pos = vector(self.bank.bank_center.x - self.col_addr_dff.width - self.bank.central_bus_width, col_addr_pos = vector(self.bank.bank_center.x - self.col_addr_dff.width - self.bank.central_bus_width,
data_gap - self.col_addr_dff.height) data_gap - self.col_addr_dff.height)
self.col_addr_dff_inst[port].place(col_addr_pos) self.col_addr_dff_insts[port].place(col_addr_pos)
# Add the data flops below the bank to the right of the center of bank: # Add the data flops below the bank to the right of the center of bank:
# This relies on the center point of the bank: # This relies on the center point of the bank:
@ -84,7 +84,7 @@ class sram_1bank(sram_base):
# sense amps. # sense amps.
data_pos = vector(self.bank.bank_center.x, data_pos = vector(self.bank.bank_center.x,
data_gap - self.data_dff.height) data_gap - self.data_dff.height)
self.data_dff_inst[port].place(data_pos) self.data_dff_insts[port].place(data_pos)
# two supply rails are already included in the bank, so just 2 here. # two supply rails are already included in the bank, so just 2 here.
# self.width = self.bank.width + self.control_logic.width + 2*self.supply_rail_pitch # self.width = self.bank.width + self.control_logic.width + 2*self.supply_rail_pitch
@ -97,7 +97,7 @@ class sram_1bank(sram_base):
for port in self.all_ports: for port in self.all_ports:
# Connect the control pins as inputs # Connect the control pins as inputs
for signal in self.control_logic_inputs[port] + ["clk"]: for signal in self.control_logic_inputs[port] + ["clk"]:
self.copy_layout_pin(self.control_logic_inst[port], signal, signal+"{}".format(port)) self.copy_layout_pin(self.control_logic_insts[port], signal, signal+"{}".format(port))
if port in self.read_ports: if port in self.read_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
@ -105,14 +105,14 @@ class sram_1bank(sram_base):
# Lower address bits # Lower address bits
for bit in range(self.col_addr_size): for bit in range(self.col_addr_size):
self.copy_layout_pin(self.col_addr_dff_inst[port], "din_{}".format(bit),"ADDR{0}[{1}]".format(port,bit)) self.copy_layout_pin(self.col_addr_dff_insts[port], "din_{}".format(bit),"ADDR{0}[{1}]".format(port,bit))
# Upper address bits # Upper address bits
for bit in range(self.row_addr_size): for bit in range(self.row_addr_size):
self.copy_layout_pin(self.row_addr_dff_inst[port], "din_{}".format(bit),"ADDR{0}[{1}]".format(port,bit+self.col_addr_size)) self.copy_layout_pin(self.row_addr_dff_insts[port], "din_{}".format(bit),"ADDR{0}[{1}]".format(port,bit+self.col_addr_size))
if port in self.write_ports: if port in self.write_ports:
for bit in range(self.word_size): for bit in range(self.word_size):
self.copy_layout_pin(self.data_dff_inst[port], "din_{}".format(bit), "DIN{0}[{1}]".format(port,bit)) self.copy_layout_pin(self.data_dff_insts[port], "din_{}".format(bit), "DIN{0}[{1}]".format(port,bit))
def route(self): def route(self):
""" Route a single bank SRAM """ """ Route a single bank SRAM """
@ -135,7 +135,7 @@ class sram_1bank(sram_base):
# This is the actual input to the SRAM # This is the actual input to the SRAM
for port in self.all_ports: for port in self.all_ports:
self.copy_layout_pin(self.control_logic_inst[port], "clk", "clk{}".format(port)) self.copy_layout_pin(self.control_logic_insts[port], "clk", "clk{}".format(port))
# Connect all of these clock pins to the clock in the central bus # Connect all of these clock pins to the clock in the central bus
# This is something like a "spine" clock distribution. The two spines # This is something like a "spine" clock distribution. The two spines
@ -147,23 +147,23 @@ class sram_1bank(sram_base):
bank_clk_buf_bar_pos = bank_clk_buf_bar_pin.center() bank_clk_buf_bar_pos = bank_clk_buf_bar_pin.center()
if self.col_addr_dff: if self.col_addr_dff:
dff_clk_pin = self.col_addr_dff_inst[port].get_pin("clk") dff_clk_pin = self.col_addr_dff_insts[port].get_pin("clk")
dff_clk_pos = dff_clk_pin.center() dff_clk_pos = dff_clk_pin.center()
mid_pos = vector(bank_clk_buf_pos.x, dff_clk_pos.y) mid_pos = vector(bank_clk_buf_pos.x, dff_clk_pos.y)
self.add_wire(("metal3","via2","metal2"),[dff_clk_pos, mid_pos, bank_clk_buf_pos]) self.add_wire(("metal3","via2","metal2"),[dff_clk_pos, mid_pos, bank_clk_buf_pos])
data_dff_clk_pin = self.data_dff_inst[port].get_pin("clk") data_dff_clk_pin = self.data_dff_insts[port].get_pin("clk")
data_dff_clk_pos = data_dff_clk_pin.center() data_dff_clk_pos = data_dff_clk_pin.center()
mid_pos = vector(bank_clk_buf_pos.x, data_dff_clk_pos.y) mid_pos = vector(bank_clk_buf_pos.x, data_dff_clk_pos.y)
self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, bank_clk_buf_pos]) self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, bank_clk_buf_pos])
# This uses a metal2 track to the right of the control/row addr DFF # This uses a metal2 track to the right of the control/row addr DFF
# to route vertically. # to route vertically.
control_clk_buf_pin = self.control_logic_inst[port].get_pin("clk_buf") control_clk_buf_pin = self.control_logic_insts[port].get_pin("clk_buf")
control_clk_buf_pos = control_clk_buf_pin.rc() control_clk_buf_pos = control_clk_buf_pin.rc()
row_addr_clk_pin = self.row_addr_dff_inst[port].get_pin("clk") row_addr_clk_pin = self.row_addr_dff_insts[port].get_pin("clk")
row_addr_clk_pos = row_addr_clk_pin.rc() row_addr_clk_pos = row_addr_clk_pin.rc()
mid1_pos = vector(self.row_addr_dff_inst[port].rx() + self.m2_pitch, mid1_pos = vector(self.row_addr_dff_insts[port].rx() + self.m2_pitch,
row_addr_clk_pos.y) row_addr_clk_pos.y)
mid2_pos = vector(mid1_pos.x, mid2_pos = vector(mid1_pos.x,
control_clk_buf_pos.y) control_clk_buf_pos.y)
@ -176,7 +176,7 @@ class sram_1bank(sram_base):
""" Route the outputs from the control logic module """ """ Route the outputs from the control logic module """
for port in self.all_ports: for port in self.all_ports:
for signal in self.control_logic_outputs[port]: for signal in self.control_logic_outputs[port]:
src_pin = self.control_logic_inst[port].get_pin(signal) src_pin = self.control_logic_insts[port].get_pin(signal)
dest_pin = self.bank_inst.get_pin(signal+"{}".format(port)) dest_pin = self.bank_inst.get_pin(signal+"{}".format(port))
self.connect_rail_from_left_m2m3(src_pin, dest_pin) self.connect_rail_from_left_m2m3(src_pin, dest_pin)
self.add_via_center(layers=("metal1","via1","metal2"), self.add_via_center(layers=("metal1","via1","metal2"),
@ -190,7 +190,7 @@ class sram_1bank(sram_base):
for bit in range(self.row_addr_size): for bit in range(self.row_addr_size):
flop_name = "dout_{}".format(bit) flop_name = "dout_{}".format(bit)
bank_name = "addr{0}_{1}".format(port,bit+self.col_addr_size) bank_name = "addr{0}_{1}".format(port,bit+self.col_addr_size)
flop_pin = self.row_addr_dff_inst[port].get_pin(flop_name) flop_pin = self.row_addr_dff_insts[port].get_pin(flop_name)
bank_pin = self.bank_inst.get_pin(bank_name) bank_pin = self.bank_inst.get_pin(bank_name)
flop_pos = flop_pin.center() flop_pos = flop_pin.center()
bank_pos = bank_pin.center() bank_pos = bank_pin.center()
@ -206,13 +206,13 @@ class sram_1bank(sram_base):
bus_names = ["addr_{}".format(x) for x in range(self.col_addr_size)] bus_names = ["addr_{}".format(x) for x in range(self.col_addr_size)]
col_addr_bus_offsets = self.create_horizontal_bus(layer="metal1", col_addr_bus_offsets = self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch, pitch=self.m1_pitch,
offset=self.col_addr_dff_inst[port].ul() + vector(0, self.m1_pitch), offset=self.col_addr_dff_insts[port].ul() + vector(0, self.m1_pitch),
names=bus_names, names=bus_names,
length=self.col_addr_dff_inst[port].width) length=self.col_addr_dff_insts[port].width)
dff_names = ["dout_{}".format(x) for x in range(self.col_addr_size)] dff_names = ["dout_{}".format(x) for x in range(self.col_addr_size)]
data_dff_map = zip(dff_names, bus_names) data_dff_map = zip(dff_names, bus_names)
self.connect_horizontal_bus(data_dff_map, self.col_addr_dff_inst[port], col_addr_bus_offsets) self.connect_horizontal_bus(data_dff_map, self.col_addr_dff_insts[port], col_addr_bus_offsets)
bank_names = ["addr{0}_{1}".format(port,x) for x in range(self.col_addr_size)] bank_names = ["addr{0}_{1}".format(port,x) for x in range(self.col_addr_size)]
data_bank_map = zip(bank_names, bus_names) data_bank_map = zip(bank_names, bus_names)
@ -223,13 +223,13 @@ class sram_1bank(sram_base):
""" Connect the output of the data flops to the write driver """ """ Connect the output of the data flops to the write driver """
# This is where the channel will start (y-dimension at least) # This is where the channel will start (y-dimension at least)
for port in self.write_ports: for port in self.write_ports:
offset = self.data_dff_inst[port].ul() + vector(0, 2*self.m1_pitch) offset = self.data_dff_insts[port].ul() + vector(0, 2*self.m1_pitch)
dff_names = ["dout_{}".format(x) for x in range(self.word_size)] dff_names = ["dout_{}".format(x) for x in range(self.word_size)]
bank_names = ["din{0}_{1}".format(port,x) for x in range(self.word_size)] bank_names = ["din{0}_{1}".format(port,x) for x in range(self.word_size)]
route_map = list(zip(bank_names, dff_names)) route_map = list(zip(bank_names, dff_names))
dff_pins = {key: self.data_dff_inst[port].get_pin(key) for key in dff_names } dff_pins = {key: self.data_dff_insts[port].get_pin(key) for key in dff_names }
bank_pins = {key: self.bank_inst.get_pin(key) for key in bank_names } bank_pins = {key: self.bank_inst.get_pin(key) for key in bank_names }
# Combine the dff and bank pins into a single dictionary of pin name to pin. # Combine the dff and bank pins into a single dictionary of pin name to pin.
all_pins = {**dff_pins, **bank_pins} all_pins = {**dff_pins, **bank_pins}
@ -245,7 +245,7 @@ class sram_1bank(sram_base):
""" """
for n in self.control_logic_outputs[0]: for n in self.control_logic_outputs[0]:
pin = self.control_logic_inst[0].get_pin(n) pin = self.control_logic_insts[0].get_pin(n)
self.add_label(text=n, self.add_label(text=n,
layer=pin.layer, layer=pin.layer,
offset=pin.center()) offset=pin.center())

View File

@ -216,20 +216,24 @@ class sram_base(design):
self.mod_bitcell = getattr(c, OPTS.bitcell) self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell() self.bitcell = self.mod_bitcell()
#c = reload(__import__(OPTS.control_logic)) c = reload(__import__(OPTS.control_logic))
#self.mod_control_logic = getattr(c, OPTS.control_logic) self.mod_control_logic = getattr(c, OPTS.control_logic)
from control_logic import control_logic
# Create the control logic module for each port type # Create the control logic module for each port type
if OPTS.num_rw_ports>0: if len(self.readwrite_ports)>0:
self.control_logic = self.control_logic_rw = control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, port_type="rw") self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row,
port_type="rw")
self.add_mod(self.control_logic_rw) self.add_mod(self.control_logic_rw)
if OPTS.num_w_ports>0: if len(self.write_ports)>0:
self.control_logic_w = control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, port_type="w") self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row,
port_type="w")
self.add_mod(self.control_logic_w) self.add_mod(self.control_logic_w)
if OPTS.num_r_ports>0: if len(self.read_ports)>0:
self.control_logic_r = control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, port_type="r") self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row,
port_type="r")
self.add_mod(self.control_logic_r) self.add_mod(self.control_logic_r)
# Create the address and control flops (but not the clk) # Create the address and control flops (but not the clk)
@ -382,7 +386,8 @@ class sram_base(design):
def create_control_logic(self): def create_control_logic(self):
""" Add and place control logic """ """ Add control logic instances """
insts = [] insts = []
for port in self.all_ports: for port in self.all_ports:
if port in self.readwrite_ports: if port in self.readwrite_ports:
@ -392,8 +397,7 @@ class sram_base(design):
else: else:
mod = self.control_logic_r mod = self.control_logic_r
insts.append(self.add_inst(name="control{}".format(port), insts.append(self.add_inst(name="control{}".format(port), mod=mod))
mod=mod))
temp = ["csb{}".format(port)] temp = ["csb{}".format(port)]
if port in self.readwrite_ports: if port in self.readwrite_ports:

View File

@ -0,0 +1,60 @@
#!/usr/bin/env python3
"""
Run a regression test on 1rw 1r sram bank
"""
import unittest
from testutils import header,openram_test
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
class single_bank_1rw_1r_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
from bank import bank
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=16)
c.words_per_row=1
debug.info(1, "No column mux")
a = bank(c, name="bank1_single")
self.local_check(a)
c.num_words=32
c.words_per_row=2
debug.info(1, "Two way column mux")
a = bank(c, name="bank2_single")
self.local_check(a)
c.num_words=64
c.words_per_row=4
debug.info(1, "Four way column mux")
a = bank(c, name="bank3_single")
self.local_check(a)
c.word_size=2
c.num_words=128
c.words_per_row=8
debug.info(1, "Eight way column mux")
a = bank(c, name="bank4_single")
self.local_check(a)
globals.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

BIN
images/SCMOS_16kb_sram.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 KiB

2
images/download.svg Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="112" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="112" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h71v20H0z"/><path fill="#007ec6" d="M71 0h41v20H71z"/><path fill="url(#b)" d="M0 0h112v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><text x="365" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="610">download </text><text x="365" y="140" transform="scale(.1)" textLength="610">download </text><text x="905" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="310">latest</text><text x="905" y="140" transform="scale(.1)" textLength="310">latest</text></g> </svg>

After

Width:  |  Height:  |  Size: 1004 B

1
images/license_badge.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="136" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="136" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h51v20H0z"/><path fill="#007ec6" d="M51 0h85v20H51z"/><path fill="url(#b)" d="M0 0h136v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"> <text x="265" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="410">License</text><text x="265" y="140" transform="scale(.1)" textLength="410">License</text><text x="925" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="750">BSD 3-Clause</text><text x="925" y="140" transform="scale(.1)" textLength="750">BSD 3-Clause</text></g> </svg>

After

Width:  |  Height:  |  Size: 971 B