mirror of https://github.com/VLSIDA/OpenRAM.git
Use packages for imports.
Must set PYTHONPATH to include OPENRAM_HOME now. Reorganizes subdirs as packages. Rewrites unit tests to use packages. Update README.md with instructions, dependencies etc. Update sky130 module imports. Change tech specific package from modules to custom.
This commit is contained in:
parent
58ea148d47
commit
d92c7a634d
56
README.md
56
README.md
|
|
@ -26,28 +26,33 @@ things that need to be fixed.
|
|||
|
||||
# Basic Setup
|
||||
|
||||
## Docker
|
||||
|
||||
We have a [docker setup](./docker) to run OpenRAM.
|
||||
|
||||
## Dependencies
|
||||
|
||||
The OpenRAM compiler has very few dependencies:
|
||||
+ [Ngspice] 34 (or later) or HSpice I-2013.12-1 (or later) or CustomSim 2017 (or later) or [Xyce] 7.4 (or later)
|
||||
Please see the Dockerfile for the required versions of tools.
|
||||
|
||||
In general, the OpenRAM compiler has very few dependencies:
|
||||
+ Docker
|
||||
+ Make
|
||||
+ Python 3.6 or higher
|
||||
+ Various Python packages (pip install -r requirements.txt)
|
||||
+ [Git]
|
||||
|
||||
If you want to perform DRC and LVS, you will need either:
|
||||
+ Calibre (for [FreePDK45])
|
||||
+ [Magic] 8.3.197 or newer
|
||||
+ [Netgen] 1.5.195 or newer
|
||||
## Docker
|
||||
|
||||
We have a [docker setup](./docker) to run OpenRAM. To use this, you should run:
|
||||
```
|
||||
cd openram/docker
|
||||
make build
|
||||
```
|
||||
This must be run once and will take a while to build all the tools.
|
||||
|
||||
|
||||
## Environment
|
||||
|
||||
You must set two environment variables:
|
||||
+ OPENRAM\_HOME should point to the compiler source directory.
|
||||
+ OPENERAM\_TECH should point to one or more root technology directories (colon separated).
|
||||
|
||||
## Environment
|
||||
|
||||
For example add this to your .bashrc:
|
||||
|
||||
|
|
@ -56,17 +61,23 @@ For example add this to your .bashrc:
|
|||
export OPENRAM_TECH="$HOME/openram/technology"
|
||||
```
|
||||
|
||||
You may also wish to add OPENRAM\_HOME to your PYTHONPATH:
|
||||
You should also add OPENRAM\_HOME to your PYTHONPATH:
|
||||
|
||||
```
|
||||
export PYTHONPATH="$PYTHONPATH:$OPENRAM_HOME"
|
||||
export PYTHONPATH=$OPENRAM_HOME
|
||||
```
|
||||
Note that if you want symbols to resolve in your editor, you may also want to add the specific technology
|
||||
directory that you use and any custom technology modules as well. For example:
|
||||
```
|
||||
export PYTHONPATH="$OPENRAM_HOME:$OPENRAM_TECH/sky130:$OPENRAM_TECH/sky130/custom"
|
||||
```
|
||||
|
||||
We include the tech files necessary for [SCMOS] SCN4M_SUBM,
|
||||
[FreePDK45]. The [SCMOS] spice models, however, are
|
||||
generic and should be replaced with foundry models. You may get the
|
||||
entire [FreePDK45 PDK here][FreePDK45].
|
||||
|
||||
```
|
||||
|
||||
### Sky130 Setup
|
||||
|
||||
To install [Sky130], you must have the open_pdks files installed in $PDK_ROOT.
|
||||
|
|
@ -80,7 +91,7 @@ by running:
|
|||
|
||||
cd $HOME/openram
|
||||
make install
|
||||
```
|
||||
|
||||
# Basic Usage
|
||||
|
||||
Once you have defined the environment, you can run OpenRAM from the command line
|
||||
|
|
@ -88,7 +99,7 @@ using a single configuration file written in Python.
|
|||
|
||||
For example, create a file called *myconfig.py* specifying the following
|
||||
parameters for your memory:
|
||||
|
||||
```
|
||||
# Data word size
|
||||
word_size = 2
|
||||
# Number of words in the memory
|
||||
|
|
@ -142,9 +153,9 @@ make -j 3
|
|||
```
|
||||
The -j can run with 3 threads. By default, this will run in all technologies.
|
||||
|
||||
To run a specific test:
|
||||
To run a specific test in all technologies:
|
||||
```
|
||||
ce openram/compiler/tests
|
||||
cd openram/compiler/tests
|
||||
make 05_bitcell_array_test
|
||||
```
|
||||
To run a specific technology:
|
||||
|
|
@ -159,6 +170,14 @@ pass it as an argument to OpenRAM:
|
|||
ARGS="-v" make 05_bitcell_array_test
|
||||
```
|
||||
|
||||
Unit test results are put in a directory:
|
||||
```
|
||||
openram/compiler/tests/results/<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
|
||||
|
||||
+ [Port it](./PORTING.md) to a new technology.
|
||||
|
|
@ -207,6 +226,7 @@ If I forgot to add you, please let me know!
|
|||
[dev-group-subscribe]: mailto:openram-dev-group+subscribe@ucsc.edu
|
||||
[user-group-subscribe]: mailto:openram-user-group+subscribe@ucsc.edu
|
||||
|
||||
[Klayout]: https://www.klayout.de/
|
||||
[Magic]: http://opencircuitdesign.com/magic/
|
||||
[Netgen]: http://opencircuitdesign.com/netgen/
|
||||
[Qflow]: http://opencircuitdesign.com/qflow/history.html
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
from .channel_route import *
|
||||
from .contact import *
|
||||
from .delay_data import *
|
||||
from .design import *
|
||||
from .errors import *
|
||||
from .geometry import *
|
||||
from .hierarchy_design import *
|
||||
from .hierarchy_layout import *
|
||||
from .hierarchy_spice import *
|
||||
from .lef import *
|
||||
from .logical_effort import *
|
||||
from .pin_layout import *
|
||||
from .power_data import *
|
||||
from .route import *
|
||||
from .timing_graph import *
|
||||
from .utils import *
|
||||
from .vector import *
|
||||
from .verilog import *
|
||||
from .wire_path import *
|
||||
from .wire import *
|
||||
from .wire_spice_model import *
|
||||
|
|
@ -8,8 +8,8 @@
|
|||
import collections
|
||||
import debug
|
||||
from tech import drc
|
||||
from vector import vector
|
||||
import design
|
||||
from .vector import vector
|
||||
from .design import design
|
||||
|
||||
|
||||
class channel_net():
|
||||
|
|
@ -75,7 +75,7 @@ class channel_net():
|
|||
return min_overlap or max_overlap
|
||||
|
||||
|
||||
class channel_route(design.design):
|
||||
class channel_route(design):
|
||||
|
||||
unique_id = 0
|
||||
|
||||
|
|
|
|||
|
|
@ -5,16 +5,14 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import hierarchy_design
|
||||
import debug
|
||||
from tech import drc, layer
|
||||
import tech
|
||||
from vector import vector
|
||||
from sram_factory import factory
|
||||
import sys
|
||||
from .hierarchy_design import hierarchy_design
|
||||
from .vector import vector
|
||||
from tech import drc, layer, preferred_directions
|
||||
from tech import layer as tech_layers
|
||||
|
||||
|
||||
class contact(hierarchy_design.hierarchy_design):
|
||||
class contact(hierarchy_design):
|
||||
"""
|
||||
Object for a contact shape with its conductor enclosures. Creates
|
||||
a contact array minimum active or poly enclosure and metal1
|
||||
|
|
@ -51,20 +49,20 @@ class contact(hierarchy_design.hierarchy_design):
|
|||
|
||||
# Non-preferred directions
|
||||
if directions == "nonpref":
|
||||
first_dir = "H" if tech.preferred_directions[layer_stack[0]]=="V" else "V"
|
||||
second_dir = "H" if tech.preferred_directions[layer_stack[2]]=="V" else "V"
|
||||
first_dir = "H" if preferred_directions[layer_stack[0]]=="V" else "V"
|
||||
second_dir = "H" if preferred_directions[layer_stack[2]]=="V" else "V"
|
||||
self.directions = (first_dir, second_dir)
|
||||
# Preferred directions
|
||||
elif directions == "pref":
|
||||
self.directions = (tech.preferred_directions[layer_stack[0]],
|
||||
tech.preferred_directions[layer_stack[2]])
|
||||
self.directions = (preferred_directions[layer_stack[0]],
|
||||
preferred_directions[layer_stack[2]])
|
||||
# User directions
|
||||
elif directions:
|
||||
self.directions = directions
|
||||
# Preferred directions
|
||||
else:
|
||||
self.directions = (tech.preferred_directions[layer_stack[0]],
|
||||
tech.preferred_directions[layer_stack[2]])
|
||||
self.directions = (preferred_directions[layer_stack[0]],
|
||||
preferred_directions[layer_stack[2]])
|
||||
self.offset = vector(0, 0)
|
||||
self.implant_type = implant_type
|
||||
self.well_type = well_type
|
||||
|
|
@ -101,7 +99,7 @@ class contact(hierarchy_design.hierarchy_design):
|
|||
self.second_layer_name = second_layer
|
||||
|
||||
# Contacts will have unique per first layer
|
||||
if via_layer in tech.layer:
|
||||
if via_layer in tech_layers:
|
||||
self.via_layer_name = via_layer
|
||||
elif via_layer == "contact":
|
||||
if first_layer in ("active", "poly"):
|
||||
|
|
@ -194,7 +192,7 @@ class contact(hierarchy_design.hierarchy_design):
|
|||
def create_nitride_cut_enclosure(self):
|
||||
""" Special layer that encloses poly contacts in some processes """
|
||||
# Check if there is a special poly nitride cut layer
|
||||
if "npc" not in tech.layer:
|
||||
if "npc" not in tech_layers:
|
||||
return
|
||||
|
||||
npc_enclose_poly = drc("npc_enclose_poly")
|
||||
|
|
@ -256,7 +254,7 @@ class contact(hierarchy_design.hierarchy_design):
|
|||
|
||||
# Optionally implant well if layer exists
|
||||
well_layer = "{}well".format(self.well_type)
|
||||
if well_layer in tech.layer:
|
||||
if well_layer in tech_layers:
|
||||
well_width_rule = drc("minwidth_" + well_layer)
|
||||
self.well_enclose_active = drc(well_layer + "_enclose_active")
|
||||
self.well_width = max(self.first_layer_width + 2 * self.well_enclose_active,
|
||||
|
|
@ -275,33 +273,3 @@ class contact(hierarchy_design.hierarchy_design):
|
|||
return self.return_power()
|
||||
|
||||
|
||||
# Set up a static for each layer to be used for measurements
|
||||
for layer_stack in tech.layer_stacks:
|
||||
(layer1, via, layer2) = layer_stack
|
||||
cont = factory.create(module_type="contact",
|
||||
layer_stack=layer_stack)
|
||||
module = sys.modules[__name__]
|
||||
# Also create a contact that is just the first layer
|
||||
if layer1 == "poly" or layer1 == "active":
|
||||
setattr(module, layer1 + "_contact", cont)
|
||||
else:
|
||||
setattr(module, layer1 + "_via", cont)
|
||||
|
||||
# Set up a static for each well contact for measurements
|
||||
if "nwell" in tech.layer:
|
||||
cont = factory.create(module_type="contact",
|
||||
layer_stack=tech.active_stack,
|
||||
implant_type="n",
|
||||
well_type="n")
|
||||
module = sys.modules[__name__]
|
||||
setattr(module, "nwell_contact", cont)
|
||||
|
||||
if "pwell" in tech.layer:
|
||||
cont = factory.create(module_type="contact",
|
||||
layer_stack=tech.active_stack,
|
||||
implant_type="p",
|
||||
well_type="p")
|
||||
module = sys.modules[__name__]
|
||||
setattr(module, "pwell_contact", cont)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,15 +5,13 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
from hierarchy_design import hierarchy_design
|
||||
import utils
|
||||
import contact
|
||||
import debug
|
||||
from tech import GDS, layer
|
||||
from tech import preferred_directions
|
||||
from tech import cell_properties as props
|
||||
from globals import OPTS
|
||||
import re
|
||||
import debug
|
||||
from . import utils
|
||||
from .hierarchy_design import hierarchy_design
|
||||
|
||||
|
||||
class design(hierarchy_design):
|
||||
|
|
@ -82,201 +80,6 @@ class design(hierarchy_design):
|
|||
for pin in pins:
|
||||
print(pin_name, pin)
|
||||
|
||||
@classmethod
|
||||
def setup_drc_constants(design):
|
||||
"""
|
||||
These are some DRC constants used in many places
|
||||
in the compiler.
|
||||
"""
|
||||
# Make some local rules for convenience
|
||||
from tech import drc
|
||||
for rule in drc.keys():
|
||||
# Single layer width rules
|
||||
match = re.search(r"minwidth_(.*)", rule)
|
||||
if match:
|
||||
if match.group(1) == "active_contact":
|
||||
setattr(design, "contact_width", drc(match.group(0)))
|
||||
else:
|
||||
setattr(design, match.group(1) + "_width", drc(match.group(0)))
|
||||
|
||||
# Single layer area rules
|
||||
match = re.search(r"minarea_(.*)", rule)
|
||||
if match:
|
||||
setattr(design, match.group(0), drc(match.group(0)))
|
||||
|
||||
# Single layer spacing rules
|
||||
match = re.search(r"(.*)_to_(.*)", rule)
|
||||
if match and match.group(1) == match.group(2):
|
||||
setattr(design, match.group(1) + "_space", drc(match.group(0)))
|
||||
elif match and match.group(1) != match.group(2):
|
||||
if match.group(2) == "poly_active":
|
||||
setattr(design, match.group(1) + "_to_contact",
|
||||
drc(match.group(0)))
|
||||
else:
|
||||
setattr(design, match.group(0), drc(match.group(0)))
|
||||
|
||||
match = re.search(r"(.*)_enclose_(.*)", rule)
|
||||
if match:
|
||||
setattr(design, match.group(0), drc(match.group(0)))
|
||||
|
||||
match = re.search(r"(.*)_extend_(.*)", rule)
|
||||
if match:
|
||||
setattr(design, match.group(0), drc(match.group(0)))
|
||||
|
||||
# Create the maximum well extend active that gets used
|
||||
# by cells to extend the wells for interaction with other cells
|
||||
from tech import layer
|
||||
design.well_extend_active = 0
|
||||
if "nwell" in layer:
|
||||
design.well_extend_active = max(design.well_extend_active, design.nwell_extend_active)
|
||||
if "pwell" in layer:
|
||||
design.well_extend_active = max(design.well_extend_active, design.pwell_extend_active)
|
||||
|
||||
# The active offset is due to the well extension
|
||||
if "pwell" in layer:
|
||||
design.pwell_enclose_active = drc("pwell_enclose_active")
|
||||
else:
|
||||
design.pwell_enclose_active = 0
|
||||
if "nwell" in layer:
|
||||
design.nwell_enclose_active = drc("nwell_enclose_active")
|
||||
else:
|
||||
design.nwell_enclose_active = 0
|
||||
# Use the max of either so that the poly gates will align properly
|
||||
design.well_enclose_active = max(design.pwell_enclose_active,
|
||||
design.nwell_enclose_active,
|
||||
design.active_space)
|
||||
|
||||
# These are for debugging previous manual rules
|
||||
if False:
|
||||
print("poly_width", design.poly_width)
|
||||
print("poly_space", design.poly_space)
|
||||
print("m1_width", design.m1_width)
|
||||
print("m1_space", design.m1_space)
|
||||
print("m2_width", design.m2_width)
|
||||
print("m2_space", design.m2_space)
|
||||
print("m3_width", design.m3_width)
|
||||
print("m3_space", design.m3_space)
|
||||
print("m4_width", design.m4_width)
|
||||
print("m4_space", design.m4_space)
|
||||
print("active_width", design.active_width)
|
||||
print("active_space", design.active_space)
|
||||
print("contact_width", design.contact_width)
|
||||
print("poly_to_active", design.poly_to_active)
|
||||
print("poly_extend_active", design.poly_extend_active)
|
||||
print("poly_to_contact", design.poly_to_contact)
|
||||
print("active_contact_to_gate", design.active_contact_to_gate)
|
||||
print("poly_contact_to_gate", design.poly_contact_to_gate)
|
||||
print("well_enclose_active", design.well_enclose_active)
|
||||
print("implant_enclose_active", design.implant_enclose_active)
|
||||
print("implant_space", design.implant_space)
|
||||
import sys
|
||||
sys.exit(1)
|
||||
|
||||
@classmethod
|
||||
def setup_layer_constants(design):
|
||||
"""
|
||||
These are some layer constants used
|
||||
in many places in the compiler.
|
||||
"""
|
||||
|
||||
from tech import layer_indices
|
||||
import tech
|
||||
for layer_id in layer_indices:
|
||||
key = "{}_stack".format(layer_id)
|
||||
|
||||
# Set the stack as a local helper
|
||||
try:
|
||||
layer_stack = getattr(tech, key)
|
||||
setattr(design, key, layer_stack)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
# Skip computing the pitch for non-routing layers
|
||||
if layer_id in ["active", "nwell"]:
|
||||
continue
|
||||
|
||||
# Add the pitch
|
||||
setattr(design,
|
||||
"{}_pitch".format(layer_id),
|
||||
design.compute_pitch(layer_id, True))
|
||||
|
||||
# Add the non-preferrd pitch (which has vias in the "wrong" way)
|
||||
setattr(design,
|
||||
"{}_nonpref_pitch".format(layer_id),
|
||||
design.compute_pitch(layer_id, False))
|
||||
|
||||
if False:
|
||||
from tech import preferred_directions
|
||||
print(preferred_directions)
|
||||
from tech import layer_indices
|
||||
for name in layer_indices:
|
||||
if name == "active":
|
||||
continue
|
||||
try:
|
||||
print("{0} width {1} space {2}".format(name,
|
||||
getattr(design, "{}_width".format(name)),
|
||||
getattr(design, "{}_space".format(name))))
|
||||
|
||||
print("pitch {0} nonpref {1}".format(getattr(design, "{}_pitch".format(name)),
|
||||
getattr(design, "{}_nonpref_pitch".format(name))))
|
||||
except AttributeError:
|
||||
pass
|
||||
import sys
|
||||
sys.exit(1)
|
||||
|
||||
@staticmethod
|
||||
def compute_pitch(layer, preferred=True):
|
||||
|
||||
"""
|
||||
This is the preferred direction pitch
|
||||
i.e. we take the minimum or maximum contact dimension
|
||||
"""
|
||||
# Find the layer stacks this is used in
|
||||
from tech import layer_stacks
|
||||
pitches = []
|
||||
for stack in layer_stacks:
|
||||
# Compute the pitch with both vias above and below (if they exist)
|
||||
if stack[0] == layer:
|
||||
pitches.append(design.compute_layer_pitch(stack, preferred))
|
||||
if stack[2] == layer:
|
||||
pitches.append(design.compute_layer_pitch(stack[::-1], True))
|
||||
|
||||
return max(pitches)
|
||||
|
||||
@staticmethod
|
||||
def get_preferred_direction(layer):
|
||||
return preferred_directions[layer]
|
||||
|
||||
@staticmethod
|
||||
def compute_layer_pitch(layer_stack, preferred):
|
||||
|
||||
(layer1, via, layer2) = layer_stack
|
||||
try:
|
||||
if layer1 == "poly" or layer1 == "active":
|
||||
contact1 = getattr(contact, layer1 + "_contact")
|
||||
else:
|
||||
contact1 = getattr(contact, layer1 + "_via")
|
||||
except AttributeError:
|
||||
contact1 = getattr(contact, layer2 + "_via")
|
||||
|
||||
if preferred:
|
||||
if preferred_directions[layer1] == "V":
|
||||
contact_width = contact1.first_layer_width
|
||||
else:
|
||||
contact_width = contact1.first_layer_height
|
||||
else:
|
||||
if preferred_directions[layer1] == "V":
|
||||
contact_width = contact1.first_layer_height
|
||||
else:
|
||||
contact_width = contact1.first_layer_width
|
||||
layer_space = getattr(design, layer1 + "_space")
|
||||
|
||||
#print(layer_stack)
|
||||
#print(contact1)
|
||||
pitch = contact_width + layer_space
|
||||
|
||||
return utils.round_to_grid(pitch)
|
||||
|
||||
def setup_multiport_constants(self):
|
||||
"""
|
||||
These are contants and lists that aid multiport design.
|
||||
|
|
@ -324,6 +127,4 @@ class design(hierarchy_design):
|
|||
total_module_power += inst.mod.analytical_power(corner, load)
|
||||
return total_module_power
|
||||
|
||||
design.setup_drc_constants()
|
||||
design.setup_layer_constants()
|
||||
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@
|
|||
This provides a set of useful generic types for the gdsMill interface.
|
||||
"""
|
||||
import debug
|
||||
from vector import vector
|
||||
from .vector import vector
|
||||
import tech
|
||||
import math
|
||||
import copy
|
||||
import numpy as np
|
||||
from globals import OPTS
|
||||
from utils import round_to_grid
|
||||
from .utils import round_to_grid
|
||||
|
||||
|
||||
class geometry:
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import hierarchy_layout
|
||||
import hierarchy_spice
|
||||
from .hierarchy_layout import layout
|
||||
from .hierarchy_spice import spice
|
||||
import debug
|
||||
import os
|
||||
from globals import OPTS
|
||||
|
||||
|
||||
class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||
class hierarchy_design(spice, layout):
|
||||
"""
|
||||
Design Class for all modules to inherit the base features.
|
||||
Class consisting of a set of modules and instances of these modules
|
||||
|
|
@ -32,8 +32,8 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
|||
name = OPTS.output_name + "_" + name
|
||||
cell_name = name
|
||||
|
||||
hierarchy_spice.spice.__init__(self, name, cell_name)
|
||||
hierarchy_layout.layout.__init__(self, name, cell_name)
|
||||
spice.__init__(self, name, cell_name)
|
||||
layout.__init__(self, name, cell_name)
|
||||
self.init_graph_params()
|
||||
|
||||
def get_layout_pins(self, inst):
|
||||
|
|
|
|||
|
|
@ -5,21 +5,26 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import geometry
|
||||
import gdsMill
|
||||
import debug
|
||||
from math import sqrt
|
||||
from tech import drc, GDS
|
||||
from tech import layer as techlayer
|
||||
from tech import layer_indices
|
||||
from tech import layer_stacks
|
||||
from tech import preferred_directions
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
from math import sqrt
|
||||
import debug
|
||||
from gdsMill import gdsMill
|
||||
import tech
|
||||
from tech import drc, GDS
|
||||
from tech import layer as tech_layer
|
||||
from tech import layer_indices as tech_layer_indices
|
||||
from tech import preferred_directions
|
||||
from tech import layer_stacks as tech_layer_stacks
|
||||
from tech import active_stack as tech_active_stack
|
||||
from sram_factory import factory
|
||||
from globals import OPTS
|
||||
from vector import vector
|
||||
from pin_layout import pin_layout
|
||||
from utils import round_to_grid
|
||||
from .vector import vector
|
||||
from .pin_layout import pin_layout
|
||||
from .utils import round_to_grid
|
||||
from . import geometry
|
||||
|
||||
try:
|
||||
from tech import special_purposes
|
||||
except ImportError:
|
||||
|
|
@ -64,11 +69,241 @@ class layout():
|
|||
|
||||
self.gds_read()
|
||||
|
||||
if "contact" not in self.name:
|
||||
if not hasattr(layout, "_drc_constants"):
|
||||
layout._drc_constants = True
|
||||
layout.setup_drc_constants()
|
||||
layout.setup_contacts()
|
||||
layout.setup_layer_constants()
|
||||
|
||||
|
||||
@classmethod
|
||||
def setup_drc_constants(layout):
|
||||
"""
|
||||
These are some DRC constants used in many places
|
||||
in the compiler.
|
||||
"""
|
||||
|
||||
# Make some local rules for convenience
|
||||
for rule in drc.keys():
|
||||
# Single layer width rules
|
||||
match = re.search(r"minwidth_(.*)", rule)
|
||||
if match:
|
||||
if match.group(1) == "active_contact":
|
||||
setattr(layout, "contact_width", drc(match.group(0)))
|
||||
else:
|
||||
setattr(layout, match.group(1) + "_width", drc(match.group(0)))
|
||||
|
||||
# Single layer area rules
|
||||
match = re.search(r"minarea_(.*)", rule)
|
||||
if match:
|
||||
setattr(layout, match.group(0), drc(match.group(0)))
|
||||
|
||||
# Single layer spacing rules
|
||||
match = re.search(r"(.*)_to_(.*)", rule)
|
||||
if match and match.group(1) == match.group(2):
|
||||
setattr(layout, match.group(1) + "_space", drc(match.group(0)))
|
||||
elif match and match.group(1) != match.group(2):
|
||||
if match.group(2) == "poly_active":
|
||||
setattr(layout, match.group(1) + "_to_contact",
|
||||
drc(match.group(0)))
|
||||
else:
|
||||
setattr(layout, match.group(0), drc(match.group(0)))
|
||||
|
||||
match = re.search(r"(.*)_enclose_(.*)", rule)
|
||||
if match:
|
||||
setattr(layout, match.group(0), drc(match.group(0)))
|
||||
|
||||
match = re.search(r"(.*)_extend_(.*)", rule)
|
||||
if match:
|
||||
setattr(layout, match.group(0), drc(match.group(0)))
|
||||
|
||||
# Create the maximum well extend active that gets used
|
||||
# by cells to extend the wells for interaction with other cells
|
||||
layout.well_extend_active = 0
|
||||
if "nwell" in tech_layer:
|
||||
layout.well_extend_active = max(layout.well_extend_active, layout.nwell_extend_active)
|
||||
if "pwell" in tech_layer:
|
||||
layout.well_extend_active = max(layout.well_extend_active, layout.pwell_extend_active)
|
||||
|
||||
# The active offset is due to the well extension
|
||||
if "pwell" in tech_layer:
|
||||
layout.pwell_enclose_active = drc("pwell_enclose_active")
|
||||
else:
|
||||
layout.pwell_enclose_active = 0
|
||||
if "nwell" in tech_layer:
|
||||
layout.nwell_enclose_active = drc("nwell_enclose_active")
|
||||
else:
|
||||
layout.nwell_enclose_active = 0
|
||||
# Use the max of either so that the poly gates will align properly
|
||||
layout.well_enclose_active = max(layout.pwell_enclose_active,
|
||||
layout.nwell_enclose_active,
|
||||
layout.active_space)
|
||||
|
||||
# These are for debugging previous manual rules
|
||||
if False:
|
||||
print("poly_width", layout.poly_width)
|
||||
print("poly_space", layout.poly_space)
|
||||
print("m1_width", layout.m1_width)
|
||||
print("m1_space", layout.m1_space)
|
||||
print("m2_width", layout.m2_width)
|
||||
print("m2_space", layout.m2_space)
|
||||
print("m3_width", layout.m3_width)
|
||||
print("m3_space", layout.m3_space)
|
||||
print("m4_width", layout.m4_width)
|
||||
print("m4_space", layout.m4_space)
|
||||
print("active_width", layout.active_width)
|
||||
print("active_space", layout.active_space)
|
||||
print("contact_width", layout.contact_width)
|
||||
print("poly_to_active", layout.poly_to_active)
|
||||
print("poly_extend_active", layout.poly_extend_active)
|
||||
print("poly_to_contact", layout.poly_to_contact)
|
||||
print("active_contact_to_gate", layout.active_contact_to_gate)
|
||||
print("poly_contact_to_gate", layout.poly_contact_to_gate)
|
||||
print("well_enclose_active", layout.well_enclose_active)
|
||||
print("implant_enclose_active", layout.implant_enclose_active)
|
||||
print("implant_space", layout.implant_space)
|
||||
import sys
|
||||
sys.exit(1)
|
||||
|
||||
@classmethod
|
||||
def setup_layer_constants(layout):
|
||||
"""
|
||||
These are some layer constants used
|
||||
in many places in the compiler.
|
||||
"""
|
||||
try:
|
||||
from tech import power_grid
|
||||
self.pwr_grid_layers = [power_grid[0], power_grid[2]]
|
||||
layout.pwr_grid_layers = [power_grid[0], power_grid[2]]
|
||||
except ImportError:
|
||||
self.pwr_grid_layers = ["m3", "m4"]
|
||||
layout.pwr_grid_layers = ["m3", "m4"]
|
||||
|
||||
for layer_id in tech_layer_indices:
|
||||
key = "{}_stack".format(layer_id)
|
||||
|
||||
# Set the stack as a local helper
|
||||
try:
|
||||
layer_stack = getattr(tech, key)
|
||||
setattr(layout, key, layer_stack)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
# Skip computing the pitch for non-routing layers
|
||||
if layer_id in ["active", "nwell"]:
|
||||
continue
|
||||
|
||||
# Add the pitch
|
||||
setattr(layout,
|
||||
"{}_pitch".format(layer_id),
|
||||
layout.compute_pitch(layer_id, True))
|
||||
|
||||
# Add the non-preferrd pitch (which has vias in the "wrong" way)
|
||||
setattr(layout,
|
||||
"{}_nonpref_pitch".format(layer_id),
|
||||
layout.compute_pitch(layer_id, False))
|
||||
|
||||
if False:
|
||||
for name in tech_layer_indices:
|
||||
if name == "active":
|
||||
continue
|
||||
try:
|
||||
print("{0} width {1} space {2}".format(name,
|
||||
getattr(layout, "{}_width".format(name)),
|
||||
getattr(layout, "{}_space".format(name))))
|
||||
|
||||
print("pitch {0} nonpref {1}".format(getattr(layout, "{}_pitch".format(name)),
|
||||
getattr(layout, "{}_nonpref_pitch".format(name))))
|
||||
except AttributeError:
|
||||
pass
|
||||
import sys
|
||||
sys.exit(1)
|
||||
|
||||
@staticmethod
|
||||
def compute_pitch(layer, preferred=True):
|
||||
"""
|
||||
This is the preferred direction pitch
|
||||
i.e. we take the minimum or maximum contact dimension
|
||||
"""
|
||||
# Find the layer stacks this is used in
|
||||
pitches = []
|
||||
for stack in tech_layer_stacks:
|
||||
# Compute the pitch with both vias above and below (if they exist)
|
||||
if stack[0] == layer:
|
||||
pitches.append(layout.compute_layer_pitch(stack, preferred))
|
||||
if stack[2] == layer:
|
||||
pitches.append(layout.compute_layer_pitch(stack[::-1], True))
|
||||
|
||||
return max(pitches)
|
||||
|
||||
@staticmethod
|
||||
def get_preferred_direction(layer):
|
||||
return preferred_directions[layer]
|
||||
|
||||
@staticmethod
|
||||
def compute_layer_pitch(layer_stack, preferred):
|
||||
|
||||
(layer1, via, layer2) = layer_stack
|
||||
try:
|
||||
if layer1 == "poly" or layer1 == "active":
|
||||
contact1 = getattr(layout, layer1 + "_contact")
|
||||
else:
|
||||
contact1 = getattr(layout, layer1 + "_via")
|
||||
except AttributeError:
|
||||
contact1 = getattr(layout, layer2 + "_via")
|
||||
|
||||
if preferred:
|
||||
if preferred_directions[layer1] == "V":
|
||||
contact_width = contact1.first_layer_width
|
||||
else:
|
||||
contact_width = contact1.first_layer_height
|
||||
else:
|
||||
if preferred_directions[layer1] == "V":
|
||||
contact_width = contact1.first_layer_height
|
||||
else:
|
||||
contact_width = contact1.first_layer_width
|
||||
layer_space = getattr(layout, layer1 + "_space")
|
||||
|
||||
#print(layer_stack)
|
||||
#print(contact1)
|
||||
pitch = contact_width + layer_space
|
||||
|
||||
return round_to_grid(pitch)
|
||||
|
||||
|
||||
@classmethod
|
||||
def setup_contacts(layout):
|
||||
# Set up a static for each layer to be used for measurements
|
||||
# unless we are a contact class!
|
||||
|
||||
for layer_stack in tech_layer_stacks:
|
||||
(layer1, via, layer2) = layer_stack
|
||||
cont = factory.create(module_type="contact",
|
||||
layer_stack=layer_stack)
|
||||
module = sys.modules[__name__]
|
||||
# Also create a contact that is just the first layer
|
||||
if layer1 == "poly" or layer1 == "active":
|
||||
setattr(layout, layer1 + "_contact", cont)
|
||||
else:
|
||||
setattr(layout, layer1 + "_via", cont)
|
||||
|
||||
# Set up a static for each well contact for measurements
|
||||
if "nwell" in tech_layer:
|
||||
cont = factory.create(module_type="contact",
|
||||
layer_stack=tech_active_stack,
|
||||
implant_type="n",
|
||||
well_type="n")
|
||||
module = sys.modules[__name__]
|
||||
setattr(layout, "nwell_contact", cont)
|
||||
|
||||
if "pwell" in tech_layer:
|
||||
cont = factory.create(module_type="contact",
|
||||
layer_stack=tech_active_stack,
|
||||
implant_type="p",
|
||||
well_type="p")
|
||||
module = sys.modules[__name__]
|
||||
setattr(layout, "pwell_contact", cont)
|
||||
|
||||
|
||||
|
||||
############################################################
|
||||
# GDS layout
|
||||
|
|
@ -171,7 +406,7 @@ class layout():
|
|||
this layout on a layer
|
||||
"""
|
||||
# Only consider the layer not the purpose for now
|
||||
layerNumber = techlayer[layer][0]
|
||||
layerNumber = tech_layer[layer][0]
|
||||
try:
|
||||
highestx = max(obj.rx() for obj in self.objs if obj.layerNumber == layerNumber)
|
||||
except ValueError:
|
||||
|
|
@ -195,7 +430,7 @@ class layout():
|
|||
this layout on a layer
|
||||
"""
|
||||
# Only consider the layer not the purpose for now
|
||||
layerNumber = techlayer[layer][0]
|
||||
layerNumber = tech_layer[layer][0]
|
||||
try:
|
||||
lowestx = min(obj.lx() for obj in self.objs if obj.layerNumber == layerNumber)
|
||||
except ValueError:
|
||||
|
|
@ -273,7 +508,7 @@ class layout():
|
|||
width = drc["minwidth_{}".format(layer)]
|
||||
if not height:
|
||||
height = drc["minwidth_{}".format(layer)]
|
||||
lpp = techlayer[layer]
|
||||
lpp = tech_layer[layer]
|
||||
self.objs.append(geometry.rectangle(lpp,
|
||||
offset,
|
||||
width,
|
||||
|
|
@ -289,7 +524,7 @@ class layout():
|
|||
width = drc["minwidth_{}".format(layer)]
|
||||
if not height:
|
||||
height = drc["minwidth_{}".format(layer)]
|
||||
lpp = techlayer[layer]
|
||||
lpp = tech_layer[layer]
|
||||
corrected_offset = offset - vector(0.5 * width, 0.5 * height)
|
||||
self.objs.append(geometry.rectangle(lpp,
|
||||
corrected_offset,
|
||||
|
|
@ -599,10 +834,10 @@ class layout():
|
|||
|
||||
def get_metal_layers(self, from_layer, to_layer):
|
||||
|
||||
from_id = layer_indices[from_layer]
|
||||
to_id = layer_indices[to_layer]
|
||||
from_id = tech_layer_indices[from_layer]
|
||||
to_id = tech_layer_indices[to_layer]
|
||||
|
||||
layer_list = [x for x in layer_indices.keys() if layer_indices[x] >= from_id and layer_indices[x] < to_id]
|
||||
layer_list = [x for x in tech_layer_indices.keys() if tech_layer_indices[x] >= from_id and tech_layer_indices[x] < to_id]
|
||||
|
||||
return layer_list
|
||||
|
||||
|
|
@ -938,22 +1173,22 @@ class layout():
|
|||
def add_label(self, text, layer, offset=[0, 0], zoom=None):
|
||||
"""Adds a text label on the given layer,offset, and zoom level"""
|
||||
debug.info(5, "add label " + str(text) + " " + layer + " " + str(offset))
|
||||
lpp = techlayer[layer]
|
||||
lpp = tech_layer[layer]
|
||||
self.objs.append(geometry.label(text, lpp, offset, zoom))
|
||||
return self.objs[-1]
|
||||
|
||||
def add_path(self, layer, coordinates, width=None):
|
||||
"""Connects a routing path on given layer,coordinates,width."""
|
||||
debug.info(4, "add path " + str(layer) + " " + str(coordinates))
|
||||
import wire_path
|
||||
from . import wire_path
|
||||
# NOTE: (UNTESTED) add_path(...) is currently not used
|
||||
# lpp = techlayer[layer]
|
||||
# lpp = tech_layer[layer]
|
||||
# self.objs.append(geometry.path(lpp, coordinates, width))
|
||||
|
||||
wire_path.wire_path(obj=self,
|
||||
layer=layer,
|
||||
position_list=coordinates,
|
||||
width=width)
|
||||
wire_path(obj=self,
|
||||
layer=layer,
|
||||
position_list=coordinates,
|
||||
width=width)
|
||||
|
||||
def add_route(self, layers, coordinates, layer_widths):
|
||||
"""Connects a routing path on given layer,coordinates,width. The
|
||||
|
|
@ -961,13 +1196,13 @@ class layout():
|
|||
preferred direction routing whereas this includes layers in
|
||||
the coordinates.
|
||||
"""
|
||||
import route
|
||||
from . import route
|
||||
debug.info(4, "add route " + str(layers) + " " + str(coordinates))
|
||||
# add an instance of our path that breaks down into rectangles and contacts
|
||||
route.route(obj=self,
|
||||
layer_stack=layers,
|
||||
path=coordinates,
|
||||
layer_widths=layer_widths)
|
||||
route(obj=self,
|
||||
layer_stack=layers,
|
||||
path=coordinates,
|
||||
layer_widths=layer_widths)
|
||||
|
||||
def add_zjog(self, layer, start, end, first_direction="H", var_offset=0.5, fixed_offset=None):
|
||||
"""
|
||||
|
|
@ -994,9 +1229,9 @@ class layout():
|
|||
else:
|
||||
debug.error("Invalid direction for jog -- must be H or V.")
|
||||
|
||||
if layer in layer_stacks:
|
||||
if layer in tech_layer_stacks:
|
||||
self.add_wire(layer, [start, mid1, mid2, end])
|
||||
elif layer in techlayer:
|
||||
elif layer in tech_layer:
|
||||
self.add_path(layer, [start, mid1, mid2, end])
|
||||
else:
|
||||
debug.error("Could not find layer {}".format(layer))
|
||||
|
|
@ -1012,13 +1247,13 @@ class layout():
|
|||
def add_wire(self, layers, coordinates, widen_short_wires=True):
|
||||
"""Connects a routing path on given layer,coordinates,width.
|
||||
The layers are the (horizontal, via, vertical). """
|
||||
import wire
|
||||
from . import wire
|
||||
# add an instance of our path that breaks down
|
||||
# into rectangles and contacts
|
||||
wire.wire(obj=self,
|
||||
layer_stack=layers,
|
||||
position_list=coordinates,
|
||||
widen_short_wires=widen_short_wires)
|
||||
wire(obj=self,
|
||||
layer_stack=layers,
|
||||
position_list=coordinates,
|
||||
widen_short_wires=widen_short_wires)
|
||||
|
||||
def add_via(self, layers, offset, size=[1, 1], directions=None, implant_type=None, well_type=None):
|
||||
""" Add a three layer via structure. """
|
||||
|
|
@ -1086,8 +1321,8 @@ class layout():
|
|||
via = None
|
||||
cur_layer = from_layer
|
||||
while cur_layer != to_layer:
|
||||
from_id = layer_indices[cur_layer]
|
||||
to_id = layer_indices[to_layer]
|
||||
from_id = tech_layer_indices[cur_layer]
|
||||
to_id = tech_layer_indices[to_layer]
|
||||
|
||||
if from_id < to_id: # grow the stack up
|
||||
search_id = 0
|
||||
|
|
@ -1096,7 +1331,7 @@ class layout():
|
|||
search_id = 2
|
||||
next_id = 0
|
||||
|
||||
curr_stack = next(filter(lambda stack: stack[search_id] == cur_layer, layer_stacks), None)
|
||||
curr_stack = next(filter(lambda stack: stack[search_id] == cur_layer, tech_layer_stacks), None)
|
||||
|
||||
via = self.add_via_center(layers=curr_stack,
|
||||
size=size,
|
||||
|
|
@ -1209,9 +1444,9 @@ class layout():
|
|||
if not self.is_library_cell and not self.bounding_box:
|
||||
# If there is a boundary layer, and we didn't create one, add one.
|
||||
boundary_layers = []
|
||||
if "boundary" in techlayer.keys():
|
||||
if "boundary" in tech_layer.keys():
|
||||
boundary_layers.append("boundary")
|
||||
if "stdc" in techlayer.keys():
|
||||
if "stdc" in tech_layer.keys():
|
||||
boundary_layers.append("stdc")
|
||||
boundary = [self.find_lowest_coords(),
|
||||
self.find_highest_coords()]
|
||||
|
|
@ -1221,7 +1456,7 @@ class layout():
|
|||
width = boundary[1][0] - boundary[0][0]
|
||||
|
||||
for boundary_layer in boundary_layers:
|
||||
(layer_number, layer_purpose) = techlayer[boundary_layer]
|
||||
(layer_number, layer_purpose) = tech_layer[boundary_layer]
|
||||
gds_layout.addBox(layerNumber=layer_number,
|
||||
purposeNumber=layer_purpose,
|
||||
offsetInMicrons=boundary[0],
|
||||
|
|
@ -1270,7 +1505,7 @@ class layout():
|
|||
Do not write the pins since they aren't obstructions.
|
||||
"""
|
||||
if type(layer) == str:
|
||||
lpp = techlayer[layer]
|
||||
lpp = tech_layer[layer]
|
||||
else:
|
||||
lpp = layer
|
||||
|
||||
|
|
@ -1514,8 +1749,8 @@ class layout():
|
|||
"""
|
||||
Wrapper to create a vertical channel route
|
||||
"""
|
||||
import channel_route
|
||||
cr = channel_route.channel_route(netlist, offset, layer_stack, directions, vertical=True, parent=self)
|
||||
from .channel_route import channel_route
|
||||
cr = channel_route(netlist, offset, layer_stack, directions, vertical=True, parent=self)
|
||||
# This causes problem in magic since it sometimes cannot extract connectivity of isntances
|
||||
# with no active devices.
|
||||
# self.add_inst(cr.name, cr)
|
||||
|
|
@ -1526,8 +1761,8 @@ class layout():
|
|||
"""
|
||||
Wrapper to create a horizontal channel route
|
||||
"""
|
||||
import channel_route
|
||||
cr = channel_route.channel_route(netlist, offset, layer_stack, directions, vertical=False, parent=self)
|
||||
from .channel_route import channel_route
|
||||
cr = channel_route(netlist, offset, layer_stack, directions, vertical=False, parent=self)
|
||||
# This causes problem in magic since it sometimes cannot extract connectivity of isntances
|
||||
# with no active devices.
|
||||
# self.add_inst(cr.name, cr)
|
||||
|
|
@ -1540,9 +1775,9 @@ class layout():
|
|||
return
|
||||
|
||||
boundary_layers = []
|
||||
if "stdc" in techlayer.keys():
|
||||
if "stdc" in tech_layer.keys():
|
||||
boundary_layers.append("stdc")
|
||||
if "boundary" in techlayer.keys():
|
||||
if "boundary" in tech_layer.keys():
|
||||
boundary_layers.append("boundary")
|
||||
# Save the last one as self.bounding_box
|
||||
for boundary_layer in boundary_layers:
|
||||
|
|
@ -1791,7 +2026,7 @@ class layout():
|
|||
def add_dnwell(self, bbox=None, inflate=1):
|
||||
""" Create a dnwell, along with nwell moat at border. """
|
||||
|
||||
if "dnwell" not in techlayer:
|
||||
if "dnwell" not in tech_layer:
|
||||
return
|
||||
|
||||
if not bbox:
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@ import math
|
|||
import tech
|
||||
from globals import OPTS
|
||||
from pprint import pformat
|
||||
from delay_data import delay_data
|
||||
from wire_spice_model import wire_spice_model
|
||||
from power_data import power_data
|
||||
import logical_effort
|
||||
from .delay_data import delay_data
|
||||
from .wire_spice_model import wire_spice_model
|
||||
from .power_data import power_data
|
||||
from .logical_effort import convert_relative_c_to_farad, convert_farad_to_relative_c
|
||||
|
||||
|
||||
class spice():
|
||||
|
|
@ -443,7 +443,7 @@ class spice():
|
|||
|
||||
# FIXME: Slew is not used in the model right now.
|
||||
# Can be added heuristically as linear factor
|
||||
relative_cap = logical_effort.convert_farad_to_relative_c(load)
|
||||
relative_cap = convert_farad_to_relative_c(load)
|
||||
stage_effort = self.get_stage_effort(relative_cap)
|
||||
|
||||
# If it fails, then keep running with a valid object.
|
||||
|
|
@ -511,7 +511,7 @@ class spice():
|
|||
# Override this function within a module if a more accurate input capacitance is needed.
|
||||
# Input/outputs with differing capacitances is not implemented.
|
||||
relative_cap = self.input_load()
|
||||
return logical_effort.convert_relative_c_to_farad(relative_cap)
|
||||
return convert_relative_c_to_farad(relative_cap)
|
||||
|
||||
def input_load(self):
|
||||
"""Inform users undefined relative capacitance functions used for analytical delays."""
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
from base import vector
|
||||
from base import pin_layout
|
||||
from tech import layer_names
|
||||
import os
|
||||
import shutil
|
||||
from globals import OPTS
|
||||
from vector import vector
|
||||
from pin_layout import pin_layout
|
||||
|
||||
|
||||
class lef:
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
from tech import drc, parameter, spice
|
||||
from tech import parameter
|
||||
|
||||
class logical_effort():
|
||||
"""
|
||||
|
|
@ -81,4 +81,4 @@ def convert_farad_to_relative_c(c_farad):
|
|||
|
||||
def convert_relative_c_to_farad(c_relative):
|
||||
"""Converts capacitance in logical effort relative units to Femto-Farads."""
|
||||
return c_relative/parameter['cap_relative_per_ff']
|
||||
return c_relative/parameter['cap_relative_per_ff']
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
#
|
||||
import debug
|
||||
from tech import GDS, drc
|
||||
from vector import vector
|
||||
from .vector import vector
|
||||
from tech import layer, layer_indices
|
||||
import math
|
||||
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
from tech import drc
|
||||
import debug
|
||||
from design import design
|
||||
from .design import design
|
||||
from .vector import vector
|
||||
from .vector3d import vector3d
|
||||
from tech import drc
|
||||
from itertools import tee
|
||||
from vector import vector
|
||||
from vector3d import vector3d
|
||||
from sram_factory import factory
|
||||
|
||||
class route(design):
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@
|
|||
import os
|
||||
import math
|
||||
|
||||
import gdsMill
|
||||
from gdsMill import gdsMill
|
||||
import tech
|
||||
import globals
|
||||
import debug
|
||||
from vector import vector
|
||||
from pin_layout import pin_layout
|
||||
from .vector import vector
|
||||
from .pin_layout import pin_layout
|
||||
try:
|
||||
from tech import special_purposes
|
||||
except ImportError:
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
from tech import drc
|
||||
import contact
|
||||
from wire_path import wire_path
|
||||
from .wire_path import wire_path
|
||||
from sram_factory import factory
|
||||
|
||||
|
||||
|
|
@ -69,15 +68,24 @@ class wire(wire_path):
|
|||
This is contact direction independent pitch,
|
||||
i.e. we take the maximum contact dimension
|
||||
"""
|
||||
|
||||
# This is here for the unit tests which may not have
|
||||
# initialized the static parts of the layout class yet.
|
||||
from base import layout
|
||||
layout("fake", "fake")
|
||||
|
||||
(layer1, via, layer2) = layer_stack
|
||||
|
||||
if layer1 == "poly" or layer1 == "active":
|
||||
contact1 = getattr(contact, layer1 + "_contact")
|
||||
try:
|
||||
contact1 = getattr(layout, layer1 + "_contact")
|
||||
except AttributeError:
|
||||
breakpoint()
|
||||
else:
|
||||
try:
|
||||
contact1 = getattr(contact, layer1 + "_via")
|
||||
contact1 = getattr(layout, layer1 + "_via")
|
||||
except AttributeError:
|
||||
contact1 = getattr(contact, layer2 + "_via")
|
||||
contact1 = getattr(layout, layer2 + "_via")
|
||||
max_contact = max(contact1.width, contact1.height)
|
||||
|
||||
layer1_space = drc("{0}_to_{0}".format(layer1))
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
from .vector import vector
|
||||
from .utils import snap_to_grid
|
||||
from .design import design
|
||||
from tech import drc
|
||||
from tech import layer as techlayer
|
||||
import debug
|
||||
from vector import vector
|
||||
from utils import snap_to_grid
|
||||
|
||||
def create_rectilinear_route(my_list):
|
||||
""" Add intermediate nodes if it isn't rectilinear. Also skip
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import math
|
|||
import tech
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
import timing_graph
|
||||
from base import timing_graph
|
||||
|
||||
|
||||
class simulation():
|
||||
|
|
@ -572,7 +572,7 @@ class simulation():
|
|||
self.sram.graph_exclude_column_mux(self.bitline_column, port)
|
||||
|
||||
# Generate new graph every analysis as edges might change depending on test bit
|
||||
self.graph = timing_graph.timing_graph()
|
||||
self.graph = timing_graph()
|
||||
self.sram_instance_name = "X{}".format(self.sram.name)
|
||||
self.sram.build_graph(self.graph, self.sram_instance_name, self.pins)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
from .datasheet_gen import datasheet_gen
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
from table_gen import *
|
||||
from .table_gen import *
|
||||
import os
|
||||
import base64
|
||||
from globals import OPTS
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ from globals import OPTS
|
|||
import os
|
||||
import math
|
||||
import csv
|
||||
import datasheet
|
||||
import table_gen
|
||||
from .datasheet import datasheet
|
||||
from .table_gen import table_gen
|
||||
|
||||
# def process_name(corner):
|
||||
# """
|
||||
|
|
@ -400,7 +400,7 @@ def parse_characterizer_csv(f, pages):
|
|||
if found == 0:
|
||||
|
||||
# if this is the first corner for this sram, run first time configuration and set up tables
|
||||
new_sheet = datasheet.datasheet(NAME)
|
||||
new_sheet = datasheet(NAME)
|
||||
pages.append(new_sheet)
|
||||
|
||||
new_sheet.git_id = ORIGIN_ID
|
||||
|
|
@ -411,12 +411,12 @@ def parse_characterizer_csv(f, pages):
|
|||
new_sheet.description = [NAME, NUM_WORDS, NUM_BANKS, NUM_RW_PORTS, NUM_W_PORTS,
|
||||
NUM_R_PORTS, TECH_NAME, MIN_PERIOD, WORD_SIZE, ORIGIN_ID, DATETIME]
|
||||
|
||||
new_sheet.corners_table = table_gen.table_gen("corners")
|
||||
new_sheet.corners_table = table_gen("corners")
|
||||
new_sheet.corners_table.add_row(
|
||||
['Transistor Type', 'Power Supply', 'Temperature', 'Corner Name'])
|
||||
new_sheet.corners_table.add_row(
|
||||
[PROC, VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')])
|
||||
new_sheet.operating_table = table_gen.table_gen(
|
||||
new_sheet.operating_table = table_gen(
|
||||
"operating_table")
|
||||
new_sheet.operating_table.add_row(
|
||||
['Parameter', 'Min', 'Typ', 'Max', 'Units'])
|
||||
|
|
@ -432,10 +432,10 @@ def parse_characterizer_csv(f, pages):
|
|||
# failed to provide non-zero MIN_PERIOD
|
||||
new_sheet.operating_table.add_row(
|
||||
['Operating Frequency (F)', '', '', "not available in netlist only", 'MHz'])
|
||||
new_sheet.power_table = table_gen.table_gen("power")
|
||||
new_sheet.power_table = table_gen("power")
|
||||
new_sheet.power_table.add_row(
|
||||
['Pins', 'Mode', 'Power', 'Units'])
|
||||
new_sheet.timing_table = table_gen.table_gen("timing")
|
||||
new_sheet.timing_table = table_gen("timing")
|
||||
new_sheet.timing_table.add_row(
|
||||
['Parameter', 'Min', 'Max', 'Units'])
|
||||
# parse initial timing information
|
||||
|
|
@ -592,10 +592,10 @@ def parse_characterizer_csv(f, pages):
|
|||
else:
|
||||
break
|
||||
|
||||
new_sheet.dlv_table = table_gen.table_gen("dlv")
|
||||
new_sheet.dlv_table = table_gen("dlv")
|
||||
new_sheet.dlv_table.add_row(['Type', 'Description', 'Link'])
|
||||
|
||||
new_sheet.io_table = table_gen.table_gen("io")
|
||||
new_sheet.io_table = table_gen("io")
|
||||
new_sheet.io_table.add_row(['Type', 'Value'])
|
||||
|
||||
if not OPTS.netlist_only:
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
|
||||
class table_gen:
|
||||
"""small library of functions to generate the html tables"""
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
from .custom_cell_properties import *
|
||||
from .custom_layer_properties import *
|
||||
from .design_rules import *
|
||||
from .module_type import *
|
||||
from .drc_lut import *
|
||||
from .drc_value import *
|
||||
|
|
@ -6,8 +6,8 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
from drc_value import *
|
||||
from drc_lut import *
|
||||
from .drc_value import *
|
||||
from .drc_lut import *
|
||||
|
||||
|
||||
class design_rules(dict):
|
||||
|
|
|
|||
|
|
@ -252,7 +252,8 @@ def setup_bitcell():
|
|||
|
||||
# See if bitcell exists
|
||||
try:
|
||||
__import__(OPTS.bitcell)
|
||||
c = importlib.import_module("modules." + OPTS.bitcell)
|
||||
mod = getattr(c, OPTS.bitcell)
|
||||
except ImportError:
|
||||
# Use the pbitcell if we couldn't find a custom bitcell
|
||||
# or its custom replica bitcell
|
||||
|
|
@ -430,19 +431,12 @@ def setup_paths():
|
|||
OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME"))
|
||||
except:
|
||||
debug.error("$OPENRAM_HOME is not properly defined.", 1)
|
||||
|
||||
debug.check(os.path.isdir(OPENRAM_HOME),
|
||||
"$OPENRAM_HOME does not exist: {0}".format(OPENRAM_HOME))
|
||||
|
||||
# Add all of the subdirs to the python path
|
||||
# These subdirs are modules and don't need
|
||||
# to be added: characterizer, verify
|
||||
subdirlist = [item for item in os.listdir(OPENRAM_HOME) if os.path.isdir(os.path.join(OPENRAM_HOME, item))]
|
||||
for subdir in subdirlist:
|
||||
full_path = "{0}/{1}".format(OPENRAM_HOME, subdir)
|
||||
debug.check(os.path.isdir(full_path),
|
||||
"$OPENRAM_HOME/{0} does not exist: {1}".format(subdir, full_path))
|
||||
if "__pycache__" not in full_path:
|
||||
sys.path.append("{0}".format(full_path))
|
||||
if OPENRAM_HOME not in sys.path:
|
||||
debug.error("Please add OPENRAM_HOME to the PYTHONPATH.", -1)
|
||||
|
||||
# Use a unique temp subdirectory if multithreaded
|
||||
if OPTS.num_threads > 1 or OPTS.openram_temp == "/tmp":
|
||||
|
|
@ -569,18 +563,18 @@ def import_tech():
|
|||
|
||||
OPTS.openram_tech = os.path.dirname(tech_mod.__file__) + "/"
|
||||
|
||||
# Add the tech directory
|
||||
# Prepend the tech directory so it is sourced FIRST
|
||||
tech_path = OPTS.openram_tech
|
||||
sys.path.append(tech_path)
|
||||
sys.path.insert(0, tech_path)
|
||||
try:
|
||||
import tech
|
||||
except ImportError:
|
||||
debug.error("Could not load tech module.", -1)
|
||||
|
||||
# Add custom modules of the technology to the path, if they exist
|
||||
# Prepend custom modules of the technology to the path, if they exist
|
||||
custom_mod_path = os.path.join(tech_path, "modules/")
|
||||
if os.path.exists(custom_mod_path):
|
||||
sys.path.append(custom_mod_path)
|
||||
sys.path.insert(0, custom_mod_path)
|
||||
|
||||
|
||||
def print_time(name, now_time, last_time=None, indentation=2):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
from .and2_dec import *
|
||||
from .and3_dec import *
|
||||
from .and4_dec import *
|
||||
from .bank import *
|
||||
from .bitcell_1port import *
|
||||
from .bitcell_2port import *
|
||||
from .bitcell_array import *
|
||||
from .bitcell_base_array import *
|
||||
from .bitcell_base import *
|
||||
from .col_cap_array import *
|
||||
from .col_cap_bitcell_1port import *
|
||||
from .col_cap_bitcell_2port import *
|
||||
from .column_decoder import *
|
||||
from .column_mux_array import *
|
||||
from .column_mux import *
|
||||
from .control_logic import *
|
||||
from .delay_chain import *
|
||||
from .dff_array import *
|
||||
from .dff_buf_array import *
|
||||
from .dff_buf import *
|
||||
from .dff_inv_array import *
|
||||
from .dff_inv import *
|
||||
from .dff import *
|
||||
from .dummy_array import *
|
||||
from .dummy_bitcell_1port import *
|
||||
from .dummy_bitcell_2port import *
|
||||
from .dummy_pbitcell import *
|
||||
from .global_bitcell_array import *
|
||||
from .hierarchical_decoder import *
|
||||
from .hierarchical_predecode2x4 import *
|
||||
from .hierarchical_predecode3x8 import *
|
||||
from .hierarchical_predecode4x16 import *
|
||||
from .hierarchical_predecode import *
|
||||
from .inv_dec import *
|
||||
from .local_bitcell_array import *
|
||||
from .nand2_dec import *
|
||||
from .nand3_dec import *
|
||||
from .nand4_dec import *
|
||||
from .orig_bitcell_array import *
|
||||
from .pand2 import *
|
||||
from .pand3 import *
|
||||
from .pand4 import *
|
||||
from .pbitcell import *
|
||||
from .pbuf_dec import *
|
||||
from .pbuf import *
|
||||
from .pdriver import *
|
||||
from .pgate import *
|
||||
from .pinvbuf import *
|
||||
from .pinv_dec import *
|
||||
from .pinv import *
|
||||
from .pnand2 import *
|
||||
from .pnand3 import *
|
||||
from .pnand4 import *
|
||||
from .pnor2 import *
|
||||
from .port_address import *
|
||||
from .port_data import *
|
||||
from .precharge_array import *
|
||||
from .precharge import *
|
||||
from .ptristate_inv import *
|
||||
from .ptx import *
|
||||
from .pwrite_driver import *
|
||||
from .replica_bitcell_1port import *
|
||||
from .replica_bitcell_2port import *
|
||||
from .replica_bitcell_array import *
|
||||
from .replica_column import *
|
||||
from .replica_pbitcell import *
|
||||
from .row_cap_array import *
|
||||
from .row_cap_bitcell_1port import *
|
||||
from .row_cap_bitcell_2port import *
|
||||
from .sense_amp_array import *
|
||||
from .sense_amp import *
|
||||
from .tri_gate_array import *
|
||||
from .tri_gate import *
|
||||
from .wordline_buffer_array import *
|
||||
from .wordline_driver_array import *
|
||||
from .wordline_driver import *
|
||||
from .write_driver_array import *
|
||||
from .write_driver import *
|
||||
from .write_mask_and_array import *
|
||||
from .sram_1bank import *
|
||||
from .sram_config import *
|
||||
from .sram import *
|
||||
|
|
@ -6,20 +6,20 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
from vector import vector
|
||||
import design
|
||||
from base import vector
|
||||
from base import design
|
||||
from sram_factory import factory
|
||||
from globals import OPTS
|
||||
from tech import layer
|
||||
|
||||
|
||||
class and2_dec(design.design):
|
||||
class and2_dec(design):
|
||||
"""
|
||||
This is an AND with configurable drive strength.
|
||||
"""
|
||||
def __init__(self, name, size=1, height=None, add_wells=True):
|
||||
|
||||
design.design.__init__(self, name)
|
||||
design.__init__(self, name)
|
||||
|
||||
debug.info(1, "Creating and2_dec {}".format(name))
|
||||
self.add_comment("size: {}".format(size))
|
||||
|
|
|
|||
|
|
@ -6,19 +6,19 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
from vector import vector
|
||||
import design
|
||||
from base import design
|
||||
from base import vector
|
||||
from sram_factory import factory
|
||||
from globals import OPTS
|
||||
from tech import layer
|
||||
|
||||
|
||||
class and3_dec(design.design):
|
||||
class and3_dec(design):
|
||||
"""
|
||||
This is an AND with configurable drive strength.
|
||||
"""
|
||||
def __init__(self, name, size=1, height=None, add_wells=True):
|
||||
design.design.__init__(self, name)
|
||||
design.__init__(self, name)
|
||||
debug.info(1, "Creating and3_dec {}".format(name))
|
||||
self.add_comment("size: {}".format(size))
|
||||
self.size = size
|
||||
|
|
|
|||
|
|
@ -6,20 +6,20 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
from vector import vector
|
||||
import design
|
||||
from base import design
|
||||
from base import vector
|
||||
from sram_factory import factory
|
||||
from globals import OPTS
|
||||
from tech import layer
|
||||
|
||||
|
||||
class and4_dec(design.design):
|
||||
class and4_dec(design):
|
||||
"""
|
||||
This is an AND with configurable drive strength.
|
||||
"""
|
||||
def __init__(self, name, size=1, height=None, add_wells=True):
|
||||
|
||||
design.design.__init__(self, name)
|
||||
design.__init__(self, name)
|
||||
|
||||
debug.info(1, "Creating and4_dec {}".format(name))
|
||||
self.add_comment("size: {}".format(size))
|
||||
|
|
|
|||
|
|
@ -6,16 +6,16 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
import design
|
||||
from base import design
|
||||
from base import vector
|
||||
from sram_factory import factory
|
||||
from math import log, ceil, floor
|
||||
from tech import drc
|
||||
from vector import vector
|
||||
from globals import OPTS
|
||||
from tech import layer_properties as layer_props
|
||||
|
||||
|
||||
class bank(design.design):
|
||||
class bank(design):
|
||||
"""
|
||||
Dynamically generated a single bank including bitcell array,
|
||||
hierarchical_decoder, precharge, (optional column_mux and column decoder),
|
||||
|
|
|
|||
|
|
@ -5,19 +5,16 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import sys
|
||||
from tech import drc, parameter
|
||||
import debug
|
||||
import design
|
||||
import contact
|
||||
from pinv import pinv
|
||||
from pnand2 import pnand2
|
||||
from pnor2 import pnor2
|
||||
from vector import vector
|
||||
from tech import drc
|
||||
from base import design
|
||||
from base import vector
|
||||
from pgates import pinv
|
||||
from pgates import pnand2
|
||||
from pgates import pnor2
|
||||
from sram_factory import factory
|
||||
from globals import OPTS
|
||||
|
||||
class bank_select(design.design):
|
||||
class bank_select(design):
|
||||
"""Create a bank select signal that is combined with an array of
|
||||
NOR+INV gates to gate the control signals in case of multiple
|
||||
banks are created in upper level SRAM module
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@
|
|||
#
|
||||
import debug
|
||||
from tech import cell_properties as props
|
||||
import bitcell_base
|
||||
from .bitcell_base import bitcell_base
|
||||
|
||||
|
||||
class bitcell_1port(bitcell_base.bitcell_base):
|
||||
class bitcell_1port(bitcell_base):
|
||||
"""
|
||||
A single bit cell (6T, 8T, etc.) This module implements the
|
||||
single memory cell used in the design. It is a hand-made cell, so
|
||||
|
|
@ -7,10 +7,10 @@
|
|||
#
|
||||
import debug
|
||||
from tech import cell_properties as props
|
||||
import bitcell_base
|
||||
from .bitcell_base import bitcell_base
|
||||
|
||||
|
||||
class bitcell_2port(bitcell_base.bitcell_base):
|
||||
class bitcell_2port(bitcell_base):
|
||||
"""
|
||||
A single bit cell (6T, 8T, etc.) This module implements the
|
||||
single memory cell used in the design. It is a hand-made cell, so
|
||||
|
|
@ -103,4 +103,4 @@ class bitcell_2port(bitcell_base.bitcell_base):
|
|||
def is_non_inverting(self):
|
||||
"""Return input to output polarity for module"""
|
||||
|
||||
return False
|
||||
return False
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
from bitcell_base_array import bitcell_base_array
|
||||
from .bitcell_base_array import bitcell_base_array
|
||||
from tech import drc, spice
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
|
|
|
|||
|
|
@ -7,18 +7,18 @@
|
|||
#
|
||||
|
||||
import debug
|
||||
import design
|
||||
from base import design
|
||||
from globals import OPTS
|
||||
import logical_effort
|
||||
from base import logical_effort
|
||||
from tech import parameter, drc, layer, spice
|
||||
|
||||
|
||||
class bitcell_base(design.design):
|
||||
class bitcell_base(design):
|
||||
"""
|
||||
Base bitcell parameters to be over-riden.
|
||||
"""
|
||||
def __init__(self, name, cell_name=None, prop=None):
|
||||
design.design.__init__(self, name, cell_name, prop)
|
||||
design.__init__(self, name, cell_name, prop)
|
||||
|
||||
# Set the bitcell specific properties
|
||||
if prop:
|
||||
|
|
@ -37,12 +37,12 @@ class bitcell_base(design.design):
|
|||
# min size NMOS gate load
|
||||
read_port_load = 0.5
|
||||
|
||||
return logical_effort.logical_effort('bitline',
|
||||
size,
|
||||
cin,
|
||||
load + read_port_load,
|
||||
parasitic_delay,
|
||||
False)
|
||||
return logical_effort('bitline',
|
||||
size,
|
||||
cin,
|
||||
load + read_port_load,
|
||||
parasitic_delay,
|
||||
False)
|
||||
|
||||
def analytical_power(self, corner, load):
|
||||
"""Bitcell power in nW. Only characterizes leakage."""
|
||||
|
|
@ -264,4 +264,4 @@ class bitcell_base(design.design):
|
|||
else:
|
||||
delay = math.sqrt(2*tstep*(vdd-spice["nom_threshold"])/m)
|
||||
|
||||
return delay
|
||||
return delay
|
||||
|
|
@ -6,12 +6,12 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
import design
|
||||
from base import design
|
||||
from sram_factory import factory
|
||||
from globals import OPTS
|
||||
|
||||
|
||||
class bitcell_base_array(design.design):
|
||||
class bitcell_base_array(design):
|
||||
"""
|
||||
Abstract base class for bitcell-arrays -- bitcell, dummy, replica
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# Copyright (c) 2016-2021 Regents of the University of California
|
||||
# All rights reserved.
|
||||
#
|
||||
from bitcell_base_array import bitcell_base_array
|
||||
from .bitcell_base_array import bitcell_base_array
|
||||
from sram_factory import factory
|
||||
from globals import OPTS
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@
|
|||
#
|
||||
import debug
|
||||
from tech import cell_properties as props
|
||||
import bitcell_base
|
||||
from .bitcell_base import bitcell_base
|
||||
|
||||
|
||||
class col_cap_bitcell_1port(bitcell_base.bitcell_base):
|
||||
class col_cap_bitcell_1port(bitcell_base):
|
||||
"""
|
||||
Column end cap cell.
|
||||
"""
|
||||
|
|
@ -7,10 +7,10 @@
|
|||
#
|
||||
import debug
|
||||
from tech import cell_properties as props
|
||||
import bitcell_base
|
||||
from .bitcell_base import bitcell_base
|
||||
|
||||
|
||||
class col_cap_bitcell_2port(bitcell_base.bitcell_base):
|
||||
class col_cap_bitcell_2port(bitcell_base):
|
||||
"""
|
||||
Column end cap cell.
|
||||
"""
|
||||
|
|
@ -5,16 +5,16 @@
|
|||
#
|
||||
from tech import drc
|
||||
import debug
|
||||
import design
|
||||
from base import design
|
||||
import math
|
||||
from sram_factory import factory
|
||||
from vector import vector
|
||||
from base import vector
|
||||
from globals import OPTS
|
||||
from tech import cell_properties
|
||||
from tech import layer_properties as layer_props
|
||||
|
||||
|
||||
class column_decoder(design.design):
|
||||
class column_decoder(design):
|
||||
"""
|
||||
Create the column mux decoder.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -5,16 +5,17 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import pgate
|
||||
from .pgate import *
|
||||
import debug
|
||||
from tech import drc, layer
|
||||
from vector import vector
|
||||
from base import vector
|
||||
from .pgate import *
|
||||
from sram_factory import factory
|
||||
from tech import cell_properties as cell_props
|
||||
from globals import OPTS
|
||||
|
||||
|
||||
class column_mux(pgate.pgate):
|
||||
class column_mux(pgate):
|
||||
"""
|
||||
This module implements the columnmux bitline cell used in the design.
|
||||
Creates a single column mux cell with the given integer size relative
|
||||
|
|
@ -5,16 +5,16 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import design
|
||||
from base import design
|
||||
import debug
|
||||
from tech import layer, preferred_directions
|
||||
from vector import vector
|
||||
from base import vector
|
||||
from sram_factory import factory
|
||||
from globals import OPTS
|
||||
from tech import layer_properties as layer_props
|
||||
|
||||
|
||||
class column_mux_array(design.design):
|
||||
class column_mux_array(design):
|
||||
"""
|
||||
Dynamically generated column mux array.
|
||||
Array of column mux to read the bitlines through the 6T.
|
||||
|
|
|
|||
|
|
@ -5,16 +5,16 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import design
|
||||
from base import design
|
||||
import debug
|
||||
from sram_factory import factory
|
||||
import math
|
||||
from vector import vector
|
||||
from base import vector
|
||||
from globals import OPTS
|
||||
import logical_effort
|
||||
from base import logical_effort
|
||||
|
||||
|
||||
class control_logic(design.design):
|
||||
class control_logic(design):
|
||||
"""
|
||||
Dynamically generated Control logic for the total SRAM circuit.
|
||||
"""
|
||||
|
|
@ -43,7 +43,7 @@ class control_logic(design.design):
|
|||
self.num_words = num_rows * words_per_row
|
||||
|
||||
self.enable_delay_chain_resizing = False
|
||||
self.inv_parasitic_delay = logical_effort.logical_effort.pinv
|
||||
self.inv_parasitic_delay = logical_effort.pinv
|
||||
|
||||
# Determines how much larger the sen delay should be. Accounts for possible error in model.
|
||||
# FIXME: This should be made a parameter
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
import design
|
||||
from vector import vector
|
||||
from base import design
|
||||
from base import vector
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
|
||||
|
||||
class delay_chain(design.design):
|
||||
class delay_chain(design):
|
||||
"""
|
||||
Generate a delay chain with the given number of stages and fanout.
|
||||
Input is a list contains the electrical effort (fanout) of each stage.
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import design
|
||||
from base import design
|
||||
from tech import cell_properties as props
|
||||
from tech import spice
|
||||
|
||||
|
||||
class dff(design.design):
|
||||
class dff(design):
|
||||
"""
|
||||
Memory address flip-flop
|
||||
"""
|
||||
|
|
@ -6,13 +6,13 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
import design
|
||||
from vector import vector
|
||||
from base import design
|
||||
from base import vector
|
||||
from sram_factory import factory
|
||||
from globals import OPTS
|
||||
|
||||
|
||||
class dff_array(design.design):
|
||||
class dff_array(design):
|
||||
"""
|
||||
This is a simple row (or multiple rows) of flops.
|
||||
Unlike the data flops, these are never spaced out.
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
import design
|
||||
from base import design
|
||||
from tech import layer
|
||||
from vector import vector
|
||||
from base import vector
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
|
||||
|
||||
class dff_buf(design.design):
|
||||
class dff_buf(design):
|
||||
"""
|
||||
This is a simple buffered DFF. The output is buffered
|
||||
with two inverters, of variable size, to provide q
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
import design
|
||||
from vector import vector
|
||||
from base import design
|
||||
from base import vector
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
|
||||
|
||||
class dff_buf_array(design.design):
|
||||
class dff_buf_array(design):
|
||||
"""
|
||||
This is a simple row (or multiple rows) of flops.
|
||||
Unlike the data flops, these are never spaced out.
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
import design
|
||||
from vector import vector
|
||||
from base import design
|
||||
from base import vector
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
|
||||
|
||||
class dff_inv(design.design):
|
||||
class dff_inv(design):
|
||||
"""
|
||||
This is a simple DFF with an inverted output. Some DFFs
|
||||
do not have Qbar, so this will create it.
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
import design
|
||||
from vector import vector
|
||||
from base import design
|
||||
from base import vector
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
|
||||
|
||||
class dff_inv_array(design.design):
|
||||
class dff_inv_array(design):
|
||||
"""
|
||||
This is a simple row (or multiple rows) of flops.
|
||||
Unlike the data flops, these are never spaced out.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# Copyright (c) 2016-2021 Regents of the University of California
|
||||
# All rights reserved.
|
||||
#
|
||||
from bitcell_base_array import bitcell_base_array
|
||||
from .bitcell_base_array import bitcell_base_array
|
||||
from sram_factory import factory
|
||||
from globals import OPTS
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@
|
|||
#
|
||||
import debug
|
||||
from tech import cell_properties as props
|
||||
import bitcell_base
|
||||
from .bitcell_base import bitcell_base
|
||||
|
||||
|
||||
class dummy_bitcell_1port(bitcell_base.bitcell_base):
|
||||
class dummy_bitcell_1port(bitcell_base):
|
||||
"""
|
||||
A single bit cell (6T, 8T, etc.) This module implements the
|
||||
single memory cell used in the design. It is a hand-made cell, so
|
||||
|
|
@ -7,10 +7,10 @@
|
|||
#
|
||||
import debug
|
||||
from tech import cell_properties as props
|
||||
import bitcell_base
|
||||
from .bitcell_base import bitcell_base
|
||||
|
||||
|
||||
class dummy_bitcell_2port(bitcell_base.bitcell_base):
|
||||
class dummy_bitcell_2port(bitcell_base):
|
||||
"""
|
||||
A single bit cell which is forced to store a 0.
|
||||
This module implements the single memory cell used in the design. It
|
||||
|
|
@ -6,13 +6,13 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
import design
|
||||
from vector import vector
|
||||
from base import design
|
||||
from base import vector
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
|
||||
|
||||
class dummy_pbitcell(design.design):
|
||||
class dummy_pbitcell(design):
|
||||
"""
|
||||
Creates a replica bitcell using pbitcell
|
||||
"""
|
||||
|
|
@ -23,7 +23,7 @@ class dummy_pbitcell(design.design):
|
|||
self.num_r_ports = OPTS.num_r_ports
|
||||
self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports
|
||||
|
||||
design.design.__init__(self, name)
|
||||
design.__init__(self, name)
|
||||
debug.info(1, "create a dummy bitcell using pbitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports,
|
||||
self.num_w_ports,
|
||||
self.num_r_ports))
|
||||
|
|
@ -5,16 +5,16 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import bitcell_base_array
|
||||
from .bitcell_base_array import bitcell_base_array
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
from vector import vector
|
||||
from base import vector
|
||||
import debug
|
||||
from numpy import cumsum
|
||||
from tech import layer_properties as layer_props
|
||||
|
||||
|
||||
class global_bitcell_array(bitcell_base_array.bitcell_base_array):
|
||||
class global_bitcell_array(bitcell_base_array):
|
||||
"""
|
||||
Creates a global bitcell array.
|
||||
Rows is an integer number for all local arrays.
|
||||
|
|
|
|||
|
|
@ -6,17 +6,17 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
import design
|
||||
from base import design
|
||||
import math
|
||||
from sram_factory import factory
|
||||
from vector import vector
|
||||
from base import vector
|
||||
from globals import OPTS
|
||||
from tech import layer_indices
|
||||
from tech import layer_stacks
|
||||
from tech import layer_properties as layer_props
|
||||
from tech import drc
|
||||
|
||||
class hierarchical_decoder(design.design):
|
||||
class hierarchical_decoder(design):
|
||||
"""
|
||||
Dynamically generated hierarchical decoder.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
import design
|
||||
from base import design
|
||||
import math
|
||||
from vector import vector
|
||||
from base import vector
|
||||
from sram_factory import factory
|
||||
from globals import OPTS
|
||||
from tech import layer_properties as layer_props
|
||||
|
|
@ -18,7 +18,7 @@ from tech import preferred_directions
|
|||
from tech import drc
|
||||
|
||||
|
||||
class hierarchical_predecode(design.design):
|
||||
class hierarchical_predecode(design):
|
||||
"""
|
||||
Pre 2x4 and 3x8 and TBD 4x16 decoder shared code.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
from hierarchical_predecode import hierarchical_predecode
|
||||
from .hierarchical_predecode import hierarchical_predecode
|
||||
from globals import OPTS
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
from hierarchical_predecode import hierarchical_predecode
|
||||
from .hierarchical_predecode import hierarchical_predecode
|
||||
from globals import OPTS
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
from hierarchical_predecode import hierarchical_predecode
|
||||
from .hierarchical_predecode import hierarchical_predecode
|
||||
from globals import OPTS
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import design
|
||||
import logical_effort
|
||||
from base import design
|
||||
from base import logical_effort
|
||||
from tech import cell_properties as props
|
||||
from tech import spice, parameter
|
||||
|
||||
|
||||
class inv_dec(design.design):
|
||||
class inv_dec(design):
|
||||
"""
|
||||
INV for address decoders.
|
||||
"""
|
||||
|
|
@ -51,12 +51,12 @@ class inv_dec(design.design):
|
|||
Input inverted by this stage.
|
||||
"""
|
||||
parasitic_delay = 1
|
||||
return logical_effort.logical_effort(self.name,
|
||||
self.size,
|
||||
self.input_load(),
|
||||
cout,
|
||||
parasitic_delay,
|
||||
not inp_is_rise)
|
||||
return logical_effort(self.name,
|
||||
self.size,
|
||||
self.input_load(),
|
||||
cout,
|
||||
parasitic_delay,
|
||||
not inp_is_rise)
|
||||
|
||||
def build_graph(self, graph, inst_name, port_nets):
|
||||
"""
|
||||
|
|
@ -5,15 +5,15 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import bitcell_base_array
|
||||
from .bitcell_base_array import bitcell_base_array
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
from vector import vector
|
||||
from base import vector
|
||||
import debug
|
||||
from tech import layer_properties as layer_props
|
||||
|
||||
|
||||
class local_bitcell_array(bitcell_base_array.bitcell_base_array):
|
||||
class local_bitcell_array(bitcell_base_array):
|
||||
"""
|
||||
A local bitcell array is a bitcell array with a wordline driver.
|
||||
This can either be a single aray on its own if there is no hierarchical WL
|
||||
|
|
|
|||
|
|
@ -8,15 +8,14 @@
|
|||
import sys
|
||||
from tech import drc, parameter
|
||||
import debug
|
||||
import design
|
||||
from base import design
|
||||
import math
|
||||
from math import log,sqrt,ceil
|
||||
import contact
|
||||
from vector import vector
|
||||
from base import vector
|
||||
from sram_factory import factory
|
||||
from globals import OPTS
|
||||
|
||||
class multibank(design.design):
|
||||
class multibank(design):
|
||||
"""
|
||||
Dynamically generated a single bank including bitcell array,
|
||||
hierarchical_decoder, precharge, (optional column_mux and column decoder),
|
||||
|
|
@ -799,7 +798,7 @@ class multibank(design.design):
|
|||
self.add_wire(("m3","via2","m2"),[in_pin, rail_pos, rail_pos - vector(0,self.m2_pitch)])
|
||||
# Bring it up to M2 for M2/M3 routing
|
||||
self.add_via(layers=self.m1_stack,
|
||||
offset=in_pin + contact.m1_via.offset,
|
||||
offset=in_pin + self.m1_via.offset,
|
||||
rotate=90)
|
||||
self.add_via(layers=self.m2_stack,
|
||||
offset=in_pin + self.m2m3_via_offset,
|
||||
|
|
@ -812,7 +811,7 @@ class multibank(design.design):
|
|||
rail_pos = vector(self.rail_1_x_offsets[rail], in_pin.y)
|
||||
self.add_wire(("m3","via2","m2"),[in_pin, rail_pos, rail_pos - vector(0,self.m2_pitch)])
|
||||
self.add_via(layers=self.m1_stack,
|
||||
offset=in_pin + contact.m1_via.offset,
|
||||
offset=in_pin + self.m1_via.offset,
|
||||
rotate=90)
|
||||
self.add_via(layers=self.m2_stack,
|
||||
offset=in_pin + self.m2m3_via_offset,
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import design
|
||||
from base import design
|
||||
from tech import spice, parameter, drc
|
||||
from tech import cell_properties as props
|
||||
import logical_effort
|
||||
from base import logical_effort
|
||||
|
||||
|
||||
class nand2_dec(design.design):
|
||||
class nand2_dec(design):
|
||||
"""
|
||||
2-input NAND decoder for address decoders.
|
||||
"""
|
||||
|
|
@ -56,12 +56,12 @@ class nand2_dec(design.design):
|
|||
Input inverted by this stage.
|
||||
"""
|
||||
parasitic_delay = 2
|
||||
return logical_effort.logical_effort(self.name,
|
||||
self.size,
|
||||
self.input_load(),
|
||||
cout,
|
||||
parasitic_delay,
|
||||
not inp_is_rise)
|
||||
return logical_effort(self.name,
|
||||
self.size,
|
||||
self.input_load(),
|
||||
cout,
|
||||
parasitic_delay,
|
||||
not inp_is_rise)
|
||||
|
||||
def build_graph(self, graph, inst_name, port_nets):
|
||||
"""
|
||||
|
|
@ -96,4 +96,4 @@ class nand2_dec(design.design):
|
|||
pmos_drain_c = self.drain_c_(self.pmos_width*mult,
|
||||
1,
|
||||
mult)
|
||||
return nmos_drain_c + pmos_drain_c
|
||||
return nmos_drain_c + pmos_drain_c
|
||||
|
|
@ -5,13 +5,13 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import design
|
||||
from base import design
|
||||
from tech import spice, parameter, drc
|
||||
from tech import cell_properties as props
|
||||
import logical_effort
|
||||
from base import logical_effort
|
||||
|
||||
|
||||
class nand3_dec(design.design):
|
||||
class nand3_dec(design):
|
||||
"""
|
||||
3-input NAND decoder for address decoders.
|
||||
"""
|
||||
|
|
@ -56,12 +56,12 @@ class nand3_dec(design.design):
|
|||
Input inverted by this stage.
|
||||
"""
|
||||
parasitic_delay = 2
|
||||
return logical_effort.logical_effort(self.name,
|
||||
self.size,
|
||||
self.input_load(),
|
||||
cout,
|
||||
parasitic_delay,
|
||||
not inp_is_rise)
|
||||
return logical_effort(self.name,
|
||||
self.size,
|
||||
self.input_load(),
|
||||
cout,
|
||||
parasitic_delay,
|
||||
not inp_is_rise)
|
||||
|
||||
def build_graph(self, graph, inst_name, port_nets):
|
||||
"""
|
||||
|
|
@ -96,4 +96,4 @@ class nand3_dec(design.design):
|
|||
pmos_drain_c = self.drain_c_(self.pmos_width*mult,
|
||||
1,
|
||||
mult)
|
||||
return nmos_drain_c + pmos_drain_c
|
||||
return nmos_drain_c + pmos_drain_c
|
||||
|
|
@ -5,13 +5,13 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import design
|
||||
from base import design
|
||||
from tech import spice, parameter, drc
|
||||
from tech import cell_properties as props
|
||||
import logical_effort
|
||||
from base import logical_effort
|
||||
|
||||
|
||||
class nand4_dec(design.design):
|
||||
class nand4_dec(design):
|
||||
"""
|
||||
4-input NAND decoder for address decoders.
|
||||
"""
|
||||
|
|
@ -56,12 +56,12 @@ class nand4_dec(design.design):
|
|||
Input inverted by this stage.
|
||||
"""
|
||||
parasitic_delay = 2
|
||||
return logical_effort.logical_effort(self.name,
|
||||
self.size,
|
||||
self.input_load(),
|
||||
cout,
|
||||
parasitic_delay,
|
||||
not inp_is_rise)
|
||||
return logical_effort(self.name,
|
||||
self.size,
|
||||
self.input_load(),
|
||||
cout,
|
||||
parasitic_delay,
|
||||
not inp_is_rise)
|
||||
|
||||
def build_graph(self, graph, inst_name, port_nets):
|
||||
"""
|
||||
|
|
@ -96,4 +96,4 @@ class nand4_dec(design.design):
|
|||
pmos_drain_c = self.drain_c_(self.pmos_width*mult,
|
||||
1,
|
||||
mult)
|
||||
return nmos_drain_c + pmos_drain_c
|
||||
return nmos_drain_c + pmos_drain_c
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
from bitcell_base_array import bitcell_base_array
|
||||
from .bitcell_base_array import bitcell_base_array
|
||||
from tech import drc, spice
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
from vector import vector
|
||||
import pgate
|
||||
from base import vector
|
||||
from .pgate import *
|
||||
from sram_factory import factory
|
||||
|
||||
|
||||
class pand2(pgate.pgate):
|
||||
class pand2(pgate):
|
||||
"""
|
||||
This is an AND (or NAND) with configurable drive strength.
|
||||
"""
|
||||
|
|
@ -6,12 +6,12 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
from vector import vector
|
||||
import pgate
|
||||
from base import vector
|
||||
from .pgate import *
|
||||
from sram_factory import factory
|
||||
|
||||
|
||||
class pand3(pgate.pgate):
|
||||
class pand3(pgate):
|
||||
"""
|
||||
This is a simple buffer used for driving loads.
|
||||
"""
|
||||
|
|
@ -6,12 +6,12 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
from vector import vector
|
||||
import pgate
|
||||
from base import vector
|
||||
from .pgate import *
|
||||
from sram_factory import factory
|
||||
|
||||
|
||||
class pand4(pgate.pgate):
|
||||
class pand4(pgate):
|
||||
"""
|
||||
This is a simple buffer used for driving loads.
|
||||
"""
|
||||
|
|
@ -5,18 +5,17 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import contact
|
||||
import debug
|
||||
from base import logical_effort
|
||||
from base import vector
|
||||
from tech import drc, parameter, layer
|
||||
from tech import cell_properties as props
|
||||
from vector import vector
|
||||
from ptx import ptx
|
||||
from globals import OPTS
|
||||
import logical_effort
|
||||
import bitcell_base
|
||||
from .ptx import ptx
|
||||
from .bitcell_base import bitcell_base
|
||||
|
||||
|
||||
class pbitcell(bitcell_base.bitcell_base):
|
||||
class pbitcell(bitcell_base):
|
||||
"""
|
||||
This module implements a parametrically sized multi-port bitcell,
|
||||
with a variable number of read/write, write, and read ports
|
||||
|
|
@ -45,7 +44,7 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
self.gnd_layer = "m1"
|
||||
self.gnd_dir = "H"
|
||||
|
||||
bitcell_base.bitcell_base.__init__(self, name)
|
||||
bitcell_base.__init__(self, name)
|
||||
fmt_str = "{0} rw ports, {1} w ports and {2} r ports"
|
||||
info_string = fmt_str.format(self.num_rw_ports,
|
||||
self.num_w_ports,
|
||||
|
|
@ -222,20 +221,20 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
|
||||
# y-offset for the access transistor's gate contact
|
||||
self.gate_contact_yoffset = max_contact_extension + self.m2_space \
|
||||
+ 0.5 * max(contact.poly_contact.height, contact.m1_via.height)
|
||||
+ 0.5 * max(self.poly_contact.height, self.m1_via.height)
|
||||
|
||||
# y-position of access transistors
|
||||
self.port_ypos = self.m1_space + 0.5 * contact.m1_via.height + self.gate_contact_yoffset
|
||||
self.port_ypos = self.m1_space + 0.5 * self.m1_via.height + self.gate_contact_yoffset
|
||||
|
||||
# y-position of inverter nmos
|
||||
self.inverter_nmos_ypos = self.port_ypos
|
||||
|
||||
# spacing between ports (same for read/write and write ports)
|
||||
self.bitline_offset = -0.5 * self.readwrite_nmos.active_width \
|
||||
+ 0.5 * contact.m1_via.height \
|
||||
+ 0.5 * self.m1_via.height \
|
||||
+ self.m2_space + self.m2_width
|
||||
m2_constraint = self.bitline_offset + self.m2_space \
|
||||
+ 0.5 * contact.m1_via.height \
|
||||
+ 0.5 * self.m1_via.height \
|
||||
- 0.5 * self.readwrite_nmos.active_width
|
||||
self.write_port_spacing = max(self.active_space,
|
||||
self.m1_space,
|
||||
|
|
@ -243,7 +242,7 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
self.read_port_spacing = self.bitline_offset + self.m2_space
|
||||
|
||||
# spacing between cross coupled inverters
|
||||
self.inverter_to_inverter_spacing = contact.poly_contact.width + self.m1_space
|
||||
self.inverter_to_inverter_spacing = self.poly_contact.width + self.m1_space
|
||||
|
||||
# calculations related to inverter connections
|
||||
inverter_pmos_contact_extension = 0.5 * \
|
||||
|
|
@ -252,19 +251,19 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
(self.inverter_nmos.active_contact.height - self.inverter_nmos.active_height)
|
||||
self.inverter_gap = max(self.poly_to_active,
|
||||
self.m1_space + inverter_nmos_contact_extension) \
|
||||
+ self.poly_to_contact + 2 * contact.poly_contact.width \
|
||||
+ self.poly_to_contact + 2 * self.poly_contact.width \
|
||||
+ self.m1_space + inverter_pmos_contact_extension
|
||||
self.cross_couple_lower_ypos = self.inverter_nmos_ypos \
|
||||
+ self.inverter_nmos.active_height \
|
||||
+ max(self.poly_to_active,
|
||||
self.m1_space + inverter_nmos_contact_extension) \
|
||||
+ 0.5 * contact.poly_contact.width
|
||||
+ 0.5 * self.poly_contact.width
|
||||
self.cross_couple_upper_ypos = self.inverter_nmos_ypos \
|
||||
+ self.inverter_nmos.active_height \
|
||||
+ max(self.poly_to_active,
|
||||
self.m1_space + inverter_nmos_contact_extension) \
|
||||
+ self.poly_to_contact \
|
||||
+ 1.5 * contact.poly_contact.width
|
||||
+ 1.5 * self.poly_contact.width
|
||||
|
||||
# spacing between wordlines (and gnd)
|
||||
self.m1_offset = -0.5 * self.m1_width
|
||||
|
|
@ -300,7 +299,7 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
(self.write_nmos.active_width + self.write_port_spacing) \
|
||||
- self.num_r_ports * \
|
||||
(self.read_port_width + self.read_port_spacing) \
|
||||
- self.bitline_offset - 0.5 * contact.m1_via.width
|
||||
- self.bitline_offset - 0.5 * self.m1_via.width
|
||||
|
||||
self.width = -2 * self.leftmost_xpos
|
||||
self.height = self.topmost_ypos - self.botmost_ypos
|
||||
|
|
@ -390,14 +389,14 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
# add contacts to connect gate poly to drain/source
|
||||
# metal1 (to connect Q to Q_bar)
|
||||
contact_offset_left = vector(self.inverter_nmos_left.get_pin("D").rc().x \
|
||||
+ 0.5 * contact.poly_contact.height,
|
||||
+ 0.5 * self.poly_contact.height,
|
||||
self.cross_couple_upper_ypos)
|
||||
self.add_via_center(layers=self.poly_stack,
|
||||
offset=contact_offset_left,
|
||||
directions=("H", "H"))
|
||||
|
||||
contact_offset_right = vector(self.inverter_nmos_right.get_pin("S").lc().x \
|
||||
- 0.5*contact.poly_contact.height,
|
||||
- 0.5*self.poly_contact.height,
|
||||
self.cross_couple_lower_ypos)
|
||||
self.add_via_center(layers=self.poly_stack,
|
||||
offset=contact_offset_right,
|
||||
|
|
@ -414,11 +413,11 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
if OPTS.use_pex:
|
||||
# add labels to cross couple inverter for extracted simulation
|
||||
contact_offset_left_output = vector(self.inverter_nmos_left.get_pin("D").rc().x \
|
||||
+ 0.5 * contact.poly.height,
|
||||
+ 0.5 * self.poly.height,
|
||||
self.cross_couple_upper_ypos)
|
||||
|
||||
contact_offset_right_output = vector(self.inverter_nmos_right.get_pin("S").lc().x \
|
||||
- 0.5*contact.poly.height,
|
||||
- 0.5*self.poly.height,
|
||||
self.cross_couple_lower_ypos)
|
||||
self.add_pex_labels(contact_offset_left_output, contact_offset_right_output)
|
||||
|
||||
|
|
@ -896,7 +895,7 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
directions="nonpref")
|
||||
|
||||
self.add_path("m2",
|
||||
[port_contact_offest, bl_offset], width=contact.m1_via.height)
|
||||
[port_contact_offest, bl_offset], width=self.m1_via.height)
|
||||
|
||||
for k in range(self.total_ports):
|
||||
port_contact_offest = right_port_transistors[k].get_pin("D").center()
|
||||
|
|
@ -909,7 +908,7 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
directions="nonpref")
|
||||
|
||||
self.add_path("m2",
|
||||
[port_contact_offest, br_offset], width=contact.m1_via.height)
|
||||
[port_contact_offest, br_offset], width=self.m1_via.height)
|
||||
|
||||
def route_supplies(self):
|
||||
""" Route inverter nmos and read-access nmos to gnd. Route inverter pmos to vdd. """
|
||||
|
|
@ -928,9 +927,9 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
|
||||
|
||||
if position.x > 0:
|
||||
contact_correct = 0.5 * contact.m1_via.height
|
||||
contact_correct = 0.5 * self.m1_via.height
|
||||
else:
|
||||
contact_correct = -0.5 * contact.m1_via.height
|
||||
contact_correct = -0.5 * self.m1_via.height
|
||||
supply_offset = vector(position.x + contact_correct,
|
||||
self.gnd_position.y)
|
||||
self.add_via_center(layers=self.m1_stack,
|
||||
|
|
@ -997,7 +996,7 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
"""
|
||||
# add poly to metal1 contacts for gates of the inverters
|
||||
left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x \
|
||||
- self.poly_to_contact - 0.5*contact.poly_contact.width,
|
||||
- self.poly_to_contact - 0.5*self.poly_contact.width,
|
||||
self.cross_couple_upper_ypos)
|
||||
self.add_via_center(layers=self.poly_stack,
|
||||
offset=left_storage_contact,
|
||||
|
|
@ -1005,7 +1004,7 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
|
||||
|
||||
right_storage_contact = vector(self.inverter_nmos_right.get_pin("G").rc().x \
|
||||
+ self.poly_to_contact + 0.5*contact.poly_contact.width,
|
||||
+ self.poly_to_contact + 0.5*self.poly_contact.width,
|
||||
self.cross_couple_upper_ypos)
|
||||
self.add_via_center(layers=self.poly_stack,
|
||||
offset=right_storage_contact,
|
||||
|
|
@ -1192,12 +1191,12 @@ class pbitcell(bitcell_base.bitcell_base):
|
|||
# min size NMOS gate load
|
||||
read_port_load = self.num_r_ports / 2
|
||||
total_load = load + read_port_load + write_port_load
|
||||
return logical_effort.logical_effort('bitline',
|
||||
size,
|
||||
cin,
|
||||
load + read_port_load,
|
||||
parasitic_delay,
|
||||
False)
|
||||
return logical_effort('bitline',
|
||||
size,
|
||||
cin,
|
||||
load + read_port_load,
|
||||
parasitic_delay,
|
||||
False)
|
||||
|
||||
def input_load(self):
|
||||
""" Return the relative capacitance of the access transistor gates """
|
||||
|
|
@ -6,12 +6,12 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
from vector import vector
|
||||
import pgate
|
||||
from base import vector
|
||||
from .pgate import *
|
||||
from sram_factory import factory
|
||||
|
||||
|
||||
class pbuf(pgate.pgate):
|
||||
class pbuf(pgate):
|
||||
"""
|
||||
This is a simple buffer used for driving loads.
|
||||
"""
|
||||
|
|
@ -6,12 +6,12 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
from vector import vector
|
||||
import pgate
|
||||
from base import vector
|
||||
from .pgate import *
|
||||
from sram_factory import factory
|
||||
|
||||
|
||||
class pbuf_dec(pgate.pgate):
|
||||
class pbuf_dec(pgate):
|
||||
"""
|
||||
This is a simple buffer used for driving wordlines.
|
||||
"""
|
||||
|
|
@ -25,7 +25,7 @@ class pbuf_dec(pgate.pgate):
|
|||
self.height = height
|
||||
|
||||
# Creates the netlist and layout
|
||||
pgate.pgate.__init__(self, name, height)
|
||||
pgate.__init__(self, name, height)
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
|
|
@ -6,12 +6,12 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
import pgate
|
||||
from vector import vector
|
||||
from .pgate import *
|
||||
from base import vector
|
||||
from sram_factory import factory
|
||||
|
||||
|
||||
class pdriver(pgate.pgate):
|
||||
class pdriver(pgate):
|
||||
"""
|
||||
This instantiates an even or odd number of inverters
|
||||
sized for driving a load.
|
||||
|
|
@ -5,20 +5,20 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import contact
|
||||
import design
|
||||
from base import design
|
||||
from base import vector
|
||||
import debug
|
||||
import math
|
||||
from bisect import bisect_left
|
||||
from tech import layer, drc
|
||||
from vector import vector
|
||||
from globals import OPTS
|
||||
from tech import cell_properties as cell_props
|
||||
|
||||
if cell_props.ptx.bin_spice_models:
|
||||
from tech import nmos_bins, pmos_bins
|
||||
|
||||
|
||||
class pgate(design.design):
|
||||
class pgate(design):
|
||||
"""
|
||||
This is a module that implements some shared
|
||||
functions for parameterized gates.
|
||||
|
|
@ -113,14 +113,14 @@ class pgate(design.design):
|
|||
left_gate_offset = vector(nmos_gate_pin.lx(), ypos)
|
||||
|
||||
# Center is completely symmetric.
|
||||
contact_width = contact.poly_contact.width
|
||||
contact_width = self.poly_contact.width
|
||||
|
||||
if position == "center":
|
||||
contact_offset = left_gate_offset \
|
||||
+ vector(0.5 * self.poly_width, 0)
|
||||
elif position == "farleft":
|
||||
contact_offset = left_gate_offset \
|
||||
- vector(0.5 * contact.poly_contact.width, 0)
|
||||
- vector(0.5 * self.poly_contact.width, 0)
|
||||
elif position == "left":
|
||||
contact_offset = left_gate_offset \
|
||||
- vector(0.5 * contact_width - 0.5 * self.poly_width, 0)
|
||||
|
|
@ -146,7 +146,7 @@ class pgate(design.design):
|
|||
+ left_gate_offset.scale(0.5, 0)
|
||||
self.add_rect_center(layer="poly",
|
||||
offset=mid_point,
|
||||
height=contact.poly_contact.first_layer_width,
|
||||
height=self.poly_contact.first_layer_width,
|
||||
width=left_gate_offset.x - contact_offset.x)
|
||||
|
||||
return via
|
||||
|
|
@ -216,6 +216,7 @@ class pgate(design.design):
|
|||
# Offset by half a contact in x and y
|
||||
contact_offset += vector(0.5 * pmos.active_contact.first_layer_width,
|
||||
0.5 * pmos.active_contact.first_layer_height)
|
||||
# This over-rides the default one with a custom direction
|
||||
self.nwell_contact = self.add_via_center(layers=layer_stack,
|
||||
offset=contact_offset,
|
||||
implant_type="n",
|
||||
|
|
@ -372,7 +373,7 @@ class pgate(design.design):
|
|||
# It was already set or is left as default (minimum)
|
||||
# Width is determined by well contact and spacing and allowing a supply via between each cell
|
||||
if self.add_wells:
|
||||
width = max(self.nwell_contact.rx(), self.pwell_contact.rx()) + self.m1_space + 0.5 * contact.m1_via.width
|
||||
width = max(self.nwell_contact.rx(), self.pwell_contact.rx()) + self.m1_space + 0.5 * self.m1_via.width
|
||||
# Height is an input parameter, so it is not recomputed.
|
||||
else:
|
||||
max_active_xoffset = self.find_highest_layer_coords("active").x
|
||||
|
|
@ -5,22 +5,21 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import contact
|
||||
import pgate
|
||||
import debug
|
||||
from .pgate import *
|
||||
from base import vector
|
||||
from base import logical_effort
|
||||
from base.utils import round_to_grid
|
||||
from base.errors import drc_error
|
||||
import operator
|
||||
from tech import drc, parameter, spice
|
||||
from vector import vector
|
||||
from math import ceil
|
||||
from globals import OPTS
|
||||
from utils import round_to_grid
|
||||
import logical_effort
|
||||
from sram_factory import factory
|
||||
from errors import drc_error
|
||||
from tech import cell_properties as cell_props
|
||||
|
||||
|
||||
class pinv(pgate.pgate):
|
||||
class pinv(pgate):
|
||||
"""
|
||||
Pinv generates gds of a parametrically sized inverter. The
|
||||
size is specified as the drive size (relative to minimum NMOS) and
|
||||
|
|
@ -89,8 +88,8 @@ class pinv(pgate.pgate):
|
|||
self.nmos_width = self.nmos_size * drc("minwidth_tx")
|
||||
self.pmos_width = self.pmos_size * drc("minwidth_tx")
|
||||
if cell_props.ptx.bin_spice_models:
|
||||
(self.nmos_width, self.tx_mults) = pgate.pgate.best_bin("nmos", self.nmos_width)
|
||||
(self.pmos_width, self.tx_mults) = pgate.pgate.best_bin("pmos", self.pmos_width)
|
||||
(self.nmos_width, self.tx_mults) = pgate.best_bin("nmos", self.nmos_width)
|
||||
(self.pmos_width, self.tx_mults) = pgate.best_bin("pmos", self.pmos_width)
|
||||
return
|
||||
|
||||
# Do a quick sanity check and bail if unlikely feasible height
|
||||
|
|
@ -106,8 +105,8 @@ class pinv(pgate.pgate):
|
|||
tx_type="pmos")
|
||||
tx_height = nmos.poly_height + pmos.poly_height
|
||||
# rotated m1 pitch or poly to active spacing
|
||||
min_channel = max(contact.poly_contact.width + self.m1_space,
|
||||
contact.poly_contact.width + 2 * self.poly_to_active)
|
||||
min_channel = max(self.poly_contact.width + self.m1_space,
|
||||
self.poly_contact.width + 2 * self.poly_to_active)
|
||||
|
||||
total_height = tx_height + min_channel + 2 * self.top_bottom_space
|
||||
# debug.check(self.height > total_height,
|
||||
|
|
@ -322,12 +321,12 @@ class pinv(pgate.pgate):
|
|||
Input inverted by this stage.
|
||||
"""
|
||||
parasitic_delay = 1
|
||||
return logical_effort.logical_effort(self.name,
|
||||
self.size,
|
||||
self.input_load(),
|
||||
cout,
|
||||
parasitic_delay,
|
||||
not inp_is_rise)
|
||||
return logical_effort(self.name,
|
||||
self.size,
|
||||
self.input_load(),
|
||||
cout,
|
||||
parasitic_delay,
|
||||
not inp_is_rise)
|
||||
|
||||
def build_graph(self, graph, inst_name, port_nets):
|
||||
"""
|
||||
|
|
@ -5,17 +5,16 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import contact
|
||||
import pinv
|
||||
import debug
|
||||
from base import vector
|
||||
from .pinv import pinv
|
||||
from tech import drc, parameter, layer
|
||||
from vector import vector
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
from tech import cell_properties as cell_props
|
||||
|
||||
|
||||
class pinv_dec(pinv.pinv):
|
||||
class pinv_dec(pinv):
|
||||
"""
|
||||
This is another version of pinv but with layout for the decoder.
|
||||
Other stuff is the same (netlist, sizes, etc.)
|
||||
|
|
@ -78,7 +77,7 @@ class pinv_dec(pinv.pinv):
|
|||
self.add_path("poly", [nmos_gate_pos, pmos_gate_pos])
|
||||
|
||||
# Center is completely symmetric.
|
||||
contact_width = contact.poly_contact.width
|
||||
contact_width = self.poly_contact.width
|
||||
contact_offset = nmos_gate_pin.lc() \
|
||||
- vector(self.poly_extend_active + 0.5 * contact_width, 0)
|
||||
via = self.add_via_stack_center(from_layer="poly",
|
||||
|
|
@ -126,7 +125,7 @@ class pinv_dec(pinv.pinv):
|
|||
y_offset = (0.5 * (self.height - self.nmos.width) + self.nmos.width) * 0.9
|
||||
|
||||
# offset so that the input contact is over from the left edge by poly spacing
|
||||
x_offset = self.nmos.active_offset.y + contact.poly_contact.width + self.poly_space
|
||||
x_offset = self.nmos.active_offset.y + self.poly_contact.width + self.poly_space
|
||||
self.nmos_pos = vector(x_offset, y_offset)
|
||||
self.nmos_inst.place(self.nmos_pos,
|
||||
rotate=270)
|
||||
|
|
@ -192,20 +191,20 @@ class pinv_dec(pinv.pinv):
|
|||
|
||||
source_pos = self.pmos_inst.get_pin("S").center()
|
||||
contact_pos = vector(source_pos.x, self.height)
|
||||
self.nwell_contact = self.add_via_center(layers=self.active_stack,
|
||||
offset=contact_pos,
|
||||
implant_type="n",
|
||||
well_type="n")
|
||||
self.add_via_center(layers=self.active_stack,
|
||||
offset=contact_pos,
|
||||
implant_type="n",
|
||||
well_type="n")
|
||||
self.add_via_stack_center(offset=contact_pos,
|
||||
from_layer=self.active_stack[2],
|
||||
to_layer=self.supply_layer)
|
||||
|
||||
source_pos = self.nmos_inst.get_pin("S").center()
|
||||
contact_pos = vector(source_pos.x, self.height)
|
||||
self.pwell_contact= self.add_via_center(layers=self.active_stack,
|
||||
offset=contact_pos,
|
||||
implant_type="p",
|
||||
well_type="p")
|
||||
self.add_via_center(layers=self.active_stack,
|
||||
offset=contact_pos,
|
||||
implant_type="p",
|
||||
well_type="p")
|
||||
self.add_via_stack_center(offset=contact_pos,
|
||||
from_layer=self.active_stack[2],
|
||||
to_layer=self.supply_layer)
|
||||
|
|
@ -6,12 +6,12 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
import pgate
|
||||
from vector import vector
|
||||
from .pgate import *
|
||||
from base import vector
|
||||
from sram_factory import factory
|
||||
from tech import layer
|
||||
|
||||
class pinvbuf(pgate.pgate):
|
||||
class pinvbuf(pgate):
|
||||
"""
|
||||
This is a simple inverter/buffer used for driving loads. It is
|
||||
used in the column decoder for 1:2 decoding and as the clock buffer.
|
||||
|
|
@ -5,17 +5,16 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import pgate
|
||||
from .pgate import *
|
||||
import debug
|
||||
from tech import drc, parameter, spice
|
||||
from vector import vector
|
||||
import logical_effort
|
||||
from base import vector
|
||||
from base import logical_effort
|
||||
from sram_factory import factory
|
||||
import contact
|
||||
from tech import cell_properties as cell_props
|
||||
|
||||
|
||||
class pnand2(pgate.pgate):
|
||||
class pnand2(pgate):
|
||||
"""
|
||||
This module generates gds of a parametrically sized 2-input nand.
|
||||
This model use ptx to generate a 2-input nand within a cetrain height.
|
||||
|
|
@ -175,11 +174,11 @@ class pnand2(pgate.pgate):
|
|||
# Top of NMOS drain
|
||||
bottom_pin = self.nmos1_inst.get_pin("D")
|
||||
# active contact metal to poly contact metal spacing
|
||||
active_contact_to_poly_contact = bottom_pin.uy() + self.route_layer_space + 0.5 * contact.poly_contact.second_layer_height
|
||||
active_contact_to_poly_contact = bottom_pin.uy() + self.route_layer_space + 0.5 * self.poly_contact.second_layer_height
|
||||
# active diffusion to poly contact spacing
|
||||
# doesn't use nmos uy because that is calculated using offset + poly height
|
||||
active_top = self.nmos1_inst.by() + self.nmos1_inst.mod.active_height
|
||||
active_to_poly_contact = active_top + self.poly_to_active + 0.5 * contact.poly_contact.first_layer_height
|
||||
active_to_poly_contact = active_top + self.poly_to_active + 0.5 * self.poly_contact.first_layer_height
|
||||
active_to_poly_contact2 = active_top + self.poly_contact_to_gate + 0.5 * self.route_layer_width
|
||||
self.inputA_yoffset = max(active_contact_to_poly_contact,
|
||||
active_to_poly_contact,
|
||||
|
|
@ -193,9 +192,9 @@ class pnand2(pgate.pgate):
|
|||
|
||||
self.inputB_yoffset = self.inputA_yoffset + 2 * self.m3_pitch
|
||||
# # active contact metal to poly contact metal spacing
|
||||
# active_contact_to_poly_contact = self.output_yoffset - self.route_layer_space - 0.5 * contact.poly_contact.second_layer_height
|
||||
# active_contact_to_poly_contact = self.output_yoffset - self.route_layer_space - 0.5 * self.poly_contact.second_layer_height
|
||||
# active_bottom = self.pmos1_inst.by()
|
||||
# active_to_poly_contact = active_bottom - self.poly_to_active - 0.5 * contact.poly_contact.first_layer_height
|
||||
# active_to_poly_contact = active_bottom - self.poly_to_active - 0.5 * self.poly_contact.first_layer_height
|
||||
# active_to_poly_contact2 = active_bottom - self.poly_contact_to_gate - 0.5 * self.route_layer_width
|
||||
# self.inputB_yoffset = min(active_contact_to_poly_contact,
|
||||
# active_to_poly_contact,
|
||||
|
|
@ -215,7 +214,7 @@ class pnand2(pgate.pgate):
|
|||
""" Route the Z output """
|
||||
|
||||
# One routing track layer below the PMOS contacts
|
||||
route_layer_offset = 0.5 * contact.poly_contact.second_layer_height + self.route_layer_space
|
||||
route_layer_offset = 0.5 * self.poly_contact.second_layer_height + self.route_layer_space
|
||||
self.output_yoffset = self.pmos1_inst.get_pin("D").by() - route_layer_offset
|
||||
|
||||
|
||||
|
|
@ -297,12 +296,12 @@ class pnand2(pgate.pgate):
|
|||
Input inverted by this stage.
|
||||
"""
|
||||
parasitic_delay = 2
|
||||
return logical_effort.logical_effort(self.name,
|
||||
self.size,
|
||||
self.input_load(),
|
||||
cout,
|
||||
parasitic_delay,
|
||||
not inp_is_rise)
|
||||
return logical_effort(self.name,
|
||||
self.size,
|
||||
self.input_load(),
|
||||
cout,
|
||||
parasitic_delay,
|
||||
not inp_is_rise)
|
||||
|
||||
def build_graph(self, graph, inst_name, port_nets):
|
||||
"""
|
||||
|
|
@ -5,17 +5,16 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import pgate
|
||||
from .pgate import *
|
||||
import debug
|
||||
from tech import drc, parameter, spice
|
||||
from vector import vector
|
||||
import logical_effort
|
||||
from base import vector
|
||||
from base import logical_effort
|
||||
from sram_factory import factory
|
||||
import contact
|
||||
from tech import cell_properties as cell_props
|
||||
|
||||
|
||||
class pnand3(pgate.pgate):
|
||||
class pnand3(pgate):
|
||||
"""
|
||||
This module generates gds of a parametrically sized 2-input nand.
|
||||
This model use ptx to generate a 2-input nand within a cetrain height.
|
||||
|
|
@ -204,17 +203,17 @@ class pnand3(pgate.pgate):
|
|||
""" Route the A and B and C inputs """
|
||||
|
||||
# We can use this pitch because the contacts and overlap won't be adjacent
|
||||
non_contact_pitch = 0.5 * self.m1_width + self.m1_space + 0.5 * contact.poly_contact.second_layer_height
|
||||
non_contact_pitch = 0.5 * self.m1_width + self.m1_space + 0.5 * self.poly_contact.second_layer_height
|
||||
pmos_drain_bottom = self.pmos1_inst.get_pin("D").by()
|
||||
self.output_yoffset = pmos_drain_bottom - 0.5 * self.route_layer_width - self.route_layer_space
|
||||
|
||||
bottom_pin = self.nmos1_inst.get_pin("D")
|
||||
# active contact metal to poly contact metal spacing
|
||||
active_contact_to_poly_contact = bottom_pin.uy() + self.m1_space + 0.5 * contact.poly_contact.second_layer_height
|
||||
active_contact_to_poly_contact = bottom_pin.uy() + self.m1_space + 0.5 * self.poly_contact.second_layer_height
|
||||
# active diffusion to poly contact spacing
|
||||
# doesn't use nmos uy because that is calculated using offset + poly height
|
||||
active_top = self.nmos1_inst.by() + self.nmos1_inst.mod.active_height
|
||||
active_to_poly_contact = active_top + self.poly_to_active + 0.5 * contact.poly_contact.first_layer_height
|
||||
active_to_poly_contact = active_top + self.poly_to_active + 0.5 * self.poly_contact.first_layer_height
|
||||
active_to_poly_contact2 = active_top + self.poly_contact_to_gate + 0.5 * self.route_layer_width
|
||||
self.inputA_yoffset = max(active_contact_to_poly_contact,
|
||||
active_to_poly_contact,
|
||||
|
|
@ -328,12 +327,12 @@ class pnand3(pgate.pgate):
|
|||
Input inverted by this stage.
|
||||
"""
|
||||
parasitic_delay = 3
|
||||
return logical_effort.logical_effort(self.name,
|
||||
self.size,
|
||||
self.input_load(),
|
||||
cout,
|
||||
parasitic_delay,
|
||||
not inp_is_rise)
|
||||
return logical_effort(self.name,
|
||||
self.size,
|
||||
self.input_load(),
|
||||
cout,
|
||||
parasitic_delay,
|
||||
not inp_is_rise)
|
||||
|
||||
def build_graph(self, graph, inst_name, port_nets):
|
||||
"""
|
||||
|
|
@ -5,17 +5,16 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import pgate
|
||||
from .pgate import *
|
||||
import debug
|
||||
from tech import drc, parameter, spice
|
||||
from vector import vector
|
||||
import logical_effort
|
||||
from base import vector
|
||||
from base import logical_effort
|
||||
from sram_factory import factory
|
||||
import contact
|
||||
from tech import cell_properties as cell_props
|
||||
|
||||
|
||||
class pnand4(pgate.pgate):
|
||||
class pnand4(pgate):
|
||||
"""
|
||||
This module generates gds of a parametrically sized 4-input nand.
|
||||
This model use ptx to generate a 4-input nand within a cetrain height.
|
||||
|
|
@ -225,11 +224,11 @@ class pnand4(pgate.pgate):
|
|||
|
||||
bottom_pin = self.nmos1_inst.get_pin("D")
|
||||
# active contact metal to poly contact metal spacing
|
||||
active_contact_to_poly_contact = bottom_pin.uy() + self.m1_space + 0.5 * contact.poly_contact.second_layer_height
|
||||
active_contact_to_poly_contact = bottom_pin.uy() + self.m1_space + 0.5 * self.poly_contact.second_layer_height
|
||||
# active diffusion to poly contact spacing
|
||||
# doesn't use nmos uy because that is calculated using offset + poly height
|
||||
active_top = self.nmos1_inst.by() + self.nmos1_inst.mod.active_height
|
||||
active_to_poly_contact = active_top + self.poly_to_active + 0.5 * contact.poly_contact.first_layer_height
|
||||
active_to_poly_contact = active_top + self.poly_to_active + 0.5 * self.poly_contact.first_layer_height
|
||||
active_to_poly_contact2 = active_top + self.poly_contact_to_gate + 0.5 * self.route_layer_width
|
||||
self.inputA_yoffset = max(active_contact_to_poly_contact,
|
||||
active_to_poly_contact,
|
||||
|
|
@ -350,12 +349,12 @@ class pnand4(pgate.pgate):
|
|||
Input inverted by this stage.
|
||||
"""
|
||||
parasitic_delay = 3
|
||||
return logical_effort.logical_effort(self.name,
|
||||
self.size,
|
||||
self.input_load(),
|
||||
cout,
|
||||
parasitic_delay,
|
||||
not inp_is_rise)
|
||||
return logical_effort(self.name,
|
||||
self.size,
|
||||
self.input_load(),
|
||||
cout,
|
||||
parasitic_delay,
|
||||
not inp_is_rise)
|
||||
|
||||
def build_graph(self, graph, inst_name, port_nets):
|
||||
"""
|
||||
|
|
@ -384,4 +383,4 @@ class pnand4(pgate.pgate):
|
|||
pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults,
|
||||
1,
|
||||
self.tx_mults)
|
||||
return nmos_drain_c + pmos_drain_c
|
||||
return nmos_drain_c + pmos_drain_c
|
||||
|
|
@ -5,15 +5,15 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import pgate
|
||||
from .pgate import *
|
||||
import debug
|
||||
from tech import drc, parameter, spice
|
||||
from vector import vector
|
||||
from base import vector
|
||||
from sram_factory import factory
|
||||
from tech import cell_properties as cell_props
|
||||
|
||||
|
||||
class pnor2(pgate.pgate):
|
||||
class pnor2(pgate):
|
||||
"""
|
||||
This module generates gds of a parametrically sized 2-input nor.
|
||||
This model use ptx to generate a 2-input nor within a cetrain height.
|
||||
|
|
@ -5,15 +5,15 @@
|
|||
#
|
||||
from math import log, ceil
|
||||
import debug
|
||||
import design
|
||||
from base import design
|
||||
from sram_factory import factory
|
||||
from vector import vector
|
||||
from base import vector
|
||||
from tech import layer, drc
|
||||
from globals import OPTS
|
||||
from tech import layer_properties as layer_props
|
||||
|
||||
|
||||
class port_address(design.design):
|
||||
class port_address(design):
|
||||
"""
|
||||
Create the address port (row decoder and wordline driver)..
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -5,17 +5,17 @@
|
|||
#
|
||||
from tech import drc
|
||||
import debug
|
||||
import design
|
||||
from base import design
|
||||
import math
|
||||
from sram_factory import factory
|
||||
from collections import namedtuple
|
||||
from vector import vector
|
||||
from base import vector
|
||||
from globals import OPTS
|
||||
from tech import cell_properties
|
||||
from tech import layer_properties as layer_props
|
||||
|
||||
|
||||
class port_data(design.design):
|
||||
class port_data(design):
|
||||
"""
|
||||
Create the data port (column mux, sense amps, write driver, etc.) for the given port number.
|
||||
Port 0 always has the RBL on the left while port 1 is on the right.
|
||||
|
|
|
|||
|
|
@ -5,18 +5,17 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import contact
|
||||
import design
|
||||
from base import design
|
||||
import debug
|
||||
from pgate import pgate
|
||||
from .pgate import *
|
||||
from tech import parameter, drc
|
||||
from vector import vector
|
||||
from base import vector
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
from tech import cell_properties as cell_props
|
||||
|
||||
|
||||
class precharge(design.design):
|
||||
class precharge(design):
|
||||
"""
|
||||
Creates a single precharge cell
|
||||
This module implements the precharge bitline cell used in the design.
|
||||
|
|
@ -178,7 +177,7 @@ class precharge(design.design):
|
|||
pin_offset = self.lower_pmos_inst.get_pin("G").lr()
|
||||
# This is an extra space down for some techs with contact to active spacing
|
||||
contact_space = max(self.poly_space,
|
||||
self.poly_contact_to_gate) + 0.5 * contact.poly_contact.first_layer_height
|
||||
self.poly_contact_to_gate) + 0.5 * self.poly_contact.first_layer_height
|
||||
offset = pin_offset - vector(0, contact_space)
|
||||
self.add_via_stack_center(from_layer="poly",
|
||||
to_layer=self.en_layer,
|
||||
|
|
@ -198,7 +197,7 @@ class precharge(design.design):
|
|||
|
||||
# adds the contact from active to metal1
|
||||
offset_height = self.upper_pmos1_inst.uy() + \
|
||||
contact.active_contact.height + \
|
||||
self.active_contact.height + \
|
||||
self.nwell_extend_active
|
||||
self.well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1, 0) + \
|
||||
vector(0, offset_height)
|
||||
|
|
@ -210,7 +209,7 @@ class precharge(design.design):
|
|||
to_layer=self.bitline_layer,
|
||||
offset=self.well_contact_pos)
|
||||
|
||||
self.height = self.well_contact_pos.y + contact.active_contact.height + self.m1_space
|
||||
self.height = self.well_contact_pos.y + self.active_contact.height + self.m1_space
|
||||
|
||||
# nwell should span the whole design since it is pmos only
|
||||
self.add_rect(layer="nwell",
|
||||
|
|
@ -5,14 +5,14 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import design
|
||||
from base import design
|
||||
import debug
|
||||
from vector import vector
|
||||
from base import vector
|
||||
from sram_factory import factory
|
||||
from globals import OPTS
|
||||
|
||||
|
||||
class precharge_array(design.design):
|
||||
class precharge_array(design):
|
||||
"""
|
||||
Dynamically generated precharge array of all bitlines. Cols is number
|
||||
of bit line columns, height is the height of the bit-cell array.
|
||||
|
|
|
|||
|
|
@ -5,15 +5,14 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import contact
|
||||
import pgate
|
||||
from .pgate import *
|
||||
import debug
|
||||
from tech import drc, parameter, spice
|
||||
from vector import vector
|
||||
from base import vector
|
||||
from sram_factory import factory
|
||||
|
||||
|
||||
class ptristate_inv(pgate.pgate):
|
||||
class ptristate_inv(pgate):
|
||||
"""
|
||||
ptristate generates gds of a parametrically sized tristate inverter.
|
||||
There is some flexibility in the size, but we do not allow multiple fingers
|
||||
|
|
@ -131,8 +130,8 @@ class ptristate_inv(pgate.pgate):
|
|||
"""
|
||||
|
||||
pmos_yoff = self.height - self.pmos.active_height \
|
||||
- self.top_bottom_space - 0.5 * contact.active_contact.height
|
||||
nmos_yoff = self.top_bottom_space + 0.5 * contact.active_contact.height
|
||||
- self.top_bottom_space - 0.5 * self.active_contact.height
|
||||
nmos_yoff = self.top_bottom_space + 0.5 * self.active_contact.height
|
||||
|
||||
# Tristate transistors
|
||||
pmos1_pos = vector(self.pmos.active_offset.x, pmos_yoff)
|
||||
|
|
@ -188,16 +187,16 @@ class ptristate_inv(pgate.pgate):
|
|||
|
||||
drain_pos = self.nmos1_inst.get_pin("S").center()
|
||||
vdd_pos = self.get_pin("vdd").center()
|
||||
self.nwell_contact = self.add_via_center(layers=layer_stack,
|
||||
offset=vector(drain_pos.x, vdd_pos.y),
|
||||
implant_type="n",
|
||||
well_type="n")
|
||||
self.add_via_center(layers=layer_stack,
|
||||
offset=vector(drain_pos.x, vdd_pos.y),
|
||||
implant_type="n",
|
||||
well_type="n")
|
||||
|
||||
gnd_pos = self.get_pin("gnd").center()
|
||||
self.pwell_contact = self.add_via_center(layers=layer_stack,
|
||||
offset=vector(drain_pos.x, gnd_pos.y),
|
||||
implant_type="p",
|
||||
well_type="p")
|
||||
self.add_via_center(layers=layer_stack,
|
||||
offset=vector(drain_pos.x, gnd_pos.y),
|
||||
implant_type="p",
|
||||
well_type="p")
|
||||
|
||||
def connect_rails(self):
|
||||
""" Connect the nmos and pmos to its respective power rails """
|
||||
|
|
@ -5,18 +5,17 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import design
|
||||
import debug
|
||||
from base import design
|
||||
from base import logical_effort
|
||||
from base import vector
|
||||
from tech import layer, drc, spice
|
||||
from vector import vector
|
||||
from sram_factory import factory
|
||||
import contact
|
||||
import logical_effort
|
||||
from globals import OPTS
|
||||
from tech import cell_properties as cell_props
|
||||
|
||||
|
||||
class ptx(design.design):
|
||||
class ptx(design):
|
||||
"""
|
||||
This module generates gds and spice of a parametrically NMOS or
|
||||
PMOS sized transistor. Pins are accessed as D, G, S, B. Width is
|
||||
|
|
@ -198,12 +197,12 @@ class ptx(design.design):
|
|||
|
||||
# This is the extra poly spacing due to the poly contact to poly contact pitch
|
||||
# of contacted gates
|
||||
extra_poly_contact_width = contact.poly_contact.width - self.poly_width
|
||||
extra_poly_contact_width = self.poly_contact.width - self.poly_width
|
||||
|
||||
# This is the spacing between S/D contacts
|
||||
# This is the spacing between the poly gates
|
||||
self.min_poly_pitch = self.poly_space + self.poly_width
|
||||
self.contacted_poly_pitch = self.poly_space + contact.poly_contact.width
|
||||
self.contacted_poly_pitch = self.poly_space + self.poly_contact.width
|
||||
self.contact_pitch = 2 * self.active_contact_to_gate + self.poly_width + self.contact_width
|
||||
self.poly_pitch = max(self.min_poly_pitch,
|
||||
self.contacted_poly_pitch,
|
||||
|
|
@ -487,11 +486,11 @@ class ptx(design.design):
|
|||
# FIXME: Using the same definition as the pinv.py.
|
||||
parasitic_delay = 1
|
||||
size = self.mults * self.tx_width / drc("minwidth_tx")
|
||||
return logical_effort.logical_effort(self.name,
|
||||
size,
|
||||
self.input_load(),
|
||||
cout,
|
||||
parasitic_delay)
|
||||
return logical_effort(self.name,
|
||||
size,
|
||||
self.input_load(),
|
||||
cout,
|
||||
parasitic_delay)
|
||||
|
||||
def input_load(self):
|
||||
"""
|
||||
|
|
@ -5,15 +5,15 @@
|
|||
#(acting for and on behalf of Oklahoma State University)
|
||||
#All rights reserved.
|
||||
#
|
||||
import design
|
||||
from base import design
|
||||
from tech import parameter
|
||||
import debug
|
||||
from vector import vector
|
||||
from base import vector
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
|
||||
|
||||
class pwrite_driver(design.design):
|
||||
class pwrite_driver(design):
|
||||
"""
|
||||
The pwrite_driver is two tristate inverters that drive the bitlines.
|
||||
The data input is first inverted before one tristate.
|
||||
|
|
@ -6,13 +6,13 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
import bitcell_base
|
||||
from .bitcell_base import bitcell_base
|
||||
from tech import cell_properties as props
|
||||
from tech import parameter, drc
|
||||
import logical_effort
|
||||
from base import logical_effort
|
||||
|
||||
|
||||
class replica_bitcell_1port(bitcell_base.bitcell_base):
|
||||
class replica_bitcell_1port(bitcell_base):
|
||||
"""
|
||||
A single bit cell (6T, 8T, etc.)
|
||||
This module implements the single memory cell used in the design. It
|
||||
|
|
@ -28,7 +28,7 @@ class replica_bitcell_1port(bitcell_base.bitcell_base):
|
|||
size = 0.5 # This accounts for bitline being drained thought the access TX and internal node
|
||||
cin = 3 # Assumes always a minimum sizes inverter. Could be specified in the tech.py file.
|
||||
read_port_load = 0.5 # min size NMOS gate load
|
||||
return logical_effort.logical_effort('bitline', size, cin, load + read_port_load, parasitic_delay, False)
|
||||
return logical_effort('bitline', size, cin, load + read_port_load, parasitic_delay, False)
|
||||
|
||||
def input_load(self):
|
||||
"""Return the relative capacitance of the access transistor gates"""
|
||||
|
|
@ -52,4 +52,4 @@ class replica_bitcell_1port(bitcell_base.bitcell_base):
|
|||
def is_non_inverting(self):
|
||||
"""Return input to output polarity for module"""
|
||||
|
||||
return False
|
||||
return False
|
||||
|
|
@ -6,13 +6,13 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
import bitcell_base
|
||||
from .bitcell_base import bitcell_base
|
||||
from tech import cell_properties as props
|
||||
from tech import parameter, drc
|
||||
import logical_effort
|
||||
from base import logical_effort
|
||||
|
||||
|
||||
class replica_bitcell_2port(bitcell_base.bitcell_base):
|
||||
class replica_bitcell_2port(bitcell_base):
|
||||
"""
|
||||
A single bit cell which is forced to store a 0.
|
||||
This module implements the single memory cell used in the design. It
|
||||
|
|
@ -28,7 +28,7 @@ class replica_bitcell_2port(bitcell_base.bitcell_base):
|
|||
size = 0.5 # This accounts for bitline being drained thought the access TX and internal node
|
||||
cin = 3 # Assumes always a minimum sizes inverter. Could be specified in the tech.py file.
|
||||
read_port_load = 0.5 # min size NMOS gate load
|
||||
return logical_effort.logical_effort('bitline', size, cin, load + read_port_load, parasitic_delay, False)
|
||||
return logical_effort('bitline', size, cin, load + read_port_load, parasitic_delay, False)
|
||||
|
||||
def input_load(self):
|
||||
"""Return the relative capacitance of the access transistor gates"""
|
||||
|
|
@ -53,4 +53,4 @@ class replica_bitcell_2port(bitcell_base.bitcell_base):
|
|||
def is_non_inverting(self):
|
||||
"""Return input to output polarity for module"""
|
||||
|
||||
return False
|
||||
return False
|
||||
|
|
@ -5,12 +5,11 @@
|
|||
#
|
||||
|
||||
import debug
|
||||
from bitcell_base_array import bitcell_base_array
|
||||
from pbitcell import pbitcell
|
||||
from contact import contact
|
||||
from tech import drc, spice, preferred_directions
|
||||
from base import vector
|
||||
from base import contact
|
||||
from .bitcell_base_array import bitcell_base_array
|
||||
from tech import drc, spice
|
||||
from tech import cell_properties as props
|
||||
from vector import vector
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
from bitcell_base_array import bitcell_base_array
|
||||
from .bitcell_base_array import bitcell_base_array
|
||||
from sram_factory import factory
|
||||
from vector import vector
|
||||
from base import vector
|
||||
from globals import OPTS
|
||||
from tech import layer_properties as layer_props
|
||||
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
import design
|
||||
from vector import vector
|
||||
from base import design
|
||||
from base import vector
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
|
||||
|
||||
class replica_pbitcell(design.design):
|
||||
class replica_pbitcell(design):
|
||||
"""
|
||||
Creates a replica bitcell using pbitcell
|
||||
"""
|
||||
|
|
@ -25,7 +25,7 @@ class replica_pbitcell(design.design):
|
|||
self.num_r_ports = OPTS.num_r_ports
|
||||
self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports
|
||||
|
||||
design.design.__init__(self, name, cell_name)
|
||||
design.__init__(self, name, cell_name)
|
||||
debug.info(1, "create a replica bitcell using pbitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports,
|
||||
self.num_w_ports,
|
||||
self.num_r_ports))
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
# Copyright (c) 2016-2021 Regents of the University of California
|
||||
# All rights reserved.
|
||||
#
|
||||
from bitcell_base_array import bitcell_base_array
|
||||
from .bitcell_base_array import bitcell_base_array
|
||||
from sram_factory import factory
|
||||
from globals import OPTS
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@
|
|||
#
|
||||
import debug
|
||||
from tech import cell_properties as props
|
||||
import bitcell_base
|
||||
from .bitcell_base import bitcell_base
|
||||
|
||||
|
||||
class row_cap_bitcell_1port(bitcell_base.bitcell_base):
|
||||
class row_cap_bitcell_1port(bitcell_base):
|
||||
"""
|
||||
Row end cap cell.
|
||||
"""
|
||||
|
|
@ -7,10 +7,10 @@
|
|||
#
|
||||
import debug
|
||||
from tech import cell_properties as props
|
||||
import bitcell_base
|
||||
from .bitcell_base import bitcell_base
|
||||
|
||||
|
||||
class row_cap_bitcell_2port(bitcell_base.bitcell_base):
|
||||
class row_cap_bitcell_2port(bitcell_base):
|
||||
"""
|
||||
Row end cap cell.
|
||||
"""
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue