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:
mrg 2022-07-13 10:57:56 -07:00
parent 58ea148d47
commit d92c7a634d
388 changed files with 1450 additions and 1391 deletions

View File

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

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

@ -0,0 +1,21 @@
from .channel_route import *
from .contact import *
from .delay_data import *
from .design import *
from .errors import *
from .geometry import *
from .hierarchy_design import *
from .hierarchy_layout import *
from .hierarchy_spice import *
from .lef import *
from .logical_effort import *
from .pin_layout import *
from .power_data import *
from .route import *
from .timing_graph import *
from .utils import *
from .vector import *
from .verilog import *
from .wire_path import *
from .wire import *
from .wire_spice_model import *

View File

@ -8,8 +8,8 @@
import collections
import 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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']

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

@ -0,0 +1,6 @@
from .custom_cell_properties import *
from .custom_layer_properties import *
from .design_rules import *
from .module_type import *
from .drc_lut import *
from .drc_value import *

View File

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

View File

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

View File

@ -0,0 +1,82 @@
from .and2_dec import *
from .and3_dec import *
from .and4_dec import *
from .bank import *
from .bitcell_1port import *
from .bitcell_2port import *
from .bitcell_array import *
from .bitcell_base_array import *
from .bitcell_base import *
from .col_cap_array import *
from .col_cap_bitcell_1port import *
from .col_cap_bitcell_2port import *
from .column_decoder import *
from .column_mux_array import *
from .column_mux import *
from .control_logic import *
from .delay_chain import *
from .dff_array import *
from .dff_buf_array import *
from .dff_buf import *
from .dff_inv_array import *
from .dff_inv import *
from .dff import *
from .dummy_array import *
from .dummy_bitcell_1port import *
from .dummy_bitcell_2port import *
from .dummy_pbitcell import *
from .global_bitcell_array import *
from .hierarchical_decoder import *
from .hierarchical_predecode2x4 import *
from .hierarchical_predecode3x8 import *
from .hierarchical_predecode4x16 import *
from .hierarchical_predecode import *
from .inv_dec import *
from .local_bitcell_array import *
from .nand2_dec import *
from .nand3_dec import *
from .nand4_dec import *
from .orig_bitcell_array import *
from .pand2 import *
from .pand3 import *
from .pand4 import *
from .pbitcell import *
from .pbuf_dec import *
from .pbuf import *
from .pdriver import *
from .pgate import *
from .pinvbuf import *
from .pinv_dec import *
from .pinv import *
from .pnand2 import *
from .pnand3 import *
from .pnand4 import *
from .pnor2 import *
from .port_address import *
from .port_data import *
from .precharge_array import *
from .precharge import *
from .ptristate_inv import *
from .ptx import *
from .pwrite_driver import *
from .replica_bitcell_1port import *
from .replica_bitcell_2port import *
from .replica_bitcell_array import *
from .replica_column import *
from .replica_pbitcell import *
from .row_cap_array import *
from .row_cap_bitcell_1port import *
from .row_cap_bitcell_2port import *
from .sense_amp_array import *
from .sense_amp import *
from .tri_gate_array import *
from .tri_gate import *
from .wordline_buffer_array import *
from .wordline_driver_array import *
from .wordline_driver import *
from .write_driver_array import *
from .write_driver import *
from .write_mask_and_array import *
from .sram_1bank import *
from .sram_config import *
from .sram import *

View File

@ -6,20 +6,20 @@
# All rights reserved.
#
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))

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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