diff --git a/.coveragerc b/.coveragerc
index 0df8ae34..df762ed7 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -8,6 +8,8 @@ omit =
*/tests/*
# ignore the debug utilities
debug.py
+ # ignore the no DRC/LVS tool options
+ none.py
[paths]
source =
../..
@@ -21,6 +23,8 @@ source =
exclude_lines =
pragma: no cover
def __repr__
+ def __str__
+ class gdsStreamer
except Exception
raise AssertionError
raise NotImplementedError
diff --git a/OpenRAM_ICCAD_2016_presentation.pdf b/OpenRAM_ICCAD_2016_presentation.pdf
deleted file mode 100644
index 0575e52b..00000000
Binary files a/OpenRAM_ICCAD_2016_presentation.pdf and /dev/null differ
diff --git a/README.md b/README.md
index d6a5b581..961c6272 100644
--- a/README.md
+++ b/README.md
@@ -4,13 +4,13 @@
[](./LICENSE)
Master:
-[](https://github.com/VLSIDA/OpenRAM/commits/master)
-
+%[](https://github.com/VLSIDA/OpenRAM/commits/master)
+
[](https://github.com/VLSIDA/OpenRAM/archive/master.zip)
Dev:
-[](https://github.com/VLSIDA/OpenRAM/commits/dev)
-
+[](https://github.com/VLSIDA/OpenRAM/commits/dev)
+
[](https://github.com/VLSIDA/OpenRAM/archive/dev.zip)
An open-source static random access memory (SRAM) compiler.
@@ -24,6 +24,13 @@ other views necessary to use SRAMs in ASIC design. OpenRAM supports
integration in both commercial and open-source flows with both
predictive and fabricable technologies.
+# Documentation
+
+Please take a look at our presentation We have created a detailed
+presentation that serves as our [documentation][documentation].
+This is the most up-to-date information, so please let us know if you see
+things that need to be fixed.
+
# Basic Setup
## Docker Image
@@ -67,7 +74,7 @@ You may also wish to add OPENRAM\_HOME to your PYTHONPATH:
export PYTHONPATH="$PYTHONPATH:$OPENRAM_HOME"
```
-We include the tech files necessary for [FreePDK45] and [SCMOS]
+We include the tech files necessary for [SCMOS]
SCN4M_SUBM. The [SCMOS] spice models, however, are generic and should
be replaced with foundry models. If you are using [FreePDK45], you
should also have that set up and have the environment variable point
@@ -196,6 +203,7 @@ Each specific technology (e.g., [FreePDK45]) should be a subdirectory
# Further Help
+ [Additional hints](./HINTS.md)
++ [Documentation][documentation]
+ [OpenRAM Slack Workspace][Slack]
+ [OpenRAM Users Group][user-group] ([subscribe here][user-group-subscribe])
+ [OpenRAM Developers Group][dev-group] ([subscribe here][dev-group-subscribe])
@@ -232,7 +240,7 @@ If I forgot to add you, please let me know!
[Github pull request]: https://github.com/VLSIDA/OpenRAM/pulls
[Github projects]: https://github.com/VLSIDA/OpenRAM/projects
-[email me]: mailto:mrg+openram@ucsc.edu
+[documentation]: https://docs.google.com/presentation/d/10InGB33N51I6oBHnqpU7_w9DXlx-qe9zdrlco2Yc5co/edit?usp=sharing
[dev-group]: mailto:openram-dev-group@ucsc.edu
[user-group]: mailto:openram-user-group@ucsc.edu
[dev-group-subscribe]: mailto:openram-dev-group+subscribe@ucsc.edu
diff --git a/compiler/base/contact.py b/compiler/base/contact.py
index 39cb7b52..be3af1ce 100644
--- a/compiler/base/contact.py
+++ b/compiler/base/contact.py
@@ -1,7 +1,14 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import hierarchy_design
import debug
import utils
-from tech import drc
+from tech import drc,layer
from vector import vector
@@ -9,44 +16,36 @@ class contact(hierarchy_design.hierarchy_design):
"""
Object for a contact shape with its conductor enclosures.
Creates a contact array minimum active or poly enclosure and metal1 enclosure.
- This class has enclosure on multiple sides of the contact whereas a via may
- have extension on two or four sides.
+ This class has enclosure on two or four sides of the contact.
+ The direction specifies whether the first and second layer have asymmetric extension in the H or V direction.
+
The well/implant_type is an option to add a select/implant layer enclosing the contact. This is
necessary to import layouts into Magic which requires the select to be in the same GDS
hierarchy as the contact.
"""
- def __init__(self, layer_stack, dimensions=[1,1], implant_type=None, well_type=None, name=""):
+ def __init__(self, layer_stack, dimensions=(1,1), directions=("V","V"), implant_type=None, well_type=None, name=""):
# This will ignore the name parameter since we can guarantee a unique name here
- if implant_type or well_type:
- name = "{0}_{1}_{2}_{3}x{4}_{5}{6}".format(layer_stack[0],
- layer_stack[1],
- layer_stack[2],
- dimensions[0],
- dimensions[1],
- implant_type,
- well_type)
-
- else:
- name = "{0}_{1}_{2}_{3}x{4}".format(layer_stack[0],
- layer_stack[1],
- layer_stack[2],
- dimensions[0],
- dimensions[1])
-
hierarchy_design.hierarchy_design.__init__(self, name)
debug.info(4, "create contact object {0}".format(name))
-
+ self.add_comment("layers: {0}".format(layer_stack))
+ self.add_comment("dimensions: {0}".format(dimensions))
+ if implant_type or well_type:
+ self.add_comment("implant type: {0}\nwell_type: {1}".format(implant_type,well_type))
+
self.layer_stack = layer_stack
self.dimensions = dimensions
+ self.directions = directions
self.offset = vector(0,0)
self.implant_type = implant_type
self.well_type = well_type
- self.pins = [] # used for matching parm lengths
+ # Module does not have pins, but has empty pin list.
+ self.pins = []
self.create_layout()
def create_layout(self):
+
self.setup_layers()
self.setup_layout_constants()
self.create_contact_array()
@@ -63,6 +62,8 @@ class contact(hierarchy_design.hierarchy_design):
debug.error(-1,"Must define both implant and well type or none at all.")
def setup_layers(self):
+ """ Locally assign the layer names. """
+
(first_layer, via_layer, second_layer) = self.layer_stack
self.first_layer_name = first_layer
self.via_layer_name = via_layer
@@ -75,37 +76,58 @@ class contact(hierarchy_design.hierarchy_design):
self.second_layer_name = second_layer
def setup_layout_constants(self):
+ """ Determine the design rules for the enclosure layers """
+
self.contact_width = drc("minwidth_{0}". format(self.via_layer_name))
contact_to_contact = drc("{0}_to_{0}".format(self.via_layer_name))
self.contact_pitch = self.contact_width + contact_to_contact
+
self.contact_array_width = self.contact_width + (self.dimensions[0] - 1) * self.contact_pitch
self.contact_array_height = self.contact_width + (self.dimensions[1] - 1) * self.contact_pitch
# DRC rules
+ # The extend rule applies to asymmetric enclosures in one direction.
+ # The enclosure rule applies to symmetric enclosure component.
+
first_layer_minwidth = drc("minwidth_{0}".format(self.first_layer_name))
- first_layer_minarea = drc("minarea_{0}".format(self.first_layer_name))
first_layer_enclosure = drc("{0}_enclosure_{1}".format(self.first_layer_name, self.via_layer_name))
first_layer_extend = drc("{0}_extend_{1}".format(self.first_layer_name, self.via_layer_name))
+
second_layer_minwidth = drc("minwidth_{0}".format(self.second_layer_name))
- second_layer_minarea = drc("minarea_{0}".format(self.second_layer_name))
second_layer_enclosure = drc("{0}_enclosure_{1}".format(self.second_layer_name, self.via_layer_name))
second_layer_extend = drc("{0}_extend_{1}".format(self.second_layer_name, self.via_layer_name))
- self.first_layer_horizontal_enclosure = max((first_layer_minwidth - self.contact_array_width) / 2,
- first_layer_enclosure)
- self.first_layer_vertical_enclosure = max(utils.ceil((first_layer_minarea
- / (self.contact_array_width + 2*self.first_layer_horizontal_enclosure)
- - self.contact_array_height)/2),
- (first_layer_minwidth - self.contact_array_height)/2,
- first_layer_extend)
- self.second_layer_horizontal_enclosure = max((second_layer_minwidth - self.contact_array_width)/2,
- second_layer_enclosure)
- self.second_layer_vertical_enclosure = max(utils.ceil((second_layer_minarea
- / (self.contact_array_width + 2*self.second_layer_horizontal_enclosure)
- - self.contact_array_height)/2),
- (second_layer_minwidth - self.contact_array_height)/2,
- second_layer_extend)
+ # In some technologies, the minimum width may be larger than the overlap requirement around the via, so
+ # check this for each dimension.
+ if self.directions[0] == "V":
+ self.first_layer_horizontal_enclosure = max(first_layer_enclosure,
+ (first_layer_minwidth - self.contact_array_width)/2)
+ self.first_layer_vertical_enclosure = max(first_layer_extend,
+ (first_layer_minwidth - self.contact_array_height)/2)
+ elif self.directions[0] == "H":
+ self.first_layer_horizontal_enclosure = max(first_layer_extend,
+ (first_layer_minwidth - self.contact_array_width)/2)
+ self.first_layer_vertical_enclosure = max(first_layer_enclosure,
+ (first_layer_minwidth - self.contact_array_height)/2)
+ else:
+ debug.error("Invalid first layer direction.", -1)
+
+ # In some technologies, the minimum width may be larger than the overlap requirement around the via, so
+ # check this for each dimension.
+ if self.directions[1] == "V":
+ self.second_layer_horizontal_enclosure = max(second_layer_enclosure,
+ (second_layer_minwidth - self.contact_array_width)/2)
+ self.second_layer_vertical_enclosure = max(second_layer_extend,
+ (second_layer_minwidth - self.contact_array_height)/2)
+ elif self.directions[1] == "H":
+ self.second_layer_horizontal_enclosure = max(second_layer_extend,
+ (second_layer_minwidth - self.contact_array_height)/2)
+ self.second_layer_vertical_enclosure = max(second_layer_enclosure,
+ (second_layer_minwidth - self.contact_array_width)/2)
+ else:
+ debug.error("Invalid second layer direction.", -1)
+
def create_contact_array(self):
""" Create the contact array at the origin"""
@@ -169,10 +191,13 @@ class contact(hierarchy_design.hierarchy_design):
from sram_factory import factory
# This is not instantiated and used for calculations only.
# These are static 1x1 contacts to reuse in all the design modules.
-well = factory.create(module_type="contact", layer_stack=("active", "contact", "metal1"))
-active = factory.create(module_type="contact", layer_stack=("active", "contact", "poly"))
-poly = factory.create(module_type="contact", layer_stack=("poly", "contact", "metal1"))
-m1m2 = factory.create(module_type="contact", layer_stack=("metal1", "via1", "metal2"))
-m2m3 = factory.create(module_type="contact", layer_stack=("metal2", "via2", "metal3"))
-m3m4 = factory.create(module_type="contact", layer_stack=("metal3", "via3", "metal4"))
+well = factory.create(module_type="contact", layer_stack=("active", "contact", "metal1"), directions=("H","V"))
+active = factory.create(module_type="contact", layer_stack=("active", "contact", "metal1"), directions=("H","V"))
+poly = factory.create(module_type="contact", layer_stack=("poly", "contact", "metal1"), directions=("V","H"))
+m1m2 = factory.create(module_type="contact", layer_stack=("metal1", "via1", "metal2"), directions=("H","V"))
+m2m3 = factory.create(module_type="contact", layer_stack=("metal2", "via2", "metal3"), directions=("V","H"))
+if "metal4" in layer.keys():
+ m3m4 = factory.create(module_type="contact", layer_stack=("metal3", "via3", "metal4"), directions=("H","V"))
+else:
+ m3m4 = None
diff --git a/compiler/base/delay_data.py b/compiler/base/delay_data.py
new file mode 100644
index 00000000..e3d5a8bc
--- /dev/null
+++ b/compiler/base/delay_data.py
@@ -0,0 +1,43 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+
+class delay_data():
+ """
+ This is the delay class to represent the delay information
+ Time is 50% of the signal to 50% of reference signal delay.
+ Slew is the 10% of the signal to 90% of signal
+ """
+ def __init__(self, delay=0.0, slew=0.0):
+ """ init function support two init method"""
+ # will take single input as a coordinate
+ self.delay = delay
+ self.slew = slew
+
+ def __str__(self):
+ """ override print function output """
+ return "Delay Data: Delay "+str(self.delay)+", Slew "+str(self.slew)+""
+
+ def __add__(self, other):
+ """
+ Override - function (left), for delay_data: a+b != b+a
+ """
+ assert isinstance(other,delay_data)
+ return delay_data(other.delay + self.delay,
+ other.slew)
+
+ def __radd__(self, other):
+ """
+ Override - function (right), for delay_data: a+b != b+a
+ """
+ assert isinstance(other,delay_data)
+ return delay_data(other.delay + self.delay,
+ self.slew)
+
+
+
+
diff --git a/compiler/base/design.py b/compiler/base/design.py
index 4e76b40a..da23aa9e 100644
--- a/compiler/base/design.py
+++ b/compiler/base/design.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
from hierarchy_design import hierarchy_design
import contact
import globals
@@ -19,13 +26,17 @@ class design(hierarchy_design):
self.setup_drc_constants()
self.setup_multiport_constants()
+ from tech import layer
self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(self.m1_space, self.m2_space)
self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(self.m2_space, self.m3_space)
- self.m3_pitch = max(contact.m3m4.width,contact.m3m4.height) + max(self.m3_space, self.m4_space)
+ if "metal4" in layer:
+ self.m3_pitch = max(contact.m3m4.width,contact.m3m4.height) + max(self.m3_space, self.m4_space)
+ else:
+ self.m3_pitch = self.m2_pitch
def setup_drc_constants(self):
""" These are some DRC constants used in many places in the compiler."""
- from tech import drc
+ from tech import drc,layer
self.well_width = drc("minwidth_well")
self.poly_width = drc("minwidth_poly")
self.poly_space = drc("poly_to_poly")
@@ -35,8 +46,9 @@ class design(hierarchy_design):
self.m2_space = drc("metal2_to_metal2")
self.m3_width = drc("minwidth_metal3")
self.m3_space = drc("metal3_to_metal3")
- self.m4_width = drc("minwidth_metal4")
- self.m4_space = drc("metal4_to_metal4")
+ if "metal4" in layer:
+ self.m4_width = drc("minwidth_metal4")
+ self.m4_space = drc("metal4_to_metal4")
self.active_width = drc("minwidth_active")
self.active_space = drc("active_to_body_active")
self.contact_width = drc("minwidth_contact")
@@ -86,8 +98,8 @@ class design(hierarchy_design):
for port in range(OPTS.num_r_ports):
self.read_ports.append(port_number)
self.readonly_ports.append(port_number)
- port_number += 1
-
+ port_number += 1
+
def analytical_power(self, corner, load):
""" Get total power of a module """
total_module_power = self.return_power()
@@ -95,13 +107,3 @@ class design(hierarchy_design):
total_module_power += inst.mod.analytical_power(corner, load)
return total_module_power
- def __str__(self):
- """ override print function output """
- pins = ",".join(self.pins)
- insts = [" {}".format(x) for x in self.insts]
- objs = [" {}".format(x) for x in self.objs]
- s = "********** design {0} **********\n".format(self.name)
- s += "\n pins ({0})={1}\n".format(len(self.pins), pins)
- s += "\n objs ({0})=\n{1}".format(len(self.objs), "\n".join(objs))
- s += "\n insts ({0})=\n{1}\n".format(len(self.insts), "\n".join(insts))
- return s
diff --git a/compiler/base/geometry.py b/compiler/base/geometry.py
index 838828df..7063cf81 100644
--- a/compiler/base/geometry.py
+++ b/compiler/base/geometry.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
"""
This provides a set of useful generic types for the gdsMill interface.
"""
@@ -158,7 +165,7 @@ class instance(geometry):
debug.info(4, "creating instance: " + self.name)
def get_blockages(self, layer, top=False):
- """ Retrieve rectangular blockages of all modules in this instance.
+ """ Retrieve blockages of all modules in this instance.
Apply the transform of the instance placement to give absolute blockages."""
angle = math.radians(float(self.rotate))
mirr = 1
@@ -176,21 +183,20 @@ class instance(geometry):
elif self.mirror=="XY":
mirr = 1
angle += math.radians(180.0)
-
- if self.mod.is_library_cell:
- # For lib cells, block the whole thing except on metal3
- # since they shouldn't use metal3
- if layer==tech.layer["metal1"] or layer==tech.layer["metal2"]:
- return [self.transform_coords(self.mod.get_boundary(), self.offset, mirr, angle)]
- else:
- return []
- else:
- blockages = self.mod.get_blockages(layer)
- new_blockages = []
+ new_blockages = []
+ if self.mod.is_library_cell:
+ # Writes library cell blockages as shapes instead of a large metal blockage
+ blockages = []
+ blockages = self.mod.gds.getBlockages(layer)
for b in blockages:
new_blockages.append(self.transform_coords(b,self.offset, mirr, angle))
- return new_blockages
+ else:
+ blockages = self.mod.get_blockages(layer)
+ for b in blockages:
+ new_blockages.append(self.transform_coords(b,self.offset, mirr, angle))
+ return new_blockages
+
def gds_write_file(self, new_layout):
"""Recursively writes all the sub-modules in this instance"""
@@ -371,8 +377,8 @@ class rectangle(geometry):
def __str__(self):
""" override print function output """
- return "rect: @" + str(self.offset) + " " + str(self.width) + "x" + str(self.height) + " layer=" +str(self.layerNumber)
+ return self.__repr__()
def __repr__(self):
""" override print function output """
- return "( rect: @" + str(self.offset) + " " + str(self.width) + "x" + str(self.height) + " layer=" + str(self.layerNumber) + " )"
+ return "( rect: @" + str(self.offset) + " WxH=" + str(self.width) + "x" + str(self.height) + " layer=" + str(self.layerNumber) + " )"
diff --git a/compiler/base/graph_util.py b/compiler/base/graph_util.py
new file mode 100644
index 00000000..5d1ee692
--- /dev/null
+++ b/compiler/base/graph_util.py
@@ -0,0 +1,130 @@
+import os, copy
+from collections import defaultdict
+
+import gdsMill
+import tech
+import math
+import globals
+import debug
+from vector import vector
+from pin_layout import pin_layout
+
+class timing_graph():
+ """
+ Implements a directed graph
+ Nodes are currently just Strings.
+ """
+
+ def __init__(self):
+ self.graph = defaultdict(set)
+ self.all_paths = []
+ self.edge_mods = {}
+
+ def add_edge(self, src_node, dest_node, edge_mod):
+ """Adds edge to graph. Nodes added as well if they do not exist.
+ Module which defines the edge must be provided for timing information."""
+
+ src_node = src_node.lower()
+ dest_node = dest_node.lower()
+ self.graph[src_node].add(dest_node)
+ self.edge_mods[(src_node, dest_node)] = edge_mod
+
+ def add_node(self, node):
+ """Add node to graph with no edges"""
+
+ node = node.lower()
+ if not node in self.graph:
+ self.graph[node] = set()
+
+ def remove_edges(self, node):
+ """Helper function to remove edges, useful for removing vdd/gnd"""
+
+ node = node.lower()
+ self.graph[node] = set()
+
+ def get_all_paths(self, src_node, dest_node, remove_rail_nodes=True, reduce_paths=True):
+ """Traverse all paths from source to destination"""
+
+ src_node = src_node.lower()
+ dest_node = dest_node.lower()
+
+ # Remove vdd and gnd by default
+ # Will require edits if separate supplies are implemented.
+ if remove_rail_nodes:
+ # Names are also assumed.
+ self.remove_edges('vdd')
+ self.remove_edges('gnd')
+
+ # Mark all the vertices as not visited
+ visited = set()
+
+ # Create an array to store paths
+ path = []
+ self.all_paths = []
+
+ # Call the recursive helper function to print all paths
+ self.get_all_paths_util(src_node, dest_node, visited, path)
+ debug.info(2, "Paths found={}".format(len(self.all_paths)))
+
+ if reduce_paths:
+ self.reduce_paths()
+
+ return self.all_paths
+
+ def reduce_paths(self):
+ """ Remove any path that is a subset of another path """
+
+ self.all_paths = [p1 for p1 in self.all_paths if not any(set(p1)<=set(p2) for p2 in self.all_paths if p1 is not p2)]
+
+ def get_all_paths_util(self, cur_node, dest_node, visited, path):
+ """Recursive function to find all paths in a Depth First Search manner"""
+
+ # Mark the current node as visited and store in path
+ visited.add(cur_node)
+ path.append(cur_node)
+
+ # If current vertex is same as destination, then print
+ # current path[]
+ if cur_node == dest_node:
+ self.all_paths.append(copy.deepcopy(path))
+ else:
+ # If current vertex is not destination
+ # Recur for all the vertices adjacent to this vertex
+ for node in self.graph[cur_node]:
+ if node not in visited:
+ self.get_all_paths_util(node, dest_node, visited, path)
+
+ # Remove current vertex from path[] and mark it as unvisited
+ path.pop()
+ visited.remove(cur_node)
+
+ def get_timing(self, path, corner, slew, load):
+ """Returns the analytical delays in the input path"""
+
+ if len(path) == 0:
+ return []
+
+ delays = []
+ cur_slew = slew
+ for i in range(len(path)-1):
+
+ path_edge_mod = self.edge_mods[(path[i], path[i+1])]
+
+ # On the output of the current stage, get COUT from all other mods connected
+ cout = 0
+ for node in self.graph[path[i+1]]:
+ output_edge_mod = self.edge_mods[(path[i+1], node)]
+ cout+=output_edge_mod.get_cin()
+ # If at the last output, include the final output load
+ if i == len(path)-2:
+ cout+=load
+
+ delays.append(path_edge_mod.analytical_delay(corner, slew, cout))
+ cur_slew = delays[-1].slew
+
+ return delays
+
+ def __str__(self):
+ """ override print function output """
+
+ return "Nodes: {}\nEdges:{} ".format(list(self.graph), self.graph)
diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py
index 1dc052e3..e4c77987 100644
--- a/compiler/base/hierarchy_design.py
+++ b/compiler/base/hierarchy_design.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import hierarchy_layout
import hierarchy_spice
import globals
@@ -5,6 +12,7 @@ import verify
import debug
import os
from globals import OPTS
+import graph_util
total_drc_errors = 0
total_lvs_errors = 0
@@ -21,37 +29,10 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp"
self.name = name
- hierarchy_layout.layout.__init__(self, name)
hierarchy_spice.spice.__init__(self, name)
-
+ hierarchy_layout.layout.__init__(self, name)
+ self.init_graph_params()
- # Check if the name already exists, if so, give an error
- # because each reference must be a unique name.
- # These modules ensure unique names or have no changes if they
- # aren't unique
- ok_list = ['contact',
- 'ptx',
- 'pbitcell',
- 'replica_pbitcell',
- 'sram',
- 'hierarchical_predecode2x4',
- 'hierarchical_predecode3x8']
-
- # Library cells don't change
- if self.is_library_cell:
- return
- # Name is unique so far
- elif name not in hierarchy_design.name_map:
- hierarchy_design.name_map.append(name)
- else:
- # Name is in our list of exceptions (they don't change)
- for ok_names in ok_list:
- if ok_names == self.__class__.__name__:
- break
- else:
- debug.error("Duplicate layout reference name {0} of class {1}. GDS2 requires names be unique.".format(name,self.__class__),-1)
-
-
def get_layout_pins(self,inst):
""" Return a map of pin locations of the instance offset """
# find the instance
@@ -64,12 +45,17 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
return inst_map
- def DRC_LVS(self, final_verification=False):
+ def DRC_LVS(self, final_verification=False, top_level=False):
"""Checks both DRC and LVS for a module"""
+
+ # Final verification option does not allow nets to be connected by label.
# Unit tests will check themselves.
+ if OPTS.is_unit_test:
+ return
+ if not OPTS.check_lvsdrc:
+ return
# Do not run if disabled in options.
-
- if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
+ if (OPTS.inline_lvsdrc or top_level):
global total_drc_errors
global total_lvs_errors
@@ -78,8 +64,8 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
self.sp_write(tempspice)
self.gds_write(tempgds)
- num_drc_errors = verify.run_drc(self.name, tempgds, final_verification)
- num_lvs_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification)
+ num_drc_errors = verify.run_drc(self.name, tempgds, extract=True, final_verification=final_verification)
+ num_lvs_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification)
debug.check(num_drc_errors == 0,"DRC failed for {0} with {1} error(s)".format(self.name,num_drc_errors))
debug.check(num_lvs_errors == 0,"LVS failed for {0} with {1} errors(s)".format(self.name,num_lvs_errors))
total_drc_errors += num_drc_errors
@@ -97,7 +83,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
global total_drc_errors
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp,self.name)
self.gds_write(tempgds)
- num_errors = verify.run_drc(self.name, tempgds, final_verification)
+ num_errors = verify.run_drc(self.name, tempgds, final_verification=final_verification)
total_drc_errors += num_errors
debug.check(num_errors == 0,"DRC failed for {0} with {1} error(s)".format(self.name,num_error))
@@ -114,15 +100,137 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp,self.name)
self.sp_write(tempspice)
self.gds_write(tempgds)
- num_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification)
+ num_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification)
total_lvs_errors += num_errors
debug.check(num_errors == 0,"LVS failed for {0} with {1} error(s)".format(self.name,num_errors))
os.remove(tempspice)
- os.remove(tempgds)
+ os.remove(tempgds)
+
+ def init_graph_params(self):
+ """Initializes parameters relevant to the graph creation"""
+ #Only initializes a set for checking instances which should not be added
+ self.graph_inst_exclude = set()
+
+ def build_graph(self, graph, inst_name, port_nets):
+ """Recursively create graph from instances in module."""
+
+ #Translate port names to external nets
+ if len(port_nets) != len(self.pins):
+ debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,self.pins),1)
+ port_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
+ debug.info(3, "Instance name={}".format(inst_name))
+ for subinst, conns in zip(self.insts, self.conns):
+ if subinst in self.graph_inst_exclude:
+ continue
+ subinst_name = inst_name+'.X'+subinst.name
+ subinst_ports = self.translate_nets(conns, port_dict, inst_name)
+ subinst.mod.build_graph(graph, subinst_name, subinst_ports)
+
+ def build_names(self, name_dict, inst_name, port_nets):
+ """Collects all the nets and the parent inst of that net."""
+ #Translate port names to external nets
+ if len(port_nets) != len(self.pins):
+ debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets,self.pins),1)
+ port_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
+ debug.info(3, "Instance name={}".format(inst_name))
+ for subinst, conns in zip(self.insts, self.conns):
+ subinst_name = inst_name+'.X'+subinst.name
+ subinst_ports = self.translate_nets(conns, port_dict, inst_name)
+ for si_port, conn in zip(subinst_ports, conns):
+ #Only add for first occurrence
+ if si_port.lower() not in name_dict:
+ mod_info = {'mod':self, 'int_net':conn}
+ name_dict[si_port.lower()] = mod_info
+ subinst.mod.build_names(name_dict, subinst_name, subinst_ports)
+ def find_aliases(self, inst_name, port_nets, path_nets, alias, alias_mod, exclusion_set=None):
+ """Given a list of nets, will compare the internal alias of a mod to determine
+ if the nets have a connection to this mod's net (but not inst).
+ """
+ if exclusion_set == None:
+ exclusion_set = set()
+ try:
+ self.name_dict
+ except AttributeError:
+ self.name_dict = {}
+ self.build_names(self.name_dict, inst_name, port_nets)
+ aliases = []
+ for net in path_nets:
+ net = net.lower()
+ int_net = self.name_dict[net]['int_net']
+ int_mod = self.name_dict[net]['mod']
+ if int_mod.is_net_alias(int_net, alias, alias_mod, exclusion_set):
+ aliases.append(net)
+ return aliases
+
+ def is_net_alias(self, known_net, net_alias, mod, exclusion_set):
+ """Checks if the alias_net in input mod is the same as the input net for this mod (self)."""
+ if self in exclusion_set:
+ return False
+ #Check ports of this mod
+ for pin in self.pins:
+ if self.is_net_alias_name_check(known_net, pin, net_alias, mod):
+ return True
+ #Check connections of all other subinsts
+ mod_set = set()
+ for subinst, inst_conns in zip(self.insts, self.conns):
+ for inst_conn, mod_pin in zip(inst_conns, subinst.mod.pins):
+ if self.is_net_alias_name_check(known_net, inst_conn, net_alias, mod):
+ return True
+ elif inst_conn.lower() == known_net.lower() and subinst.mod not in mod_set:
+ if subinst.mod.is_net_alias(mod_pin, net_alias, mod, exclusion_set):
+ return True
+ mod_set.add(subinst.mod)
+ return False
+
+ def is_net_alias_name_check(self, parent_net, child_net, alias_net, mod):
+ """Utility function for checking single net alias."""
+ return self == mod and \
+ child_net.lower() == alias_net.lower() and \
+ parent_net.lower() == alias_net.lower()
+
+ def get_mod_net(self, parent_net, child_inst, child_conns):
+ """Given an instance and net, returns the internal net in the mod
+ corresponding to input net."""
+ for conn, pin in zip(child_conns, child_inst.mod.pins):
+ if parent_net.lower() == conn.lower():
+ return pin
+ return None
+
+ def translate_nets(self, subinst_ports, port_dict, inst_name):
+ """Converts connection names to their spice hierarchy equivalent"""
+ converted_conns = []
+ for conn in subinst_ports:
+ if conn in port_dict:
+ converted_conns.append(port_dict[conn])
+ else:
+ converted_conns.append("{}.{}".format(inst_name, conn))
+ return converted_conns
+
+ def add_graph_edges(self, graph, port_nets):
+ """For every input, adds an edge to every output.
+ Only intended to be used for gates and other simple modules."""
+ #The final pin names will depend on the spice hierarchy, so
+ #they are passed as an input.
+ pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
+ input_pins = self.get_inputs()
+ output_pins = self.get_outputs()
+ inout_pins = self.get_inouts()
+ for inp in input_pins+inout_pins:
+ for out in output_pins+inout_pins:
+ if inp != out: #do not add self loops
+ graph.add_edge(pin_dict[inp], pin_dict[out], self)
+
def __str__(self):
""" override print function output """
- return "design: " + self.name
+ pins = ",".join(self.pins)
+ insts = [" {}".format(x) for x in self.insts]
+ objs = [" {}".format(x) for x in self.objs]
+ s = "********** design {0} **********".format(self.name)
+ s += "\n pins ({0})={1}\n".format(len(self.pins), pins)
+ s += "\n objs ({0})=\n{1}\n".format(len(self.objs), "\n".join(objs))
+ s += "\n insts ({0})=\n{1}\n".format(len(self.insts), "\n".join(insts))
+ return s
def __repr__(self):
""" override print function output """
diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py
index 7c998176..2fea5c61 100644
--- a/compiler/base/hierarchy_layout.py
+++ b/compiler/base/hierarchy_layout.py
@@ -1,4 +1,12 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import itertools
+import collections
import geometry
import gdsMill
import debug
@@ -190,7 +198,8 @@ class layout():
debug.error("Should use a pin iterator since more than one pin {}".format(text),-1)
# If we have one pin, return it and not the list.
# Otherwise, should use get_pins()
- return self.pin_map[text][0]
+ any_pin = next(iter(self.pin_map[text]))
+ return any_pin
except Exception as e:
#print e
self.gds_write("missing_pin.gds")
@@ -205,19 +214,36 @@ class layout():
if text in self.pin_map.keys():
return self.pin_map[text]
else:
- return []
-
+ return set()
+
+ def get_pin_names(self):
+ """
+ Return a pin list of all pins
+ """
+ return self.pin_map.keys()
+
def copy_layout_pin(self, instance, pin_name, new_name=""):
"""
Create a copied version of the layout pin at the current level.
You can optionally rename the pin to a new name.
"""
pins=instance.get_pins(pin_name)
+
+ debug.check(len(pins)>0,"Could not find pin {}".format(pin_name))
+
for pin in pins:
if new_name=="":
new_name = pin.name
self.add_layout_pin(new_name, pin.layer, pin.ll(), pin.width(), pin.height())
+ def copy_layout_pins(self, instance, prefix=""):
+ """
+ Create a copied version of the layout pin at the current level.
+ You can optionally rename the pin to a new name.
+ """
+ for pin_name in self.pin_map.keys():
+ self.copy_layout_pin(instance, pin_name, prefix+pin_name)
+
def add_layout_pin_segment_center(self, text, layer, start, end):
"""
Creates a path like pin with center-line convention
@@ -260,7 +286,7 @@ class layout():
"""
Delete a labeled pin (or all pins of the same name)
"""
- self.pin_map[text]=[]
+ self.pin_map[text]=set()
def add_layout_pin(self, text, layer, offset, width=None, height=None):
"""
@@ -277,13 +303,11 @@ class layout():
# Check if there's a duplicate!
# and if so, silently ignore it.
# Rounding errors may result in some duplicates.
- pin_list = self.pin_map[text]
- for pin in pin_list:
- if pin == new_pin:
- return pin
- self.pin_map[text].append(new_pin)
+ if new_pin not in self.pin_map[text]:
+ self.pin_map[text].add(new_pin)
except KeyError:
- self.pin_map[text] = [new_pin]
+ self.pin_map[text] = set()
+ self.pin_map[text].add(new_pin)
return new_pin
@@ -356,75 +380,59 @@ class layout():
layer_stack=layers,
position_list=coordinates)
- def add_contact(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
- """ This is just an alias for a via."""
- return self.add_via(layers=layers,
- offset=offset,
- size=size,
- mirror=mirror,
- rotate=rotate,
- implant_type=implant_type,
- well_type=well_type)
+ def get_preferred_direction(self, layer):
+ """ Return the preferred routing directions """
+ if layer in ["metal1", "metal3", "metal5"]:
+ return "H"
+ elif layer in ["active", "poly", "metal2", "metal4"]:
+ return "V"
+ else:
+ return "N"
- def add_contact_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
- """ This is just an alias for a via."""
- return self.add_via_center(layers=layers,
- offset=offset,
- size=size,
- mirror=mirror,
- rotate=rotate,
- implant_type=implant_type,
- well_type=well_type)
-
- def add_via(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
+
+ def add_via(self, layers, offset, size=[1,1], directions=None, implant_type=None, well_type=None):
""" Add a three layer via structure. """
+
+ if directions==None:
+ directions = (self.get_preferred_direction(layers[0]), self.get_preferred_direction(layers[2]))
+
from sram_factory import factory
via = factory.create(module_type="contact",
layer_stack=layers,
dimensions=size,
+ directions=directions,
implant_type=implant_type,
well_type=well_type)
self.add_mod(via)
inst=self.add_inst(name=via.name,
mod=via,
- offset=offset,
- mirror=mirror,
- rotate=rotate)
+ offset=offset)
# We don't model the logical connectivity of wires/paths
self.connect_inst([])
return inst
- def add_via_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
+ def add_via_center(self, layers, offset, directions=None, size=[1,1], implant_type=None, well_type=None):
""" Add a three layer via structure by the center coordinate accounting for mirroring and rotation. """
+
+ if directions==None:
+ directions = (self.get_preferred_direction(layers[0]), self.get_preferred_direction(layers[2]))
+
from sram_factory import factory
via = factory.create(module_type="contact",
layer_stack=layers,
dimensions=size,
+ directions=directions,
implant_type=implant_type,
well_type=well_type)
height = via.height
width = via.width
- debug.check(mirror=="R0","Use rotate to rotate vias instead of mirror.")
- if rotate==0:
- corrected_offset = offset + vector(-0.5*width,-0.5*height)
- elif rotate==90:
- corrected_offset = offset + vector(0.5*height,-0.5*width)
- elif rotate==180:
- corrected_offset = offset + vector(0.5*width,0.5*height)
- elif rotate==270:
- corrected_offset = offset + vector(-0.5*height,0.5*width)
- else:
- debug.error("Invalid rotation argument.",-1)
-
+ corrected_offset = offset + vector(-0.5*width,-0.5*height)
- #print(rotate,offset,"->",corrected_offset)
self.add_mod(via)
inst=self.add_inst(name=via.name,
mod=via,
- offset=corrected_offset,
- mirror=mirror,
- rotate=rotate)
+ offset=corrected_offset)
# We don't model the logical connectivity of wires/paths
self.connect_inst([])
return inst
@@ -673,90 +681,99 @@ class layout():
self.add_via_center(layers=layer_stack,
offset=bus_pos,
rotate=90)
-
+ def get_layer_pitch(self, layer):
+ """ Return the track pitch on a given layer """
+ if layer=="metal1":
+ return (self.m1_pitch,self.m1_pitch-self.m1_space,self.m1_space)
+ elif layer=="metal2":
+ return (self.m2_pitch,self.m2_pitch-self.m2_space,self.m2_space)
+ elif layer=="metal3":
+ return (self.m3_pitch,self.m3_pitch-self.m3_space,self.m3_space)
+ elif layer=="metal4":
+ from tech import layer as tech_layer
+ if "metal4" in tech_layer:
+ return (self.m3_pitch,self.m3_pitch-self.m4_space,self.m4_space)
+ else:
+ return (self.m3_pitch,self.m3_pitch-self.m3_space,self.m3_space)
+ else:
+ debug.error("Cannot find layer pitch.")
+
def add_horizontal_trunk_route(self,
pins,
trunk_offset,
- layer_stack=("metal1", "via1", "metal2"),
- pitch=None):
+ layer_stack,
+ pitch):
"""
Create a trunk route for all pins with the trunk located at the given y offset.
"""
- if not pitch:
- pitch = self.m1_pitch
-
max_x = max([pin.center().x for pin in pins])
min_x = min([pin.center().x for pin in pins])
-
- half_minwidth = 0.5*drc["minwidth_{}".format(layer_stack[0])]
# if we are less than a pitch, just create a non-preferred layer jog
- if max_x-min_x < pitch:
+ if max_x-min_x <= pitch:
+
+ half_layer_width = 0.5*drc["minwidth_{0}".format(self.vertical_layer)]
+
# Add the horizontal trunk on the vertical layer!
- self.add_path(layer_stack[2],[vector(min_x-half_minwidth,trunk_offset.y), vector(max_x+half_minwidth,trunk_offset.y)])
+ self.add_path(self.vertical_layer,[vector(min_x-half_layer_width,trunk_offset.y), vector(max_x+half_layer_width,trunk_offset.y)])
# Route each pin to the trunk
for pin in pins:
# No bend needed here
mid = vector(pin.center().x, trunk_offset.y)
- self.add_path(layer_stack[2], [pin.center(), mid])
+ self.add_path(self.vertical_layer, [pin.center(), mid])
else:
# Add the horizontal trunk
- self.add_path(layer_stack[0],[vector(min_x,trunk_offset.y), vector(max_x,trunk_offset.y)])
+ self.add_path(self.horizontal_layer,[vector(min_x,trunk_offset.y), vector(max_x,trunk_offset.y)])
trunk_mid = vector(0.5*(max_x+min_x),trunk_offset.y)
# Route each pin to the trunk
for pin in pins:
mid = vector(pin.center().x, trunk_offset.y)
- self.add_path(layer_stack[2], [pin.center(), mid])
+ self.add_path(self.vertical_layer, [pin.center(), mid])
self.add_via_center(layers=layer_stack,
offset=mid)
def add_vertical_trunk_route(self,
pins,
trunk_offset,
- layer_stack=("metal1", "via1", "metal2"),
- pitch=None):
+ layer_stack,
+ pitch):
"""
Create a trunk route for all pins with the trunk located at the given x offset.
"""
- if not pitch:
- pitch = self.m2_pitch
-
max_y = max([pin.center().y for pin in pins])
min_y = min([pin.center().y for pin in pins])
- # Add the vertical trunk
- half_minwidth = 0.5*drc["minwidth_{}".format(layer_stack[2])]
-
# if we are less than a pitch, just create a non-preferred layer jog
- if max_y-min_y < pitch:
- # Add the horizontal trunk on the vertical layer!
- self.add_path(layer_stack[0],[vector(trunk_offset.x,min_y-half_minwidth), vector(trunk_offset.x,max_y+half_minwidth)])
+ if max_y-min_y <= pitch:
+
+ half_layer_width = 0.5*drc["minwidth_{0}".format(self.horizontal_layer)]
+
+ # Add the vertical trunk on the horizontal layer!
+ self.add_path(self.horizontal_layer,[vector(trunk_offset.x,min_y-half_layer_width), vector(trunk_offset.x,max_y+half_layer_width)])
# Route each pin to the trunk
for pin in pins:
# No bend needed here
mid = vector(trunk_offset.x, pin.center().y)
- self.add_path(layer_stack[0], [pin.center(), mid])
+ self.add_path(self.horizontal_layer, [pin.center(), mid])
else:
# Add the vertical trunk
- self.add_path(layer_stack[2],[vector(trunk_offset.x,min_y), vector(trunk_offset.x,max_y)])
+ self.add_path(self.vertical_layer,[vector(trunk_offset.x,min_y), vector(trunk_offset.x,max_y)])
trunk_mid = vector(trunk_offset.x,0.5*(max_y+min_y),)
# Route each pin to the trunk
for pin in pins:
mid = vector(trunk_offset.x, pin.center().y)
- self.add_path(layer_stack[0], [pin.center(), mid])
+ self.add_path(self.horizontal_layer, [pin.center(), mid])
self.add_via_center(layers=layer_stack,
- offset=mid,
- rotate=90)
+ offset=mid)
def create_channel_route(self, netlist,
offset,
layer_stack=("metal1", "via1", "metal2"),
- pitch=None,
vertical=False):
"""
The net list is a list of the nets. Each net is a list of pins
@@ -780,7 +797,7 @@ class layout():
g[other_pin]=conflicts
return g
- def vcg_nets_overlap(net1, net2, vertical):
+ def vcg_nets_overlap(net1, net2, vertical, pitch):
"""
Check all the pin pairs on two nets and return a pin
overlap if any pin overlaps
@@ -788,12 +805,12 @@ class layout():
for pin1 in net1:
for pin2 in net2:
- if vcg_pin_overlap(pin1, pin2, vertical):
+ if vcg_pin_overlap(pin1, pin2, vertical, pitch):
return True
return False
- def vcg_pin_overlap(pin1, pin2, vertical):
+ def vcg_pin_overlap(pin1, pin2, vertical, pitch):
""" Check for vertical or horizontal overlap of the two pins """
# FIXME: If the pins are not in a row, this may break.
# However, a top pin shouldn't overlap another top pin, for example, so the
@@ -807,10 +824,15 @@ class layout():
overlaps = (not vertical and x_overlap) or (vertical and y_overlap)
return overlaps
+ if self.get_preferred_direction(layer_stack[0])=="V":
+ self.vertical_layer = layer_stack[0]
+ self.horizontal_layer = layer_stack[2]
+ else:
+ self.vertical_layer = layer_stack[2]
+ self.horizontal_layer = layer_stack[0]
-
- if not pitch:
- pitch = self.m2_pitch
+ (self.vertical_pitch,self.vertical_width,self.vertical_space) = self.get_layer_pitch(self.vertical_layer)
+ (self.horizontal_pitch,self.horizontal_width,self.horizontal_space) = self.get_layer_pitch(self.horizontal_layer)
# FIXME: Must extend this to a horizontal conflict graph too if we want to minimize the
@@ -818,10 +840,10 @@ class layout():
#hcg = {}
# Initialize the vertical conflict graph (vcg) and make a list of all pins
- vcg = {}
+ vcg = collections.OrderedDict()
# Create names for the nets for the graphs
- nets = {}
+ nets = collections.OrderedDict()
index = 0
#print(netlist)
for pin_list in netlist:
@@ -840,7 +862,9 @@ class layout():
# Skip yourself
if net_name1 == net_name2:
continue
- if vcg_nets_overlap(nets[net_name1], nets[net_name2], vertical):
+ if vertical and vcg_nets_overlap(nets[net_name1], nets[net_name2], vertical, self.vertical_pitch):
+ vcg[net_name2].append(net_name1)
+ elif not vertical and vcg_nets_overlap(nets[net_name1], nets[net_name2], vertical, self.horizontal_pitch):
vcg[net_name2].append(net_name1)
# list of routes to do
@@ -868,28 +892,33 @@ class layout():
# Add the trunk routes from the bottom up for horizontal or the left to right for vertical
if vertical:
- self.add_vertical_trunk_route(pin_list, offset, layer_stack, pitch)
- offset += vector(pitch,0)
+ self.add_vertical_trunk_route(pin_list, offset, layer_stack, self.vertical_pitch)
+ offset += vector(self.vertical_pitch,0)
else:
- self.add_horizontal_trunk_route(pin_list, offset, layer_stack, pitch)
- offset += vector(0,pitch)
+ self.add_horizontal_trunk_route(pin_list, offset, layer_stack, self.horizontal_pitch)
+ offset += vector(0,self.horizontal_pitch)
def create_vertical_channel_route(self, netlist, offset,
- layer_stack=("metal1", "via1", "metal2"),
- pitch=None):
+ layer_stack=("metal1", "via1", "metal2")):
"""
Wrapper to create a vertical channel route
"""
- self.create_channel_route(netlist, offset, layer_stack, pitch, vertical=True)
+ self.create_channel_route(netlist, offset, layer_stack, vertical=True)
def create_horizontal_channel_route(self, netlist, offset,
- layer_stack=("metal1", "via1", "metal2"),
- pitch=None):
+ layer_stack=("metal1", "via1", "metal2")):
"""
Wrapper to create a horizontal channel route
"""
- self.create_channel_route(netlist, offset, layer_stack, pitch, vertical=False)
+ self.create_channel_route(netlist, offset, layer_stack, vertical=False)
+
+ def add_boundary(self, offset=vector(0,0)):
+ """ Add boundary for debugging dimensions """
+ self.add_rect(layer="boundary",
+ offset=offset,
+ height=self.height,
+ width=self.width)
def add_enclosure(self, insts, layer="nwell"):
""" Add a layer that surrounds the given instances. Useful
@@ -927,20 +956,27 @@ class layout():
- def add_power_pin(self, name, loc, rotate=90, start_layer="metal1"):
+ def add_power_pin(self, name, loc, vertical=False, start_layer="metal1"):
"""
Add a single power pin from M3 down to M1 at the given center location.
The starting layer is specified to determine which vias are needed.
"""
-
+ if vertical:
+ direction=("V","V")
+ else:
+ direction=("H","H")
+
if start_layer=="metal1":
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=loc,
- rotate=float(rotate))
+ directions=direction)
+
+
if start_layer=="metal1" or start_layer=="metal2":
via=self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=loc,
- rotate=float(rotate))
+ directions=direction)
+
if start_layer=="metal3":
self.add_layout_pin_rect_center(text=name,
layer="metal3",
diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py
index 5f3245a8..707e7bc8 100644
--- a/compiler/base/hierarchy_spice.py
+++ b/compiler/base/hierarchy_spice.py
@@ -1,8 +1,19 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
import re
import os
import math
import tech
+from delay_data import *
+from wire_spice_model import *
+from power_data import *
+import logical_effort
class spice():
"""
@@ -17,6 +28,7 @@ class spice():
def __init__(self, name):
self.name = name
+ self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
# Holds subckts/mods for this module
self.mods = []
# Holds the pins for this module
@@ -28,7 +40,10 @@ class spice():
# Spice format)
self.conns = []
# Keep track of any comments to add the the spice
- self.comments = []
+ try:
+ self.commments
+ except:
+ self.comments = []
self.sp_read()
@@ -38,29 +53,52 @@ class spice():
def add_comment(self, comment):
""" Add a comment to the spice file """
+
+ try:
+ self.commments
+ except:
+ self.comments = []
+
self.comments.append(comment)
def add_pin(self, name, pin_type="INOUT"):
""" Adds a pin to the pins list. Default type is INOUT signal. """
self.pins.append(name)
self.pin_type[name]=pin_type
+ debug.check(pin_type in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(name,pin_type))
- def add_pin_list(self, pin_list, pin_type_list="INOUT"):
+ def add_pin_list(self, pin_list, pin_type="INOUT"):
""" Adds a pin_list to the pins list """
# The type list can be a single type for all pins
# or a list that is the same length as the pin list.
- if type(pin_type_list)==str:
+ if type(pin_type)==str:
for pin in pin_list:
- self.add_pin(pin,pin_type_list)
- elif len(pin_type_list)==len(pin_list):
- for (pin,ptype) in zip(pin_list, pin_type_list):
+ debug.check(pin_type in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(pin,pin_type))
+ self.add_pin(pin,pin_type)
+
+ elif len(pin_type)==len(pin_list):
+ for (pin,ptype) in zip(pin_list, pin_type):
+ debug.check(ptype in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(pin,ptype))
self.add_pin(pin,ptype)
else:
debug.error("Mismatch in type and pin list lengths.", -1)
+ def add_pin_types(self, type_list):
+ """Add pin types for all the cell's pins.
+ Typically, should only be used for handmade cells."""
+ #This only works if self.pins == bitcell.pin_names
+ if self.pin_names != self.pins:
+ debug.error("{} spice subcircuit port names do not match pin_names\
+ \n SPICE names={}\
+ \n Module names={}\
+ ".format(self.name, self.pin_names, self.pins),1)
+ self.pin_type = {pin:type for pin,type in zip(self.pin_names, type_list)}
+
def get_pin_type(self, name):
""" Returns the type of the signal pin. """
- return self.pin_type[name]
+ pin_type = self.pin_type[name]
+ debug.check(pin_type in self.valid_signal_types, "Invalid signaltype for {0}: {1}".format(name,pin_type))
+ return pin_type
def get_pin_dir(self, name):
""" Returns the direction of the pin. (Supply/ground are INOUT). """
@@ -88,17 +126,31 @@ class spice():
return output_list
+ def copy_pins(self, other_module, suffix=""):
+ """ This will copy all of the pins from the other module and add an optional suffix."""
+ for pin in other_module.pins:
+ self.add_pin(pin+suffix, other_module.get_pin_type(pin))
+
+ def get_inouts(self):
+ """ These use pin types to determine pin lists. These
+ may be over-ridden by submodules that didn't use pin directions yet."""
+ inout_list = []
+ for pin in self.pins:
+ if self.pin_type[pin]=="INOUT":
+ inout_list.append(pin)
+ return inout_list
+
def add_mod(self, mod):
"""Adds a subckt/submodule to the subckt hierarchy"""
self.mods.append(mod)
+
def connect_inst(self, args, check=True):
"""Connects the pins of the last instance added
It is preferred to use the function with the check to find if
there is a problem. The check option can be set to false
where we dynamically generate groups of connections after a
group of modules are generated."""
-
if (check and (len(self.insts[-1].mod.pins) != len(args))):
from pprint import pformat
modpins_string=pformat(self.insts[-1].mod.pins)
@@ -121,7 +173,13 @@ class spice():
debug.error("-----")
debug.error("Connections: \n"+str(conns_string),1)
-
+ def get_conns(self, inst):
+ """Returns the connections of a given instance."""
+ for i in range(len(self.insts)):
+ if inst is self.insts[i]:
+ return self.conns[i]
+ #If not found, returns None
+ return None
def sp_read(self):
"""Reads the sp file (and parse the pins) from the library
@@ -142,6 +200,28 @@ class spice():
else:
self.spice = []
+ def check_net_in_spice(self, net_name):
+ """Checks if a net name exists in the current. Intended to be check nets in hand-made cells."""
+ #Remove spaces and lower case then add spaces. Nets are separated by spaces.
+ net_formatted = ' '+net_name.lstrip().rstrip().lower()+' '
+ for line in self.spice:
+ #Lowercase the line and remove any part of the line that is a comment.
+ line = line.lower().split('*')[0]
+
+ #Skip .subckt or .ENDS lines
+ if line.find('.') == 0:
+ continue
+ if net_formatted in line:
+ return True
+ return False
+
+ def do_nets_exist(self, nets):
+ """For handmade cell, checks sp file contains the storage nodes."""
+ nets_match = True
+ for net in nets:
+ nets_match = nets_match and self.check_net_in_spice(net)
+ return nets_match
+
def contains(self, mod, modlist):
for x in modlist:
if x.name == mod.name:
@@ -169,9 +249,12 @@ class spice():
sp.write("\n.SUBCKT {0} {1}\n".format(self.name,
" ".join(self.pins)))
+ for pin in self.pins:
+ sp.write("* {1:6}: {0} \n".format(pin,self.pin_type[pin]))
+
for line in self.comments:
sp.write("* {}\n".format(line))
-
+
# every instance must have a set of connections, even if it is empty.
if len(self.insts)!=len(self.conns):
debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name,
@@ -221,27 +304,56 @@ class spice():
def analytical_delay(self, corner, slew, load=0.0):
"""Inform users undefined delay module while building new modules"""
- debug.warning("Design Class {0} delay function needs to be defined"
+
+ # 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)
+ stage_effort = self.get_stage_effort(relative_cap)
+
+ # If it fails, then keep running with a valid object.
+ if stage_effort == None:
+ return delay_data(0.0, 0.0)
+
+ abs_delay = stage_effort.get_absolute_delay()
+ corner_delay = self.apply_corners_analytically(abs_delay, corner)
+ SLEW_APPROXIMATION = 0.1
+ corner_slew = SLEW_APPROXIMATION*corner_delay
+ return delay_data(corner_delay, corner_slew)
+
+ def get_stage_effort(self, cout, inp_is_rise=True):
+ """Inform users undefined delay module while building new modules"""
+ debug.warning("Design Class {0} logical effort function needs to be defined"
+ .format(self.__class__.__name__))
+ debug.warning("Class {0} name {1}"
+ .format(self.__class__.__name__,
+ self.name))
+ return None
+
+ def get_cin(self):
+ """Returns input load in Femto-Farads. All values generated using
+ relative capacitance function then converted based on tech file parameter."""
+
+ # 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)
+
+ def input_load(self):
+ """Inform users undefined relative capacitance functions used for analytical delays."""
+ debug.warning("Design Class {0} input capacitance function needs to be defined"
.format(self.__class__.__name__))
debug.warning("Class {0} name {1}"
.format(self.__class__.__name__,
self.name))
- # return 0 to keep code running while building
- return delay_data(0.0, 0.0)
-
+ return 0
+
def cal_delay_with_rc(self, corner, r, c ,slew, swing = 0.5):
"""
Calculate the delay of a mosfet by
modeling it as a resistance driving a capacitance
"""
swing_factor = abs(math.log(1-swing)) # time constant based on swing
- proc,vdd,temp = corner
- #FIXME: type of delay is needed to know which process to use.
- proc_mult = max(self.get_process_delay_factor(proc))
- volt_mult = self.get_voltage_delay_factor(vdd)
- temp_mult = self.get_temp_delay_factor(temp)
delay = swing_factor * r * c #c is in ff and delay is in fs
- delay = delay * proc_mult * volt_mult * temp_mult
+ delay = self.apply_corners_analytically(delay, corner)
delay = delay * 0.001 #make the unit to ps
# Output slew should be linear to input slew which is described
@@ -254,6 +366,15 @@ class spice():
slew = delay * 0.6 * 2 + 0.005 * slew
return delay_data(delay = delay, slew = slew)
+ def apply_corners_analytically(self, delay, corner):
+ """Multiply delay by corner factors"""
+ proc,vdd,temp = corner
+ #FIXME: type of delay is needed to know which process to use.
+ proc_mult = max(self.get_process_delay_factor(proc))
+ volt_mult = self.get_voltage_delay_factor(vdd)
+ temp_mult = self.get_temp_delay_factor(temp)
+ return delay * proc_mult * volt_mult * temp_mult
+
def get_process_delay_factor(self, proc):
"""Returns delay increase estimate based off process
Currently does +/-10 for fast/slow corners."""
@@ -271,7 +392,7 @@ class spice():
"""Returns delay increase due to voltage.
Implemented as linear factor based off nominal voltage.
"""
- return tech.spice['vdd_nominal']/voltage
+ return tech.spice["nom_supply_voltage"]/voltage
def get_temp_delay_factor(self, temp):
"""Returns delay increase due to temperature (in C).
@@ -279,11 +400,11 @@ class spice():
"""
#Some portions of equation condensed (phi_t = k*T/q for T in Kelvin) in mV
#(k/q)/100 = .008625, The division 100 simplifies the conversion from C to K and mV to V
- thermal_voltage_nom = .008625*tech.spice["temp_nominal"]
- thermal_voltage = .008625*temp
- vthresh = (tech.spice["v_threshold_typical"]+2*(thermal_voltage-thermal_voltage_nom))
+ thermal_voltage_nom = 0.008625*tech.spice["nom_temperature"]
+ thermal_voltage = 0.008625*temp
+ vthresh = (tech.spice["nom_threshold"]+2*(thermal_voltage-thermal_voltage_nom))
#Calculate effect on Vdd-Vth. The current vdd is not used here. A separate vdd factor is calculated.
- return (tech.spice['vdd_nominal'] - tech.spice["v_threshold_typical"])/(tech.spice['vdd_nominal']-vthresh)
+ return (tech.spice["nom_supply_voltage"] - tech.spice["nom_threshold"])/(tech.spice["nom_supply_voltage"]-vthresh)
def return_delay(self, delay, slew):
return delay_data(delay, slew)
@@ -310,102 +431,3 @@ class spice():
def return_power(self, dynamic=0.0, leakage=0.0):
return power_data(dynamic, leakage)
-class delay_data:
- """
- This is the delay class to represent the delay information
- Time is 50% of the signal to 50% of reference signal delay.
- Slew is the 10% of the signal to 90% of signal
- """
- def __init__(self, delay=0.0, slew=0.0):
- """ init function support two init method"""
- # will take single input as a coordinate
- self.delay = delay
- self.slew = slew
-
- def __str__(self):
- """ override print function output """
- return "Delay Data: Delay "+str(self.delay)+", Slew "+str(self.slew)+""
-
- def __add__(self, other):
- """
- Override - function (left), for delay_data: a+b != b+a
- """
- assert isinstance(other,delay_data)
- return delay_data(other.delay + self.delay,
- other.slew)
-
- def __radd__(self, other):
- """
- Override - function (right), for delay_data: a+b != b+a
- """
- assert isinstance(other,delay_data)
- return delay_data(other.delay + self.delay,
- self.slew)
-
-class power_data:
- """
- This is the power class to represent the power information
- Dynamic and leakage power are stored as a single object with this class.
- """
- def __init__(self, dynamic=0.0, leakage=0.0):
- """ init function support two init method"""
- # will take single input as a coordinate
- self.dynamic = dynamic
- self.leakage = leakage
-
- def __str__(self):
- """ override print function output """
- return "Power Data: Dynamic "+str(self.dynamic)+", Leakage "+str(self.leakage)+" in nW"
-
- def __add__(self, other):
- """
- Override - function (left), for power_data: a+b != b+a
- """
- assert isinstance(other,power_data)
- return power_data(other.dynamic + self.dynamic,
- other.leakage + self.leakage)
-
- def __radd__(self, other):
- """
- Override - function (left), for power_data: a+b != b+a
- """
- assert isinstance(other,power_data)
- return power_data(other.dynamic + self.dynamic,
- other.leakage + self.leakage)
-
-
-class wire_spice_model:
- """
- This is the spice class to represent a wire
- """
- def __init__(self, lump_num, wire_length, wire_width):
- self.lump_num = lump_num # the number of segment the wire delay has
- self.wire_c = self.cal_wire_c(wire_length, wire_width) # c in each segment
- self.wire_r = self.cal_wire_r(wire_length, wire_width) # r in each segment
-
- def cal_wire_c(self, wire_length, wire_width):
- from tech import spice
- total_c = spice["wire_unit_c"] * wire_length * wire_width
- wire_c = total_c / self.lump_num
- return wire_c
-
- def cal_wire_r(self, wire_length, wire_width):
- from tech import spice
- total_r = spice["wire_unit_r"] * wire_length / wire_width
- wire_r = total_r / self.lump_num
- return wire_r
-
- def return_input_cap(self):
- return 0.5 * self.wire_c * self.lump_num
-
- def return_delay_over_wire(self, slew, swing = 0.5):
- # delay will be sum of arithmetic sequence start from
- # rc to self.lump_num*rc with step of rc
-
- swing_factor = abs(math.log(1-swing)) # time constant based on swing
- sum_factor = (1+self.lump_num) * self.lump_num * 0.5 # sum of the arithmetic sequence
- delay = sum_factor * swing_factor * self.wire_r * self.wire_c
- slew = delay * 2 + slew
- result= delay_data(delay, slew)
- return result
-
diff --git a/compiler/base/lef.py b/compiler/base/lef.py
index 270057cb..af539742 100644
--- a/compiler/base/lef.py
+++ b/compiler/base/lef.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import gdsMill
import tech
import globals
@@ -5,6 +12,7 @@ import math
import debug
import datetime
from collections import defaultdict
+import pdb
class lef:
"""
@@ -14,9 +22,11 @@ class lef:
"""
def __init__(self,layers):
# LEF db units per micron
- self.lef_units = 1000
+ self.lef_units = 2000
# These are the layers of the obstructions
self.lef_layers = layers
+ # Round to ensure float values are divisible by 0.0025 (the manufacturing grid)
+ self.round_grid = 4;
def lef_write(self, lef_name):
"""Write the entire lef of the object to the file."""
@@ -41,25 +51,14 @@ class lef:
self.lef.write("UNITS\n")
self.lef.write(" DATABASE MICRONS {0} ;\n".format(self.lef_units))
self.lef.write("END UNITS\n")
-
- self.lef.write("SITE MacroSite\n")
- self.indent += " "
- self.lef.write("{0}CLASS Core ;\n".format(self.indent))
- self.lef.write("{0}SIZE {1} by {2} ;\n".format(self.indent,
- self.lef_units*self.width,
- self.lef_units*self.height))
- self.indent = self.indent[:-3]
- self.lef.write("END MacroSite\n")
self.lef.write("{0}MACRO {1}\n".format(self.indent,self.name))
self.indent += " "
self.lef.write("{0}CLASS BLOCK ;\n".format(self.indent))
self.lef.write("{0}SIZE {1} BY {2} ;\n" .format(self.indent,
- self.lef_units*self.width,
- self.lef_units*self.height))
+ round(self.width,self.round_grid),
+ round(self.height,self.round_grid)))
self.lef.write("{0}SYMMETRY X Y R90 ;\n".format(self.indent))
- self.lef.write("{0}SITE MacroSite ;\n".format(self.indent))
-
def lef_write_footer(self):
self.lef.write("{0}END {1}\n".format(self.indent,self.name))
@@ -86,7 +85,7 @@ class lef:
pin_list = self.get_pins(name)
for pin in pin_list:
self.lef.write("{0}LAYER {1} ;\n".format(self.indent,pin.layer))
- self.lef_write_rect(pin.rect)
+ self.lef_write_shape(pin.rect)
# End the PORT
self.indent = self.indent[:-3]
@@ -102,15 +101,29 @@ class lef:
for layer in self.lef_layers:
self.lef.write("{0}LAYER {1} ;\n".format(self.indent,layer))
self.indent += " "
+ # pdb.set_trace()
blockages = self.get_blockages(layer,True)
for b in blockages:
- self.lef_write_rect(b)
+ # if len(b) > 2:
+ # print(b)
+ self.lef_write_shape(b)
self.indent = self.indent[:-3]
self.lef.write("{0}END\n".format(self.indent))
- def lef_write_rect(self, rect):
- """ Write a LEF rectangle """
- self.lef.write("{0}RECT ".format(self.indent))
- for item in rect:
- self.lef.write(" {0} {1}".format(self.lef_units*item[0], self.lef_units*item[1]))
- self.lef.write(" ;\n")
+ def lef_write_shape(self, rect):
+ if len(rect) == 2:
+ """ Write a LEF rectangle """
+ self.lef.write("{0}RECT ".format(self.indent))
+ for item in rect:
+ # print(rect)
+ self.lef.write(" {0} {1}".format(round(item[0],self.round_grid), round(item[1],self.round_grid)))
+ self.lef.write(" ;\n")
+ else:
+ """ Write a LEF polygon """
+ self.lef.write("{0}POLYGON ".format(self.indent))
+ for item in rect:
+ self.lef.write(" {0} {1}".format(round(item[0],self.round_grid), round(item[1],self.round_grid)))
+ # for i in range(0,len(rect)):
+ # self.lef.write(" {0} {1}".format(round(rect[i][0],self.round_grid), round(rect[i][1],self.round_grid)))
+ self.lef.write(" ;\n")
+
diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py
index 44b005f6..2d389119 100644
--- a/compiler/base/pin_layout.py
+++ b/compiler/base/pin_layout.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
from tech import GDS, drc
from vector import vector
diff --git a/compiler/base/power_data.py b/compiler/base/power_data.py
new file mode 100644
index 00000000..77d50d34
--- /dev/null
+++ b/compiler/base/power_data.py
@@ -0,0 +1,38 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+
+class power_data():
+ """
+ This is the power class to represent the power information
+ Dynamic and leakage power are stored as a single object with this class.
+ """
+ def __init__(self, dynamic=0.0, leakage=0.0):
+ """ init function support two init method"""
+ # will take single input as a coordinate
+ self.dynamic = dynamic
+ self.leakage = leakage
+
+ def __str__(self):
+ """ override print function output """
+ return "Power Data: Dynamic "+str(self.dynamic)+", Leakage "+str(self.leakage)+" in nW"
+
+ def __add__(self, other):
+ """
+ Override - function (left), for power_data: a+b != b+a
+ """
+ assert isinstance(other,power_data)
+ return power_data(other.dynamic + self.dynamic,
+ other.leakage + self.leakage)
+
+ def __radd__(self, other):
+ """
+ Override - function (left), for power_data: a+b != b+a
+ """
+ assert isinstance(other,power_data)
+ return power_data(other.dynamic + self.dynamic,
+ other.leakage + self.leakage)
diff --git a/compiler/base/route.py b/compiler/base/route.py
index c6ce906b..c3e446a3 100644
--- a/compiler/base/route.py
+++ b/compiler/base/route.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
from tech import drc
import debug
from design import design
@@ -65,7 +72,7 @@ class route(design):
for p0,p1 in plist:
if p0.z != p1.z: # via
via_size = [self.num_vias]*2
- self.obj.add_via_center(self.layer_stack,vector(p0.x,p0.y),size=via_size,rotate=90)
+ self.obj.add_via_center(self.layer_stack,vector(p0.x,p0.y),size=via_size)
elif p0.x != p1.x and p0.y != p1.y: # diagonal!
debug.error("Diagonal route! {}".format(self.path),-3)
else:
diff --git a/compiler/base/utils.py b/compiler/base/utils.py
index 8ca22fa9..61e12096 100644
--- a/compiler/base/utils.py
+++ b/compiler/base/utils.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import os
import gdsMill
import tech
diff --git a/compiler/base/vector.py b/compiler/base/vector.py
index 6069a1ab..8bf09f7d 100644
--- a/compiler/base/vector.py
+++ b/compiler/base/vector.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
import math
import tech
diff --git a/compiler/base/verilog.py b/compiler/base/verilog.py
index a2ddcadf..ff13c4f4 100644
--- a/compiler/base/verilog.py
+++ b/compiler/base/verilog.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
class verilog:
@@ -14,7 +21,11 @@ class verilog:
self.vf.write("// OpenRAM SRAM model\n")
self.vf.write("// Words: {0}\n".format(self.num_words))
- self.vf.write("// Word size: {0}\n\n".format(self.word_size))
+ self.vf.write("// Word size: {0}\n".format(self.word_size))
+ if self.write_size:
+ self.vf.write("// Write size: {0}\n\n".format(self.write_size))
+ else:
+ self.vf.write("\n")
self.vf.write("module {0}(\n".format(self.name))
for port in self.all_ports:
@@ -25,16 +36,25 @@ class verilog:
elif port in self.write_ports:
self.vf.write("// Port {0}: W\n".format(port))
if port in self.readwrite_ports:
- self.vf.write(" clk{0},csb{0},web{0},ADDR{0},DIN{0},DOUT{0}".format(port))
+ self.vf.write(" clk{0},csb{0},web{0},".format(port))
+ if self.write_size:
+ self.vf.write("wmask{},".format(port))
+ self.vf.write("addr{0},din{0},dout{0}".format(port))
elif port in self.write_ports:
- self.vf.write(" clk{0},csb{0},ADDR{0},DIN{0}".format(port))
+ self.vf.write(" clk{0},csb{0},".format(port))
+ if self.write_size:
+ self.vf.write("wmask{},".format(port))
+ self.vf.write("addr{0},din{0}".format(port))
elif port in self.read_ports:
- self.vf.write(" clk{0},csb{0},ADDR{0},DOUT{0}".format(port))
+ self.vf.write(" clk{0},csb{0},addr{0},dout{0}".format(port))
# Continue for every port on a new line
if port != self.all_ports[-1]:
self.vf.write(",\n")
self.vf.write("\n );\n\n")
-
+
+ if self.write_size:
+ self.num_wmasks = int(self.word_size/self.write_size)
+ self.vf.write(" parameter NUM_WMASKS = {0} ;\n".format(self.num_wmasks))
self.vf.write(" parameter DATA_WIDTH = {0} ;\n".format(self.word_size))
self.vf.write(" parameter ADDR_WIDTH = {0} ;\n".format(self.addr_size))
self.vf.write(" parameter RAM_DEPTH = 1 << ADDR_WIDTH;\n")
@@ -78,11 +98,14 @@ class verilog:
self.vf.write(" reg csb{0}_reg;\n".format(port))
if port in self.readwrite_ports:
self.vf.write(" reg web{0}_reg;\n".format(port))
- self.vf.write(" reg [ADDR_WIDTH-1:0] ADDR{0}_reg;\n".format(port))
if port in self.write_ports:
- self.vf.write(" reg [DATA_WIDTH-1:0] DIN{0}_reg;\n".format(port))
+ if self.write_size:
+ self.vf.write(" reg [NUM_WMASKS-1:0] wmask{0}_reg;\n".format(port))
+ self.vf.write(" reg [ADDR_WIDTH-1:0] addr{0}_reg;\n".format(port))
+ if port in self.write_ports:
+ self.vf.write(" reg [DATA_WIDTH-1:0] din{0}_reg;\n".format(port))
if port in self.read_ports:
- self.vf.write(" reg [DATA_WIDTH-1:0] DOUT{0};\n".format(port))
+ self.vf.write(" reg [DATA_WIDTH-1:0] dout{0};\n".format(port))
def add_flops(self, port):
"""
@@ -95,24 +118,33 @@ class verilog:
self.vf.write(" csb{0}_reg = csb{0};\n".format(port))
if port in self.readwrite_ports:
self.vf.write(" web{0}_reg = web{0};\n".format(port))
- self.vf.write(" ADDR{0}_reg = ADDR{0};\n".format(port))
if port in self.write_ports:
- self.vf.write(" DIN{0}_reg = DIN{0};\n".format(port))
+ if self.write_size:
+ self.vf.write(" wmask{0}_reg = wmask{0};\n".format(port))
+ self.vf.write(" addr{0}_reg = addr{0};\n".format(port))
+ if port in self.write_ports:
+ self.vf.write(" din{0}_reg = din{0};\n".format(port))
if port in self.read_ports:
- self.vf.write(" DOUT{0} = {1}'bx;\n".format(port,self.word_size))
+ self.vf.write(" dout{0} = {1}'bx;\n".format(port,self.word_size))
if port in self.readwrite_ports:
self.vf.write(" if ( !csb{0}_reg && web{0}_reg ) \n".format(port))
- self.vf.write(" $display($time,\" Reading %m ADDR{0}=%b DOUT{0}=%b\",ADDR{0}_reg,mem[ADDR{0}_reg]);\n".format(port))
+ self.vf.write(" $display($time,\" Reading %m addr{0}=%b dout{0}=%b\",addr{0}_reg,mem[addr{0}_reg]);\n".format(port))
elif port in self.read_ports:
self.vf.write(" if ( !csb{0}_reg ) \n".format(port))
- self.vf.write(" $display($time,\" Reading %m ADDR{0}=%b DOUT{0}=%b\",ADDR{0}_reg,mem[ADDR{0}_reg]);\n".format(port))
-
+ self.vf.write(" $display($time,\" Reading %m addr{0}=%b dout{0}=%b\",addr{0}_reg,mem[addr{0}_reg]);\n".format(port))
if port in self.readwrite_ports:
self.vf.write(" if ( !csb{0}_reg && !web{0}_reg )\n".format(port))
- self.vf.write(" $display($time,\" Writing %m ADDR{0}=%b DIN{0}=%b\",ADDR{0}_reg,DIN{0}_reg);\n".format(port))
+ if self.write_size:
+ self.vf.write(" $display($time,\" Writing %m addr{0}=%b din{0}=%b wmask{0}=%b\",addr{0}_reg,din{0}_reg,wmask{0}_reg);\n".format(port))
+ else:
+ self.vf.write(" $display($time,\" Writing %m addr{0}=%b din{0}=%b\",addr{0}_reg,din{0}_reg);\n".format(port))
elif port in self.write_ports:
self.vf.write(" if ( !csb{0}_reg )\n".format(port))
- self.vf.write(" $display($time,\" Writing %m ADDR{0}=%b DIN{0}=%b\",ADDR{0}_reg,DIN{0}_reg);\n".format(port))
+ if self.write_size:
+ self.vf.write(" $display($time,\" Writing %m addr{0}=%b din{0}=%b wmask{0}=%b\",addr{0}_reg,din{0}_reg,wmask{0}_reg);\n".format(port))
+ else:
+ self.vf.write(" $display($time,\" Writing %m addr{0}=%b din{0}=%b\",addr{0}_reg,din{0}_reg);\n".format(port))
+
self.vf.write(" end\n\n")
@@ -124,11 +156,13 @@ class verilog:
self.vf.write(" input csb{0}; // active low chip select\n".format(port))
if port in self.readwrite_ports:
self.vf.write(" input web{0}; // active low write control\n".format(port))
- self.vf.write(" input [ADDR_WIDTH-1:0] ADDR{0};\n".format(port))
+ if self.write_size:
+ self.vf.write(" input [NUM_WMASKS-1:0] wmask{0}; // write mask\n".format(port))
+ self.vf.write(" input [ADDR_WIDTH-1:0] addr{0};\n".format(port))
if port in self.write_ports:
- self.vf.write(" input [DATA_WIDTH-1:0] DIN{0};\n".format(port))
+ self.vf.write(" input [DATA_WIDTH-1:0] din{0};\n".format(port))
if port in self.read_ports:
- self.vf.write(" output [DATA_WIDTH-1:0] DOUT{0};\n".format(port))
+ self.vf.write(" output [DATA_WIDTH-1:0] dout{0};\n".format(port))
def add_write_block(self, port):
"""
@@ -141,10 +175,25 @@ class verilog:
self.vf.write(" always @ (negedge clk{0})\n".format(port))
self.vf.write(" begin : MEM_WRITE{0}\n".format(port))
if port in self.readwrite_ports:
- self.vf.write(" if ( !csb{0}_reg && !web{0}_reg )\n".format(port))
+ if self.write_size:
+ self.vf.write(" if ( !csb{0}_reg && !web{0}_reg ) begin\n".format(port))
+ else:
+ self.vf.write(" if ( !csb{0}_reg && !web{0}_reg )\n".format(port))
else:
- self.vf.write(" if (!csb{0}_reg)\n".format(port))
- self.vf.write(" mem[ADDR{0}_reg] = DIN{0}_reg;\n".format(port))
+ if self.write_size:
+ self.vf.write(" if (!csb{0}_reg) begin\n".format(port))
+ else:
+ self.vf.write(" if (!csb{0}_reg)\n".format(port))
+
+ if self.write_size:
+ for mask in range(0,self.num_wmasks):
+ lower = mask * self.write_size
+ upper = lower + self.write_size-1
+ self.vf.write(" if (wmask{0}_reg[{1}])\n".format(port,mask))
+ self.vf.write(" mem[addr{0}_reg][{1}:{2}] = din{0}_reg[{1}:{2}];\n".format(port,upper,lower))
+ self.vf.write(" end\n")
+ else:
+ self.vf.write(" mem[addr{0}_reg] = din{0}_reg;\n".format(port))
self.vf.write(" end\n")
def add_read_block(self, port):
@@ -160,6 +209,6 @@ class verilog:
self.vf.write(" if (!csb{0}_reg && web{0}_reg)\n".format(port))
else:
self.vf.write(" if (!csb{0}_reg)\n".format(port))
- self.vf.write(" DOUT{0} <= #(DELAY) mem[ADDR{0}_reg];\n".format(port))
+ self.vf.write(" dout{0} <= #(DELAY) mem[addr{0}_reg];\n".format(port))
self.vf.write(" end\n")
diff --git a/compiler/base/wire.py b/compiler/base/wire.py
index 8bc250fa..bf1daa6a 100644
--- a/compiler/base/wire.py
+++ b/compiler/base/wire.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
from tech import drc
import debug
from wire_path import wire_path
@@ -62,18 +69,15 @@ class wire(wire_path):
continue
if a[1] == c[1]:
continue
- via_offset = [offset[0] + 0.5*c_height,
- offset[1] - 0.5*c_width]
- self.obj.add_via(layers=self.layer_stack,
- offset=via_offset,
- rotate=90)
- corner_offset = [offset[0] - 0.5*(c_height + self.vert_layer_width),
- offset[1] + 0.5*(c_width - self.horiz_layer_width)]
+ self.obj.add_via_center(layers=self.layer_stack,
+ offset=offset)
def create_rectangles(self):
- """ Create the actual rectangles on teh appropriate layers
- using the position list of the corners. """
+ """
+ Create the actual rectangles on the appropriate layers
+ using the position list of the corners.
+ """
pl = self.position_list # position list
for index in range(len(pl) - 1):
if pl[index][0] != pl[index + 1][0]:
diff --git a/compiler/base/wire_path.py b/compiler/base/wire_path.py
index ec5d01bf..ebfb8a0a 100644
--- a/compiler/base/wire_path.py
+++ b/compiler/base/wire_path.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
from tech import drc
from tech import layer as techlayer
import debug
diff --git a/compiler/base/wire_spice_model.py b/compiler/base/wire_spice_model.py
new file mode 100644
index 00000000..5624b575
--- /dev/null
+++ b/compiler/base/wire_spice_model.py
@@ -0,0 +1,42 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+
+class wire_spice_model():
+ """
+ This is the spice class to represent a wire
+ """
+ def __init__(self, lump_num, wire_length, wire_width):
+ self.lump_num = lump_num # the number of segment the wire delay has
+ self.wire_c = self.cal_wire_c(wire_length, wire_width) # c in each segment
+ self.wire_r = self.cal_wire_r(wire_length, wire_width) # r in each segment
+
+ def cal_wire_c(self, wire_length, wire_width):
+ from tech import spice
+ total_c = spice["wire_unit_c"] * wire_length * wire_width
+ wire_c = total_c / self.lump_num
+ return wire_c
+
+ def cal_wire_r(self, wire_length, wire_width):
+ from tech import spice
+ total_r = spice["wire_unit_r"] * wire_length / wire_width
+ wire_r = total_r / self.lump_num
+ return wire_r
+
+ def return_input_cap(self):
+ return 0.5 * self.wire_c * self.lump_num
+
+ def return_delay_over_wire(self, slew, swing = 0.5):
+ # delay will be sum of arithmetic sequence start from
+ # rc to self.lump_num*rc with step of rc
+
+ swing_factor = abs(math.log(1-swing)) # time constant based on swing
+ sum_factor = (1+self.lump_num) * self.lump_num * 0.5 # sum of the arithmetic sequence
+ delay = sum_factor * swing_factor * self.wire_r * self.wire_c
+ slew = delay * 2 + slew
+ result= delay_data(delay, slew)
+ return result
diff --git a/compiler/bitcells/bitcell.py b/compiler/bitcells/bitcell.py
index ed1647a8..cad069a5 100644
--- a/compiler/bitcells/bitcell.py
+++ b/compiler/bitcells/bitcell.py
@@ -1,7 +1,15 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import design
import debug
import utils
from tech import GDS,layer,parameter,drc
+import logical_effort
class bitcell(design.design):
"""
@@ -12,6 +20,8 @@ class bitcell(design.design):
"""
pin_names = ["bl", "br", "wl", "vdd", "gnd"]
+ storage_nets = ['Q', 'Qbar']
+ type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("cell_6t", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "cell_6t", GDS["unit"])
@@ -23,49 +33,50 @@ class bitcell(design.design):
self.width = bitcell.width
self.height = bitcell.height
self.pin_map = bitcell.pin_map
+ self.add_pin_types(self.type_list)
+ self.nets_match = self.do_nets_exist(self.storage_nets)
- def analytical_delay(self, corner, slew, load=0, swing = 0.5):
- # delay of bit cell is not like a driver(from WL)
- # so the slew used should be 0
- # it should not be slew dependent?
- # because the value is there
- # the delay is only over half transsmission gate
- from tech import spice
- r = spice["min_tx_r"]*3
- c_para = spice["min_tx_drain_c"]
- result = self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew, swing = swing)
- return result
-
+ def get_stage_effort(self, load):
+ parasitic_delay = 1
+ 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.
+ return logical_effort.logical_effort('bitline', size, cin, load, parasitic_delay, False)
- def list_bitcell_pins(self, col, row):
- """ Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """
- bitcell_pins = ["bl_{0}".format(col),
- "br_{0}".format(col),
- "wl_{0}".format(row),
- "vdd",
- "gnd"]
- return bitcell_pins
-
- def list_all_wl_names(self):
+ def get_all_wl_names(self):
""" Creates a list of all wordline pin names """
row_pins = ["wl"]
return row_pins
- def list_all_bitline_names(self):
+ def get_all_bitline_names(self):
""" Creates a list of all bitline pin names (both bl and br) """
column_pins = ["bl", "br"]
return column_pins
- def list_all_bl_names(self):
+ def get_all_bl_names(self):
""" Creates a list of all bl pins names """
column_pins = ["bl"]
return column_pins
- def list_all_br_names(self):
+ def get_all_br_names(self):
""" Creates a list of all br pins names """
column_pins = ["br"]
return column_pins
+ def get_bl_name(self, port=0):
+ """Get bl name"""
+ debug.check(port==0,"One port for bitcell only.")
+ return "bl"
+
+ def get_br_name(self, port=0):
+ """Get bl name"""
+ debug.check(port==0,"One port for bitcell only.")
+ return "br"
+
+ def get_wl_name(self, port=0):
+ """Get wl name"""
+ debug.check(port==0,"One port for bitcell only.")
+ return "wl"
+
def analytical_power(self, corner, load):
"""Bitcell power in nW. Only characterizes leakage."""
from tech import spice
@@ -73,10 +84,23 @@ class bitcell(design.design):
dynamic = 0 #temporary
total_power = self.return_power(dynamic, leakage)
return total_power
-
- def get_wl_cin(self):
+
+ def get_storage_net_names(self):
+ """Returns names of storage nodes in bitcell in [non-inverting, inverting] format."""
+ #Checks that they do exist
+ if self.nets_match:
+ return self.storage_nets
+ else:
+ debug.info(1,"Storage nodes={} not found in spice file.".format(self.storage_nets))
+ return None
+
+ def input_load(self):
"""Return the relative capacitance of the access transistor gates"""
- #This is a handmade cell so the value must be entered in the tech.py file or estimated.
- #Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
+
+ # FIXME: This applies to bitline capacitances as well.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin
+
+ def build_graph(self, graph, inst_name, port_nets):
+ """Adds edges based on inputs/outputs. Overrides base class function."""
+ self.add_graph_edges(graph, port_nets)
diff --git a/compiler/bitcells/bitcell_1rw_1r.py b/compiler/bitcells/bitcell_1rw_1r.py
index a96dcff0..0d536b38 100644
--- a/compiler/bitcells/bitcell_1rw_1r.py
+++ b/compiler/bitcells/bitcell_1rw_1r.py
@@ -1,7 +1,15 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import design
import debug
import utils
from tech import GDS,layer,parameter,drc
+import logical_effort
class bitcell_1rw_1r(design.design):
"""
@@ -12,6 +20,8 @@ class bitcell_1rw_1r(design.design):
"""
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
+ type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"]
+ storage_nets = ['Q', 'Q_bar']
(width,height) = utils.get_libcell_size("cell_1rw_1r", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "cell_1rw_1r", GDS["unit"])
@@ -23,21 +33,17 @@ class bitcell_1rw_1r(design.design):
self.width = bitcell_1rw_1r.width
self.height = bitcell_1rw_1r.height
self.pin_map = bitcell_1rw_1r.pin_map
-
- def analytical_delay(self, corner, slew, load=0, swing = 0.5):
- # delay of bit cell is not like a driver(from WL)
- # so the slew used should be 0
- # it should not be slew dependent?
- # because the value is there
- # the delay is only over half transsmission gate
- from tech import spice
- r = spice["min_tx_r"]*3
- c_para = spice["min_tx_drain_c"]
- result = self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew, swing = swing)
- return result
+ self.add_pin_types(self.type_list)
+ self.nets_match = self.do_nets_exist(self.storage_nets)
+
+ def get_stage_effort(self, load):
+ parasitic_delay = 1
+ 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)
-
- def list_bitcell_pins(self, col, row):
+ def get_bitcell_pins(self, col, row):
""" Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """
bitcell_pins = ["bl0_{0}".format(col),
"br0_{0}".format(col),
@@ -49,46 +55,61 @@ class bitcell_1rw_1r(design.design):
"gnd"]
return bitcell_pins
- def list_all_wl_names(self):
+ def get_all_wl_names(self):
""" Creates a list of all wordline pin names """
row_pins = ["wl0", "wl1"]
return row_pins
- def list_all_bitline_names(self):
+ def get_all_bitline_names(self):
""" Creates a list of all bitline pin names (both bl and br) """
column_pins = ["bl0", "br0", "bl1", "br1"]
return column_pins
- def list_all_bl_names(self):
+ def get_all_bl_names(self):
""" Creates a list of all bl pins names """
column_pins = ["bl0", "bl1"]
return column_pins
- def list_all_br_names(self):
+ def get_all_br_names(self):
""" Creates a list of all br pins names """
column_pins = ["br0", "br1"]
return column_pins
- def list_read_bl_names(self):
+ def get_read_bl_names(self):
""" Creates a list of bl pin names associated with read ports """
column_pins = ["bl0", "bl1"]
return column_pins
- def list_read_br_names(self):
+ def get_read_br_names(self):
""" Creates a list of br pin names associated with read ports """
column_pins = ["br0", "br1"]
return column_pins
- def list_write_bl_names(self):
+ def get_write_bl_names(self):
""" Creates a list of bl pin names associated with write ports """
column_pins = ["bl0"]
return column_pins
- def list_write_br_names(self):
+ def get_write_br_names(self):
""" Creates a list of br pin names asscociated with write ports"""
column_pins = ["br0"]
return column_pins
+ def get_bl_name(self, port=0):
+ """Get bl name by port"""
+ debug.check(port<2,"Two ports for bitcell_1rw_1r only.")
+ return "bl{}".format(port)
+
+ def get_br_name(self, port=0):
+ """Get bl name by port"""
+ debug.check(port<2,"Two ports for bitcell_1rw_1r only.")
+ return "br{}".format(port)
+
+ def get_wl_name(self, port=0):
+ """Get wl name by port"""
+ debug.check(port<2,"Two ports for bitcell_1rw_1r only.")
+ return "wl{}".format(port)
+
def analytical_power(self, corner, load):
"""Bitcell power in nW. Only characterizes leakage."""
from tech import spice
@@ -97,10 +118,31 @@ class bitcell_1rw_1r(design.design):
total_power = self.return_power(dynamic, leakage)
return total_power
- def get_wl_cin(self):
+ def input_load(self):
"""Return the relative capacitance of the access transistor gates"""
- #This is a handmade cell so the value must be entered in the tech.py file or estimated.
- #Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
- #FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
+
+ # FIXME: This applies to bitline capacitances as well.
+ # FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin
+
+ def get_storage_net_names(self):
+ """Returns names of storage nodes in bitcell in [non-inverting, inverting] format."""
+ #Checks that they do exist
+ if self.nets_match:
+ return self.storage_nets
+ else:
+ debug.info(1,"Storage nodes={} not found in spice file.".format(self.storage_nets))
+ return None
+
+ def build_graph(self, graph, inst_name, port_nets):
+ """Adds edges to graph. Multiport bitcell timing graph is too complex
+ to use the add_graph_edges function."""
+ pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
+ #Edges hardcoded here. Essentially wl->bl/br for both ports.
+ # Port 0 edges
+ graph.add_edge(pin_dict["wl0"], pin_dict["bl0"], self)
+ graph.add_edge(pin_dict["wl0"], pin_dict["br0"], self)
+ # Port 1 edges
+ graph.add_edge(pin_dict["wl1"], pin_dict["bl1"], self)
+ graph.add_edge(pin_dict["wl1"], pin_dict["br1"], self)
diff --git a/compiler/bitcells/bitcell_1w_1r.py b/compiler/bitcells/bitcell_1w_1r.py
index e2cc662b..7e8c9e75 100644
--- a/compiler/bitcells/bitcell_1w_1r.py
+++ b/compiler/bitcells/bitcell_1w_1r.py
@@ -1,7 +1,15 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import design
import debug
import utils
from tech import GDS,layer,parameter,drc
+import logical_effort
class bitcell_1w_1r(design.design):
"""
@@ -12,6 +20,8 @@ class bitcell_1w_1r(design.design):
"""
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
+ type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", "INPUT", "INPUT", "POWER", "GROUND"]
+ storage_nets = ['Q', 'Q_bar']
(width,height) = utils.get_libcell_size("cell_1w_1r", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "cell_1w_1r", GDS["unit"])
@@ -23,21 +33,17 @@ class bitcell_1w_1r(design.design):
self.width = bitcell_1w_1r.width
self.height = bitcell_1w_1r.height
self.pin_map = bitcell_1w_1r.pin_map
+ self.add_pin_types(self.type_list)
+ self.nets_match = self.do_nets_exist(self.storage_nets)
- def analytical_delay(self, corner, slew, load=0, swing = 0.5):
- # delay of bit cell is not like a driver(from WL)
- # so the slew used should be 0
- # it should not be slew dependent?
- # because the value is there
- # the delay is only over half transsmission gate
- from tech import spice
- r = spice["min_tx_r"]*3
- c_para = spice["min_tx_drain_c"]
- result = self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew, swing = swing)
- return result
+ def get_stage_effort(self, load):
+ parasitic_delay = 1
+ 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)
-
- def list_bitcell_pins(self, col, row):
+ def get_bitcell_pins(self, col, row):
""" Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """
bitcell_pins = ["bl0_{0}".format(col),
"br0_{0}".format(col),
@@ -49,46 +55,59 @@ class bitcell_1w_1r(design.design):
"gnd"]
return bitcell_pins
- def list_all_wl_names(self):
+ def get_all_wl_names(self):
""" Creates a list of all wordline pin names """
row_pins = ["wl0", "wl1"]
return row_pins
- def list_all_bitline_names(self):
+ def get_all_bitline_names(self):
""" Creates a list of all bitline pin names (both bl and br) """
column_pins = ["bl0", "br0", "bl1", "br1"]
return column_pins
- def list_all_bl_names(self):
+ def get_all_bl_names(self):
""" Creates a list of all bl pins names """
column_pins = ["bl0", "bl1"]
return column_pins
- def list_all_br_names(self):
+ def get_all_br_names(self):
""" Creates a list of all br pins names """
column_pins = ["br0", "br1"]
return column_pins
- def list_read_bl_names(self):
+ def get_read_bl_names(self):
""" Creates a list of bl pin names associated with read ports """
column_pins = ["bl0", "bl1"]
return column_pins
- def list_read_br_names(self):
+ def get_read_br_names(self):
""" Creates a list of br pin names associated with read ports """
column_pins = ["br0", "br1"]
return column_pins
- def list_write_bl_names(self):
+ def get_write_bl_names(self):
""" Creates a list of bl pin names associated with write ports """
column_pins = ["bl0"]
return column_pins
- def list_write_br_names(self):
+ def get_write_br_names(self):
""" Creates a list of br pin names asscociated with write ports"""
column_pins = ["br0"]
return column_pins
+ def get_bl_name(self, port=0):
+ """Get bl name by port"""
+ return "bl{}".format(port)
+
+ def get_br_name(self, port=0):
+ """Get bl name by port"""
+ return "br{}".format(port)
+
+ def get_wl_name(self, port=0):
+ """Get wl name by port"""
+ debug.check(port<2,"Two ports for bitcell_1rw_1r only.")
+ return "wl{}".format(port)
+
def analytical_power(self, corner, load):
"""Bitcell power in nW. Only characterizes leakage."""
from tech import spice
@@ -97,10 +116,29 @@ class bitcell_1w_1r(design.design):
total_power = self.return_power(dynamic, leakage)
return total_power
- def get_wl_cin(self):
+ def input_load(self):
"""Return the relative capacitance of the access transistor gates"""
- #This is a handmade cell so the value must be entered in the tech.py file or estimated.
- #Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
- #FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
+
+ # FIXME: This applies to bitline capacitances as well.
+ # FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin
+
+ def get_storage_net_names(self):
+ """Returns names of storage nodes in bitcell in [non-inverting, inverting] format."""
+ #Checks that they do exist
+ if self.nets_match:
+ return self.storage_nets
+ else:
+ debug.info(1,"Storage nodes={} not found in spice file.".format(self.storage_nets))
+ return None
+
+ def build_graph(self, graph, inst_name, port_nets):
+ """Adds edges to graph. Multiport bitcell timing graph is too complex
+ to use the add_graph_edges function."""
+ pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
+ #Edges hardcoded here. Essentially wl->bl/br for both ports.
+ # Port 0 edges
+ graph.add_edge(pin_dict["wl1"], pin_dict["bl1"], self)
+ graph.add_edge(pin_dict["wl1"], pin_dict["br1"], self)
+ # Port 1 is a write port, so its timing is not considered here.
diff --git a/compiler/bitcells/dummy_bitcell.py b/compiler/bitcells/dummy_bitcell.py
new file mode 100644
index 00000000..db748203
--- /dev/null
+++ b/compiler/bitcells/dummy_bitcell.py
@@ -0,0 +1,48 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import design
+import debug
+import utils
+from tech import GDS,layer,parameter,drc
+import logical_effort
+
+class dummy_bitcell(design.design):
+ """
+ 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
+ the layout and netlist should be available in the technology
+ library.
+ """
+
+ pin_names = ["bl", "br", "wl", "vdd", "gnd"]
+ (width,height) = utils.get_libcell_size("dummy_cell_6t", GDS["unit"], layer["boundary"])
+ pin_map = utils.get_libcell_pins(pin_names, "dummy_cell_6t", GDS["unit"])
+
+ def __init__(self, name=""):
+ # Ignore the name argument
+ design.design.__init__(self, "dummy_cell_6t")
+ debug.info(2, "Create dummy bitcell")
+
+ self.width = dummy_bitcell.width
+ self.height = dummy_bitcell.height
+ self.pin_map = dummy_bitcell.pin_map
+
+ def analytical_power(self, corner, load):
+ """Bitcell power in nW. Only characterizes leakage."""
+ from tech import spice
+ leakage = spice["bitcell_leakage"]
+ dynamic = 0 #temporary
+ total_power = self.return_power(dynamic, leakage)
+ return total_power
+
+ def get_wl_cin(self):
+ """Return the relative capacitance of the access transistor gates"""
+ #This is a handmade cell so the value must be entered in the tech.py file or estimated.
+ #Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
+ access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
+ return 2*access_tx_cin
diff --git a/compiler/bitcells/dummy_bitcell_1rw_1r.py b/compiler/bitcells/dummy_bitcell_1rw_1r.py
new file mode 100644
index 00000000..f8986f2d
--- /dev/null
+++ b/compiler/bitcells/dummy_bitcell_1rw_1r.py
@@ -0,0 +1,45 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import design
+import debug
+import utils
+from tech import GDS,layer,drc,parameter
+
+class dummy_bitcell_1rw_1r(design.design):
+ """
+ A single bit cell which is forced to store a 0.
+ This module implements the single memory cell used in the design. It
+ is a hand-made cell, so the layout and netlist should be available in
+ the technology library. """
+
+ pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
+ type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"]
+ (width,height) = utils.get_libcell_size("dummy_cell_1rw_1r", GDS["unit"], layer["boundary"])
+ pin_map = utils.get_libcell_pins(pin_names, "dummy_cell_1rw_1r", GDS["unit"])
+
+ def __init__(self, name=""):
+ # Ignore the name argument
+ design.design.__init__(self, "dummy_cell_1rw_1r")
+ debug.info(2, "Create dummy bitcell 1rw+1r object")
+
+ self.width = dummy_bitcell_1rw_1r.width
+ self.height = dummy_bitcell_1rw_1r.height
+ self.pin_map = dummy_bitcell_1rw_1r.pin_map
+ self.add_pin_types(self.type_list)
+
+ def get_wl_cin(self):
+ """Return the relative capacitance of the access transistor gates"""
+ #This is a handmade cell so the value must be entered in the tech.py file or estimated.
+ #Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
+ #FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
+ access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
+ return 2*access_tx_cin
+
+ def build_graph(self, graph, inst_name, port_nets):
+ """Dummy bitcells are cannot form a path and be part of the timing graph"""
+ return
diff --git a/compiler/bitcells/dummy_bitcell_1w_1r.py b/compiler/bitcells/dummy_bitcell_1w_1r.py
new file mode 100644
index 00000000..ef451b8c
--- /dev/null
+++ b/compiler/bitcells/dummy_bitcell_1w_1r.py
@@ -0,0 +1,45 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import design
+import debug
+import utils
+from tech import GDS,layer,drc,parameter
+
+class dummy_bitcell_1w_1r(design.design):
+ """
+ A single bit cell which is forced to store a 0.
+ This module implements the single memory cell used in the design. It
+ is a hand-made cell, so the layout and netlist should be available in
+ the technology library. """
+
+ pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
+ type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", "INPUT", "INPUT", "POWER", "GROUND"]
+ (width,height) = utils.get_libcell_size("dummy_cell_1w_1r", GDS["unit"], layer["boundary"])
+ pin_map = utils.get_libcell_pins(pin_names, "dummy_cell_1w_1r", GDS["unit"])
+
+ def __init__(self, name=""):
+ # Ignore the name argument
+ design.design.__init__(self, "dummy_cell_1w_1r")
+ debug.info(2, "Create dummy bitcell 1w+1r object")
+
+ self.width = dummy_bitcell_1w_1r.width
+ self.height = dummy_bitcell_1w_1r.height
+ self.pin_map = dummy_bitcell_1w_1r.pin_map
+ self.add_pin_types(self.type_list)
+
+ def get_wl_cin(self):
+ """Return the relative capacitance of the access transistor gates"""
+ #This is a handmade cell so the value must be entered in the tech.py file or estimated.
+ #Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
+ #FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
+ access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
+ return 2*access_tx_cin
+
+ def build_graph(self, graph, inst_name, port_nets):
+ """Dummy bitcells are cannot form a path and be part of the timing graph"""
+ return
diff --git a/compiler/bitcells/dummy_pbitcell.py b/compiler/bitcells/dummy_pbitcell.py
new file mode 100644
index 00000000..ee15e03c
--- /dev/null
+++ b/compiler/bitcells/dummy_pbitcell.py
@@ -0,0 +1,91 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import debug
+import design
+from tech import drc, spice,parameter
+from vector import vector
+from globals import OPTS
+from sram_factory import factory
+
+class dummy_pbitcell(design.design):
+ """
+ Creates a replica bitcell using pbitcell
+ """
+
+ def __init__(self, name):
+ self.num_rw_ports = OPTS.num_rw_ports
+ self.num_w_ports = OPTS.num_w_ports
+ 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)
+ 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))
+
+ self.create_netlist()
+ self.create_layout()
+
+ def create_netlist(self):
+ self.add_pins()
+ self.add_modules()
+ self.create_modules()
+
+ def create_layout(self):
+ self.place_pbitcell()
+ self.route_rbc_connections()
+ self.DRC_LVS()
+
+ def add_pins(self):
+ for port in range(self.total_ports):
+ self.add_pin("bl{}".format(port))
+ self.add_pin("br{}".format(port))
+
+ for port in range(self.total_ports):
+ self.add_pin("wl{}".format(port))
+
+ self.add_pin("vdd")
+ self.add_pin("gnd")
+
+ def add_modules(self):
+ self.prbc = factory.create(module_type="pbitcell",dummy_bitcell=True)
+ self.add_mod(self.prbc)
+
+ self.height = self.prbc.height
+ self.width = self.prbc.width
+
+ def create_modules(self):
+ self.prbc_inst = self.add_inst(name="pbitcell",
+ mod=self.prbc)
+
+ temp = []
+ for port in range(self.total_ports):
+ temp.append("bl{}".format(port))
+ temp.append("br{}".format(port))
+ for port in range(self.total_ports):
+ temp.append("wl{}".format(port))
+ temp.append("vdd")
+ temp.append("gnd")
+ self.connect_inst(temp)
+
+ def place_pbitcell(self):
+ self.prbc_inst.place(offset=vector(0,0))
+
+ def route_rbc_connections(self):
+ for port in range(self.total_ports):
+ self.copy_layout_pin(self.prbc_inst, "bl{}".format(port))
+ self.copy_layout_pin(self.prbc_inst, "br{}".format(port))
+ for port in range(self.total_ports):
+ self.copy_layout_pin(self.prbc_inst, "wl{}".format(port))
+ self.copy_layout_pin(self.prbc_inst, "vdd")
+ self.copy_layout_pin(self.prbc_inst, "gnd")
+
+ def get_wl_cin(self):
+ """Return the relative capacitance of the access transistor gates"""
+ #This module is made using a pbitcell. Get the cin from that module
+ return self.prbc.get_wl_cin()
diff --git a/compiler/bitcells/pbitcell.py b/compiler/bitcells/pbitcell.py
index 55712e44..919a0316 100644
--- a/compiler/bitcells/pbitcell.py
+++ b/compiler/bitcells/pbitcell.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import contact
import design
import debug
@@ -5,6 +12,7 @@ from tech import drc, parameter, spice
from vector import vector
from ptx import ptx
from globals import OPTS
+import logical_effort
class pbitcell(design.design):
"""
@@ -12,22 +20,32 @@ class pbitcell(design.design):
with a variable number of read/write, write, and read ports
"""
- def __init__(self, name, replica_bitcell=False):
+ def __init__(self, name, replica_bitcell=False, dummy_bitcell=False):
self.num_rw_ports = OPTS.num_rw_ports
self.num_w_ports = OPTS.num_w_ports
self.num_r_ports = OPTS.num_r_ports
self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports
self.replica_bitcell = replica_bitcell
+ self.dummy_bitcell = dummy_bitcell
design.design.__init__(self, name)
- debug.info(2, "create a multi-port bitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports,
- self.num_w_ports,
- self.num_r_ports))
+ info_string = "{0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports,
+ self.num_w_ports,
+ self.num_r_ports)
+ debug.info(2, "create a multi-port bitcell with {}".format(info_string))
+ self.add_comment(info_string)
+
+ if self.dummy_bitcell:
+ self.add_comment("dummy bitcell")
+ if self.replica_bitcell:
+ self.add_comment("replica bitcell")
self.create_netlist()
- # We must always create the bitcell layout because some transistor sizes in the other netlists depend on it
+ # We must always create the bitcell layout
+ # because some transistor sizes in the other netlists depend on it
self.create_layout()
+ self.add_boundary()
def create_netlist(self):
self.add_pins()
@@ -71,9 +89,7 @@ class pbitcell(design.design):
# in netlist_only mode, calling offset_all_coordinates or translate_all will not be possible
# this function is not needed to calculate the dimensions of pbitcell in netlist_only mode though
if not OPTS.netlist_only:
- self.offset_all_coordinates()
- gnd_overlap = vector(0, 0.5*contact.well.width)
- self.translate_all(gnd_overlap)
+ self.translate_all(vector(self.leftmost_xpos, self.botmost_ypos))
def add_pins(self):
@@ -90,50 +106,53 @@ class pbitcell(design.design):
port = 0
for k in range(self.num_rw_ports):
- self.add_pin("bl{}".format(port))
- self.add_pin("br{}".format(port))
+ self.add_pin("bl{}".format(port), "OUTPUT")
+ self.add_pin("br{}".format(port), "OUTPUT")
self.rw_bl_names.append("bl{}".format(port))
self.rw_br_names.append("br{}".format(port))
port += 1
for k in range(self.num_w_ports):
- self.add_pin("bl{}".format(port))
- self.add_pin("br{}".format(port))
+ self.add_pin("bl{}".format(port), "INPUT")
+ self.add_pin("br{}".format(port), "INPUT")
self.w_bl_names.append("bl{}".format(port))
self.w_br_names.append("br{}".format(port))
port += 1
for k in range(self.num_r_ports):
- self.add_pin("bl{}".format(port))
- self.add_pin("br{}".format(port))
+ self.add_pin("bl{}".format(port), "OUTPUT")
+ self.add_pin("br{}".format(port), "OUTPUT")
self.r_bl_names.append("bl{}".format(port))
self.r_br_names.append("br{}".format(port))
port += 1
port = 0
for k in range(self.num_rw_ports):
- self.add_pin("wl{}".format(port))
+ self.add_pin("wl{}".format(port), "INPUT")
self.rw_wl_names.append("wl{}".format(port))
port += 1
for k in range(self.num_w_ports):
- self.add_pin("wl{}".format(port))
+ self.add_pin("wl{}".format(port), "INPUT")
self.w_wl_names.append("wl{}".format(port))
port += 1
for k in range(self.num_r_ports):
- self.add_pin("wl{}".format(port))
+ self.add_pin("wl{}".format(port), "INPUT")
self.r_wl_names.append("wl{}".format(port))
port += 1
- self.add_pin("vdd")
- self.add_pin("gnd")
+ self.add_pin("vdd", "POWER")
+ self.add_pin("gnd", "GROUND")
# if this is a replica bitcell, replace the instances of Q_bar with vdd
if self.replica_bitcell:
self.Q_bar = "vdd"
else:
self.Q_bar = "Q_bar"
-
+ self.Q = "Q"
+ self.storage_nets = [self.Q, self.Q_bar]
+
def add_modules(self):
""" Determine size of transistors and add ptx modules """
- # if there are any read/write ports, then the inverter nmos is sized based the number of read/write ports
+ # if there are any read/write ports,
+ # then the inverter nmos is sized based the number of read/write ports
if(self.num_rw_ports > 0):
inverter_nmos_width = self.num_rw_ports*parameter["6T_inv_nmos_size"]
inverter_pmos_width = parameter["6T_inv_pmos_size"]
@@ -141,7 +160,8 @@ class pbitcell(design.design):
write_nmos_width = parameter["6T_access_size"]
read_nmos_width = 2*parameter["6T_inv_pmos_size"]
- # if there are no read/write ports, then the inverter nmos is statically sized for the dual port case
+ # if there are no read/write ports,
+ # then the inverter nmos is statically sized for the dual port case
else:
inverter_nmos_width = 2*parameter["6T_inv_pmos_size"]
inverter_pmos_width = parameter["6T_inv_pmos_size"]
@@ -175,14 +195,21 @@ class pbitcell(design.design):
def calculate_spacing(self):
""" Calculate transistor spacings """
+
# calculate metal contact extensions over transistor active
- readwrite_nmos_contact_extension = 0.5*(self.readwrite_nmos.active_contact.height - self.readwrite_nmos.active_height)
- write_nmos_contact_extension = 0.5*(self.write_nmos.active_contact.height - self.write_nmos.active_height)
- read_nmos_contact_extension = 0.5*(self.read_nmos.active_contact.height - self.read_nmos.active_height)
- max_contact_extension = max(readwrite_nmos_contact_extension, write_nmos_contact_extension, read_nmos_contact_extension)
+ readwrite_nmos_contact_extension = 0.5*(self.readwrite_nmos.active_contact.height \
+ - self.readwrite_nmos.active_height)
+ write_nmos_contact_extension = 0.5*(self.write_nmos.active_contact.height \
+ - self.write_nmos.active_height)
+ read_nmos_contact_extension = 0.5*(self.read_nmos.active_contact.height \
+ - self.read_nmos.active_height)
+ max_contact_extension = max(readwrite_nmos_contact_extension,
+ write_nmos_contact_extension,
+ read_nmos_contact_extension)
# y-offset for the access transistor's gate contact
- self.gate_contact_yoffset = max_contact_extension + self.m2_space + 0.5*max(contact.poly.height, contact.m1m2.height)
+ self.gate_contact_yoffset = max_contact_extension + self.m2_space \
+ + 0.5*max(contact.poly.height, contact.m1m2.height)
# y-position of access transistors
self.port_ypos = self.m1_space + 0.5*contact.m1m2.height + self.gate_contact_yoffset
@@ -191,13 +218,15 @@ class pbitcell(design.design):
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.m1m2.height + self.m2_space + self.m2_width
- m2_constraint = self.bitline_offset + self.m2_space + 0.5*contact.m1m2.height - 0.5*self.readwrite_nmos.active_width
+ self.bitline_offset = -0.5*self.readwrite_nmos.active_width + 0.5*contact.m1m2.height \
+ + self.m2_space + self.m2_width
+ m2_constraint = self.bitline_offset + self.m2_space + 0.5*contact.m1m2.height \
+ - 0.5*self.readwrite_nmos.active_width
self.write_port_spacing = max(self.active_space, self.m1_space, m2_constraint)
self.read_port_spacing = self.bitline_offset + self.m2_space
# spacing between cross coupled inverters
- self.inverter_to_inverter_spacing = contact.poly.height + self.m1_space
+ self.inverter_to_inverter_spacing = contact.poly.width + self.m1_space
# calculations related to inverter connections
inverter_pmos_contact_extension = 0.5*(self.inverter_pmos.active_contact.height - self.inverter_pmos.active_height)
@@ -214,11 +243,11 @@ class pbitcell(design.design):
+ 1.5*contact.poly.width
# spacing between wordlines (and gnd)
- self.rowline_spacing = self.m1_space + contact.m1m2.width
- self.rowline_offset = -0.5*self.m1_width
+ self.m1_offset = -0.5*self.m1_width
# spacing for vdd
- implant_constraint = max(inverter_pmos_contact_extension, 0) + 2*self.implant_enclose_active + 0.5*(contact.well.width - self.m1_width)
+ implant_constraint = max(inverter_pmos_contact_extension, 0) + 2*self.implant_enclose_active \
+ + 0.5*(contact.well.width - self.m1_width)
metal1_constraint = max(inverter_pmos_contact_extension, 0) + self.m1_space
self.vdd_offset = max(implant_constraint, metal1_constraint) + 0.5*self.m1_width
@@ -228,8 +257,10 @@ class pbitcell(design.design):
def calculate_postions(self):
""" Calculate positions that describe the edges and dimensions of the cell """
- self.botmost_ypos = -0.5*self.m1_width - self.total_ports*self.rowline_spacing
- self.topmost_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height + self.inverter_gap + self.inverter_pmos.active_height + self.vdd_offset
+ self.botmost_ypos = self.m1_offset - self.total_ports*self.m1_pitch
+ self.topmost_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height \
+ + self.inverter_gap + self.inverter_pmos.active_height \
+ + self.vdd_offset
self.leftmost_xpos = -0.5*self.inverter_to_inverter_spacing - self.inverter_nmos.active_width \
- self.num_rw_ports*(self.readwrite_nmos.active_width + self.write_port_spacing) \
@@ -239,9 +270,9 @@ class pbitcell(design.design):
self.width = -2*self.leftmost_xpos
self.height = self.topmost_ypos - self.botmost_ypos
-
self.center_ypos = 0.5*(self.topmost_ypos + self.botmost_ypos)
-
+
+
def create_storage(self):
"""
Creates the crossed coupled inverters that act as storage for the bitcell.
@@ -250,20 +281,20 @@ class pbitcell(design.design):
# create active for nmos
self.inverter_nmos_left = self.add_inst(name="inverter_nmos_left",
mod=self.inverter_nmos)
- self.connect_inst(["Q", self.Q_bar, "gnd", "gnd"])
+ self.connect_inst([self.Q, self.Q_bar, "gnd", "gnd"])
self.inverter_nmos_right = self.add_inst(name="inverter_nmos_right",
mod=self.inverter_nmos)
- self.connect_inst(["gnd", "Q", self.Q_bar, "gnd"])
+ self.connect_inst(["gnd", self.Q, self.Q_bar, "gnd"])
# create active for pmos
self.inverter_pmos_left = self.add_inst(name="inverter_pmos_left",
mod=self.inverter_pmos)
- self.connect_inst(["Q", self.Q_bar, "vdd", "vdd"])
+ self.connect_inst([self.Q, self.Q_bar, "vdd", "vdd"])
self.inverter_pmos_right = self.add_inst(name="inverter_pmos_right",
mod=self.inverter_pmos)
- self.connect_inst(["vdd", "Q", self.Q_bar, "vdd"])
+ self.connect_inst(["vdd", self.Q, self.Q_bar, "vdd"])
def place_storage(self):
""" Places the transistors for the crossed coupled inverters in the bitcell """
@@ -291,19 +322,26 @@ class pbitcell(design.design):
self.add_path("poly", [self.inverter_nmos_right.get_pin("G").uc(), self.inverter_pmos_right.get_pin("G").bc()])
# connect output (drain/source) of inverters
- self.add_path("metal1", [self.inverter_nmos_left.get_pin("D").uc(), self.inverter_pmos_left.get_pin("D").bc()], width=contact.well.second_layer_width)
- self.add_path("metal1", [self.inverter_nmos_right.get_pin("S").uc(), self.inverter_pmos_right.get_pin("S").bc()], width=contact.well.second_layer_width)
+ self.add_path("metal1",
+ [self.inverter_nmos_left.get_pin("D").uc(), self.inverter_pmos_left.get_pin("D").bc()],
+ width=contact.active.second_layer_width)
+ self.add_path("metal1",
+ [self.inverter_nmos_right.get_pin("S").uc(), self.inverter_pmos_right.get_pin("S").bc()],
+ width=contact.active.second_layer_width)
# 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.height, self.cross_couple_upper_ypos)
- self.add_contact_center(layers=("poly", "contact", "metal1"),
- offset=contact_offset_left,
- rotate=90)
+ contact_offset_left = vector(self.inverter_nmos_left.get_pin("D").rc().x + 0.5*contact.poly.height,
+ self.cross_couple_upper_ypos)
+ self.add_via_center(layers=("poly", "contact", "metal1"),
+ offset=contact_offset_left,
+ directions=("H","H"))
- contact_offset_right = vector(self.inverter_nmos_right.get_pin("S").lc().x - 0.5*contact.poly.height, self.cross_couple_lower_ypos)
- self.add_contact_center(layers=("poly", "contact", "metal1"),
- offset=contact_offset_right,
- rotate=90)
+
+ contact_offset_right = vector(self.inverter_nmos_right.get_pin("S").lc().x - 0.5*contact.poly.height,
+ self.cross_couple_lower_ypos)
+ self.add_via_center(layers=("poly", "contact", "metal1"),
+ offset=contact_offset_right,
+ directions=("H","H"))
# connect contacts to gate poly (cross couple connections)
gate_offset_right = vector(self.inverter_nmos_right.get_pin("G").lc().x, contact_offset_left.y)
@@ -315,21 +353,21 @@ class pbitcell(design.design):
def route_rails(self):
""" Adds gnd and vdd rails and connects them to the inverters """
# Add rails for vdd and gnd
- gnd_ypos = self.rowline_offset - self.total_ports*self.rowline_spacing
+ gnd_ypos = self.m1_offset - self.total_ports*self.m1_pitch
self.gnd_position = vector(0, gnd_ypos)
self.add_rect_center(layer="metal1",
offset=self.gnd_position,
- width=self.width,
- height=self.m1_width)
+ width=self.width)
self.add_power_pin("gnd", vector(0,gnd_ypos))
- vdd_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height + self.inverter_gap + self.inverter_pmos.active_height + self.vdd_offset
+ vdd_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height \
+ + self.inverter_gap + self.inverter_pmos.active_height \
+ + self.vdd_offset
self.vdd_position = vector(0, vdd_ypos)
self.add_rect_center(layer="metal1",
offset=self.vdd_position,
- width=self.width,
- height=self.m1_width)
+ width=self.width)
self.add_power_pin("vdd", vector(0,vdd_ypos))
def create_readwrite_ports(self):
@@ -347,14 +385,20 @@ class pbitcell(design.design):
# iterate over the number of read/write ports
for k in range(0,self.num_rw_ports):
+ bl_name = self.rw_bl_names[k]
+ br_name = self.rw_br_names[k]
+ if self.dummy_bitcell:
+ bl_name += "_noconn"
+ br_name += "_noconn"
+
# add read/write transistors
self.readwrite_nmos_left[k] = self.add_inst(name="readwrite_nmos_left{}".format(k),
mod=self.readwrite_nmos)
- self.connect_inst([self.rw_bl_names[k], self.rw_wl_names[k], "Q", "gnd"])
+ self.connect_inst([bl_name, self.rw_wl_names[k], self.Q, "gnd"])
self.readwrite_nmos_right[k] = self.add_inst(name="readwrite_nmos_right{}".format(k),
mod=self.readwrite_nmos)
- self.connect_inst([self.Q_bar, self.rw_wl_names[k], self.rw_br_names[k], "gnd"])
+ self.connect_inst([self.Q_bar, self.rw_wl_names[k], br_name, "gnd"])
def place_readwrite_ports(self):
""" Places read/write ports in the bit cell """
@@ -380,13 +424,12 @@ class pbitcell(design.design):
self.readwrite_nmos_right[k].place(offset=[right_readwrite_transistor_xpos, self.port_ypos])
# add pin for RWWL
- rwwl_ypos = self.rowline_offset - k*self.rowline_spacing
+ rwwl_ypos = self.m1_offset - k*self.m1_pitch
self.rwwl_positions[k] = vector(0, rwwl_ypos)
self.add_layout_pin_rect_center(text=self.rw_wl_names[k],
layer="metal1",
offset=self.rwwl_positions[k],
- width=self.width,
- height=self.m1_width)
+ width=self.width)
# add pins for RWBL and RWBR
rwbl_xpos = left_readwrite_transistor_xpos - self.bitline_offset + 0.5*self.m2_width
@@ -394,15 +437,14 @@ class pbitcell(design.design):
self.add_layout_pin_rect_center(text=self.rw_bl_names[k],
layer="metal2",
offset=self.rwbl_positions[k],
- width=drc["minwidth_metal2"],
height=self.height)
- rwbr_xpos = right_readwrite_transistor_xpos + self.readwrite_nmos.active_width + self.bitline_offset - 0.5*self.m2_width
+ rwbr_xpos = right_readwrite_transistor_xpos + self.readwrite_nmos.active_width \
+ + self.bitline_offset - 0.5*self.m2_width
self.rwbr_positions[k] = vector(rwbr_xpos, self.center_ypos)
self.add_layout_pin_rect_center(text=self.rw_br_names[k],
layer="metal2",
offset=self.rwbr_positions[k],
- width=drc["minwidth_metal2"],
height=self.height)
# update furthest left and right transistor edges
@@ -423,14 +465,20 @@ class pbitcell(design.design):
# iterate over the number of write ports
for k in range(0,self.num_w_ports):
+ bl_name = self.w_bl_names[k]
+ br_name = self.w_br_names[k]
+ if self.dummy_bitcell:
+ bl_name += "_noconn"
+ br_name += "_noconn"
+
# add write transistors
self.write_nmos_left[k] = self.add_inst(name="write_nmos_left{}".format(k),
mod=self.write_nmos)
- self.connect_inst([self.w_bl_names[k], self.w_wl_names[k], "Q", "gnd"])
+ self.connect_inst([bl_name, self.w_wl_names[k], self.Q, "gnd"])
self.write_nmos_right[k] = self.add_inst(name="write_nmos_right{}".format(k),
mod=self.write_nmos)
- self.connect_inst([self.Q_bar, self.w_wl_names[k], self.w_br_names[k], "gnd"])
+ self.connect_inst([self.Q_bar, self.w_wl_names[k], br_name, "gnd"])
def place_write_ports(self):
""" Places write ports in the bit cell """
@@ -457,13 +505,13 @@ class pbitcell(design.design):
self.write_nmos_right[k].place(offset=[right_write_transistor_xpos, self.port_ypos])
# add pin for WWL
- wwl_ypos = rwwl_ypos = self.rowline_offset - self.num_rw_ports*self.rowline_spacing - k*self.rowline_spacing
+ wwl_ypos = rwwl_ypos = self.m1_offset - self.num_rw_ports*self.m1_pitch \
+ - k*self.m1_pitch
self.wwl_positions[k] = vector(0, wwl_ypos)
self.add_layout_pin_rect_center(text=self.w_wl_names[k],
layer="metal1",
offset=self.wwl_positions[k],
- width=self.width,
- height=self.m1_width)
+ width=self.width)
# add pins for WBL and WBR
wbl_xpos = left_write_transistor_xpos - self.bitline_offset + 0.5*self.m2_width
@@ -471,15 +519,14 @@ class pbitcell(design.design):
self.add_layout_pin_rect_center(text=self.w_bl_names[k],
layer="metal2",
offset=self.wbl_positions[k],
- width=drc["minwidth_metal2"],
height=self.height)
- wbr_xpos = right_write_transistor_xpos + self.write_nmos.active_width + self.bitline_offset - 0.5*self.m2_width
+ wbr_xpos = right_write_transistor_xpos + self.write_nmos.active_width + self.bitline_offset \
+ - 0.5*self.m2_width
self.wbr_positions[k] = vector(wbr_xpos, self.center_ypos)
self.add_layout_pin_rect_center(text=self.w_br_names[k],
layer="metal2",
offset=self.wbr_positions[k],
- width=drc["minwidth_metal2"],
height=self.height)
# update furthest left and right transistor edges
@@ -506,6 +553,12 @@ class pbitcell(design.design):
# iterate over the number of read ports
for k in range(0,self.num_r_ports):
+ bl_name = self.r_bl_names[k]
+ br_name = self.r_br_names[k]
+ if self.dummy_bitcell:
+ bl_name += "_noconn"
+ br_name += "_noconn"
+
# add read-access transistors
self.read_access_nmos_left[k] = self.add_inst(name="read_access_nmos_left{}".format(k),
mod=self.read_nmos)
@@ -513,16 +566,16 @@ class pbitcell(design.design):
self.read_access_nmos_right[k] = self.add_inst(name="read_access_nmos_right{}".format(k),
mod=self.read_nmos)
- self.connect_inst(["gnd", "Q", "RA_to_R_right{}".format(k), "gnd"])
+ self.connect_inst(["gnd", self.Q, "RA_to_R_right{}".format(k), "gnd"])
# add read transistors
self.read_nmos_left[k] = self.add_inst(name="read_nmos_left{}".format(k),
mod=self.read_nmos)
- self.connect_inst([self.r_bl_names[k], self.r_wl_names[k], "RA_to_R_left{}".format(k), "gnd"])
+ self.connect_inst([bl_name, self.r_wl_names[k], "RA_to_R_left{}".format(k), "gnd"])
self.read_nmos_right[k] = self.add_inst(name="read_nmos_right{}".format(k),
mod=self.read_nmos)
- self.connect_inst(["RA_to_R_right{}".format(k), self.r_wl_names[k], self.r_br_names[k], "gnd"])
+ self.connect_inst(["RA_to_R_right{}".format(k), self.r_wl_names[k], br_name, "gnd"])
def place_read_ports(self):
""" Places the read ports in the bit cell """
@@ -556,13 +609,13 @@ class pbitcell(design.design):
self.read_nmos_right[k].place(offset=[right_read_transistor_xpos+overlap_offset, self.port_ypos])
# add pin for RWL
- rwl_ypos = rwwl_ypos = self.rowline_offset - self.num_rw_ports*self.rowline_spacing - self.num_w_ports*self.rowline_spacing - k*self.rowline_spacing
+ rwl_ypos = rwwl_ypos = self.m1_offset - self.num_rw_ports*self.m1_pitch \
+ - self.num_w_ports*self.m1_pitch - k*self.m1_pitch
self.rwl_positions[k] = vector(0, rwl_ypos)
self.add_layout_pin_rect_center(text=self.r_wl_names[k],
layer="metal1",
offset=self.rwl_positions[k],
- width=self.width,
- height=self.m1_width)
+ width=self.width)
# add pins for RBL and RBR
rbl_xpos = left_read_transistor_xpos - self.bitline_offset + 0.5*self.m2_width
@@ -570,15 +623,14 @@ class pbitcell(design.design):
self.add_layout_pin_rect_center(text=self.r_bl_names[k],
layer="metal2",
offset=self.rbl_positions[k],
- width=drc["minwidth_metal2"],
height=self.height)
- rbr_xpos = right_read_transistor_xpos + self.read_port_width + self.bitline_offset - 0.5*self.m2_width
+ rbr_xpos = right_read_transistor_xpos + self.read_port_width + self.bitline_offset \
+ - 0.5*self.m2_width
self.rbr_positions[k] = vector(rbr_xpos, self.center_ypos)
self.add_layout_pin_rect_center(text=self.r_br_names[k],
layer="metal2",
offset=self.rbr_positions[k],
- width=drc["minwidth_metal2"],
height=self.height)
def route_wordlines(self):
@@ -612,21 +664,21 @@ class pbitcell(design.design):
# first transistor on either side of the cross coupled inverters does not need to route to wordline on metal2
if (k == 0) or (k == 1):
- self.add_contact_center(layers=("poly", "contact", "metal1"),
- offset=port_contact_offset)
+ self.add_via_center(layers=("poly", "contact", "metal1"),
+ offset=port_contact_offset)
self.add_path("poly", [gate_offset, port_contact_offset])
self.add_path("metal1", [port_contact_offset, wl_contact_offset])
else:
- self.add_contact_center(layers=("poly", "contact", "metal1"),
- offset=port_contact_offset)
- self.add_contact_center(layers=("metal1", "via1", "metal2"),
- offset=port_contact_offset)
+ self.add_via_center(layers=("poly", "contact", "metal1"),
+ offset=port_contact_offset)
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=port_contact_offset)
- self.add_contact_center(layers=("metal1", "via1", "metal2"),
- offset=wl_contact_offset,
- rotate=90)
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=wl_contact_offset,
+ directions=("H","H"))
self.add_path("poly", [gate_offset, port_contact_offset])
self.add_path("metal2", [port_contact_offset, wl_contact_offset])
@@ -661,7 +713,9 @@ class pbitcell(design.design):
port_contact_offest = left_port_transistors[k].get_pin("S").center()
bl_offset = vector(bl_positions[k].x, port_contact_offest.y)
- self.add_contact_center(layers=("metal1", "via1", "metal2"),
+ # Leave bitline disconnected if a dummy cell
+ if not self.dummy_bitcell:
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=port_contact_offest)
self.add_path("metal2", [port_contact_offest, bl_offset], width=contact.m1m2.height)
@@ -670,7 +724,9 @@ class pbitcell(design.design):
port_contact_offest = right_port_transistors[k].get_pin("D").center()
br_offset = vector(br_positions[k].x, port_contact_offest.y)
- self.add_contact_center(layers=("metal1", "via1", "metal2"),
+ # Leave bitline disconnected if a dummy cell
+ if not self.dummy_bitcell:
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=port_contact_offest)
self.add_path("metal2", [port_contact_offest, br_offset], width=contact.m1m2.height)
@@ -686,17 +742,17 @@ class pbitcell(design.design):
nmos_contact_positions.append(self.read_access_nmos_right[k].get_pin("S").center())
for position in nmos_contact_positions:
- self.add_contact_center(layers=("metal1", "via1", "metal2"),
- offset=position)
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=position)
if position.x > 0:
contact_correct = 0.5*contact.m1m2.height
else:
contact_correct = -0.5*contact.m1m2.height
supply_offset = vector(position.x + contact_correct, self.gnd_position.y)
- self.add_contact_center(layers=("metal1", "via1", "metal2"),
- offset=supply_offset,
- rotate=90)
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=supply_offset,
+ directions=("H","H"))
self.add_path("metal2", [position, supply_offset])
@@ -712,39 +768,37 @@ class pbitcell(design.design):
for k in range(self.num_rw_ports):
mid = vector(self.readwrite_nmos_left[k].get_pin("D").uc().x, self.cross_couple_lower_ypos)
Q_pos = vector(self.inverter_nmos_left.get_pin("D").lx(), self.cross_couple_lower_ypos)
- self.add_path("metal1", [self.readwrite_nmos_left[k].get_pin("D").uc(), mid+vector(0,0.5*self.m1_width)], width=contact.poly.second_layer_width)
- self.add_path("metal1", [mid, Q_pos])
+ self.add_path("metal1", [self.readwrite_nmos_left[k].get_pin("D").uc(), mid, Q_pos])
mid = vector(self.readwrite_nmos_right[k].get_pin("S").uc().x, self.cross_couple_lower_ypos)
Q_bar_pos = vector(self.inverter_nmos_right.get_pin("S").rx(), self.cross_couple_lower_ypos)
- self.add_path("metal1", [self.readwrite_nmos_right[k].get_pin("S").uc(), mid+vector(0,0.5*self.m1_width)], width=contact.poly.second_layer_width)
- self.add_path("metal1", [mid, Q_bar_pos])
+ self.add_path("metal1", [self.readwrite_nmos_right[k].get_pin("S").uc(), mid, Q_bar_pos])
def route_write_access(self):
""" Routes read/write transistors to the storage component of the bitcell """
for k in range(self.num_w_ports):
mid = vector(self.write_nmos_left[k].get_pin("D").uc().x, self.cross_couple_lower_ypos)
Q_pos = vector(self.inverter_nmos_left.get_pin("D").lx(), self.cross_couple_lower_ypos)
- self.add_path("metal1", [self.write_nmos_left[k].get_pin("D").uc(), mid+vector(0,0.5*self.m1_width)], width=contact.poly.second_layer_width)
- self.add_path("metal1", [mid, Q_pos])
+ self.add_path("metal1", [self.write_nmos_left[k].get_pin("D").uc(), mid, Q_pos])
mid = vector(self.write_nmos_right[k].get_pin("S").uc().x, self.cross_couple_lower_ypos)
Q_bar_pos = vector(self.inverter_nmos_right.get_pin("S").rx(), self.cross_couple_lower_ypos)
- self.add_path("metal1", [self.write_nmos_right[k].get_pin("S").uc(), mid+vector(0,0.5*self.m1_width)], width=contact.poly.second_layer_width)
- self.add_path("metal1", [mid, Q_bar_pos])
+ self.add_path("metal1", [self.write_nmos_right[k].get_pin("S").uc(), mid, Q_bar_pos])
def route_read_access(self):
""" Routes read access transistors to the storage component of the bitcell """
# add poly to metal1 contacts for gates of the inverters
- left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x - drc["poly_to_polycontact"] - 0.5*contact.poly.width, self.cross_couple_upper_ypos)
- self.add_contact_center(layers=("poly", "contact", "metal1"),
- offset=left_storage_contact,
- rotate=90)
+ left_storage_contact = vector(self.inverter_nmos_left.get_pin("G").lc().x - self.poly_to_polycontact - 0.5*contact.poly.width,
+ self.cross_couple_upper_ypos)
+ self.add_via_center(layers=("poly", "contact", "metal1"),
+ offset=left_storage_contact,
+ directions=("H","H"))
- right_storage_contact = vector(self.inverter_nmos_right.get_pin("G").rc().x + drc["poly_to_polycontact"] + 0.5*contact.poly.width, self.cross_couple_upper_ypos)
- self.add_contact_center(layers=("poly", "contact", "metal1"),
- offset=right_storage_contact,
- rotate=90)
+ right_storage_contact = vector(self.inverter_nmos_right.get_pin("G").rc().x + self.poly_to_polycontact + 0.5*contact.poly.width,
+ self.cross_couple_upper_ypos)
+ self.add_via_center(layers=("poly", "contact", "metal1"),
+ offset=right_storage_contact,
+ directions=("H","H"))
inverter_gate_offset_left = vector(self.inverter_nmos_left.get_pin("G").lc().x, self.cross_couple_upper_ypos)
self.add_path("poly", [left_storage_contact, inverter_gate_offset_left])
@@ -757,25 +811,23 @@ class pbitcell(design.design):
for k in range(self.num_r_ports):
port_contact_offset = self.read_access_nmos_left[k].get_pin("G").uc() + vector(0, self.gate_contact_yoffset - self.poly_extend_active)
- self.add_contact_center(layers=("poly", "contact", "metal1"),
- offset=port_contact_offset)
+ self.add_via_center(layers=("poly", "contact", "metal1"),
+ offset=port_contact_offset)
self.add_path("poly", [self.read_access_nmos_left[k].get_pin("G").uc(), port_contact_offset])
mid = vector(self.read_access_nmos_left[k].get_pin("G").uc().x, self.cross_couple_upper_ypos)
- self.add_path("metal1", [port_contact_offset, mid+vector(0,0.5*self.m1_width)], width=contact.poly.second_layer_width)
- self.add_path("metal1", [mid, left_storage_contact])
+ self.add_path("metal1", [port_contact_offset, mid, left_storage_contact])
port_contact_offset = self.read_access_nmos_right[k].get_pin("G").uc() + vector(0, self.gate_contact_yoffset - self.poly_extend_active)
- self.add_contact_center(layers=("poly", "contact", "metal1"),
- offset=port_contact_offset)
+ self.add_via_center(layers=("poly", "contact", "metal1"),
+ offset=port_contact_offset)
self.add_path("poly", [self.read_access_nmos_right[k].get_pin("G").uc(), port_contact_offset])
mid = vector(self.read_access_nmos_right[k].get_pin("G").uc().x, self.cross_couple_upper_ypos)
- self.add_path("metal1", [port_contact_offset, mid+vector(0,0.5*self.m1_width)], width=contact.poly.second_layer_width)
- self.add_path("metal1", [mid, right_storage_contact])
+ self.add_path("metal1", [port_contact_offset, mid, right_storage_contact])
def extend_well(self):
"""
@@ -794,13 +846,13 @@ class pbitcell(design.design):
# extend nwell to encompass inverter_pmos
# calculate offset of the left pmos well
- inverter_well_xpos = -(self.inverter_nmos.active_width + 0.5*self.inverter_to_inverter_spacing) - drc["well_enclosure_active"]
- inverter_well_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height + self.inverter_gap - drc["well_enclosure_active"]
+ inverter_well_xpos = -(self.inverter_nmos.active_width + 0.5*self.inverter_to_inverter_spacing) - self.well_enclose_active
+ inverter_well_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height + self.inverter_gap - self.well_enclose_active
# calculate width of the two combined nwells
# calculate height to encompass nimplant connected to vdd
- well_width = 2*(self.inverter_nmos.active_width + 0.5*self.inverter_to_inverter_spacing) + 2*drc["well_enclosure_active"]
- well_height = self.vdd_position.y - inverter_well_ypos + drc["well_enclosure_active"] + drc["minwidth_tx"]
+ well_width = 2*(self.inverter_nmos.active_width + 0.5*self.inverter_to_inverter_spacing) + 2*self.well_enclose_active
+ well_height = self.vdd_position.y - inverter_well_ypos + self.well_enclose_active + drc["minwidth_tx"]
offset = [inverter_well_xpos,inverter_well_ypos]
self.add_rect(layer="nwell",
@@ -811,21 +863,21 @@ class pbitcell(design.design):
# add well contacts
# connect pimplants to gnd
offset = vector(0, self.gnd_position.y)
- self.add_contact_center(layers=("active", "contact", "metal1"),
- offset=offset,
- rotate=90,
- implant_type="p",
- well_type="p")
+ self.add_via_center(layers=("active", "contact", "metal1"),
+ offset=offset,
+ directions=("H","H"),
+ implant_type="p",
+ well_type="p")
# connect nimplants to vdd
offset = vector(0, self.vdd_position.y)
- self.add_contact_center(layers=("active", "contact", "metal1"),
- offset=offset,
- rotate=90,
- implant_type="n",
- well_type="n")
+ self.add_via_center(layers=("active", "contact", "metal1"),
+ offset=offset,
+ directions=("H","H"),
+ implant_type="n",
+ well_type="n")
- def list_bitcell_pins(self, col, row):
+ def get_bitcell_pins(self, col, row):
""" Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """
bitcell_pins = []
for port in range(self.total_ports):
@@ -837,12 +889,12 @@ class pbitcell(design.design):
bitcell_pins.append("gnd")
return bitcell_pins
- def list_all_wl_names(self):
+ def get_all_wl_names(self):
""" Creates a list of all wordline pin names """
wordline_names = self.rw_wl_names + self.w_wl_names + self.r_wl_names
return wordline_names
- def list_all_bitline_names(self):
+ def get_all_bitline_names(self):
""" Creates a list of all bitline pin names (both bl and br) """
bitline_pins = []
for port in range(self.total_ports):
@@ -850,29 +902,49 @@ class pbitcell(design.design):
bitline_pins.append("br{0}".format(port))
return bitline_pins
- def list_all_bl_names(self):
+ def get_all_bl_names(self):
""" Creates a list of all bl pins names """
- bl_pins = self.rw_bl_names + self.w_bl_names + self.r_bl_names
- return bl_pins
+ return self.rw_bl_names + self.w_bl_names + self.r_bl_names
- def list_all_br_names(self):
+ def get_all_br_names(self):
""" Creates a list of all br pins names """
- br_pins = self.rw_br_names + self.w_br_names + self.r_br_names
- return br_pins
+ return self.rw_br_names + self.w_br_names + self.r_br_names
def route_rbc_short(self):
""" route the short from Q_bar to gnd necessary for the replica bitcell """
Q_bar_pos = self.inverter_pmos_right.get_pin("S").center()
vdd_pos = self.inverter_pmos_right.get_pin("D").center()
self.add_path("metal1", [Q_bar_pos, vdd_pos])
+
+ def get_storage_net_names(self):
+ """Returns names of storage nodes in bitcell in [non-inverting, inverting] format."""
+ return self.storage_nets
+
+ def get_bl_name(self, port=0):
+ """Get bl name by port"""
+ return "bl{}".format(port)
+
+ def get_br_name(self, port=0):
+ """Get bl name by port"""
+ return "br{}".format(port)
- def analytical_delay(self, corner, slew, load=0, swing = 0.5):
- #FIXME: Delay copied exactly over from bitcell
- from tech import spice
- r = spice["min_tx_r"]*3
- c_para = spice["min_tx_drain_c"]
- result = self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew, swing = swing)
- return result
+ def get_wl_name(self, port=0):
+ """Get wl name by port"""
+ debug.check(port<2,"Two ports for bitcell_1rw_1r only.")
+ return "wl{}".format(port)
+
+
+ def get_stage_effort(self, load):
+ parasitic_delay = 1
+ 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.
+
+ #Internal loads due to port configs are halved. This is to account for the size already being halved
+ #for stacked TXs, but internal loads do not see this size estimation.
+ write_port_load = self.num_w_ports*logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap'])/2
+ read_port_load = self.num_r_ports/2 #min size NMOS gate load
+ total_load = load+read_port_load+write_port_load
+ return logical_effort.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."""
@@ -882,9 +954,27 @@ class pbitcell(design.design):
total_power = self.return_power(dynamic, leakage)
return total_power
- def get_wl_cin(self):
+ def input_load(self):
"""Return the relative capacitance of the access transistor gates"""
- #pbitcell uses the different sizing for the port access tx's. Not accounted for in this model.
+
+ # FIXME: This applies to bitline capacitances as well.
+ # pbitcell uses the different sizing for the port access tx's. Not accounted for in this model.
access_tx_cin = self.readwrite_nmos.get_cin()
return 2*access_tx_cin
+ def build_graph(self, graph, inst_name, port_nets):
+ """Adds edges to graph for pbitcell. Only readwrite and read ports."""
+
+ if self.dummy_bitcell:
+ return
+
+ pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
+ # Edges added wl->bl, wl->br for every port except write ports
+ rw_pin_names = zip(self.r_wl_names, self.r_bl_names, self.r_br_names)
+ r_pin_names = zip(self.rw_wl_names, self.rw_bl_names, self.rw_br_names)
+
+ for pin_zip in [rw_pin_names, r_pin_names]:
+ for wl,bl,br in pin_zip:
+ graph.add_edge(pin_dict[wl],pin_dict[bl], self)
+ graph.add_edge(pin_dict[wl],pin_dict[br], self)
+
diff --git a/compiler/bitcells/replica_bitcell.py b/compiler/bitcells/replica_bitcell.py
index d8b8b76e..2f804bf0 100644
--- a/compiler/bitcells/replica_bitcell.py
+++ b/compiler/bitcells/replica_bitcell.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import design
import debug
import utils
@@ -11,6 +18,7 @@ class replica_bitcell(design.design):
the technology library. """
pin_names = ["bl", "br", "wl", "vdd", "gnd"]
+ type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("replica_cell_6t", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_6t", GDS["unit"])
@@ -22,10 +30,30 @@ class replica_bitcell(design.design):
self.width = replica_bitcell.width
self.height = replica_bitcell.height
self.pin_map = replica_bitcell.pin_map
-
- def get_wl_cin(self):
+ self.add_pin_types(self.type_list)
+
+ def get_stage_effort(self, load):
+ parasitic_delay = 1
+ 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)
+
+ def input_load(self):
"""Return the relative capacitance of the access transistor gates"""
- #This is a handmade cell so the value must be entered in the tech.py file or estimated.
- #Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
+
+ # FIXME: This applies to bitline capacitances as well.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
- return 2*access_tx_cin
+ return 2*access_tx_cin
+
+ def analytical_power(self, corner, load):
+ """Bitcell power in nW. Only characterizes leakage."""
+ from tech import spice
+ leakage = spice["bitcell_leakage"]
+ dynamic = 0 #temporary
+ total_power = self.return_power(dynamic, leakage)
+ return total_power
+
+ def build_graph(self, graph, inst_name, port_nets):
+ """Adds edges based on inputs/outputs. Overrides base class function."""
+ self.add_graph_edges(graph, port_nets)
\ No newline at end of file
diff --git a/compiler/bitcells/replica_bitcell_1rw_1r.py b/compiler/bitcells/replica_bitcell_1rw_1r.py
index 8f7b3b38..0f56319e 100644
--- a/compiler/bitcells/replica_bitcell_1rw_1r.py
+++ b/compiler/bitcells/replica_bitcell_1rw_1r.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import design
import debug
import utils
@@ -11,6 +18,7 @@ class replica_bitcell_1rw_1r(design.design):
the technology library. """
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
+ type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("replica_cell_1rw_1r", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_1rw_1r", GDS["unit"])
@@ -22,11 +30,31 @@ class replica_bitcell_1rw_1r(design.design):
self.width = replica_bitcell_1rw_1r.width
self.height = replica_bitcell_1rw_1r.height
self.pin_map = replica_bitcell_1rw_1r.pin_map
+ self.add_pin_types(self.type_list)
- def get_wl_cin(self):
+ def get_stage_effort(self, load):
+ parasitic_delay = 1
+ 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)
+
+ def input_load(self):
"""Return the relative capacitance of the access transistor gates"""
- #This is a handmade cell so the value must be entered in the tech.py file or estimated.
- #Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
- #FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
+
+ # FIXME: This applies to bitline capacitances as well.
+ # FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin
+
+ def build_graph(self, graph, inst_name, port_nets):
+ """Adds edges to graph. Multiport bitcell timing graph is too complex
+ to use the add_graph_edges function."""
+ pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
+ #Edges hardcoded here. Essentially wl->bl/br for both ports.
+ # Port 0 edges
+ graph.add_edge(pin_dict["wl0"], pin_dict["bl0"], self)
+ graph.add_edge(pin_dict["wl0"], pin_dict["br0"], self)
+ # Port 1 edges
+ graph.add_edge(pin_dict["wl1"], pin_dict["bl1"], self)
+ graph.add_edge(pin_dict["wl1"], pin_dict["br1"], self)
\ No newline at end of file
diff --git a/compiler/bitcells/replica_bitcell_1w_1r.py b/compiler/bitcells/replica_bitcell_1w_1r.py
index 6f59adec..b903e0ad 100644
--- a/compiler/bitcells/replica_bitcell_1w_1r.py
+++ b/compiler/bitcells/replica_bitcell_1w_1r.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import design
import debug
import utils
@@ -11,6 +18,7 @@ class replica_bitcell_1w_1r(design.design):
the technology library. """
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
+ type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", "INPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("replica_cell_1w_1r", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_1w_1r", GDS["unit"])
@@ -22,11 +30,30 @@ class replica_bitcell_1w_1r(design.design):
self.width = replica_bitcell_1w_1r.width
self.height = replica_bitcell_1w_1r.height
self.pin_map = replica_bitcell_1w_1r.pin_map
+ self.add_pin_types(self.type_list)
- def get_wl_cin(self):
+ def get_stage_effort(self, load):
+ parasitic_delay = 1
+ 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)
+
+ def input_load(self):
"""Return the relative capacitance of the access transistor gates"""
- #This is a handmade cell so the value must be entered in the tech.py file or estimated.
- #Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width.
- #FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
+
+ # FIXME: This applies to bitline capacitances as well.
+ # FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed.
access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"]
return 2*access_tx_cin
+
+ def build_graph(self, graph, inst_name, port_nets):
+ """Adds edges to graph. Multiport bitcell timing graph is too complex
+ to use the add_graph_edges function."""
+ debug.info(1,'Adding edges for {}'.format(inst_name))
+ pin_dict = {pin:port for pin,port in zip(self.pins, port_nets)}
+ #Edges hardcoded here. Essentially wl->bl/br for the read port.
+ # Port 1 edges
+ graph.add_edge(pin_dict["wl1"], pin_dict["bl1"], self)
+ graph.add_edge(pin_dict["wl1"], pin_dict["br1"], self)
+ # Port 0 is a write port, so its timing is not considered here.
\ No newline at end of file
diff --git a/compiler/bitcells/replica_pbitcell.py b/compiler/bitcells/replica_pbitcell.py
index 4d2ecd70..4fcfb4c5 100644
--- a/compiler/bitcells/replica_pbitcell.py
+++ b/compiler/bitcells/replica_pbitcell.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
import design
from tech import drc, spice,parameter
@@ -67,8 +74,7 @@ class replica_pbitcell(design.design):
self.connect_inst(temp)
def place_pbitcell(self):
- offset = [0,0]
- self.prbc_inst.place(offset=offset)
+ self.prbc_inst.place(offset=vector(0,0))
def route_rbc_connections(self):
for port in range(self.total_ports):
@@ -78,8 +84,4 @@ class replica_pbitcell(design.design):
self.copy_layout_pin(self.prbc_inst, "wl{}".format(port))
self.copy_layout_pin(self.prbc_inst, "vdd")
self.copy_layout_pin(self.prbc_inst, "gnd")
-
- def get_wl_cin(self):
- """Return the relative capacitance of the access transistor gates"""
- #This module is made using a pbitcell. Get the cin from that module
- return self.prbc.get_wl_cin()
+
\ No newline at end of file
diff --git a/compiler/characterizer/__init__.py b/compiler/characterizer/__init__.py
index fc42a889..93dd5bcb 100644
--- a/compiler/characterizer/__init__.py
+++ b/compiler/characterizer/__init__.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import os
import debug
import globals
@@ -6,9 +13,7 @@ from .lib import *
from .delay import *
from .setup_hold import *
from .functional import *
-from .worst_case import *
from .simulation import *
-from .bitline_delay import *
from .measurements import *
from .model_check import *
diff --git a/compiler/characterizer/bit_polarity.py b/compiler/characterizer/bit_polarity.py
new file mode 100644
index 00000000..c14c167e
--- /dev/null
+++ b/compiler/characterizer/bit_polarity.py
@@ -0,0 +1,14 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+
+from enum import Enum
+
+class bit_polarity(Enum):
+ NONINVERTING = 0
+ INVERTING = 1
+
diff --git a/compiler/characterizer/bitline_delay.py b/compiler/characterizer/bitline_delay.py
deleted file mode 100644
index c85f06bc..00000000
--- a/compiler/characterizer/bitline_delay.py
+++ /dev/null
@@ -1,241 +0,0 @@
-import sys,re,shutil
-import debug
-import tech
-import math
-from .stimuli import *
-from .trim_spice import *
-from .charutils import *
-import utils
-from globals import OPTS
-from .delay import delay
-
-class bitline_delay(delay):
- """Functions to test for the worst case delay in a target SRAM
-
- The current worst case determines a feasible period for the SRAM then tests
- several bits and record the delay and differences between the bits.
-
- """
-
- def __init__(self, sram, spfile, corner):
- delay.__init__(self,sram,spfile,corner)
- self.period = tech.spice["feasible_period"]
- self.is_bitline_measure = True
-
- def create_signal_names(self):
- delay.create_signal_names(self)
- self.bl_signal_names = ["Xsram.Xbank0.bl", "Xsram.Xbank0.br"]
- self.sen_name = "Xsram.s_en"
-
- def create_measurement_names(self):
- """Create measurement names. The names themselves currently define the type of measurement"""
- #Altering the names will crash the characterizer. TODO: object orientated approach to the measurements.
- self.bl_volt_meas_names = ["volt_bl", "volt_br"]
- self.bl_delay_meas_names = ["delay_bl", "delay_br"] #only used in SPICE simulation
- self.bl_delay_result_name = "delay_bl_vth" #Used in the return value
-
- def set_probe(self,probe_address, probe_data):
- """ Probe address and data can be set separately to utilize other
- functions in this characterizer besides analyze."""
- delay.set_probe(self,probe_address, probe_data)
- self.bitline_column = self.get_data_bit_column_number(probe_address, probe_data)
-
- def write_delay_measures(self):
- """
- Write the measure statements to quantify the bitline voltage at sense amp enable 50%.
- """
- self.sf.write("\n* Measure statements for delay and power\n")
-
- # Output some comments to aid where cycles start and
- for comment in self.cycle_comments:
- self.sf.write("* {}\n".format(comment))
-
- for read_port in self.targ_read_ports:
- self.write_bitline_voltage_measures(read_port)
- self.write_bitline_delay_measures(read_port)
-
- def write_bitline_voltage_measures(self, port):
- """
- Add measurments to capture the bitline voltages at 50% Sense amp enable
- """
- debug.info(2, "Measuring bitline column={}, port={}".format(self.bitline_column,port))
- if len(self.all_ports) == 1: #special naming case for single port sram bitlines
- bitline_port = ""
- else:
- bitline_port = str(port)
-
- sen_port_name = "{}{}".format(self.sen_name,port)
- for (measure_name, bl_signal_name) in zip(self.bl_volt_meas_names, self.bl_signal_names):
- bl_port_name = "{}{}_{}".format(bl_signal_name, bitline_port, self.bitline_column)
- measure_port_name = "{}{}".format(measure_name,port)
- self.stim.gen_meas_find_voltage(measure_port_name, sen_port_name, bl_port_name, .5, "RISE", self.cycle_times[self.measure_cycles[port]["read0"]])
-
- def write_bitline_delay_measures(self, port):
- """
- Write the measure statements to quantify the delay and power results for a read port.
- """
- # add measure statements for delays/slews
- for (measure_name, bl_signal_name) in zip(self.bl_delay_meas_names, self.bl_signal_names):
- meas_values = self.get_delay_meas_values(measure_name, bl_signal_name, port)
- self.stim.gen_meas_delay(*meas_values)
-
- def get_delay_meas_values(self, delay_name, bitline_name, port):
- """Get the values needed to generate a Spice measurement statement based on the name of the measurement."""
- if len(self.all_ports) == 1: #special naming case for single port sram bitlines
- bitline_port = ""
- else:
- bitline_port = str(port)
-
- meas_name="{0}{1}".format(delay_name, port)
- targ_name = "{0}{1}_{2}".format(bitline_name,bitline_port,self.bitline_column)
- half_vdd = 0.5 * self.vdd_voltage
- trig_val = half_vdd
- targ_val = self.vdd_voltage-tech.spice["v_threshold_typical"]
- trig_name = "clk{0}".format(port)
- trig_dir="FALL"
- targ_dir="FALL"
- #Half period added to delay measurement to negative clock edge
- trig_td = targ_td = self.cycle_times[self.measure_cycles[port]["read0"]] + self.period/2
- return (meas_name,trig_name,targ_name,trig_val,targ_val,trig_dir,targ_dir,trig_td,targ_td)
-
- def gen_test_cycles_one_port(self, read_port, write_port):
- """Sets a list of key time-points [ns] of the waveform (each rising edge)
- of the cycles to do a timing evaluation of a single port """
-
- # Create the inverse address for a scratch address
- inverse_address = self.calculate_inverse_address()
-
- # For now, ignore data patterns and write ones or zeros
- data_ones = "1"*self.word_size
- data_zeros = "0"*self.word_size
-
- if self.t_current == 0:
- self.add_noop_all_ports("Idle cycle (no positive clock edge)",
- inverse_address, data_zeros)
-
- self.add_write("W data 1 address {}".format(inverse_address),
- inverse_address,data_ones,write_port)
-
- self.add_write("W data 0 address {} to write value".format(self.probe_address),
- self.probe_address,data_zeros,write_port)
- self.measure_cycles[write_port]["write0"] = len(self.cycle_times)-1
-
- # This also ensures we will have a H->L transition on the next read
- self.add_read("R data 1 address {} to set DOUT caps".format(inverse_address),
- inverse_address,data_zeros,read_port)
- self.measure_cycles[read_port]["read1"] = len(self.cycle_times)-1
-
- self.add_read("R data 0 address {} to check W0 worked".format(self.probe_address),
- self.probe_address,data_zeros,read_port)
- self.measure_cycles[read_port]["read0"] = len(self.cycle_times)-1
-
- def get_data_bit_column_number(self, probe_address, probe_data):
- """Calculates bitline column number of data bit under test using bit position and mux size"""
- if self.sram.col_addr_size>0:
- col_address = int(probe_address[0:self.sram.col_addr_size],2)
- else:
- col_address = 0
- bl_column = int(self.sram.words_per_row*probe_data + col_address)
- return bl_column
-
- def run_delay_simulation(self):
- """
- This tries to simulate a period and checks if the result works. If
- so, it returns True and the delays, slews, and powers. It
- works on the trimmed netlist by default, so powers do not
- include leakage of all cells.
- """
- #Sanity Check
- debug.check(self.period > 0, "Target simulation period non-positive")
-
- result = [{} for i in self.all_ports]
- # Checking from not data_value to data_value
- self.write_delay_stimulus()
-
- self.stim.run_sim() #running sim prodoces spice output file.
-
- for port in self.targ_read_ports:
- #Parse and check the voltage measurements
- bl_volt_meas_dict = {}
- for mname in self.bl_volt_meas_names:
- mname_port = "{}{}".format(mname,port)
- volt_meas_val = parse_spice_list("timing", mname_port)
- if type(volt_meas_val)!=float:
- debug.error("Failed to Parse Bitline Voltage:\n\t\t{0}={1}".format(mname,volt_meas_val),1)
- bl_volt_meas_dict[mname] = volt_meas_val
- result[port].update(bl_volt_meas_dict)
-
- #Parse and check the delay measurements. Intended that one measurement will fail, save the delay that did not fail.
- bl_delay_meas_dict = {}
- values_added = 0 #For error checking
- for mname in self.bl_delay_meas_names: #Parse
- mname_port = "{}{}".format(mname,port)
- delay_meas_val = parse_spice_list("timing", mname_port)
- if type(delay_meas_val)==float: #Only add if value is float, do not error.
- bl_delay_meas_dict[self.bl_delay_result_name] = delay_meas_val * 1e9 #convert to ns
- values_added+=1
- debug.check(values_added>0, "Bitline delay measurements failed in SPICE simulation.")
- debug.check(values_added<2, "Both bitlines experienced a Vth drop, check simulation results.")
- result[port].update(bl_delay_meas_dict)
-
- # The delay is from the negative edge for our SRAM
- return (True,result)
-
- def check_bitline_all_results(self, results):
- """Checks the bitline values measured for each tested port"""
- for port in self.targ_read_ports:
- self.check_bitline_port_results(results[port])
-
- def check_bitline_port_results(self, port_results):
- """Performs three different checks for the bitline values: functionality, bitline swing from vdd, and differential bit swing"""
- bl_volt, br_volt = port_results["volt_bl"], port_results["volt_br"]
- self.check_functionality(bl_volt,br_volt)
- self.check_swing_from_vdd(bl_volt,br_volt)
- self.check_differential_swing(bl_volt,br_volt)
-
- def check_functionality(self, bl_volt, br_volt):
- """Checks whether the read failed or not. Measured values are hardcoded with the intention of reading a 0."""
- if bl_volt > br_volt:
- debug.error("Read failure. Value 1 was read instead of 0.",1)
-
- def check_swing_from_vdd(self, bl_volt, br_volt):
- """Checks difference on discharging bitline from VDD to see if it is within margin of the RBL height parameter."""
- if bl_volt < br_volt:
- discharge_volt = bl_volt
- else:
- discharge_volt = br_volt
- desired_bl_volt = tech.parameter["rbl_height_percentage"]*self.vdd_voltage
- debug.info(1, "Active bitline={:.3f}v, Desired bitline={:.3f}v".format(discharge_volt,desired_bl_volt))
- vdd_error_margin = .2 #20% of vdd margin for bitline, a little high for now.
- if abs(discharge_volt - desired_bl_volt) > vdd_error_margin*self.vdd_voltage:
- debug.warning("Bitline voltage is not within {}% Vdd margin. Delay chain/RBL could need resizing.".format(vdd_error_margin*100))
-
- def check_differential_swing(self, bl_volt, br_volt):
- """This check looks at the difference between the bitline voltages. This needs to be large enough to prevent
- sensing errors."""
- bitline_swing = abs(bl_volt-br_volt)
- debug.info(1,"Bitline swing={:.3f}v".format(bitline_swing))
- vdd_error_margin = .2 #20% of vdd margin for bitline, a little high for now.
- if bitline_swing < vdd_error_margin*self.vdd_voltage:
- debug.warning("Bitline swing less than {}% Vdd margin. Sensing errors more likely to occur.".format(vdd_error_margin))
-
- def analyze(self, probe_address, probe_data, slews, loads):
- """Measures the bitline swing of the differential bitlines (bl/br) at 50% s_en """
- self.set_probe(probe_address, probe_data)
- self.load=max(loads)
- self.slew=max(slews)
-
- read_port = self.read_ports[0] #only test the first read port
- bitline_swings = {}
- self.targ_read_ports = [read_port]
- self.targ_write_ports = [self.write_ports[0]]
- debug.info(1,"Bitline swing test: corner {}".format(self.corner))
- (success, results)=self.run_delay_simulation()
- debug.check(success, "Bitline Failed: period {}".format(self.period))
- debug.info(1,"Bitline values (voltages/delays):\n\t {}".format(results[read_port]))
- self.check_bitline_all_results(results)
-
- return results
-
-
-
diff --git a/compiler/characterizer/charutils.py b/compiler/characterizer/charutils.py
index 061972cf..fa49b1ed 100644
--- a/compiler/characterizer/charutils.py
+++ b/compiler/characterizer/charutils.py
@@ -1,8 +1,15 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import re
import debug
from globals import OPTS
-
+
def relative_compare(value1,value2,error_tolerance=0.001):
""" This is used to compare relative values for convergence. """
return (abs(value1 - value2) / abs(max(value1,value2)) <= error_tolerance)
@@ -25,7 +32,6 @@ def parse_spice_list(filename, key):
f.close()
# val = re.search(r"{0}\s*=\s*(-?\d+.?\d*\S*)\s+.*".format(key), contents)
val = re.search(r"{0}\s*=\s*(-?\d+.?\d*[e]?[-+]?[0-9]*\S*)\s+.*".format(key), contents)
-
if val != None:
debug.info(4, "Key = " + key + " Val = " + val.group(1))
return convert_to_float(val.group(1))
@@ -86,4 +92,4 @@ def check_dict_values_is_float(dict):
for key, value in dict.items():
if type(value)!=float:
return False
- return True
\ No newline at end of file
+ return True
diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py
index 29b12ae9..31dc898a 100644
--- a/compiler/characterizer/delay.py
+++ b/compiler/characterizer/delay.py
@@ -1,17 +1,30 @@
-import sys,re,shutil
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import sys,re,shutil,copy
import debug
import tech
import math
from .stimuli import *
from .trim_spice import *
from .charutils import *
+from .sram_op import *
+from .bit_polarity import *
import utils
from globals import OPTS
from .simulation import simulation
from .measurements import *
+import logical_effort
+import graph_util
+from sram_factory import factory
class delay(simulation):
- """Functions to measure the delay and power of an SRAM at a given address and
+ """
+ Functions to measure the delay and power of an SRAM at a given address and
data bit.
In general, this will perform the following actions:
@@ -30,113 +43,323 @@ class delay(simulation):
def __init__(self, sram, spfile, corner):
simulation.__init__(self, sram, spfile, corner)
- # These are the member variables for a simulation
self.targ_read_ports = []
self.targ_write_ports = []
self.period = 0
+ if self.write_size:
+ self.num_wmasks = int(self.word_size / self.write_size)
+ else:
+ self.num_wmasks = 0
self.set_load_slew(0,0)
self.set_corner(corner)
+ self.create_signal_names()
+ self.add_graph_exclusions()
def create_measurement_names(self):
- """Create measurement names. The names themselves currently define the type of measurement"""
- #Altering the names will crash the characterizer. TODO: object orientated approach to the measurements.
+ """ Create measurement names. The names themselves currently define the type of measurement """
+
self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"]
self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power"]
- self.voltage_when_names = ["volt_bl", "volt_br"]
- self.bitline_delay_names = ["delay_bl", "delay_br"]
+ # self.voltage_when_names = ["volt_bl", "volt_br"]
+ # self.bitline_delay_names = ["delay_bl", "delay_br"]
def create_measurement_objects(self):
- """Create the measurements used for read and write ports"""
- self.create_read_port_measurement_objects()
- self.create_write_port_measurement_objects()
-
+ """ Create the measurements used for read and write ports """
+
+ self.read_meas_lists = self.create_read_port_measurement_objects()
+ self.write_meas_lists = self.create_write_port_measurement_objects()
+ self.check_meas_names(self.read_meas_lists+self.write_meas_lists)
+
+ def check_meas_names(self, measures_lists):
+ """
+ Given measurements (in 2d list), checks that their names are unique.
+ Spice sim will fail otherwise.
+ """
+ name_set = set()
+ for meas_list in measures_lists:
+ for meas in meas_list:
+ name = meas.name.lower()
+ debug.check(name not in name_set,("SPICE measurements must have unique names. "
+ "Duplicate name={}").format(name))
+ name_set.add(name)
+
def create_read_port_measurement_objects(self):
"""Create the measurements used for read ports: delays, slews, powers"""
-
- self.read_meas_objs = []
- trig_delay_name = "clk{0}"
- targ_name = "{0}{1}_{2}".format(self.dout_name,"{}",self.probe_data) #Empty values are the port and probe data bit
- self.read_meas_objs.append(delay_measure("delay_lh", trig_delay_name, targ_name, "RISE", "RISE", measure_scale=1e9))
- self.read_meas_objs[-1].meta_str = "read1" #Used to index time delay values when measurements written to spice file.
- self.read_meas_objs.append(delay_measure("delay_hl", trig_delay_name, targ_name, "FALL", "FALL", measure_scale=1e9))
- self.read_meas_objs[-1].meta_str = "read0"
-
- self.read_meas_objs.append(slew_measure("slew_lh", targ_name, "RISE", measure_scale=1e9))
- self.read_meas_objs[-1].meta_str = "read1"
- self.read_meas_objs.append(slew_measure("slew_hl", targ_name, "FALL", measure_scale=1e9))
- self.read_meas_objs[-1].meta_str = "read0"
-
- self.read_meas_objs.append(power_measure("read1_power", "RISE", measure_scale=1e3))
- self.read_meas_objs[-1].meta_str = "read1"
- self.read_meas_objs.append(power_measure("read0_power", "FALL", measure_scale=1e3))
- self.read_meas_objs[-1].meta_str = "read0"
-
- #This will later add a half-period to the spice time delay. Only for reading 0.
- for obj in self.read_meas_objs:
- if obj.meta_str is "read0":
- obj.meta_add_delay = True
- trig_name = "Xsram.s_en{}" #Sense amp enable
- if len(self.all_ports) == 1: #special naming case for single port sram bitlines which does not include the port in name
- port_format = ""
- else:
- port_format = "{}"
+ self.read_lib_meas = []
+ self.clk_frmt = "clk{0}" # Unformatted clock name
+ targ_name = "{0}{1}_{2}".format(self.dout_name,"{}",self.probe_data) # Empty values are the port and probe data bit
+ self.delay_meas = []
+ self.delay_meas.append(delay_measure("delay_lh", self.clk_frmt, targ_name, "RISE", "RISE", measure_scale=1e9))
+ self.delay_meas[-1].meta_str = sram_op.READ_ONE # Used to index time delay values when measurements written to spice file.
+ self.delay_meas.append(delay_measure("delay_hl", self.clk_frmt, targ_name, "FALL", "FALL", measure_scale=1e9))
+ self.delay_meas[-1].meta_str = sram_op.READ_ZERO
+ self.read_lib_meas+=self.delay_meas
- bl_name = "Xsram.Xbank0.bl{}_{}".format(port_format, self.bitline_column)
- br_name = "Xsram.Xbank0.br{}_{}".format(port_format, self.bitline_column)
- self.read_meas_objs.append(voltage_when_measure(self.voltage_when_names[0], trig_name, bl_name, "RISE", .5))
- self.read_meas_objs.append(voltage_when_measure(self.voltage_when_names[1], trig_name, br_name, "RISE", .5))
+ self.slew_meas = []
+ self.slew_meas.append(slew_measure("slew_lh", targ_name, "RISE", measure_scale=1e9))
+ self.slew_meas[-1].meta_str = sram_op.READ_ONE
+ self.slew_meas.append(slew_measure("slew_hl", targ_name, "FALL", measure_scale=1e9))
+ self.slew_meas[-1].meta_str = sram_op.READ_ZERO
+ self.read_lib_meas+=self.slew_meas
- #These are read values but need to be separated for unique error checking.
- self.create_bitline_delay_measurement_objects()
+ self.read_lib_meas.append(power_measure("read1_power", "RISE", measure_scale=1e3))
+ self.read_lib_meas[-1].meta_str = sram_op.READ_ONE
+ self.read_lib_meas.append(power_measure("read0_power", "FALL", measure_scale=1e3))
+ self.read_lib_meas[-1].meta_str = sram_op.READ_ZERO
+
+ # This will later add a half-period to the spice time delay. Only for reading 0.
+ for obj in self.read_lib_meas:
+ if obj.meta_str is sram_op.READ_ZERO:
+ obj.meta_add_delay = True
+
+ read_measures = []
+ read_measures.append(self.read_lib_meas)
+ # Other measurements associated with the read port not included in the liberty file
+ read_measures.append(self.create_bitline_measurement_objects())
+ read_measures.append(self.create_debug_measurement_objects())
+ read_measures.append(self.create_read_bit_measures())
+
+ return read_measures
- def create_bitline_delay_measurement_objects(self):
- """Create the measurements used for bitline delay values. Due to unique error checking, these are separated from other measurements.
- These measurements are only associated with read values
+ def create_bitline_measurement_objects(self):
+ """
+ Create the measurements used for bitline delay values. Due to
+ unique error checking, these are separated from other measurements.
+ These measurements are only associated with read values.
"""
- self.bitline_delay_objs = []
- trig_name = "clk{0}"
- if len(self.all_ports) == 1: #special naming case for single port sram bitlines which does not include the port in name
- port_format = ""
- else:
- port_format = "{}"
- bl_name = "Xsram.Xbank0.bl{}_{}".format(port_format, self.bitline_column)
- br_name = "Xsram.Xbank0.br{}_{}".format(port_format, self.bitline_column)
- targ_val = (self.vdd_voltage - tech.spice["v_threshold_typical"])/self.vdd_voltage #Calculate as a percentage of vdd
- targ_name = "{0}{1}_{2}".format(self.dout_name,"{}",self.probe_data) #Empty values are the port and probe data bit
- self.bitline_delay_objs.append(delay_measure(self.bitline_delay_names[0], trig_name, bl_name, "FALL", "FALL", targ_vdd=targ_val, measure_scale=1e9))
- self.bitline_delay_objs[-1].meta_str = "read0"
- self.bitline_delay_objs.append(delay_measure(self.bitline_delay_names[1], trig_name, br_name, "FALL", "FALL", targ_vdd=targ_val, measure_scale=1e9))
- self.bitline_delay_objs[-1].meta_str = "read1"
- #Enforces the time delay on the bitline measurements for read0 or read1
- for obj in self.bitline_delay_objs:
- obj.meta_add_delay = True
+ self.bitline_volt_meas = []
+
+ self.bitline_volt_meas.append(voltage_at_measure("v_bl_READ_ZERO",
+ self.bl_name))
+ self.bitline_volt_meas[-1].meta_str = sram_op.READ_ZERO
+ self.bitline_volt_meas.append(voltage_at_measure("v_br_READ_ZERO",
+ self.br_name))
+ self.bitline_volt_meas[-1].meta_str = sram_op.READ_ZERO
+
+ self.bitline_volt_meas.append(voltage_at_measure("v_bl_READ_ONE",
+ self.bl_name))
+ self.bitline_volt_meas[-1].meta_str = sram_op.READ_ONE
+ self.bitline_volt_meas.append(voltage_at_measure("v_br_READ_ONE",
+ self.br_name))
+ self.bitline_volt_meas[-1].meta_str = sram_op.READ_ONE
+ return self.bitline_volt_meas
def create_write_port_measurement_objects(self):
"""Create the measurements used for read ports: delays, slews, powers"""
- self.write_meas_objs = []
+
+ self.write_lib_meas = []
- self.write_meas_objs.append(power_measure("write1_power", "RISE", measure_scale=1e3))
- self.write_meas_objs[-1].meta_str = "write1"
- self.write_meas_objs.append(power_measure("write0_power", "FALL", measure_scale=1e3))
- self.write_meas_objs[-1].meta_str = "write0"
+ self.write_lib_meas.append(power_measure("write1_power", "RISE", measure_scale=1e3))
+ self.write_lib_meas[-1].meta_str = sram_op.WRITE_ONE
+ self.write_lib_meas.append(power_measure("write0_power", "FALL", measure_scale=1e3))
+ self.write_lib_meas[-1].meta_str = sram_op.WRITE_ZERO
+
+ write_measures = []
+ write_measures.append(self.write_lib_meas)
+ write_measures.append(self.create_write_bit_measures())
+ return write_measures
+
+ def create_debug_measurement_objects(self):
+ """Create debug measurement to help identify failures."""
+
+ self.dout_volt_meas = []
+ for meas in self.delay_meas:
+ # Output voltage measures
+ self.dout_volt_meas.append(voltage_at_measure("v_{}".format(meas.name),
+ meas.targ_name_no_port))
+ self.dout_volt_meas[-1].meta_str = meas.meta_str
+
+ self.sen_meas = delay_measure("delay_sen", self.clk_frmt, self.sen_name, "FALL", "RISE", measure_scale=1e9)
+ self.sen_meas.meta_str = sram_op.READ_ZERO
+ self.sen_meas.meta_add_delay = True
+
+ return self.dout_volt_meas+[self.sen_meas]
- def create_signal_names(self):
- self.addr_name = "A"
- self.din_name = "DIN"
- self.dout_name = "DOUT"
+ def create_read_bit_measures(self):
+ """ Adds bit measurements for read0 and read1 cycles """
- #This is TODO once multiport control has been finalized.
- #self.control_name = "CSB"
+ self.bit_meas = {bit_polarity.NONINVERTING:[], bit_polarity.INVERTING:[]}
+ meas_cycles = (sram_op.READ_ZERO, sram_op.READ_ONE)
+ for cycle in meas_cycles:
+ meas_tag = "a{}_b{}_{}".format(self.probe_address, self.probe_data, cycle.name)
+ single_bit_meas = self.get_bit_measures(meas_tag, self.probe_address, self.probe_data)
+ for polarity,meas in single_bit_meas.items():
+ meas.meta_str = cycle
+ self.bit_meas[polarity].append(meas)
+ # Dictionary values are lists, reduce to a single list of measurements
+ return [meas for meas_list in self.bit_meas.values() for meas in meas_list]
+
+ def create_write_bit_measures(self):
+ """ Adds bit measurements for write0 and write1 cycles """
+ self.bit_meas = {bit_polarity.NONINVERTING:[], bit_polarity.INVERTING:[]}
+ meas_cycles = (sram_op.WRITE_ZERO, sram_op.WRITE_ONE)
+ for cycle in meas_cycles:
+ meas_tag = "a{}_b{}_{}".format(self.probe_address, self.probe_data, cycle.name)
+ single_bit_meas = self.get_bit_measures(meas_tag, self.probe_address, self.probe_data)
+ for polarity,meas in single_bit_meas.items():
+ meas.meta_str = cycle
+ self.bit_meas[polarity].append(meas)
+ # Dictionary values are lists, reduce to a single list of measurements
+ return [meas for meas_list in self.bit_meas.values() for meas in meas_list]
+
+ def get_bit_measures(self, meas_tag, probe_address, probe_data):
+ """
+ Creates measurements for the q/qbar of input bit position.
+ meas_tag is a unique identifier for the measurement.
+ """
+
+ bit_col = self.get_data_bit_column_number(probe_address, probe_data)
+ bit_row = self.get_address_row_number(probe_address)
+ (cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, bit_row, bit_col)
+ storage_names = cell_inst.mod.get_storage_net_names()
+ debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes"
+ "supported for characterization. Storage nets={}").format(storage_names))
+ q_name = cell_name+'.'+str(storage_names[0])
+ qbar_name = cell_name+'.'+str(storage_names[1])
+
+ # Bit measures, measurements times to be defined later. The measurement names must be unique
+ # but they is enforced externally
+ q_meas = voltage_at_measure("v_q_{}".format(meas_tag), q_name, has_port=False)
+ qbar_meas = voltage_at_measure("v_qbar_{}".format(meas_tag), qbar_name, has_port=False)
+
+ return {bit_polarity.NONINVERTING:q_meas, bit_polarity.INVERTING:qbar_meas}
+
def set_load_slew(self,load,slew):
""" Set the load and slew """
+
self.load = load
self.slew = slew
+ def add_graph_exclusions(self):
+ """Exclude portions of SRAM from timing graph which are not relevant"""
+
+ # other initializations can only be done during analysis when a bit has been selected
+ # for testing.
+ self.sram.bank.graph_exclude_precharge()
+ self.sram.graph_exclude_addr_dff()
+ self.sram.graph_exclude_data_dff()
+ self.sram.graph_exclude_ctrl_dffs()
+ self.sram.bank.bitcell_array.graph_exclude_replica_col_bits()
+
+ def create_graph(self):
+ """Creates timing graph to generate the timing paths for the SRAM output."""
+
+ self.sram.bank.bitcell_array.bitcell_array.init_graph_params() # Removes previous bit exclusions
+ self.sram.bank.bitcell_array.graph_exclude_bits(self.wordline_row, self.bitline_column)
+
+ # Generate new graph every analysis as edges might change depending on test bit
+ self.graph = graph_util.timing_graph()
+ self.sram_spc_name = "X{}".format(self.sram.name)
+ self.sram.build_graph(self.graph,self.sram_spc_name,self.pins)
+
+ def set_internal_spice_names(self):
+ """Sets important names for characterization such as Sense amp enable and internal bit nets."""
+
+ port = self.read_ports[0]
+ self.graph.get_all_paths('{}{}'.format("clk", port),
+ '{}{}_{}'.format(self.dout_name, port, self.probe_data))
+
+ self.sen_name = self.get_sen_name(self.graph.all_paths)
+ debug.info(2,"s_en name = {}".format(self.sen_name))
+
+ self.bl_name,self.br_name = self.get_bl_name(self.graph.all_paths, port)
+ debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name))
+
+ def get_sen_name(self, paths):
+ """
+ Gets the signal name associated with the sense amp enable from input paths.
+ Only expects a single path to contain the sen signal name.
+ """
+
+ sa_mods = factory.get_mods(OPTS.sense_amp)
+ # Any sense amp instantiated should be identical, any change to that
+ # will require some identification to determine the mod desired.
+ debug.check(len(sa_mods) == 1, "Only expected one type of Sense Amp. Cannot perform s_en checks.")
+ enable_name = sa_mods[0].get_enable_name()
+ sen_name = self.get_alias_in_path(paths, enable_name, sa_mods[0])
+ return sen_name
+
+ def get_bl_name(self, paths, port):
+ """Gets the signal name associated with the bitlines in the bank."""
+
+ cell_mod = factory.create(module_type=OPTS.bitcell)
+ cell_bl = cell_mod.get_bl_name(port)
+ cell_br = cell_mod.get_br_name(port)
+
+ bl_found = False
+ # Only a single path should contain a single s_en name. Anything else is an error.
+ bl_names = []
+ exclude_set = self.get_bl_name_search_exclusions()
+ for int_net in [cell_bl, cell_br]:
+ bl_names.append(self.get_alias_in_path(paths, int_net, cell_mod, exclude_set))
+
+ return bl_names[0], bl_names[1]
+
+
+ def get_bl_name_search_exclusions(self):
+ """Gets the mods as a set which should be excluded while searching for name."""
+
+ # Exclude the RBL as it contains bitcells which are not in the main bitcell array
+ # so it makes the search awkward
+ return set(factory.get_mods(OPTS.replica_bitline))
+
+ def get_primary_cell_mod(self, cell_mods):
+ """
+ Distinguish bitcell array mod from replica bitline array.
+ Assume there are no replica bitcells in the primary array.
+ """
+ if len(cell_mods) == 1:
+ return cell_mods[0]
+ rbc_mods = factory.get_mods(OPTS.replica_bitcell)
+ non_rbc_mods = []
+ for bitcell in cell_mods:
+ has_cell = False
+ for replica_cell in rbc_mods:
+ has_cell = has_cell or replica_cell.contains(bitcell, replica_cell.mods)
+ if not has_cell:
+ non_rbc_mods.append(bitcell)
+ if len(non_rbc_mods) != 1:
+ debug.error('Multiple bitcell mods found. Cannot distinguish for characterization',1)
+ return non_rbc_mods[0]
+
+ def are_mod_pins_equal(self, mods):
+ """Determines if there are pins differences in the input mods"""
+
+ if len(mods) == 0:
+ return True
+ pins = mods[0].pins
+ for mod in mods[1:]:
+ if pins != mod.pins:
+ return False
+ return True
+
+ def get_alias_in_path(self, paths, int_net, mod, exclusion_set=None):
+ """
+ Finds a single alias for the int_net in given paths.
+ More or less hits cause an error
+ """
+
+ net_found = False
+ for path in paths:
+ aliases = self.sram.find_aliases(self.sram_spc_name, self.pins, path, int_net, mod, exclusion_set)
+ if net_found and len(aliases) >= 1:
+ debug.error('Found multiple paths with {} net.'.format(int_net),1)
+ elif len(aliases) > 1:
+ debug.error('Found multiple {} nets in single path.'.format(int_net),1)
+ elif not net_found and len(aliases) == 1:
+ path_net_name = aliases[0]
+ net_found = True
+ if not net_found:
+ debug.error("Could not find {} net in timing paths.".format(int_net),1)
+
+ return path_net_name
+
def check_arguments(self):
"""Checks if arguments given for write_stimulus() meets requirements"""
+
try:
int(self.probe_address, 2)
except ValueError:
@@ -148,7 +371,7 @@ class delay(simulation):
if not isinstance(self.probe_data, int) or self.probe_data>self.word_size or self.probe_data<0:
debug.error("Given probe_data is not an integer to specify a data bit",1)
- #Adding port options here which the characterizer cannot handle. Some may be added later like ROM
+ # Adding port options here which the characterizer cannot handle. Some may be added later like ROM
if len(self.read_ports) == 0:
debug.error("Characterizer does not currently support SRAMs without read ports.",1)
if len(self.write_ports) == 0:
@@ -163,12 +386,8 @@ class delay(simulation):
# instantiate the sram
self.sf.write("\n* Instantiation of the SRAM\n")
- self.stim.inst_sram(sram=self.sram,
- port_signal_names=(self.addr_name,self.din_name,self.dout_name),
- port_info=(len(self.all_ports),self.write_ports,self.read_ports),
- abits=self.addr_size,
- dbits=self.word_size,
- sram_name=self.name)
+ self.stim.inst_model(pins=self.pins,
+ model_name=self.sram.name)
self.sf.write("\n* SRAM output loads\n")
for port in self.read_ports:
for i in range(self.word_size):
@@ -176,10 +395,12 @@ class delay(simulation):
def write_delay_stimulus(self):
- """ Creates a stimulus file for simulations to probe a bitcell at a given clock period.
+ """
+ Creates a stimulus file for simulations to probe a bitcell at a given clock period.
Address and bit were previously set with set_probe().
Input slew (in ns) and output capacitive load (in fF) are required for charaterization.
"""
+
self.check_arguments()
# obtains list of time-points for each rising clk edge
@@ -274,30 +495,47 @@ class delay(simulation):
self.sf.close()
- def get_read_measure_variants(self, port, measure_obj):
- """Checks the measurement object and calls respective function for related measurement inputs."""
+ def get_measure_variants(self, port, measure_obj, measure_type=None):
+ """
+ Checks the measurement object and calls respective function for
+ related measurement inputs.
+ """
+
meas_type = type(measure_obj)
if meas_type is delay_measure or meas_type is slew_measure:
- return self.get_delay_measure_variants(port, measure_obj)
+ variant_tuple = self.get_delay_measure_variants(port, measure_obj)
elif meas_type is power_measure:
- return self.get_power_measure_variants(port, measure_obj, "read")
+ variant_tuple = self.get_power_measure_variants(port, measure_obj, measure_type)
elif meas_type is voltage_when_measure:
- return self.get_volt_when_measure_variants(port, measure_obj)
+ variant_tuple = self.get_volt_when_measure_variants(port, measure_obj)
+ elif meas_type is voltage_at_measure:
+ variant_tuple = self.get_volt_at_measure_variants(port, measure_obj)
else:
debug.error("Input function not defined for measurement type={}".format(meas_type))
-
+ # Removes port input from any object which does not use it. This shorthand only works if
+ # the measurement has port as the last input. Could be implemented by measurement type or
+ # remove entirely from measurement classes.
+ if not measure_obj.has_port:
+ variant_tuple = variant_tuple[:-1]
+ return variant_tuple
+
def get_delay_measure_variants(self, port, delay_obj):
- """Get the measurement values that can either vary from simulation to simulation (vdd, address) or port to port (time delays)"""
- #Return value is intended to match the delay measure format: trig_td, targ_td, vdd, port
- #vdd is arguably constant as that is true for a single lib file.
- if delay_obj.meta_str == "read0":
- #Falling delay are measured starting from neg. clk edge. Delay adjusted to that.
+ """
+ Get the measurement values that can either vary from simulation to
+ simulation (vdd, address) or port to port (time delays)
+ """
+
+ # Return value is intended to match the delay measure format: trig_td, targ_td, vdd, port
+ # vdd is arguably constant as that is true for a single lib file.
+ if delay_obj.meta_str == sram_op.READ_ZERO:
+ # Falling delay are measured starting from neg. clk edge. Delay adjusted to that.
meas_cycle_delay = self.cycle_times[self.measure_cycles[port][delay_obj.meta_str]]
- elif delay_obj.meta_str == "read1":
+ elif delay_obj.meta_str == sram_op.READ_ONE:
meas_cycle_delay = self.cycle_times[self.measure_cycles[port][delay_obj.meta_str]]
else:
debug.error("Unrecognised delay Index={}".format(delay_obj.meta_str),1)
+ # These measurements have there time further delayed to the neg. edge of the clock.
if delay_obj.meta_add_delay:
meas_cycle_delay += self.period/2
@@ -305,16 +543,33 @@ class delay(simulation):
def get_power_measure_variants(self, port, power_obj, operation):
"""Get the measurement values that can either vary port to port (time delays)"""
- #Return value is intended to match the power measure format: t_initial, t_final, port
+
+ # Return value is intended to match the power measure format: t_initial, t_final, port
t_initial = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]]
t_final = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]+1]
return (t_initial, t_final, port)
- def get_volt_when_measure_variants(self, port, power_obj):
- """Get the measurement values that can either vary port to port (time delays)"""
- #Only checking 0 value reads for now.
- t_trig = meas_cycle_delay = self.cycle_times[self.measure_cycles[port]["read0"]]
+ def get_volt_at_measure_variants(self, port, volt_meas):
+ """
+ Get the measurement values that can either vary port to port (time delays)
+ """
+
+ meas_cycle = self.cycle_times[self.measure_cycles[port][volt_meas.meta_str]]
+
+ # Measurement occurs slightly into the next period so we know that the value
+ # "stuck" after the end of the period -> current period start + 1.25*period
+ at_time = meas_cycle+1.25*self.period
+
+ return (at_time, port)
+
+ def get_volt_when_measure_variants(self, port, volt_meas):
+ """
+ Get the measurement values that can either vary port to port (time delays)
+ """
+
+ # Only checking 0 value reads for now.
+ t_trig = meas_cycle_delay = self.cycle_times[self.measure_cycles[port][sram_op.READ_ZERO]]
return (t_trig, self.vdd_voltage, port)
@@ -322,43 +577,45 @@ class delay(simulation):
"""
Write the measure statements to quantify the delay and power results for a read port.
"""
+
# add measure statements for delays/slews
- for measure in self.read_meas_objs+self.bitline_delay_objs:
- measure_variant_inp_tuple = self.get_read_measure_variants(port, measure)
- measure.write_measure(self.stim, measure_variant_inp_tuple)
+ for meas_list in self.read_meas_lists:
+ for measure in meas_list:
+ measure_variant_inp_tuple = self.get_measure_variants(port, measure, "read")
+ measure.write_measure(self.stim, measure_variant_inp_tuple)
- def get_write_measure_variants(self, port, measure_obj):
- """Checks the measurement object and calls respective function for related measurement inputs."""
- meas_type = type(measure_obj)
- if meas_type is power_measure:
- return self.get_power_measure_variants(port, measure_obj, "write")
- else:
- debug.error("Input function not defined for measurement type={}".format(meas_type))
def write_delay_measures_write_port(self, port):
"""
Write the measure statements to quantify the power results for a write port.
"""
+
# add measure statements for power
- for measure in self.write_meas_objs:
- measure_variant_inp_tuple = self.get_write_measure_variants(port, measure)
- measure.write_measure(self.stim, measure_variant_inp_tuple)
+ for meas_list in self.write_meas_lists:
+ for measure in meas_list:
+ measure_variant_inp_tuple = self.get_measure_variants(port, measure, "write")
+ measure.write_measure(self.stim, measure_variant_inp_tuple)
def write_delay_measures(self):
"""
Write the measure statements to quantify the delay and power results for all targeted ports.
"""
+
self.sf.write("\n* Measure statements for delay and power\n")
# Output some comments to aid where cycles start and
# what is happening
for comment in self.cycle_comments:
self.sf.write("* {}\n".format(comment))
-
+
+ self.sf.write("\n")
for read_port in self.targ_read_ports:
- self.write_delay_measures_read_port(read_port)
+ self.sf.write("* Read ports {}\n".format(read_port))
+ self.write_delay_measures_read_port(read_port)
+
for write_port in self.targ_write_ports:
- self.write_delay_measures_write_port(write_port)
+ self.sf.write("* Write ports {}\n".format(write_port))
+ self.write_delay_measures_write_port(write_port)
def write_power_measures(self):
@@ -392,35 +649,36 @@ class delay(simulation):
if (time_out <= 0):
debug.error("Timed out, could not find a feasible period.",2)
- #Clear any write target ports and set read port
- self.targ_write_ports = []
+ # Clear any write target ports and set read port
+ self.targ_write_ports = [port]
self.targ_read_ports = [port]
- success = False
debug.info(1, "Trying feasible period: {0}ns on Port {1}".format(feasible_period, port))
self.period = feasible_period
(success, results)=self.run_delay_simulation()
- #Clear these target ports after simulation
+
+ # Clear these target ports after simulation
+ self.targ_write_ports = []
self.targ_read_ports = []
if not success:
feasible_period = 2 * feasible_period
continue
- #Positions of measurements currently hardcoded. First 2 are delays, next 2 are slews
+ # Positions of measurements currently hardcoded. First 2 are delays, next 2 are slews
feasible_delays = [results[port][mname] for mname in self.delay_meas_names if "delay" in mname]
feasible_slews = [results[port][mname] for mname in self.delay_meas_names if "slew" in mname]
delay_str = "feasible_delay {0:.4f}ns/{1:.4f}ns".format(*feasible_delays)
slew_str = "slew {0:.4f}ns/{1:.4f}ns".format(*feasible_slews)
debug.info(2, "feasible_period passed for Port {3}: {0}ns {1} {2} ".format(feasible_period,
- delay_str,
- slew_str,
- port))
+ delay_str,
+ slew_str,
+ port))
if success:
debug.info(2, "Found feasible_period for port {0}: {1}ns".format(port, feasible_period))
self.period = feasible_period
- #Only return results related to input port.
+ # Only return results related to input port.
return results[port]
def find_feasible_period(self):
@@ -430,19 +688,19 @@ class delay(simulation):
"""
feasible_delays = [{} for i in self.all_ports]
- #Get initial feasible delays from first port
+ # Get initial feasible delays from first port
feasible_delays[self.read_ports[0]] = self.find_feasible_period_one_port(self.read_ports[0])
previous_period = self.period
- #Loops through all the ports checks if the feasible period works. Everything restarts it if does not.
- #Write ports do not produce delays which is why they are not included here.
+ # Loops through all the ports checks if the feasible period works. Everything restarts it if does not.
+ # Write ports do not produce delays which is why they are not included here.
i = 1
while i < len(self.read_ports):
port = self.read_ports[i]
- #Only extract port values from the specified port, not the entire results.
+ # Only extract port values from the specified port, not the entire results.
feasible_delays[port].update(self.find_feasible_period_one_port(port))
- #Function sets the period. Restart the entire process if period changes to collect accurate delays
+ # Function sets the period. Restart the entire process if period changes to collect accurate delays
if self.period > previous_period:
i = 0
else:
@@ -458,71 +716,174 @@ class delay(simulation):
works on the trimmed netlist by default, so powers do not
include leakage of all cells.
"""
- #Sanity Check
+
debug.check(self.period > 0, "Target simulation period non-positive")
- result = [{} for i in self.all_ports]
- # Checking from not data_value to data_value
self.write_delay_stimulus()
self.stim.run_sim()
+
+ return self.check_measurements()
+
+ def check_measurements(self):
+ """ Check the write and read measurements """
- #Loop through all targeted ports and collect delays and powers.
- #Too much duplicate code here. Try reducing
- for port in self.targ_read_ports:
- debug.info(2, "Check delay values for port {}".format(port))
- read_port_dict = {}
- #Get measurements from output file
- for measure in self.read_meas_objs:
- read_port_dict[measure.name] = measure.retrieve_measure(port=port)
-
- #Check timing for read ports. Power is only checked if it was read correctly
- if not self.check_valid_delays(read_port_dict):
- return (False,{})
- if not check_dict_values_is_float(read_port_dict):
- debug.error("Failed to Measure Read Port Values:\n\t\t{0}".format(read_port_dict),1) #Printing the entire dict looks bad.
-
- result[port].update(read_port_dict)
-
- bitline_delay_dict = self.evaluate_bitline_delay(port)
- result[port].update(bitline_delay_dict)
-
+ # Loop through all targeted ports and collect delays and powers.
+ result = [{} for i in self.all_ports]
+
+
+ # First, check that the memory has the right values at the right times
+ if not self.check_bit_measures():
+ return(False,{})
+
for port in self.targ_write_ports:
+ debug.info(2, "Checking write values for port {}".format(port))
write_port_dict = {}
- for measure in self.write_meas_objs:
+ for measure in self.write_lib_meas:
write_port_dict[measure.name] = measure.retrieve_measure(port=port)
if not check_dict_values_is_float(write_port_dict):
- debug.error("Failed to Measure Write Port Values:\n\t\t{0}".format(write_port_dict),1) #Printing the entire dict looks bad.
+ debug.error("Failed to Measure Write Port Values:\n\t\t{0}".format(write_port_dict),1)
result[port].update(write_port_dict)
- # The delay is from the negative edge for our SRAM
+
+ for port in self.targ_read_ports:
+ debug.info(2, "Checking read delay values for port {}".format(port))
+ # Check sen timing, then bitlines, then general measurements.
+ if not self.check_sen_measure(port):
+ return (False,{})
+
+ if not self.check_read_debug_measures(port):
+ return (False,{})
+
+ # Check timing for read ports. Power is only checked if it was read correctly
+ read_port_dict = {}
+ for measure in self.read_lib_meas:
+ read_port_dict[measure.name] = measure.retrieve_measure(port=port)
+
+ if not self.check_valid_delays(read_port_dict):
+ return (False,{})
+
+ if not check_dict_values_is_float(read_port_dict):
+ debug.error("Failed to Measure Read Port Values:\n\t\t{0}".format(read_port_dict),1)
+
+ result[port].update(read_port_dict)
+
return (True,result)
- def evaluate_bitline_delay(self, port):
- """Parse and check the bitline delay. One of the measurements is expected to fail which warrants its own function."""
- bl_delay_meas_dict = {}
- values_added = 0 #For error checking
- for measure in self.bitline_delay_objs:
- bl_delay_val = measure.retrieve_measure(port=port)
- if type(bl_delay_val) != float or 0 > bl_delay_val or bl_delay_val > self.period/2: #Only add if value is valid, do not error.
- debug.error("Bitline delay measurement failed: half-period={}, {}={}".format(self.period/2, measure.name, bl_delay_val),1)
- bl_delay_meas_dict[measure.name] = bl_delay_val
- return bl_delay_meas_dict
+ def check_sen_measure(self, port):
+ """Checks that the sen occurred within a half-period"""
+
+ sen_val = self.sen_meas.retrieve_measure(port=port)
+ debug.info(2,"s_en delay={}ns".format(sen_val))
+ if self.sen_meas.meta_add_delay:
+ max_delay = self.period/2
+ else:
+ max_delay = self.period
+ return not (type(sen_val) != float or sen_val > max_delay)
+
+
+ def check_read_debug_measures(self, port):
+ """Debug measures that indicate special conditions."""
+
+ # Currently, only check if the opposite than intended value was read during
+ # the read cycles i.e. neither of these measurements should pass.
+ # FIXME: these checks need to be re-done to be more robust against possible errors
+ bl_vals = {}
+ br_vals = {}
+ for meas in self.bitline_volt_meas:
+ val = meas.retrieve_measure(port=port)
+ if self.bl_name == meas.targ_name_no_port:
+ bl_vals[meas.meta_str] = val
+ elif self.br_name == meas.targ_name_no_port:
+ br_vals[meas.meta_str] = val
+
+ debug.info(2,"{}={}".format(meas.name,val))
+
+ dout_success = True
+ bl_success = False
+ for meas in self.dout_volt_meas:
+ val = meas.retrieve_measure(port=port)
+ debug.info(2,"{}={}".format(meas.name, val))
+ debug.check(type(val)==float, "Error retrieving numeric measurement: {0} {1}".format(meas.name,val))
+
+ if meas.meta_str == sram_op.READ_ONE and val < self.vdd_voltage*0.1:
+ dout_success = False
+ debug.info(1, "Debug measurement failed. Value {}V was read on read 1 cycle.".format(val))
+ bl_success = self.check_bitline_meas(bl_vals[sram_op.READ_ONE], br_vals[sram_op.READ_ONE])
+ elif meas.meta_str == sram_op.READ_ZERO and val > self.vdd_voltage*0.9:
+ dout_success = False
+ debug.info(1, "Debug measurement failed. Value {}V was read on read 0 cycle.".format(val))
+ bl_success = self.check_bitline_meas(br_vals[sram_op.READ_ONE], bl_vals[sram_op.READ_ONE])
+
+ # If the bitlines have a correct value while the output does not then that is a
+ # sen error. FIXME: there are other checks that can be done to solidfy this conclusion.
+ if not dout_success and bl_success:
+ debug.error("Sense amp enable timing error. Increase the delay chain through the configuration file.",1)
+
+ return dout_success
+
+
+ def check_bit_measures(self):
+ """
+ Checks the measurements which represent the internal storage voltages
+ at the end of the read cycle.
+ """
+ success = False
+ for polarity, meas_list in self.bit_meas.items():
+ for meas in meas_list:
+ val = meas.retrieve_measure()
+ debug.info(2,"{}={}".format(meas.name, val))
+ if type(val) != float:
+ continue
+ meas_cycle = meas.meta_str
+ # Loose error conditions. Assume it's not metastable but account for noise during reads.
+ if (meas_cycle == sram_op.READ_ZERO and polarity == bit_polarity.NONINVERTING) or\
+ (meas_cycle == sram_op.READ_ONE and polarity == bit_polarity.INVERTING):
+ success = val < self.vdd_voltage/2
+ elif (meas_cycle == sram_op.READ_ZERO and polarity == bit_polarity.INVERTING) or\
+ (meas_cycle == sram_op.READ_ONE and polarity == bit_polarity.NONINVERTING):
+ success = val > self.vdd_voltage/2
+ elif (meas_cycle == sram_op.WRITE_ZERO and polarity == bit_polarity.INVERTING) or\
+ (meas_cycle == sram_op.WRITE_ONE and polarity == bit_polarity.NONINVERTING):
+ success = val > self.vdd_voltage/2
+ elif (meas_cycle == sram_op.WRITE_ONE and polarity == bit_polarity.INVERTING) or\
+ (meas_cycle == sram_op.WRITE_ZERO and polarity == bit_polarity.NONINVERTING):
+ success = val < self.vdd_voltage/2
+ if not success:
+ debug.info(1,("Wrong value detected on probe bit during read/write cycle. "
+ "Check writes and control logic for bugs.\n measure={}, op={}, "
+ "bit_storage={}, V(bit)={}").format(meas.name, meas_cycle.name, polarity.name,val))
+
+ return success
+
+ def check_bitline_meas(self, v_discharged_bl, v_charged_bl):
+ """
+ Checks the value of the discharging bitline. Confirms s_en timing errors.
+ Returns true if the bitlines are at there expected value.
+ """
+ # The inputs looks at discharge/charged bitline rather than left or right (bl/br)
+ # Performs two checks, discharging bitline is at least 10% away from vdd and there is a
+ # 10% vdd difference between the bitlines. Both need to fail to be considered a s_en error.
+ min_dicharge = v_discharged_bl < self.vdd_voltage*0.9
+ min_diff = (v_charged_bl - v_discharged_bl) > self.vdd_voltage*0.1
+
+ debug.info(1,"min_dicharge={}, min_diff={}".format(min_dicharge,min_diff))
+ return (min_dicharge and min_diff)
def run_power_simulation(self):
"""
This simulates a disabled SRAM to get the leakage power when it is off.
-
"""
+
debug.info(1, "Performing leakage power simulations.")
self.write_power_stimulus(trim=False)
self.stim.run_sim()
leakage_power=parse_spice_list("timing", "leakage_power")
debug.check(leakage_power!="Failed","Could not measure leakage power.")
debug.info(1, "Leakage power of full array is {0} mW".format(leakage_power*1e3))
- #debug
- #sys.exit(1)
+ # debug
+ # sys.exit(1)
self.write_power_stimulus(trim=True)
self.stim.run_sim()
@@ -531,12 +892,13 @@ class delay(simulation):
debug.info(1, "Leakage power of trimmed array is {0} mW".format(trim_leakage_power*1e3))
# For debug, you sometimes want to inspect each simulation.
- #key=raw_input("press return to continue")
+ # key=raw_input("press return to continue")
return (leakage_power*1e3, trim_leakage_power*1e3)
def check_valid_delays(self, result_dict):
""" Check if the measurements are defined and if they are valid. """
- #Hard coded names currently
+
+ # Hard coded names currently
delay_hl = result_dict["delay_hl"]
delay_lh = result_dict["delay_lh"]
slew_hl = result_dict["slew_hl"]
@@ -554,8 +916,9 @@ class delay(simulation):
delays_str = "delay_hl={0} delay_lh={1}".format(delay_hl, delay_lh)
slews_str = "slew_hl={0} slew_lh={1}".format(slew_hl,slew_lh)
- half_period = self.period/2 #high-to-low delays start at neg. clk edge, so they need to be less than half_period
- if abs(delay_hl)>half_period or abs(delay_lh)>self.period or abs(slew_hl)>half_period or abs(slew_lh)>self.period:
+ half_period = self.period/2 # high-to-low delays start at neg. clk edge, so they need to be less than half_period
+ if abs(delay_hl)>half_period or abs(delay_lh)>self.period or abs(slew_hl)>half_period or abs(slew_lh)>self.period \
+ or delay_hl<0 or delay_lh<0 or slew_hl<0 or slew_lh<0:
debug.info(2,"UNsuccessful simulation (in ns):\n\t\t{0}\n\t\t{1}\n\t\t{2}".format(period_load_slew_str,
delays_str,
slews_str))
@@ -576,15 +939,15 @@ class delay(simulation):
lb_period = 0.0
target_period = 0.5 * (ub_period + lb_period)
- #Find the minimum period for all ports. Start at one port and perform binary search then use that delay as a starting position.
- #For testing purposes, only checks read ports.
+ # Find the minimum period for all ports. Start at one port and perform binary search then use that delay as a starting position.
+ # For testing purposes, only checks read ports.
for port in self.read_ports:
target_period = self.find_min_period_one_port(feasible_delays, port, lb_period, ub_period, target_period)
- #The min period of one port becomes the new lower bound. Reset the upper_bound.
+ # The min period of one port becomes the new lower bound. Reset the upper_bound.
lb_period = target_period
ub_period = feasible_period
- #Clear the target ports before leaving
+ # Clear the target ports before leaving
self.targ_read_ports = []
self.targ_write_ports = []
return target_period
@@ -595,13 +958,14 @@ class delay(simulation):
long period. For the current logic to characterize multiport, bounds are required as an input.
"""
- #previous_period = ub_period = self.period
- #ub_period = self.period
- #lb_period = 0.0
- #target_period = 0.5 * (ub_period + lb_period)
+ # previous_period = ub_period = self.period
+ # ub_period = self.period
+ # lb_period = 0.0
+ # target_period = 0.5 * (ub_period + lb_period)
# Binary search algorithm to find the min period (max frequency) of input port
time_out = 25
+ self.targ_write_ports = [port]
self.targ_read_ports = [port]
while True:
time_out -= 1
@@ -610,9 +974,9 @@ class delay(simulation):
self.period = target_period
debug.info(1, "MinPeriod Search Port {3}: {0}ns (ub: {1} lb: {2})".format(target_period,
- ub_period,
- lb_period,
- port))
+ ub_period,
+ lb_period,
+ port))
if self.try_period(feasible_delays):
ub_period = target_period
@@ -623,9 +987,9 @@ class delay(simulation):
# ub_period is always feasible.
return ub_period
- #Update target
+ # Update target
target_period = 0.5 * (ub_period + lb_period)
- #key=input("press return to continue")
+ # key=input("press return to continue")
def try_period(self, feasible_delays):
@@ -633,18 +997,20 @@ class delay(simulation):
This tries to simulate a period and checks if the result
works. If it does and the delay is within 5% still, it returns True.
"""
+
# Run Delay simulation but Power results not used.
(success, results) = self.run_delay_simulation()
if not success:
return False
- #Check the values of target readwrite and read ports. Write ports do not produce delays in this current version
- for port in self.targ_read_ports:
- for dname in self.delay_meas_names: #check that the delays and slews do not degrade with tested period.
+ # Check the values of target readwrite and read ports. Write ports do not produce delays in this current version
+ for port in self.targ_read_ports:
+ # check that the delays and slews do not degrade with tested period.
+ for dname in self.delay_meas_names:
- #FIXME: This is a hack solution to fix the min period search. The slew will always be based on the period when there
- #is a column mux. Therefore, the checks are skipped for this condition. This is hard to solve without changing the netlist.
- #Delays/slews based on the period will cause the min_period search to come to the wrong period.
+ # FIXME: This is a hack solution to fix the min period search. The slew will always be based on the period when there
+ # is a column mux. Therefore, the checks are skipped for this condition. This is hard to solve without changing the netlist.
+ # Delays/slews based on the period will cause the min_period search to come to the wrong period.
if self.sram.col_addr_size>0 and "slew" in dname:
continue
@@ -652,9 +1018,8 @@ class delay(simulation):
debug.info(2,"Delay too big {0} vs {1}".format(results[port][dname],feasible_delays[port][dname]))
return False
- #key=raw_input("press return to continue")
+ # key=raw_input("press return to continue")
- #Dynamic way to build string. A bit messy though.
delay_str = ', '.join("{0}={1}ns".format(mname, results[port][mname]) for mname in self.delay_meas_names)
debug.info(2,"Successful period {0}, Port {2}, {1}".format(self.period,
delay_str,
@@ -662,8 +1027,11 @@ class delay(simulation):
return True
def set_probe(self,probe_address, probe_data):
- """ Probe address and data can be set separately to utilize other
- functions in this characterizer besides analyze."""
+ """
+ Probe address and data can be set separately to utilize other
+ functions in this characterizer besides analyze.
+ """
+
self.probe_address = probe_address
self.probe_data = probe_data
self.bitline_column = self.get_data_bit_column_number(probe_address, probe_data)
@@ -672,6 +1040,7 @@ class delay(simulation):
def get_data_bit_column_number(self, probe_address, probe_data):
"""Calculates bitline column number of data bit under test using bit position and mux size"""
+
if self.sram.col_addr_size>0:
col_address = int(probe_address[0:self.sram.col_addr_size],2)
else:
@@ -681,6 +1050,7 @@ class delay(simulation):
def get_address_row_number(self, probe_address):
"""Calculates wordline row number of data bit under test using address and column mux size"""
+
return int(probe_address[self.sram.col_addr_size:],2)
def prepare_netlist(self):
@@ -704,31 +1074,26 @@ class delay(simulation):
# Make a copy in temp for debugging
shutil.copy(self.sp_file, self.sim_sp_file)
-
-
- def analyze(self,probe_address, probe_data, slews, loads):
- """
- Main function to characterize an SRAM for a table. Computes both delay and power characterization.
- """
- #Dict to hold all characterization values
- char_sram_data = {}
+ def analysis_init(self, probe_address, probe_data):
+ """Sets values which are dependent on the data address/bit being tested."""
self.set_probe(probe_address, probe_data)
- self.create_signal_names()
+ self.create_graph()
+ self.set_internal_spice_names()
self.create_measurement_names()
self.create_measurement_objects()
+ def analyze(self, probe_address, probe_data, slews, loads):
+ """
+ Main function to characterize an SRAM for a table. Computes both delay and power characterization.
+ """
+
+ # Dict to hold all characterization values
+ char_sram_data = {}
+ self.analysis_init(probe_address, probe_data)
+
self.load=max(loads)
self.slew=max(slews)
- # This is for debugging a full simulation
- # debug.info(0,"Debug simulation running...")
- # target_period=50.0
- # feasible_delay_lh=0.059083183
- # feasible_delay_hl=0.17953789
- # load=1.6728
- # slew=0.04
- # self.try_period(target_period, feasible_delay_lh, feasible_delay_hl)
- # sys.exit(1)
# 1) Find a feasible period and it's corresponding delays using the trimmed array.
feasible_delays = self.find_feasible_period()
@@ -748,22 +1113,24 @@ class delay(simulation):
self.period = min_period
char_port_data = self.simulate_loads_and_slews(slews, loads, leakage_offset)
- #FIXME: low-to-high delays are altered to be independent of the period. This makes the lib results less accurate.
+ # FIXME: low-to-high delays are altered to be independent of the period. This makes the lib results less accurate.
self.alter_lh_char_data(char_port_data)
return (char_sram_data, char_port_data)
def alter_lh_char_data(self, char_port_data):
"""Copies high-to-low data to low-to-high data to make them consistent on the same clock edge."""
- #This is basically a hack solution which should be removed/fixed later.
+
+ # This is basically a hack solution which should be removed/fixed later.
for port in self.all_ports:
char_port_data[port]['delay_lh'] = char_port_data[port]['delay_hl']
char_port_data[port]['slew_lh'] = char_port_data[port]['slew_hl']
def simulate_loads_and_slews(self, slews, loads, leakage_offset):
"""Simulate all specified output loads and input slews pairs of all ports"""
+
measure_data = self.get_empty_measure_data_dict()
- #Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways.
+ # Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways.
self.targ_read_ports = self.read_ports
self.targ_write_ports = self.write_ports
for slew in slews:
@@ -773,7 +1140,7 @@ class delay(simulation):
(success, delay_results) = self.run_delay_simulation()
debug.check(success,"Couldn't run a simulation. slew={0} load={1}\n".format(self.slew,self.load))
debug.info(1, "Simulation Passed: Port {0} slew={1} load={2}".format("All", self.slew,self.load))
- #The results has a dict for every port but dicts can be empty (e.g. ports were not targeted).
+ # The results has a dict for every port but dicts can be empty (e.g. ports were not targeted).
for port in self.all_ports:
for mname,value in delay_results[port].items():
if "power" in mname:
@@ -785,11 +1152,12 @@ class delay(simulation):
def calculate_inverse_address(self):
"""Determine dummy test address based on probe address and column mux size."""
- #The inverse address needs to share the same bitlines as the probe address as the trimming will remove all other bitlines
- #This is only an issue when there is a column mux and the address maps to different bitlines.
- column_addr = self.probe_address[:self.sram.col_addr_size] #do not invert this part
+
+ # The inverse address needs to share the same bitlines as the probe address as the trimming will remove all other bitlines
+ # This is only an issue when there is a column mux and the address maps to different bitlines.
+ column_addr = self.probe_address[:self.sram.col_addr_size] # do not invert this part
inverse_address = ""
- for c in self.probe_address[self.sram.col_addr_size:]: #invert everything else
+ for c in self.probe_address[self.sram.col_addr_size:]: # invert everything else
if c=="0":
inverse_address += "1"
elif c=="1":
@@ -808,48 +1176,51 @@ class delay(simulation):
# For now, ignore data patterns and write ones or zeros
data_ones = "1"*self.word_size
data_zeros = "0"*self.word_size
+ wmask_ones = "1"*self.num_wmasks
+ wmask_zeroes = "0"*self.num_wmasks
if self.t_current == 0:
self.add_noop_all_ports("Idle cycle (no positive clock edge)",
- inverse_address, data_zeros)
+ inverse_address, data_zeros,wmask_zeroes)
self.add_write("W data 1 address {}".format(inverse_address),
- inverse_address,data_ones,write_port)
+ inverse_address,data_ones,wmask_ones,write_port)
self.add_write("W data 0 address {} to write value".format(self.probe_address),
- self.probe_address,data_zeros,write_port)
- self.measure_cycles[write_port]["write0"] = len(self.cycle_times)-1
+ self.probe_address,data_zeros,wmask_ones,write_port)
+ self.measure_cycles[write_port][sram_op.WRITE_ZERO] = len(self.cycle_times)-1
# This also ensures we will have a H->L transition on the next read
- self.add_read("R data 1 address {} to set DOUT caps".format(inverse_address),
- inverse_address,data_zeros,read_port)
+ self.add_read("R data 1 address {} to set dout caps".format(inverse_address),
+ inverse_address,data_zeros,wmask_ones,read_port)
self.add_read("R data 0 address {} to check W0 worked".format(self.probe_address),
- self.probe_address,data_zeros,read_port)
- self.measure_cycles[read_port]["read0"] = len(self.cycle_times)-1
+ self.probe_address,data_zeros,wmask_ones,read_port)
+ self.measure_cycles[read_port][sram_op.READ_ZERO] = len(self.cycle_times)-1
self.add_noop_all_ports("Idle cycle (if read takes >1 cycle)",
- inverse_address,data_zeros)
+ inverse_address,data_zeros,wmask_zeroes)
self.add_write("W data 1 address {} to write value".format(self.probe_address),
- self.probe_address,data_ones,write_port)
- self.measure_cycles[write_port]["write1"] = len(self.cycle_times)-1
+ self.probe_address,data_ones,wmask_ones,write_port)
+ self.measure_cycles[write_port][sram_op.WRITE_ONE] = len(self.cycle_times)-1
- self.add_write("W data 0 address {} to clear DIN caps".format(inverse_address),
- inverse_address,data_zeros,write_port)
+ self.add_write("W data 0 address {} to clear din caps".format(inverse_address),
+ inverse_address,data_zeros,wmask_ones,write_port)
# This also ensures we will have a L->H transition on the next read
- self.add_read("R data 0 address {} to clear DOUT caps".format(inverse_address),
- inverse_address,data_zeros,read_port)
+ self.add_read("R data 0 address {} to clear dout caps".format(inverse_address),
+ inverse_address,data_zeros,wmask_ones,read_port)
self.add_read("R data 1 address {} to check W1 worked".format(self.probe_address),
- self.probe_address,data_zeros,read_port)
- self.measure_cycles[read_port]["read1"] = len(self.cycle_times)-1
+ self.probe_address,data_zeros,wmask_ones,read_port)
+ self.measure_cycles[read_port][sram_op.READ_ONE] = len(self.cycle_times)-1
self.add_noop_all_ports("Idle cycle (if read takes >1 cycle))",
- self.probe_address,data_zeros)
+ self.probe_address,data_zeros,wmask_zeroes)
def get_available_port(self,get_read_port):
+
"""Returns the first accessible read or write port. """
if get_read_port and len(self.read_ports) > 0:
return self.read_ports[0]
@@ -862,29 +1233,32 @@ class delay(simulation):
self.measure_cycles = [{} for port in self.all_ports]
def create_test_cycles(self):
- """Returns a list of key time-points [ns] of the waveform (each rising edge)
+ """
+ Returns a list of key time-points [ns] of the waveform (each rising edge)
of the cycles to do a timing evaluation. The last time is the end of the simulation
- and does not need a rising edge."""
- #Using this requires setting at least one port to target for simulation.
+ and does not need a rising edge.
+ """
+
+ # Using this requires setting at least one port to target for simulation.
if len(self.targ_write_ports) == 0 and len(self.targ_read_ports) == 0:
debug.error("No port selected for characterization.",1)
self.set_stimulus_variables()
- #Get any available read/write port in case only a single write or read ports is being characterized.
+ # Get any available read/write port in case only a single write or read ports is being characterized.
cur_read_port = self.get_available_port(get_read_port=True)
cur_write_port = self.get_available_port(get_read_port=False)
debug.check(cur_read_port != None, "Characterizer requires at least 1 read port")
debug.check(cur_write_port != None, "Characterizer requires at least 1 write port")
- #Create test cycles for specified target ports.
+ # Create test cycles for specified target ports.
write_pos = 0
read_pos = 0
while True:
- #Exit when all ports have been characterized
+ # Exit when all ports have been characterized
if write_pos >= len(self.targ_write_ports) and read_pos >= len(self.targ_read_ports):
break
- #Select new write and/or read ports for the next cycle. Use previous port if none remaining.
+ # Select new write and/or read ports for the next cycle. Use previous port if none remaining.
if write_pos < len(self.targ_write_ports):
cur_write_port = self.targ_write_ports[write_pos]
write_pos+=1
@@ -892,47 +1266,81 @@ class delay(simulation):
cur_read_port = self.targ_read_ports[read_pos]
read_pos+=1
- #Add test cycle of read/write port pair. One port could have been used already, but the other has not.
+ # Add test cycle of read/write port pair. One port could have been used already, but the other has not.
self.gen_test_cycles_one_port(cur_read_port, cur_write_port)
+ def sum_delays(self, delays):
+ """Adds the delays (delay_data objects) so the correct slew is maintained"""
+
+ delay = delays[0]
+ for i in range(1, len(delays)):
+ delay+=delays[i]
+ return delay
+
def analytical_delay(self, slews, loads):
- """ Return the analytical model results for the SRAM.
+ """
+ Return the analytical model results for the SRAM.
"""
if OPTS.num_rw_ports > 1 or OPTS.num_w_ports > 0 and OPTS.num_r_ports > 0:
debug.warning("Analytical characterization results are not supported for multiport.")
- self.create_signal_names()
+
+ # Probe set to 0th bit, does not matter for analytical delay.
+ self.set_probe('0'*self.addr_size, 0)
+ self.create_graph()
+ self.set_internal_spice_names()
self.create_measurement_names()
- power = self.analytical_power(slews, loads)
+
+ port = self.read_ports[0]
+ self.graph.get_all_paths('{}{}'.format("clk", port),
+ '{}{}_{}'.format(self.dout_name, port, self.probe_data))
+
+ # Select the path with the bitline (bl)
+ bl_name,br_name = self.get_bl_name(self.graph.all_paths, port)
+ bl_path = [path for path in self.graph.all_paths if bl_name in path][0]
+
+ # Set delay/power for slews and loads
port_data = self.get_empty_measure_data_dict()
+ power = self.analytical_power(slews, loads)
+ debug.info(1,'Slew, Load, Delay(ns), Slew(ns)')
+ max_delay = 0.0
for slew in slews:
for load in loads:
- self.set_load_slew(load,slew)
- bank_delay = self.sram.analytical_delay(self.corner, self.slew,self.load)
+ # Calculate delay based on slew and load
+ path_delays = self.graph.get_timing(bl_path, self.corner, slew, load)
+
+ total_delay = self.sum_delays(path_delays)
+ max_delay = max(max_delay, total_delay.delay)
+ debug.info(1,'{}, {}, {}, {}'.format(slew,load,total_delay.delay/1e3, total_delay.slew/1e3))
+
+ # Delay is only calculated on a single port and replicated for now.
for port in self.all_ports:
for mname in self.delay_meas_names+self.power_meas_names:
if "power" in mname:
port_data[port][mname].append(power.dynamic)
- elif "delay" in mname:
- port_data[port][mname].append(bank_delay[port].delay/1e3)
- elif "slew" in mname:
- port_data[port][mname].append(bank_delay[port].slew/1e3)
+ elif "delay" in mname and port in self.read_ports:
+ port_data[port][mname].append(total_delay.delay/1e3)
+ elif "slew" in mname and port in self.read_ports:
+ port_data[port][mname].append(total_delay.slew/1e3)
else:
debug.error("Measurement name not recognized: {}".format(mname),1)
+
+ # Estimate the period as double the delay with margin
period_margin = 0.1
- risefall_delay = bank_delay[self.read_ports[0]].delay/1e3
- sram_data = { "min_period":risefall_delay*2*period_margin,
+ sram_data = { "min_period":(max_delay/1e3)*2*period_margin,
"leakage_power": power.leakage}
+
debug.info(2,"SRAM Data:\n{}".format(sram_data))
debug.info(2,"Port Data:\n{}".format(port_data))
- return (sram_data,port_data)
-
+ return (sram_data,port_data)
+
def analytical_power(self, slews, loads):
"""Get the dynamic and leakage power from the SRAM"""
- #slews unused, only last load is used
+
+ # slews unused, only last load is used
load = loads[-1]
power = self.sram.analytical_power(self.corner, load)
- #convert from nW to mW
+ # convert from nW to mW
power.dynamic /= 1e6
power.leakage /= 1e6
debug.info(1,"Dynamic Power: {0} mW".format(power.dynamic))
@@ -941,6 +1349,7 @@ class delay(simulation):
def gen_data(self):
""" Generates the PWL data inputs for a simulation timing test. """
+
for write_port in self.write_ports:
for i in range(self.word_size):
sig_name="{0}{1}_{2} ".format(self.din_name,write_port, i)
@@ -951,6 +1360,7 @@ class delay(simulation):
Generates the address inputs for a simulation timing test.
This alternates between all 1's and all 0's for the address.
"""
+
for port in self.all_ports:
for i in range(self.addr_size):
sig_name = "{0}{1}_{2}".format(self.addr_name,port,i)
@@ -958,6 +1368,7 @@ class delay(simulation):
def gen_control(self):
""" Generates the control signals """
+
for port in self.all_ports:
self.stim.gen_pwl("CSB{0}".format(port), self.cycle_times, self.csb_values[port], self.period, self.slew, 0.05)
if port in self.readwrite_ports:
@@ -966,7 +1377,8 @@ class delay(simulation):
def get_empty_measure_data_dict(self):
"""Make a dict of lists for each type of delay and power measurement to append results to"""
- measure_names = self.delay_meas_names + self.power_meas_names + self.voltage_when_names + self.bitline_delay_names
- #Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists.
+
+ measure_names = self.delay_meas_names + self.power_meas_names
+ # Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists.
measure_data = [{mname:[] for mname in measure_names} for i in self.all_ports]
return measure_data
diff --git a/compiler/characterizer/functional.py b/compiler/characterizer/functional.py
index ca05648a..49907b4b 100644
--- a/compiler/characterizer/functional.py
+++ b/compiler/characterizer/functional.py
@@ -1,4 +1,12 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import sys,re,shutil
+import collections
from design import design
import debug
import math
@@ -8,9 +16,10 @@ from .stimuli import *
from .charutils import *
import utils
from globals import OPTS
-
from .simulation import simulation
from .delay import delay
+import graph_util
+from sram_factory import factory
class functional(simulation):
"""
@@ -25,19 +34,38 @@ class functional(simulation):
if OPTS.is_unit_test:
random.seed(12345)
+ if self.write_size:
+ self.num_wmasks = int(self.word_size / self.write_size)
+ else:
+ self.num_wmasks = 0
+
self.set_corner(corner)
self.set_spice_constants()
- #self.set_feasible_period(sram, spfile, corner)
self.set_stimulus_variables()
- self.create_signal_names()
+ # For the debug signal names
+ self.create_signal_names()
+ self.add_graph_exclusions()
+ self.create_graph()
+ self.set_internal_spice_names()
+ self.initialize_wmask()
+
# Number of checks can be changed
- self.num_cycles = 2
- self.stored_words = {}
+ self.num_cycles = 15
+ # This is to have ordered keys for random selection
+ self.stored_words = collections.OrderedDict()
self.write_check = []
self.read_check = []
-
+
+
+ def initialize_wmask(self):
+ self.wmask = ""
+ if self.write_size:
+ # initialize all wmask bits to 1
+ for bit in range(self.num_wmasks):
+ self.wmask += "1"
+
def run(self, feasible_period=None):
if feasible_period: #period defaults to tech.py feasible period otherwise.
self.period = feasible_period
@@ -48,7 +76,7 @@ class functional(simulation):
self.write_functional_stimulus()
self.stim.run_sim()
- # read DOUT values from SPICE simulation. If the values do not fall within the noise margins, return the error.
+ # read dout values from SPICE simulation. If the values do not fall within the noise margins, return the error.
(success, error) = self.read_stim_results()
if not success:
return (0, error)
@@ -57,37 +85,42 @@ class functional(simulation):
return self.check_stim_results()
def write_random_memory_sequence(self):
- rw_ops = ["noop", "write", "read"]
- w_ops = ["noop", "write"]
+ if self.write_size:
+ rw_ops = ["noop", "write", "partial_write", "read"]
+ w_ops = ["noop", "write", "partial_write"]
+ else:
+ rw_ops = ["noop", "write", "read"]
+ w_ops = ["noop", "write"]
r_ops = ["noop", "read"]
rw_read_din_data = "0"*self.word_size
check = 0
-
+
# First cycle idle
- comment = self.gen_cycle_comment("noop", "0"*self.word_size, "0"*self.addr_size, 0, self.t_current)
- self.add_noop_all_ports(comment, "0"*self.addr_size, "0"*self.word_size)
+ comment = self.gen_cycle_comment("noop", "0"*self.word_size, "0"*self.addr_size, self.wmask, 0, self.t_current)
+ self.add_noop_all_ports(comment, "0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks)
# Write at least once
addr = self.gen_addr()
word = self.gen_data()
- comment = self.gen_cycle_comment("write", word, addr, 0, self.t_current)
- self.add_write(comment, addr, word, 0)
+ comment = self.gen_cycle_comment("write", word, addr, self.wmask, 0, self.t_current)
+ self.add_write(comment, addr, word, self.wmask, 0)
self.stored_words[addr] = word
-
+
# Read at least once. For multiport, it is important that one read cycle uses all RW and R port to read from the same address simultaniously.
# This will test the viablilty of the transistor sizing in the bitcell.
for port in self.all_ports:
if port in self.write_ports:
- self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, port)
+ self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks, port)
else:
- comment = self.gen_cycle_comment("read", word, addr, port, self.t_current)
- self.add_read_one_port(comment, addr, rw_read_din_data, port)
+ comment = self.gen_cycle_comment("read", word, addr, self.wmask, port, self.t_current)
+ self.add_read_one_port(comment, addr, rw_read_din_data, "0"*self.num_wmasks, port)
self.write_check.append([word, "{0}{1}".format(self.dout_name,port), self.t_current+self.period, check])
check += 1
self.cycle_times.append(self.t_current)
self.t_current += self.period
# Perform a random sequence of writes and reads on random ports, using random addresses and random words
+ # and random write masks (if applicable)
for i in range(self.num_cycles):
w_addrs = []
for port in self.all_ports:
@@ -101,26 +134,48 @@ class functional(simulation):
if op == "noop":
addr = "0"*self.addr_size
word = "0"*self.word_size
- self.add_noop_one_port(addr, word, port)
+ wmask = "0" * self.num_wmasks
+ self.add_noop_one_port(addr, word, wmask, port)
elif op == "write":
addr = self.gen_addr()
word = self.gen_data()
# two ports cannot write to the same address
if addr in w_addrs:
- self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, port)
+ self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks, port)
else:
- comment = self.gen_cycle_comment("write", word, addr, port, self.t_current)
- self.add_write_one_port(comment, addr, word, port)
+ comment = self.gen_cycle_comment("write", word, addr, self.wmask, port, self.t_current)
+ self.add_write_one_port(comment, addr, word, self.wmask, port)
self.stored_words[addr] = word
w_addrs.append(addr)
+ elif op == "partial_write":
+ # write only to a word that's been written to
+ (addr,old_word) = self.get_data()
+ word = self.gen_data()
+ wmask = self.gen_wmask()
+ new_word = word
+ for bit in range(len(wmask)):
+ # When the write mask's bits are 0, the old data values should appear in the new word
+ # as to not overwrite the old values
+ if wmask[bit] == "0":
+ lower = bit * self.write_size
+ upper = lower + self.write_size - 1
+ new_word = new_word[:lower] + old_word[lower:upper+1] + new_word[upper + 1:]
+ # two ports cannot write to the same address
+ if addr in w_addrs:
+ self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks, port)
+ else:
+ comment = self.gen_cycle_comment("partial_write", word, addr, wmask, port, self.t_current)
+ self.add_write_one_port(comment, addr, word, wmask, port)
+ self.stored_words[addr] = new_word
+ w_addrs.append(addr)
else:
(addr,word) = random.choice(list(self.stored_words.items()))
# cannot read from an address that is currently being written to
if addr in w_addrs:
- self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, port)
+ self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks, port)
else:
- comment = self.gen_cycle_comment("read", word, addr, port, self.t_current)
- self.add_read_one_port(comment, addr, rw_read_din_data, port)
+ comment = self.gen_cycle_comment("read", word, addr, self.wmask, port, self.t_current)
+ self.add_read_one_port(comment, addr, rw_read_din_data, "0"*self.num_wmasks, port)
self.write_check.append([word, "{0}{1}".format(self.dout_name,port), self.t_current+self.period, check])
check += 1
@@ -128,11 +183,11 @@ class functional(simulation):
self.t_current += self.period
# Last cycle idle needed to correctly measure the value on the second to last clock edge
- comment = self.gen_cycle_comment("noop", "0"*self.word_size, "0"*self.addr_size, 0, self.t_current)
- self.add_noop_all_ports(comment, "0"*self.addr_size, "0"*self.word_size)
+ comment = self.gen_cycle_comment("noop", "0"*self.word_size, "0"*self.addr_size, self.wmask, 0, self.t_current)
+ self.add_noop_all_ports(comment, "0"*self.addr_size, "0"*self.word_size, "0"*self.num_wmasks)
def read_stim_results(self):
- # Extrat DOUT values from spice timing.lis
+ # Extrat dout values from spice timing.lis
for (word, dout_port, eo_period, check) in self.write_check:
sp_read_value = ""
for bit in range(self.word_size):
@@ -163,23 +218,47 @@ class functional(simulation):
self.read_check[i][2])
return(0, error)
return(1, "SUCCESS")
-
+
+ def gen_wmask(self):
+ wmask = ""
+ # generate a random wmask
+ for bit in range(self.num_wmasks):
+ rand = random.randint(0, 1)
+ wmask += str(rand)
+ # prevent the wmask from having all bits on or off (this is not a partial write)
+ all_zeroes = True
+ all_ones = True
+ for bit in range(self.num_wmasks):
+ if wmask[bit]=="0":
+ all_ones = False
+ elif wmask[bit]=="1":
+ all_zeroes = False
+ if all_zeroes:
+ index = random.randint(0, self.num_wmasks - 1)
+ wmask = wmask[:index] + "1" + wmask[index + 1:]
+ elif all_ones:
+ index = random.randint(0, self.num_wmasks - 1)
+ wmask = wmask[:index] + "0" + wmask[index + 1:]
+ # wmask must be reversed since a python list goes right to left and sram bits go left to right.
+ return wmask[::-1]
+
+
def gen_data(self):
""" Generates a random word to write. """
- rand = random.randint(0,(2**self.word_size)-1)
- data_bits = self.convert_to_bin(rand,False)
+ random_value = random.randint(0,(2**self.word_size)-1)
+ data_bits = self.convert_to_bin(random_value,False)
return data_bits
-
+
def gen_addr(self):
""" Generates a random address value to write to. """
- rand = random.randint(0,(2**self.addr_size)-1)
- addr_bits = self.convert_to_bin(rand,True)
- return addr_bits
+ random_value = random.randint(0,(2**self.addr_size)-1)
+ addr_bits = self.convert_to_bin(random_value,True)
+ return addr_bits
def get_data(self):
""" Gets an available address and corresponding word. """
- # Currently unused but may need later depending on how the functional test develops
- addr = random.choice(self.stored_words.keys())
+ # Used for write masks since they should be writing to previously written addresses
+ addr = random.choice(list(self.stored_words.keys()))
word = self.stored_words[addr]
return (addr,word)
@@ -189,17 +268,13 @@ class functional(simulation):
if(is_addr):
expected_value = self.addr_size
else:
+
expected_value = self.word_size
for i in range (expected_value - len(new_value)):
new_value = "0" + new_value
#print("Binary Conversion: {} to {}".format(value, new_value))
- return new_value
-
- def create_signal_names(self):
- self.addr_name = "A"
- self.din_name = "DIN"
- self.dout_name = "DOUT"
+ return new_value
def write_functional_stimulus(self):
""" Writes SPICE stimulus. """
@@ -209,9 +284,7 @@ class functional(simulation):
self.stim = stimuli(self.sf,self.corner)
#Write include statements
- self.sram_sp_file = "{}sram.sp".format(OPTS.openram_temp)
- shutil.copy(self.sp_file, self.sram_sp_file)
- self.stim.write_include(self.sram_sp_file)
+ self.stim.write_include(self.sp_file)
#Write Vdd/Gnd statements
self.sf.write("\n* Global Power Supplies\n")
@@ -219,12 +292,8 @@ class functional(simulation):
#Instantiate the SRAM
self.sf.write("\n* Instantiation of the SRAM\n")
- self.stim.inst_sram(sram=self.sram,
- port_signal_names=(self.addr_name,self.din_name,self.dout_name),
- port_info=(len(self.all_ports), self.write_ports, self.read_ports),
- abits=self.addr_size,
- dbits=self.word_size,
- sram_name=self.name)
+ self.stim.inst_model(pins=self.pins,
+ model_name=self.sram.name)
# Add load capacitance to each of the read ports
self.sf.write("\n* SRAM output loads\n")
@@ -232,9 +301,17 @@ class functional(simulation):
for bit in range(self.word_size):
sig_name="{0}{1}_{2} ".format(self.dout_name, port, bit)
self.sf.write("CD{0}{1} {2} 0 {3}f\n".format(port, bit, sig_name, self.load))
+
+ # Write important signals to stim file
+ self.sf.write("\n\n* Important signals for debug\n")
+ self.sf.write("* bl: {}\n".format(self.bl_name))
+ self.sf.write("* br: {}\n".format(self.br_name))
+ self.sf.write("* s_en: {}\n".format(self.sen_name))
+ self.sf.write("* q: {}\n".format(self.q_name))
+ self.sf.write("* qbar: {}\n".format(self.qbar_name))
# Write debug comments to stim file
- self.sf.write("\n\n * Sequence of operations\n")
+ self.sf.write("\n\n* Sequence of operations\n")
for comment in self.fn_cycle_comments:
self.sf.write("*{}\n".format(comment))
@@ -259,9 +336,20 @@ class functional(simulation):
for port in self.readwrite_ports:
self.stim.gen_pwl("WEB{}".format(port), self.cycle_times , self.web_values[port], self.period, self.slew, 0.05)
+ # Generate wmask bits
+ for port in self.write_ports:
+ if self.write_size:
+ self.sf.write("\n* Generation of wmask signals\n")
+ for bit in range(self.num_wmasks):
+ sig_name = "WMASK{0}_{1} ".format(port, bit)
+ # self.stim.gen_pwl(sig_name, self.cycle_times, self.data_values[port][bit], self.period,
+ # self.slew, 0.05)
+ self.stim.gen_pwl(sig_name, self.cycle_times, self.wmask_values[port][bit], self.period,
+ self.slew, 0.05)
+
# Generate CLK signals
for port in self.all_ports:
- self.stim.gen_pulse(sig_name="{0}{1}".format(tech.spice["clk"], port),
+ self.stim.gen_pulse(sig_name="{0}{1}".format("clk", port),
v1=self.gnd_voltage,
v2=self.vdd_voltage,
offset=self.period,
@@ -269,7 +357,7 @@ class functional(simulation):
t_rise=self.slew,
t_fall=self.slew)
- # Generate DOUT value measurements
+ # Generate dout value measurements
self.sf.write("\n * Generation of dout measurements\n")
for (word, dout_port, eo_period, check) in self.write_check:
t_intital = eo_period - 0.01*self.period
@@ -283,4 +371,117 @@ class functional(simulation):
self.stim.write_control(self.cycle_times[-1] + self.period)
self.sf.close()
+ # FIXME: refactor to share with delay.py
+ def add_graph_exclusions(self):
+ """Exclude portions of SRAM from timing graph which are not relevant"""
+
+ # other initializations can only be done during analysis when a bit has been selected
+ # for testing.
+ self.sram.bank.graph_exclude_precharge()
+ self.sram.graph_exclude_addr_dff()
+ self.sram.graph_exclude_data_dff()
+ self.sram.graph_exclude_ctrl_dffs()
+ self.sram.bank.bitcell_array.graph_exclude_replica_col_bits()
+
+ # FIXME: refactor to share with delay.py
+ def create_graph(self):
+ """Creates timing graph to generate the timing paths for the SRAM output."""
+
+ self.sram.bank.bitcell_array.init_graph_params() # Removes previous bit exclusions
+ # Does wordline=0 and column=0 just for debug names
+ self.sram.bank.bitcell_array.graph_exclude_bits(0, 0)
+
+ # Generate new graph every analysis as edges might change depending on test bit
+ self.graph = graph_util.timing_graph()
+ self.sram_spc_name = "X{}".format(self.sram.name)
+ self.sram.build_graph(self.graph,self.sram_spc_name,self.pins)
+ # FIXME: refactor to share with delay.py
+ def set_internal_spice_names(self):
+ """Sets important names for characterization such as Sense amp enable and internal bit nets."""
+
+ # For now, only testing these using first read port.
+ port = self.read_ports[0]
+ self.graph.get_all_paths('{}{}'.format("clk", port),
+ '{}{}_{}'.format(self.dout_name, port, 0).lower())
+
+ self.sen_name = self.get_sen_name(self.graph.all_paths)
+ debug.info(2,"s_en name = {}".format(self.sen_name))
+
+ self.bl_name,self.br_name = self.get_bl_name(self.graph.all_paths, port)
+ debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name))
+
+ self.q_name,self.qbar_name = self.get_bit_name()
+ debug.info(2,"q name={}\nqbar name={}".format(self.q_name,self.qbar_name))
+
+ def get_bit_name(self):
+ """ Get a bit cell name """
+ (cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, 0, 0)
+ storage_names = cell_inst.mod.get_storage_net_names()
+ debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes"
+ "supported for characterization. Storage nets={}").format(storage_names))
+ q_name = cell_name+'.'+str(storage_names[0])
+ qbar_name = cell_name+'.'+str(storage_names[1])
+
+ return (q_name,qbar_name)
+
+ # FIXME: refactor to share with delay.py
+ def get_sen_name(self, paths):
+ """
+ Gets the signal name associated with the sense amp enable from input paths.
+ Only expects a single path to contain the sen signal name.
+ """
+
+ sa_mods = factory.get_mods(OPTS.sense_amp)
+ # Any sense amp instantiated should be identical, any change to that
+ # will require some identification to determine the mod desired.
+ debug.check(len(sa_mods) == 1, "Only expected one type of Sense Amp. Cannot perform s_en checks.")
+ enable_name = sa_mods[0].get_enable_name()
+ sen_name = self.get_alias_in_path(paths, enable_name, sa_mods[0])
+ return sen_name
+
+ # FIXME: refactor to share with delay.py
+ def get_bl_name(self, paths, port):
+ """Gets the signal name associated with the bitlines in the bank."""
+
+ cell_mod = factory.create(module_type=OPTS.bitcell)
+ cell_bl = cell_mod.get_bl_name(port)
+ cell_br = cell_mod.get_br_name(port)
+
+ bl_found = False
+ # Only a single path should contain a single s_en name. Anything else is an error.
+ bl_names = []
+ exclude_set = self.get_bl_name_search_exclusions()
+ for int_net in [cell_bl, cell_br]:
+ bl_names.append(self.get_alias_in_path(paths, int_net, cell_mod, exclude_set))
+
+ return bl_names[0], bl_names[1]
+
+ def get_bl_name_search_exclusions(self):
+ """Gets the mods as a set which should be excluded while searching for name."""
+
+ # Exclude the RBL as it contains bitcells which are not in the main bitcell array
+ # so it makes the search awkward
+ return set(factory.get_mods(OPTS.replica_bitline))
+
+ def get_alias_in_path(self, paths, int_net, mod, exclusion_set=None):
+ """
+ Finds a single alias for the int_net in given paths.
+ More or less hits cause an error
+ """
+
+ net_found = False
+ for path in paths:
+ aliases = self.sram.find_aliases(self.sram_spc_name, self.pins, path, int_net, mod, exclusion_set)
+ if net_found and len(aliases) >= 1:
+ debug.error('Found multiple paths with {} net.'.format(int_net),1)
+ elif len(aliases) > 1:
+ debug.error('Found multiple {} nets in single path.'.format(int_net),1)
+ elif not net_found and len(aliases) == 1:
+ path_net_name = aliases[0]
+ net_found = True
+ if not net_found:
+ debug.error("Could not find {} net in timing paths.".format(int_net),1)
+
+ return path_net_name
+
diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py
index d24c931d..07a753a7 100644
--- a/compiler/characterizer/lib.py
+++ b/compiler/characterizer/lib.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import os,sys,re
import debug
import math
@@ -102,6 +109,8 @@ class lib:
#set the read and write port as inputs.
self.write_data_bus(port)
self.write_addr_bus(port)
+ if self.sram.write_size:
+ self.write_wmask_bus(port)
self.write_control_pins(port) #need to split this into sram and port control signals
self.write_clk_timing_power(port)
@@ -141,9 +150,9 @@ class lib:
self.lib.write(" area : {};\n\n".format(self.sram.width * self.sram.height))
#Build string of all control signals.
- control_str = 'CSb0' #assume at least 1 port
+ control_str = 'csb0' #assume at least 1 port
for i in range(1, self.total_port_num):
- control_str += ' & CSb{0}'.format(i)
+ control_str += ' & csb{0}'.format(i)
# Leakage is included in dynamic when macro is enabled
self.lib.write(" leakage_power () {\n")
@@ -154,13 +163,17 @@ class lib:
def write_units(self):
- """ Adds default units for time, voltage, current,..."""
-
+ """ Adds default units for time, voltage, current,...
+ Valid values are 1mV, 10mV, 100mV, and 1V.
+ For time: Valid values are 1ps, 10ps, 100ps, and 1ns.
+ For power: Valid values are 1mW, 100uW (for 100mW), 10uW (for 10mW),
+ 1uW (for 1mW), 100nW, 10nW, 1nW, 100pW, 10pW, and 1pW.
+ """
self.lib.write(" time_unit : \"1ns\" ;\n")
- self.lib.write(" voltage_unit : \"1v\" ;\n")
+ self.lib.write(" voltage_unit : \"1V\" ;\n")
self.lib.write(" current_unit : \"1mA\" ;\n")
self.lib.write(" resistance_unit : \"1kohm\" ;\n")
- self.lib.write(" capacitive_load_unit(1 ,fF) ;\n")
+ self.lib.write(" capacitive_load_unit(1, pF) ;\n")
self.lib.write(" leakage_power_unit : \"1mW\" ;\n")
self.lib.write(" pulling_resistance_unit :\"1kohm\" ;\n")
self.lib.write(" operating_conditions(OC){\n")
@@ -232,7 +245,9 @@ class lib:
self.lib.write(" variable_1 : input_net_transition;\n")
self.lib.write(" variable_2 : total_output_net_capacitance;\n")
self.write_index(1,self.slews)
- self.write_index(2,self.loads)
+ # Dividing by 1000 to all cap values since output of .sp is in fF,
+ # and it needs to be in pF for Innovus.
+ self.write_index(2,self.loads/1000)
self.lib.write(" }\n\n")
CONS = ["CONSTRAINT_TABLE"]
@@ -265,10 +280,10 @@ class lib:
# self.lib.write(" }\n\n")
def write_bus(self):
- """ Adds format of DATA and ADDR bus."""
+ """ Adds format of data and addr bus."""
self.lib.write("\n\n")
- self.lib.write(" type (DATA){\n")
+ self.lib.write(" type (data){\n")
self.lib.write(" base_type : array;\n")
self.lib.write(" data_type : bit;\n")
self.lib.write(" bit_width : {0};\n".format(self.sram.word_size))
@@ -276,7 +291,7 @@ class lib:
self.lib.write(" bit_to : {0};\n".format(self.sram.word_size - 1))
self.lib.write(" }\n\n")
- self.lib.write(" type (ADDR){\n")
+ self.lib.write(" type (addr){\n")
self.lib.write(" base_type : array;\n")
self.lib.write(" data_type : bit;\n")
self.lib.write(" bit_width : {0};\n".format(self.sram.addr_size))
@@ -284,6 +299,15 @@ class lib:
self.lib.write(" bit_to : {0};\n".format(self.sram.addr_size - 1))
self.lib.write(" }\n\n")
+ if self.sram.write_size:
+ self.lib.write(" type (wmask){\n")
+ self.lib.write(" base_type : array;\n")
+ self.lib.write(" data_type : bit;\n")
+ self.lib.write(" bit_width : {0};\n".format(self.sram.num_wmasks))
+ self.lib.write(" bit_from : 0;\n")
+ self.lib.write(" bit_to : {0};\n".format(self.sram.num_wmasks - 1))
+ self.lib.write(" }\n\n")
+
def write_FF_setuphold(self, port):
""" Adds Setup and Hold timing results"""
@@ -316,18 +340,18 @@ class lib:
def write_data_bus_output(self, read_port):
""" Adds data bus timing results."""
- self.lib.write(" bus(DOUT{0}){{\n".format(read_port))
- self.lib.write(" bus_type : DATA; \n")
+ self.lib.write(" bus(dout{0}){{\n".format(read_port))
+ self.lib.write(" bus_type : data; \n")
self.lib.write(" direction : output; \n")
# This is conservative, but limit to range that we characterized.
- self.lib.write(" max_capacitance : {0}; \n".format(max(self.loads)))
- self.lib.write(" min_capacitance : {0}; \n".format(min(self.loads)))
+ self.lib.write(" max_capacitance : {0}; \n".format(max(self.loads)/1000))
+ self.lib.write(" min_capacitance : {0}; \n".format(min(self.loads)/1000))
self.lib.write(" memory_read(){ \n")
- self.lib.write(" address : ADDR{0}; \n".format(read_port))
+ self.lib.write(" address : addr{0}; \n".format(read_port))
self.lib.write(" }\n")
- self.lib.write(" pin(DOUT{0}[{1}:0]){{\n".format(read_port,self.sram.word_size-1))
+ self.lib.write(" pin(dout{0}[{1}:0]){{\n".format(read_port,self.sram.word_size-1))
self.lib.write(" timing(){ \n")
self.lib.write(" timing_sense : non_unate; \n")
self.lib.write(" related_pin : \"clk{0}\"; \n".format(read_port))
@@ -349,18 +373,18 @@ class lib:
self.lib.write(" }\n\n") # bus
def write_data_bus_input(self, write_port):
- """ Adds DIN data bus timing results."""
+ """ Adds din data bus timing results."""
- self.lib.write(" bus(DIN{0}){{\n".format(write_port))
- self.lib.write(" bus_type : DATA; \n")
+ self.lib.write(" bus(din{0}){{\n".format(write_port))
+ self.lib.write(" bus_type : data; \n")
self.lib.write(" direction : input; \n")
# This is conservative, but limit to range that we characterized.
- self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"]))
+ self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"]/1000))
self.lib.write(" memory_write(){ \n")
- self.lib.write(" address : ADDR{0}; \n".format(write_port))
+ self.lib.write(" address : addr{0}; \n".format(write_port))
self.lib.write(" clocked_on : clk{0}; \n".format(write_port))
self.lib.write(" }\n")
- self.lib.write(" pin(DIN{0}[{1}:0]){{\n".format(write_port,self.sram.word_size-1))
+ self.lib.write(" pin(din{0}[{1}:0]){{\n".format(write_port,self.sram.word_size-1))
self.write_FF_setuphold(write_port)
self.lib.write(" }\n") # pin
self.lib.write(" }\n") #bus
@@ -375,31 +399,45 @@ class lib:
def write_addr_bus(self, port):
""" Adds addr bus timing results."""
- self.lib.write(" bus(ADDR{0}){{\n".format(port))
- self.lib.write(" bus_type : ADDR; \n")
+ self.lib.write(" bus(addr{0}){{\n".format(port))
+ self.lib.write(" bus_type : addr; \n")
self.lib.write(" direction : input; \n")
- self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"]))
+ self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"]/1000))
self.lib.write(" max_transition : {0};\n".format(self.slews[-1]))
- self.lib.write(" pin(ADDR{0}[{1}:0])".format(port,self.sram.addr_size-1))
+ self.lib.write(" pin(addr{0}[{1}:0])".format(port,self.sram.addr_size-1))
self.lib.write("{\n")
self.write_FF_setuphold(port)
self.lib.write(" }\n")
self.lib.write(" }\n\n")
+ def write_wmask_bus(self, port):
+ """ Adds addr bus timing results."""
+
+ self.lib.write(" bus(wmask{0}){{\n".format(port))
+ self.lib.write(" bus_type : wmask; \n")
+ self.lib.write(" direction : input; \n")
+ self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"] / 1000))
+ self.lib.write(" max_transition : {0};\n".format(self.slews[-1]))
+ self.lib.write(" pin(wmask{0}[{1}:0])".format(port, self.sram.num_wmasks - 1))
+ self.lib.write("{\n")
+
+ self.write_FF_setuphold(port)
+ self.lib.write(" }\n")
+ self.lib.write(" }\n\n")
def write_control_pins(self, port):
""" Adds control pins timing results."""
#The control pins are still to be determined. This is a placeholder for what could be.
- ctrl_pin_names = ["CSb{0}".format(port)]
+ ctrl_pin_names = ["csb{0}".format(port)]
if port in self.readwrite_ports:
- ctrl_pin_names.append("WEb{0}".format(port))
+ ctrl_pin_names.append("web{0}".format(port))
for i in ctrl_pin_names:
self.lib.write(" pin({0})".format(i))
self.lib.write("{\n")
self.lib.write(" direction : input; \n")
- self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"]))
+ self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"]/1000))
self.write_FF_setuphold(port)
self.lib.write(" }\n\n")
@@ -410,7 +448,7 @@ class lib:
self.lib.write(" clock : true;\n")
self.lib.write(" direction : input; \n")
# FIXME: This depends on the clock buffer size in the control logic
- self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"]))
+ self.lib.write(" capacitance : {0}; \n".format(tech.spice["dff_in_cap"]/1000))
self.add_clk_control_power(port)
@@ -445,10 +483,10 @@ class lib:
if port in self.write_ports:
if port in self.read_ports:
- web_name = " & !WEb{0}".format(port)
+ web_name = " & !web{0}".format(port)
avg_write_power = np.mean(self.char_port_results[port]["write1_power"] + self.char_port_results[port]["write0_power"])
self.lib.write(" internal_power(){\n")
- self.lib.write(" when : \"!CSb{0} & clk{0}{1}\"; \n".format(port, web_name))
+ self.lib.write(" when : \"!csb{0} & clk{0}{1}\"; \n".format(port, web_name))
self.lib.write(" rise_power(scalar){\n")
self.lib.write(" values(\"{0}\");\n".format(avg_write_power/2.0))
self.lib.write(" }\n")
@@ -459,10 +497,10 @@ class lib:
if port in self.read_ports:
if port in self.write_ports:
- web_name = " & WEb{0}".format(port)
+ web_name = " & web{0}".format(port)
avg_read_power = np.mean(self.char_port_results[port]["read1_power"] + self.char_port_results[port]["read0_power"])
self.lib.write(" internal_power(){\n")
- self.lib.write(" when : \"!CSb{0} & !clk{0}{1}\"; \n".format(port, web_name))
+ self.lib.write(" when : \"!csb{0} & !clk{0}{1}\"; \n".format(port, web_name))
self.lib.write(" rise_power(scalar){\n")
self.lib.write(" values(\"{0}\");\n".format(avg_read_power/2.0))
self.lib.write(" }\n")
@@ -473,7 +511,7 @@ class lib:
# Have 0 internal power when disabled, this will be represented as leakage power.
self.lib.write(" internal_power(){\n")
- self.lib.write(" when : \"CSb{0}\"; \n".format(port))
+ self.lib.write(" when : \"csb{0}\"; \n".format(port))
self.lib.write(" rise_power(scalar){\n")
self.lib.write(" values(\"0\");\n")
self.lib.write(" }\n")
@@ -564,10 +602,10 @@ class lib:
datasheet.write(str(self.sram.width * self.sram.height)+',')
# write timing information for all ports
for port in self.all_ports:
- #DIN timings
+ #din timings
if port in self.write_ports:
datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},".format(
- "DIN{1}[{0}:0]".format(self.sram.word_size - 1, port),
+ "din{1}[{0}:0]".format(self.sram.word_size - 1, port),
min(list(map(round_time,self.times["setup_times_LH"]))),
max(list(map(round_time,self.times["setup_times_LH"]))),
@@ -583,10 +621,10 @@ class lib:
))
for port in self.all_ports:
- #DOUT timing
+ #dout timing
if port in self.read_ports:
datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},".format(
- "DOUT{1}[{0}:0]".format(self.sram.word_size - 1, port),
+ "dout{1}[{0}:0]".format(self.sram.word_size - 1, port),
min(list(map(round_time,self.char_port_results[port]["delay_lh"]))),
max(list(map(round_time,self.char_port_results[port]["delay_lh"]))),
@@ -603,9 +641,9 @@ class lib:
))
for port in self.all_ports:
- #CSb timings
+ #csb timings
datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},".format(
- "CSb{0}".format(port),
+ "csb{0}".format(port),
min(list(map(round_time,self.times["setup_times_LH"]))),
max(list(map(round_time,self.times["setup_times_LH"]))),
@@ -621,9 +659,9 @@ class lib:
))
for port in self.all_ports:
- #ADDR timings
+ #addr timings
datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},".format(
- "ADDR{1}[{0}:0]".format(self.sram.addr_size - 1, port),
+ "addr{1}[{0}:0]".format(self.sram.addr_size - 1, port),
min(list(map(round_time,self.times["setup_times_LH"]))),
max(list(map(round_time,self.times["setup_times_LH"]))),
@@ -642,9 +680,9 @@ class lib:
for port in self.all_ports:
if port in self.readwrite_ports:
- #WEb timings
+ #web timings
datasheet.write("{0},{1},{2},{3},{4},{5},{6},{7},{8},".format(
- "WEb{0}".format(port),
+ "web{0}".format(port),
min(list(map(round_time,self.times["setup_times_LH"]))),
max(list(map(round_time,self.times["setup_times_LH"]))),
@@ -666,8 +704,8 @@ class lib:
# write dynamic power usage
if port in self.read_ports:
- web_name = " & !WEb{0}".format(port)
- name = "!CSb{0} & clk{0}{1}".format(port, web_name)
+ web_name = " & !web{0}".format(port)
+ name = "!csb{0} & clk{0}{1}".format(port, web_name)
read_write = 'Read'
datasheet.write("{0},{1},{2},{3},".format(
@@ -679,8 +717,8 @@ class lib:
))
if port in self.write_ports:
- web_name = " & WEb{0}".format(port)
- name = "!CSb{0} & !clk{0}{1}".format(port, web_name)
+ web_name = " & web{0}".format(port)
+ name = "!csb{0} & !clk{0}{1}".format(port, web_name)
read_write = 'Write'
datasheet.write("{0},{1},{2},{3},".format(
@@ -692,9 +730,9 @@ class lib:
))
# write leakage power
- control_str = 'CSb0'
+ control_str = 'csb0'
for i in range(1, self.total_port_num):
- control_str += ' & CSb{0}'.format(i)
+ control_str += ' & csb{0}'.format(i)
datasheet.write("{0},{1},{2},".format('leak', control_str, self.char_sram_results["leakage_power"]))
diff --git a/compiler/characterizer/logical_effort.py b/compiler/characterizer/logical_effort.py
index c80e69a2..42ac8861 100644
--- a/compiler/characterizer/logical_effort.py
+++ b/compiler/characterizer/logical_effort.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
from tech import drc, parameter, spice
@@ -9,51 +16,69 @@ class logical_effort():
beta = parameter["beta"]
min_inv_cin = 1+beta
pinv=parameter["min_inv_para_delay"]
+ tau = parameter['le_tau']
def __init__(self, name, size, cin, cout, parasitic, out_is_rise=True):
self.name = name
self.cin = cin
self.cout = cout
self.logical_effort = (self.cin/size)/logical_effort.min_inv_cin
- self.eletrical_effort = self.cout/self.cin
+ self.electrical_effort = self.cout/self.cin
self.parasitic_scale = parasitic
self.is_rise = out_is_rise
def __str__(self):
return "Name={}, g={}, h={}, p={}*pinv, rise_delay={}".format(self.name,
self.logical_effort,
- self.eletrical_effort,
+ self.electrical_effort,
self.parasitic_scale,
self.is_rise
)
def get_stage_effort(self):
- return self.logical_effort*self.eletrical_effort
+ return self.logical_effort*self.electrical_effort
- def get_parasitic_delay(self, pinv):
- return pinv * self.parasitic_scale
+ def get_parasitic_delay(self):
+ return logical_effort.pinv*self.parasitic_scale
- def get_stage_delay(self, pinv):
- return self.get_stage_effort()+self.get_parasitic_delay(pinv)
+ def get_stage_delay(self):
+ return self.get_stage_effort()+self.get_parasitic_delay()
-def calculate_delays(stage_effort_list, pinv):
+ def get_absolute_delay(self):
+ return logical_effort.tau*self.get_stage_delay()
+
+def calculate_delays(stage_effort_list):
"""Convert stage effort objects to list of delay values"""
- return [stage.get_stage_delay(pinv) for stage in stage_effort_list]
+ return [stage.get_stage_delay() for stage in stage_effort_list]
-def calculate_relative_delay(stage_effort_list, pinv=parameter["min_inv_para_delay"]):
+def calculate_relative_delay(stage_effort_list):
"""Calculates the total delay of a given delay path made of a list of logical effort objects."""
- total_rise_delay, total_fall_delay = calculate_relative_rise_fall_delays(stage_effort_list, pinv)
+ total_rise_delay, total_fall_delay = calculate_relative_rise_fall_delays(stage_effort_list)
return total_rise_delay + total_fall_delay
+
+def calculate_absolute_delay(stage_effort_list):
+ """Calculates the total delay of a given delay path made of a list of logical effort objects."""
+ total_delay = 0
+ for stage in stage_effort_list:
+ total_delay+=stage.get_absolute_delay()
+ return total_delay
-def calculate_relative_rise_fall_delays(stage_effort_list, pinv=parameter["min_inv_para_delay"]):
+def calculate_relative_rise_fall_delays(stage_effort_list):
"""Calculates the rise/fall delays of a given delay path made of a list of logical effort objects."""
debug.info(2, "Calculating rise/fall relative delays")
total_rise_delay, total_fall_delay = 0,0
for stage in stage_effort_list:
debug.info(2, stage)
if stage.is_rise:
- total_rise_delay += stage.get_stage_delay(pinv)
+ total_rise_delay += stage.get_stage_delay()
else:
- total_fall_delay += stage.get_stage_delay(pinv)
+ total_fall_delay += stage.get_stage_delay()
return total_rise_delay, total_fall_delay
-
\ No newline at end of file
+
+def convert_farad_to_relative_c(c_farad):
+ """Converts capacitance in Femto-Farads to relative capacitance."""
+ return c_farad*parameter['cap_relative_per_ff']
+
+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']
\ No newline at end of file
diff --git a/compiler/characterizer/measurements.py b/compiler/characterizer/measurements.py
index e3d16584..54f9973f 100644
--- a/compiler/characterizer/measurements.py
+++ b/compiler/characterizer/measurements.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
from tech import drc, parameter, spice
from abc import ABC, abstractmethod
@@ -6,10 +13,11 @@ from .charutils import *
class spice_measurement(ABC):
"""Base class for spice stimulus measurements."""
- def __init__(self, measure_name, measure_scale=None):
+ def __init__(self, measure_name, measure_scale=None, has_port=True):
#Names must be unique for correct spice simulation, but not enforced here.
self.name = measure_name
self.measure_scale = measure_scale
+ self.has_port = has_port #Needed for error checking
#Some meta values used externally. variables are added here for consistency accross the objects
self.meta_str = None
self.meta_add_delay = False
@@ -28,18 +36,29 @@ class spice_measurement(ABC):
measure_vals = self.get_measure_values(*input_tuple)
measure_func(stim_obj, *measure_vals)
- def retrieve_measure(self, port=""):
- value = parse_spice_list("timing", "{0}{1}".format(self.name.lower(), port))
+ def retrieve_measure(self, port=None):
+ self.port_error_check(port)
+ if port != None:
+ value = parse_spice_list("timing", "{0}{1}".format(self.name.lower(), port))
+ else:
+ value = parse_spice_list("timing", "{0}".format(self.name.lower()))
if type(value)!=float or self.measure_scale == None:
return value
else:
return value*self.measure_scale
-
+
+ def port_error_check(self, port):
+ if self.has_port and port == None:
+ debug.error("Cannot retrieve measurement, port input was expected.",1)
+ elif not self.has_port and port != None:
+ debug.error("Unexpected port input received during measure retrieval.",1)
+
class delay_measure(spice_measurement):
"""Generates a spice measurement for the delay of 50%-to-50% points of two signals."""
- def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, targ_dir_str, trig_vdd=0.5, targ_vdd=0.5, measure_scale=None):
- spice_measurement.__init__(self, measure_name, measure_scale)
+ def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, targ_dir_str,\
+ trig_vdd=0.5, targ_vdd=0.5, measure_scale=None, has_port=True):
+ spice_measurement.__init__(self, measure_name, measure_scale, has_port)
self.set_meas_constants(trig_name, targ_name, trig_dir_str, targ_dir_str, trig_vdd, targ_vdd)
def get_measure_function(self):
@@ -49,10 +68,8 @@ class delay_measure(spice_measurement):
"""Set the constants for this measurement: signal names, directions, and trigger scales"""
self.trig_dir_str = trig_dir_str
self.targ_dir_str = targ_dir_str
-
self.trig_val_of_vdd = trig_vdd
self.targ_val_of_vdd = targ_vdd
-
self.trig_name_no_port = trig_name
self.targ_name_no_port = targ_name
@@ -60,9 +77,10 @@ class delay_measure(spice_measurement):
def get_measure_values(self, trig_td, targ_td, vdd_voltage, port=None):
"""Constructs inputs to stimulus measurement function. Variant values are inputs here."""
+ self.port_error_check(port)
trig_val = self.trig_val_of_vdd * vdd_voltage
targ_val = self.targ_val_of_vdd * vdd_voltage
-
+
if port != None:
#For dictionary indexing reasons, the name is formatted differently than the signals
meas_name = "{}{}".format(self.name, port)
@@ -72,13 +90,12 @@ class delay_measure(spice_measurement):
meas_name = self.name
trig_name = self.trig_name_no_port
targ_name = self.targ_name_no_port
-
return (meas_name,trig_name,targ_name,trig_val,targ_val,self.trig_dir_str,self.targ_dir_str,trig_td,targ_td)
class slew_measure(delay_measure):
- def __init__(self, measure_name, signal_name, slew_dir_str, measure_scale=None):
- spice_measurement.__init__(self, measure_name, measure_scale)
+ def __init__(self, measure_name, signal_name, slew_dir_str, measure_scale=None, has_port=True):
+ spice_measurement.__init__(self, measure_name, measure_scale, has_port)
self.set_meas_constants(signal_name, slew_dir_str)
def set_meas_constants(self, signal_name, slew_dir_str):
@@ -94,7 +111,6 @@ class slew_measure(delay_measure):
self.targ_val_of_vdd = 0.1
else:
debug.error("Unrecognised slew measurement direction={}".format(slew_dir_str),1)
-
self.trig_name_no_port = signal_name
self.targ_name_no_port = signal_name
@@ -103,8 +119,8 @@ class slew_measure(delay_measure):
class power_measure(spice_measurement):
"""Generates a spice measurement for the average power between two time points."""
- def __init__(self, measure_name, power_type="", measure_scale=None):
- spice_measurement.__init__(self, measure_name, measure_scale)
+ def __init__(self, measure_name, power_type="", measure_scale=None, has_port=True):
+ spice_measurement.__init__(self, measure_name, measure_scale, has_port)
self.set_meas_constants(power_type)
def get_measure_function(self):
@@ -117,6 +133,7 @@ class power_measure(spice_measurement):
def get_measure_values(self, t_initial, t_final, port=None):
"""Constructs inputs to stimulus measurement function. Variant values are inputs here."""
+ self.port_error_check(port)
if port != None:
meas_name = "{}{}".format(self.name, port)
else:
@@ -126,8 +143,8 @@ class power_measure(spice_measurement):
class voltage_when_measure(spice_measurement):
"""Generates a spice measurement to measure the voltage of a signal based on the voltage of another."""
- def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, trig_vdd, measure_scale=None):
- spice_measurement.__init__(self, measure_name, measure_scale)
+ def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, trig_vdd, measure_scale=None, has_port=True):
+ spice_measurement.__init__(self, measure_name, measure_scale, has_port)
self.set_meas_constants(trig_name, targ_name, trig_dir_str, trig_vdd)
def get_measure_function(self):
@@ -137,13 +154,12 @@ class voltage_when_measure(spice_measurement):
"""Sets values useful for power simulations. This value is only meta related to the lib file (rise/fall)"""
self.trig_dir_str = trig_dir_str
self.trig_val_of_vdd = trig_vdd
-
self.trig_name_no_port = trig_name
self.targ_name_no_port = targ_name
def get_measure_values(self, trig_td, vdd_voltage, port=None):
"""Constructs inputs to stimulus measurement function. Variant values are inputs here."""
-
+ self.port_error_check(port)
if port != None:
#For dictionary indexing reasons, the name is formatted differently than the signals
meas_name = "{}{}".format(self.name, port)
@@ -153,7 +169,33 @@ class voltage_when_measure(spice_measurement):
meas_name = self.name
trig_name = self.trig_name_no_port
targ_name = self.targ_name_no_port
-
- trig_voltage = self.trig_val_of_vdd*vdd_voltage
-
- return (meas_name,trig_name,targ_name,trig_voltage,self.trig_dir_str,trig_td)
\ No newline at end of file
+ trig_voltage = self.trig_val_of_vdd*vdd_voltage
+ return (meas_name,trig_name,targ_name,trig_voltage,self.trig_dir_str,trig_td)
+
+class voltage_at_measure(spice_measurement):
+ """Generates a spice measurement to measure the voltage at a specific time.
+ The time is considered variant with different periods."""
+
+ def __init__(self, measure_name, targ_name, measure_scale=None, has_port=True):
+ spice_measurement.__init__(self, measure_name, measure_scale, has_port)
+ self.set_meas_constants(targ_name)
+
+ def get_measure_function(self):
+ return stimuli.gen_meas_find_voltage_at_time
+
+ def set_meas_constants(self, targ_name):
+ """Sets values useful for power simulations. This value is only meta related to the lib file (rise/fall)"""
+ self.targ_name_no_port = targ_name
+
+ def get_measure_values(self, time_at, port=None):
+ """Constructs inputs to stimulus measurement function. Variant values are inputs here."""
+ self.port_error_check(port)
+ if port != None:
+ #For dictionary indexing reasons, the name is formatted differently than the signals
+ meas_name = "{}{}".format(self.name, port)
+ targ_name = self.targ_name_no_port.format(port)
+ else:
+ meas_name = self.name
+ targ_name = self.targ_name_no_port
+ return (meas_name,targ_name,time_at)
+
\ No newline at end of file
diff --git a/compiler/characterizer/model_check.py b/compiler/characterizer/model_check.py
index 12bc5d58..b35c3c47 100644
--- a/compiler/characterizer/model_check.py
+++ b/compiler/characterizer/model_check.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import sys,re,shutil
import debug
import tech
@@ -18,69 +25,113 @@ class model_check(delay):
"""
- def __init__(self, sram, spfile, corner):
+ def __init__(self, sram, spfile, corner, custom_delaychain=False):
delay.__init__(self,sram,spfile,corner)
self.period = tech.spice["feasible_period"]
self.create_data_names()
+ self.custom_delaychain=custom_delaychain
def create_data_names(self):
self.wl_meas_name, self.wl_model_name = "wl_measures", "wl_model"
self.sae_meas_name, self.sae_model_name = "sae_measures", "sae_model"
self.wl_slew_name, self.sae_slew_name = "wl_slews", "sae_slews"
+ self.bl_meas_name, self.bl_slew_name = "bl_measures", "bl_slews"
+ self.power_name = "total_power"
- def create_measurement_names(self):
+ def create_measurement_names(self, port):
"""Create measurement names. The names themselves currently define the type of measurement"""
#Create delay measurement names
wl_en_driver_delay_names = ["delay_wl_en_dvr_{}".format(stage) for stage in range(1,self.get_num_wl_en_driver_stages())]
wl_driver_delay_names = ["delay_wl_dvr_{}".format(stage) for stage in range(1,self.get_num_wl_driver_stages())]
sen_driver_delay_names = ["delay_sen_dvr_{}".format(stage) for stage in range(1,self.get_num_sen_driver_stages())]
- dc_delay_names = ["delay_delay_chain_stage_{}".format(stage) for stage in range(1,self.get_num_delay_stages()+1)]
+ if self.custom_delaychain:
+ dc_delay_names = ['delay_dc_out_final']
+ else:
+ dc_delay_names = ["delay_delay_chain_stage_{}".format(stage) for stage in range(1,self.get_num_delay_stages()+1)]
self.wl_delay_meas_names = wl_en_driver_delay_names+["delay_wl_en", "delay_wl_bar"]+wl_driver_delay_names+["delay_wl"]
- self.rbl_delay_meas_names = ["delay_gated_clk_nand", "delay_delay_chain_in"]+dc_delay_names
+ if port not in self.sram.readonly_ports:
+ self.rbl_delay_meas_names = ["delay_gated_clk_nand", "delay_delay_chain_in"]+dc_delay_names
+ else:
+ self.rbl_delay_meas_names = ["delay_gated_clk_nand"]+dc_delay_names
self.sae_delay_meas_names = ["delay_pre_sen"]+sen_driver_delay_names+["delay_sen"]
+ # if self.custom_delaychain:
+ # self.delay_chain_indices = (len(self.rbl_delay_meas_names), len(self.rbl_delay_meas_names)+1)
+ # else:
self.delay_chain_indices = (len(self.rbl_delay_meas_names)-len(dc_delay_names), len(self.rbl_delay_meas_names))
#Create slew measurement names
wl_en_driver_slew_names = ["slew_wl_en_dvr_{}".format(stage) for stage in range(1,self.get_num_wl_en_driver_stages())]
wl_driver_slew_names = ["slew_wl_dvr_{}".format(stage) for stage in range(1,self.get_num_wl_driver_stages())]
sen_driver_slew_names = ["slew_sen_dvr_{}".format(stage) for stage in range(1,self.get_num_sen_driver_stages())]
- dc_slew_names = ["slew_delay_chain_stage_{}".format(stage) for stage in range(1,self.get_num_delay_stages()+1)]
+ if self.custom_delaychain:
+ dc_slew_names = ['slew_dc_out_final']
+ else:
+ dc_slew_names = ["slew_delay_chain_stage_{}".format(stage) for stage in range(1,self.get_num_delay_stages()+1)]
self.wl_slew_meas_names = ["slew_wl_gated_clk_bar"]+wl_en_driver_slew_names+["slew_wl_en", "slew_wl_bar"]+wl_driver_slew_names+["slew_wl"]
- self.rbl_slew_meas_names = ["slew_rbl_gated_clk_bar","slew_gated_clk_nand", "slew_delay_chain_in"]+dc_slew_names
+ if port not in self.sram.readonly_ports:
+ self.rbl_slew_meas_names = ["slew_rbl_gated_clk_bar","slew_gated_clk_nand", "slew_delay_chain_in"]+dc_slew_names
+ else:
+ self.rbl_slew_meas_names = ["slew_rbl_gated_clk_bar"]+dc_slew_names
self.sae_slew_meas_names = ["slew_replica_bl0", "slew_pre_sen"]+sen_driver_slew_names+["slew_sen"]
- def create_signal_names(self):
+ self.bitline_meas_names = ["delay_wl_to_bl", "delay_bl_to_dout"]
+ self.power_meas_names = ['read0_power']
+
+ def create_signal_names(self, port):
"""Creates list of the signal names used in the spice file along the wl and sen paths.
Names are re-harded coded here; i.e. the names are hardcoded in most of OpenRAM and are
replicated here.
"""
delay.create_signal_names(self)
#Signal names are all hardcoded, need to update to make it work for probe address and different configurations.
- wl_en_driver_signals = ["Xsram.Xcontrol0.Xbuf_wl_en.Zb{}_int".format(stage) for stage in range(1,self.get_num_wl_en_driver_stages())]
- wl_driver_signals = ["Xsram.Xbank0.Xwordline_driver0.Xwl_driver_inv{}.Zb{}_int".format(self.wordline_row, stage) for stage in range(1,self.get_num_wl_driver_stages())]
- sen_driver_signals = ["Xsram.Xcontrol0.Xbuf_s_en.Zb{}_int".format(stage) for stage in range(1,self.get_num_sen_driver_stages())]
- delay_chain_signal_names = ["Xsram.Xcontrol0.Xreplica_bitline.Xdelay_chain.dout_{}".format(stage) for stage in range(1,self.get_num_delay_stages())]
-
- self.wl_signal_names = ["Xsram.Xcontrol0.gated_clk_bar"]+\
+ wl_en_driver_signals = ["Xsram.Xcontrol{}.Xbuf_wl_en.Zb{}_int".format('{}', stage) for stage in range(1,self.get_num_wl_en_driver_stages())]
+ wl_driver_signals = ["Xsram.Xbank0.Xwordline_driver{}.Xwl_driver_inv{}.Zb{}_int".format('{}', self.wordline_row, stage) for stage in range(1,self.get_num_wl_driver_stages())]
+ sen_driver_signals = ["Xsram.Xcontrol{}.Xbuf_s_en.Zb{}_int".format('{}',stage) for stage in range(1,self.get_num_sen_driver_stages())]
+ if self.custom_delaychain:
+ delay_chain_signal_names = []
+ else:
+ delay_chain_signal_names = ["Xsram.Xcontrol{}.Xreplica_bitline.Xdelay_chain.dout_{}".format('{}', stage) for stage in range(1,self.get_num_delay_stages())]
+ if len(self.sram.all_ports) > 1:
+ port_format = '{}'
+ else:
+ port_format = ''
+ self.wl_signal_names = ["Xsram.Xcontrol{}.gated_clk_bar".format('{}')]+\
wl_en_driver_signals+\
- ["Xsram.wl_en0", "Xsram.Xbank0.Xwordline_driver0.wl_bar_{}".format(self.wordline_row)]+\
+ ["Xsram.wl_en{}".format('{}'), "Xsram.Xbank0.Xwordline_driver{}.wl_bar_{}".format('{}',self.wordline_row)]+\
wl_driver_signals+\
- ["Xsram.Xbank0.wl_{}".format(self.wordline_row)]
- pre_delay_chain_names = ["Xsram.Xcontrol0.gated_clk_bar", "Xsram.Xcontrol0.Xand2_rbl_in.zb_int", "Xsram.Xcontrol0.rbl_in"]
+ ["Xsram.Xbank0.wl{}_{}".format(port_format, self.wordline_row)]
+ pre_delay_chain_names = ["Xsram.Xcontrol{}.gated_clk_bar".format('{}')]
+ if port not in self.sram.readonly_ports:
+ pre_delay_chain_names+= ["Xsram.Xcontrol{}.Xand2_rbl_in.zb_int".format('{}'), "Xsram.Xcontrol{}.rbl_in".format('{}')]
+
self.rbl_en_signal_names = pre_delay_chain_names+\
delay_chain_signal_names+\
- ["Xsram.Xcontrol0.Xreplica_bitline.delayed_en"]
- self.sae_signal_names = ["Xsram.Xcontrol0.Xreplica_bitline.bl0_0", "Xsram.Xcontrol0.pre_s_en"]+\
+ ["Xsram.Xcontrol{}.Xreplica_bitline.delayed_en".format('{}')]
+
+
+ self.sae_signal_names = ["Xsram.Xcontrol{}.Xreplica_bitline.bl0_0".format('{}'), "Xsram.Xcontrol{}.pre_s_en".format('{}')]+\
sen_driver_signals+\
- ["Xsram.s_en0"]
+ ["Xsram.s_en{}".format('{}')]
+
+ dout_name = "{0}{1}_{2}".format(self.dout_name,"{}",self.probe_data) #Empty values are the port and probe data bit
+ self.bl_signal_names = ["Xsram.Xbank0.wl{}_{}".format(port_format, self.wordline_row),\
+ "Xsram.Xbank0.bl{}_{}".format(port_format, self.bitline_column),\
+ dout_name]
def create_measurement_objects(self):
"""Create the measurements used for read and write ports"""
- self.create_wordline_measurement_objects()
- self.create_sae_measurement_objects()
- self.all_measures = self.wl_meas_objs+self.sae_meas_objs
+ self.create_wordline_meas_objs()
+ self.create_sae_meas_objs()
+ self.create_bl_meas_objs()
+ self.create_power_meas_objs()
+ self.all_measures = self.wl_meas_objs+self.sae_meas_objs+self.bl_meas_objs+self.power_meas_objs
- def create_wordline_measurement_objects(self):
+ def create_power_meas_objs(self):
+ """Create power measurement object. Only one."""
+ self.power_meas_objs = []
+ self.power_meas_objs.append(power_measure(self.power_meas_names[0], "FALL", measure_scale=1e3))
+
+ def create_wordline_meas_objs(self):
"""Create the measurements to measure the wordline path from the gated_clk_bar signal"""
self.wl_meas_objs = []
trig_dir = "RISE"
@@ -102,7 +153,19 @@ class model_check(delay):
targ_dir = temp_dir
self.wl_meas_objs.append(slew_measure(self.wl_slew_meas_names[-1], self.wl_signal_names[-1], trig_dir, measure_scale=1e9))
- def create_sae_measurement_objects(self):
+ def create_bl_meas_objs(self):
+ """Create the measurements to measure the bitline to dout, static stages"""
+ #Bitline has slightly different measurements, objects appends hardcoded.
+ self.bl_meas_objs = []
+ trig_dir, targ_dir = "RISE", "FALL" #Only check read 0
+ self.bl_meas_objs.append(delay_measure(self.bitline_meas_names[0],
+ self.bl_signal_names[0],
+ self.bl_signal_names[-1],
+ trig_dir,
+ targ_dir,
+ measure_scale=1e9))
+
+ def create_sae_meas_objs(self):
"""Create the measurements to measure the sense amp enable path from the gated_clk_bar signal. The RBL splits this path into two."""
self.sae_meas_objs = []
@@ -123,6 +186,13 @@ class model_check(delay):
temp_dir = trig_dir
trig_dir = targ_dir
targ_dir = temp_dir
+ if self.custom_delaychain: #Hack for custom delay chains
+ self.sae_meas_objs[-2] = delay_measure(self.rbl_delay_meas_names[-1],
+ self.rbl_en_signal_names[-2],
+ self.rbl_en_signal_names[-1],
+ "RISE",
+ "RISE",
+ measure_scale=1e9)
self.sae_meas_objs.append(slew_measure(self.rbl_slew_meas_names[-1],
self.rbl_en_signal_names[-1],
trig_dir,
@@ -131,7 +201,6 @@ class model_check(delay):
#Add measurements from rbl_out to sae. Trigger directions do not invert from previous stage due to RBL.
trig_dir = "FALL"
targ_dir = "RISE"
- #Add measurements from gated_clk_bar to RBL
for i in range(1, len(self.sae_signal_names)):
self.sae_meas_objs.append(delay_measure(self.sae_delay_meas_names[i-1],
self.sae_signal_names[i-1],
@@ -169,10 +238,22 @@ class model_check(delay):
or port to port (time delays)"""
#Return value is intended to match the delay measure format: trig_td, targ_td, vdd, port
#Assuming only read 0 for now
- if not (type(measure_obj) is delay_measure or type(measure_obj) is slew_measure):
+ debug.info(3,"Power measurement={}".format(measure_obj))
+ if (type(measure_obj) is delay_measure or type(measure_obj) is slew_measure):
+ meas_cycle_delay = self.cycle_times[self.measure_cycles[port]["read0"]] + self.period/2
+ return (meas_cycle_delay, meas_cycle_delay, self.vdd_voltage, port)
+ elif type(measure_obj) is power_measure:
+ return self.get_power_measure_variants(port, measure_obj, "read")
+ else:
debug.error("Measurement not recognized by the model checker.",1)
- meas_cycle_delay = self.cycle_times[self.measure_cycles[port]["read0"]] + self.period/2
- return (meas_cycle_delay, meas_cycle_delay, self.vdd_voltage, port)
+
+ def get_power_measure_variants(self, port, power_obj, operation):
+ """Get the measurement values that can either vary port to port (time delays)"""
+ #Return value is intended to match the power measure format: t_initial, t_final, port
+ t_initial = self.cycle_times[self.measure_cycles[port]["read0"]]
+ t_final = self.cycle_times[self.measure_cycles[port]["read0"]+1]
+
+ return (t_initial, t_final, port)
def write_measures_read_port(self, port):
"""
@@ -186,7 +267,8 @@ class model_check(delay):
def get_measurement_values(self, meas_objs, port):
"""Gets the delays and slews from a specified port from the spice output file and returns them as lists."""
delay_meas_list = []
- slew_meas_list = []
+ slew_meas_list = []
+ power_meas_list=[]
for measure in meas_objs:
measure_value = measure.retrieve_measure(port=port)
if type(measure_value) != float:
@@ -195,9 +277,11 @@ class model_check(delay):
delay_meas_list.append(measure_value)
elif type(measure)is slew_measure:
slew_meas_list.append(measure_value)
+ elif type(measure)is power_measure:
+ power_meas_list.append(measure_value)
else:
debug.error("Measurement object not recognized.",1)
- return delay_meas_list, slew_meas_list
+ return delay_meas_list, slew_meas_list,power_meas_list
def run_delay_simulation(self):
"""
@@ -213,6 +297,9 @@ class model_check(delay):
wl_slew_result = [[] for i in self.all_ports]
sae_delay_result = [[] for i in self.all_ports]
sae_slew_result = [[] for i in self.all_ports]
+ bl_delay_result = [[] for i in self.all_ports]
+ bl_slew_result = [[] for i in self.all_ports]
+ power_result = [[] for i in self.all_ports]
# Checking from not data_value to data_value
self.write_delay_stimulus()
@@ -221,9 +308,11 @@ class model_check(delay):
#Retrieve the results from the output file
for port in self.targ_read_ports:
#Parse and check the voltage measurements
- wl_delay_result[port], wl_slew_result[port] = self.get_measurement_values(self.wl_meas_objs, port)
- sae_delay_result[port], sae_slew_result[port] = self.get_measurement_values(self.sae_meas_objs, port)
- return (True,wl_delay_result, sae_delay_result, wl_slew_result, sae_slew_result)
+ wl_delay_result[port], wl_slew_result[port],_ = self.get_measurement_values(self.wl_meas_objs, port)
+ sae_delay_result[port], sae_slew_result[port],_ = self.get_measurement_values(self.sae_meas_objs, port)
+ bl_delay_result[port], bl_slew_result[port],_ = self.get_measurement_values(self.bl_meas_objs, port)
+ _,__,power_result[port] = self.get_measurement_values(self.power_meas_objs, port)
+ return (True,wl_delay_result, sae_delay_result, wl_slew_result, sae_slew_result, bl_delay_result, bl_slew_result, power_result)
def get_model_delays(self, port):
"""Get model delays based on port. Currently assumes single RW port."""
@@ -292,37 +381,43 @@ class model_check(delay):
errors = self.calculate_error_l2_norm(scaled_meas, scaled_model)
debug.info(1, "Errors:\n{}\n".format(errors))
- def analyze(self, probe_address, probe_data, slews, loads):
+ def analyze(self, probe_address, probe_data, slews, loads, port):
"""Measures entire delay path along the wordline and sense amp enable and compare it to the model delays."""
self.load=max(loads)
self.slew=max(slews)
self.set_probe(probe_address, probe_data)
- self.create_signal_names()
- self.create_measurement_names()
+ self.create_signal_names(port)
+ self.create_measurement_names(port)
self.create_measurement_objects()
data_dict = {}
read_port = self.read_ports[0] #only test the first read port
+ read_port = port
self.targ_read_ports = [read_port]
self.targ_write_ports = [self.write_ports[0]]
debug.info(1,"Model test: corner {}".format(self.corner))
- (success, wl_delays, sae_delays, wl_slews, sae_slews)=self.run_delay_simulation()
+ (success, wl_delays, sae_delays, wl_slews, sae_slews, bl_delays, bl_slews, powers)=self.run_delay_simulation()
debug.check(success, "Model measurements Failed: period={}".format(self.period))
- wl_model_delays, sae_model_delays = self.get_model_delays(read_port)
debug.info(1,"Measured Wordline delays (ns):\n\t {}".format(wl_delays[read_port]))
- debug.info(1,"Wordline model delays:\n\t {}".format(wl_model_delays))
debug.info(1,"Measured Wordline slews:\n\t {}".format(wl_slews[read_port]))
debug.info(1,"Measured SAE delays (ns):\n\t {}".format(sae_delays[read_port]))
- debug.info(1,"SAE model delays:\n\t {}".format(sae_model_delays))
debug.info(1,"Measured SAE slews:\n\t {}".format(sae_slews[read_port]))
+ debug.info(1,"Measured Bitline delays (ns):\n\t {}".format(bl_delays[read_port]))
data_dict[self.wl_meas_name] = wl_delays[read_port]
- data_dict[self.wl_model_name] = wl_model_delays
data_dict[self.sae_meas_name] = sae_delays[read_port]
- data_dict[self.sae_model_name] = sae_model_delays
data_dict[self.wl_slew_name] = wl_slews[read_port]
data_dict[self.sae_slew_name] = sae_slews[read_port]
+ data_dict[self.bl_meas_name] = bl_delays[read_port]
+ data_dict[self.power_name] = powers[read_port]
+
+ if not OPTS.use_tech_delay_chain_size: #Model is not used in this case
+ wl_model_delays, sae_model_delays = self.get_model_delays(read_port)
+ debug.info(1,"Wordline model delays:\n\t {}".format(wl_model_delays))
+ debug.info(1,"SAE model delays:\n\t {}".format(sae_model_delays))
+ data_dict[self.wl_model_name] = wl_model_delays
+ data_dict[self.sae_model_name] = sae_model_delays
#Some evaluations of the model and measured values
# debug.info(1, "Comparing wordline measurements and model.")
@@ -337,11 +432,17 @@ class model_check(delay):
name_dict = {}
#Signal names are more descriptive than the measurement names, first value trimmed to match size of measurements names.
name_dict[self.wl_meas_name] = self.wl_signal_names[1:]
- name_dict[self.wl_model_name] = name_dict["wl_measures"] #model uses same names as measured.
name_dict[self.sae_meas_name] = self.rbl_en_signal_names[1:]+self.sae_signal_names[1:]
- name_dict[self.sae_model_name] = name_dict["sae_measures"]
name_dict[self.wl_slew_name] = self.wl_slew_meas_names
name_dict[self.sae_slew_name] = self.rbl_slew_meas_names+self.sae_slew_meas_names
+ name_dict[self.bl_meas_name] = self.bitline_meas_names[0:1]
+ name_dict[self.power_name] = self.power_meas_names
+ #name_dict[self.wl_slew_name] = self.wl_slew_meas_names
+
+ if not OPTS.use_tech_delay_chain_size:
+ name_dict[self.wl_model_name] = name_dict["wl_measures"] #model uses same names as measured.
+ name_dict[self.sae_model_name] = name_dict["sae_measures"]
+
return name_dict
diff --git a/compiler/characterizer/setup_hold.py b/compiler/characterizer/setup_hold.py
index 8a515776..8def076d 100644
--- a/compiler/characterizer/setup_hold.py
+++ b/compiler/characterizer/setup_hold.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import sys
import tech
from .stimuli import *
@@ -329,10 +336,10 @@ class setup_hold():
for self.related_input_slew in related_slews:
for self.constrained_input_slew in constrained_slews:
# convert from ps to ns
- LH_setup.append(tech.spice["msflop_setup"]/1e3)
- HL_setup.append(tech.spice["msflop_setup"]/1e3)
- LH_hold.append(tech.spice["msflop_hold"]/1e3)
- HL_hold.append(tech.spice["msflop_hold"]/1e3)
+ LH_setup.append(tech.spice["dff_setup"]/1e3)
+ HL_setup.append(tech.spice["dff_setup"]/1e3)
+ LH_hold.append(tech.spice["dff_hold"]/1e3)
+ HL_hold.append(tech.spice["dff_hold"]/1e3)
times = {"setup_times_LH": LH_setup,
"setup_times_HL": HL_setup,
diff --git a/compiler/characterizer/simulation.py b/compiler/characterizer/simulation.py
index beca0502..5203c732 100644
--- a/compiler/characterizer/simulation.py
+++ b/compiler/characterizer/simulation.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import sys,re,shutil
from design import design
import debug
@@ -17,15 +24,18 @@ class simulation():
self.name = self.sram.name
self.word_size = self.sram.word_size
self.addr_size = self.sram.addr_size
- self.num_cols = self.sram.num_cols
- self.num_rows = self.sram.num_rows
- self.num_banks = self.sram.num_banks
+ self.write_size = self.sram.write_size
self.sp_file = spfile
self.all_ports = self.sram.all_ports
self.readwrite_ports = self.sram.readwrite_ports
self.read_ports = self.sram.read_ports
self.write_ports = self.sram.write_ports
+ if self.write_size:
+ self.num_wmasks = int(self.word_size/self.write_size)
+ else:
+ self.num_wmasks = 0
+
def set_corner(self,corner):
""" Set the corner values """
@@ -36,12 +46,25 @@ class simulation():
""" sets feasible timing parameters """
self.period = tech.spice["feasible_period"]
self.slew = tech.spice["rise_time"]*2
- self.load = tech.spice["msflop_in_cap"]*4
+ self.load = tech.spice["dff_in_cap"]*4
- self.v_high = self.vdd_voltage - tech.spice["v_threshold_typical"]
- self.v_low = tech.spice["v_threshold_typical"]
+ self.v_high = self.vdd_voltage - tech.spice["nom_threshold"]
+ self.v_low = tech.spice["nom_threshold"]
self.gnd_voltage = 0
+ def create_signal_names(self):
+ self.addr_name = "a"
+ self.din_name = "din"
+ self.dout_name = "dout"
+ self.pins = self.gen_pin_names(port_signal_names=(self.addr_name,self.din_name,self.dout_name),
+ port_info=(len(self.all_ports),self.write_ports,self.read_ports),
+ abits=self.addr_size,
+ dbits=self.word_size)
+ debug.check(len(self.sram.pins) == len(self.pins), "Number of pins generated for characterization \
+ do match pins of SRAM\nsram.pins = {0}\npin_names = {1}".format(self.sram.pins,self.pins))
+ #This is TODO once multiport control has been finalized.
+ #self.control_name = "CSB"
+
def set_stimulus_variables(self):
# Clock signals
self.cycle_times = []
@@ -54,6 +77,7 @@ class simulation():
# Three dimensional list to handle each addr and data bits for wach port over the number of checks
self.addr_values = [[[] for bit in range(self.addr_size)] for port in self.all_ports]
self.data_values = [[[] for bit in range(self.word_size)] for port in self.write_ports]
+ self.wmask_values = [[[] for bit in range(self.num_wmasks)] for port in self.write_ports]
# For generating comments in SPICE stimulus
self.cycle_comments = []
@@ -105,8 +129,22 @@ class simulation():
else:
debug.error("Non-binary address string",1)
bit -= 1
+
+ def add_wmask(self, wmask, port):
+ """ Add the array of address values """
+ debug.check(len(wmask) == self.num_wmasks, "Invalid wmask size.")
+
+ bit = self.num_wmasks - 1
+ for c in wmask:
+ if c == "0":
+ self.wmask_values[port][bit].append(0)
+ elif c == "1":
+ self.wmask_values[port][bit].append(1)
+ else:
+ debug.error("Non-binary wmask string", 1)
+ bit -= 1
- def add_write(self, comment, address, data, port):
+ def add_write(self, comment, address, data, wmask, port):
""" Add the control values for a write cycle. """
debug.check(port in self.write_ports, "Cannot add write cycle to a read port. Port {0}, Write Ports {1}".format(port, self.write_ports))
debug.info(2, comment)
@@ -119,15 +157,16 @@ class simulation():
self.add_control_one_port(port, "write")
self.add_data(data,port)
self.add_address(address,port)
+ self.add_wmask(wmask,port)
#This value is hard coded here. Possibly change to member variable or set in add_noop_one_port
noop_data = "0"*self.word_size
#Add noops to all other ports.
for unselected_port in self.all_ports:
if unselected_port != port:
- self.add_noop_one_port(address, noop_data, unselected_port)
+ self.add_noop_one_port(address, noop_data, wmask, unselected_port)
- def add_read(self, comment, address, din_data, port):
+ def add_read(self, comment, address, din_data, wmask, port):
""" Add the control values for a read cycle. """
debug.check(port in self.read_ports, "Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port, self.read_ports))
debug.info(2, comment)
@@ -141,6 +180,7 @@ class simulation():
#If the port is also a readwrite then add data.
if port in self.write_ports:
self.add_data(din_data,port)
+ self.add_wmask(wmask,port)
self.add_address(address, port)
#This value is hard coded here. Possibly change to member variable or set in add_noop_one_port
@@ -148,9 +188,9 @@ class simulation():
#Add noops to all other ports.
for unselected_port in self.all_ports:
if unselected_port != port:
- self.add_noop_one_port(address, noop_data, unselected_port)
+ self.add_noop_one_port(address, noop_data, wmask, unselected_port)
- def add_noop_all_ports(self, comment, address, data):
+ def add_noop_all_ports(self, comment, address, data, wmask):
""" Add the control values for a noop to all ports. """
debug.info(2, comment)
self.fn_cycle_comments.append(comment)
@@ -160,19 +200,20 @@ class simulation():
self.t_current += self.period
for port in self.all_ports:
- self.add_noop_one_port(address, data, port)
-
- def add_write_one_port(self, comment, address, data, port):
+ self.add_noop_one_port(address, data, wmask, port)
+
+ def add_write_one_port(self, comment, address, data, wmask, port):
""" Add the control values for a write cycle. Does not increment the period. """
debug.check(port in self.write_ports, "Cannot add write cycle to a read port. Port {0}, Write Ports {1}".format(port, self.write_ports))
debug.info(2, comment)
self.fn_cycle_comments.append(comment)
-
+
self.add_control_one_port(port, "write")
self.add_data(data,port)
self.add_address(address,port)
+ self.add_wmask(wmask,port)
- def add_read_one_port(self, comment, address, din_data, port):
+ def add_read_one_port(self, comment, address, din_data, wmask, port):
""" Add the control values for a read cycle. Does not increment the period. """
debug.check(port in self.read_ports, "Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port, self.read_ports))
debug.info(2, comment)
@@ -182,13 +223,15 @@ class simulation():
#If the port is also a readwrite then add data.
if port in self.write_ports:
self.add_data(din_data,port)
+ self.add_wmask(wmask,port)
self.add_address(address, port)
- def add_noop_one_port(self, address, data, port):
+ def add_noop_one_port(self, address, data, wmask, port):
""" Add the control values for a noop to a single port. Does not increment the period. """
self.add_control_one_port(port, "noop")
if port in self.write_ports:
self.add_data(data,port)
+ self.add_wmask(wmask,port)
self.add_address(address, port)
def append_cycle_comment(self, port, comment):
@@ -202,24 +245,74 @@ class simulation():
time_spacing,
comment))
- def gen_cycle_comment(self, op, word, addr, port, t_current):
+ def gen_cycle_comment(self, op, word, addr, wmask, port, t_current):
if op == "noop":
comment = "\tIdle during cycle {0} ({1}ns - {2}ns)".format(int(t_current/self.period),
t_current,
t_current+self.period)
elif op == "write":
comment = "\tWriting {0} to address {1} (from port {2}) during cycle {3} ({4}ns - {5}ns)".format(word,
- addr,
- port,
- int(t_current/self.period),
- t_current,
- t_current+self.period)
+ addr,
+ port,
+ int(t_current/self.period),
+ t_current,
+ t_current+self.period)
+ elif op == "partial_write":
+ comment = "\tWriting (partial) {0} to address {1} with mask bit {2} (from port {3}) during cycle {4} ({5}ns - {6}ns)".format(word,
+ addr,
+ wmask,
+ port,
+ int(t_current / self.period),
+ t_current,
+ t_current + self.period)
else:
comment = "\tReading {0} from address {1} (from port {2}) during cycle {3} ({4}ns - {5}ns)".format(word,
- addr,
- port,
- int(t_current/self.period),
- t_current,
- t_current+self.period)
+ addr,
+ port,
+ int(t_current/self.period),
+ t_current,
+ t_current+self.period)
+
+
return comment
+ def gen_pin_names(self, port_signal_names, port_info, abits, dbits):
+ """Creates the pins names of the SRAM based on the no. of ports."""
+ #This may seem redundant as the pin names are already defined in the sram. However, it is difficult
+ #to extract the functionality from the names, so they are recreated. As the order is static, changing
+ #the order of the pin names will cause issues here.
+ pin_names = []
+ (addr_name, din_name, dout_name) = port_signal_names
+ (total_ports, write_index, read_index) = port_info
+
+ for write_input in write_index:
+ for i in range(dbits):
+ pin_names.append("{0}{1}_{2}".format(din_name,write_input, i))
+
+ for port in range(total_ports):
+ for i in range(abits):
+ pin_names.append("{0}{1}_{2}".format(addr_name,port,i))
+
+ #Control signals not finalized.
+ for port in range(total_ports):
+ pin_names.append("CSB{0}".format(port))
+ for port in range(total_ports):
+ if (port in read_index) and (port in write_index):
+ pin_names.append("WEB{0}".format(port))
+
+ for port in range(total_ports):
+ pin_names.append("{0}{1}".format("clk", port))
+
+ if self.write_size:
+ for port in write_index:
+ for bit in range(self.num_wmasks):
+ pin_names.append("WMASK{0}_{1}".format(port,bit))
+
+ for read_output in read_index:
+ for i in range(dbits):
+ pin_names.append("{0}{1}_{2}".format(dout_name,read_output, i))
+
+ pin_names.append("{0}".format("vdd"))
+ pin_names.append("{0}".format("gnd"))
+ return pin_names
+
diff --git a/compiler/characterizer/sram_op.py b/compiler/characterizer/sram_op.py
new file mode 100644
index 00000000..58999ca0
--- /dev/null
+++ b/compiler/characterizer/sram_op.py
@@ -0,0 +1,15 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+
+from enum import Enum
+
+class sram_op(Enum):
+ READ_ZERO = 0
+ READ_ONE = 1
+ WRITE_ZERO = 2
+ WRITE_ONE = 3
diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py
index 3b569b2a..41a3428f 100644
--- a/compiler/characterizer/stimuli.py
+++ b/compiler/characterizer/stimuli.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
"""
This file generates simple spice cards for simulation. There are
various functions that can be be used to generate stimulus for other
@@ -17,63 +24,27 @@ class stimuli():
""" Class for providing stimuli functions """
def __init__(self, stim_file, corner):
- self.vdd_name = tech.spice["vdd_name"]
- self.gnd_name = tech.spice["gnd_name"]
+ self.vdd_name = "vdd"
+ self.gnd_name = "gnd"
self.pmos_name = tech.spice["pmos"]
self.nmos_name = tech.spice["nmos"]
- self.tx_width = tech.spice["minwidth_tx"]
- self.tx_length = tech.spice["channel"]
+ self.tx_width = tech.drc["minwidth_tx"]
+ self.tx_length = tech.drc["minlength_channel"]
self.sf = stim_file
(self.process, self.voltage, self.temperature) = corner
self.device_models = tech.spice["fet_models"][self.process]
- def inst_sram(self, sram, port_signal_names, port_info, abits, dbits, sram_name):
+ self.sram_name = "Xsram"
+
+ def inst_sram(self, pins, inst_name):
""" Function to instatiate an SRAM subckt. """
- pin_names = self.gen_pin_names(port_signal_names, port_info, abits, dbits)
- #Only checking length. This should check functionality as well (TODO) and/or import that information from the SRAM
- debug.check(len(sram.pins) == len(pin_names), "Number of pins generated for characterization do match pins of SRAM\nsram.pins = {0}\npin_names = {1}".format(sram.pins,pin_names))
-
- self.sf.write("Xsram ")
- for pin in pin_names:
+
+ self.sf.write("{} ".format(self.sram_name))
+ for pin in self.sram_pins:
self.sf.write("{0} ".format(pin))
- self.sf.write("{0}\n".format(sram_name))
-
- def gen_pin_names(self, port_signal_names, port_info, abits, dbits):
- """Creates the pins names of the SRAM based on the no. of ports."""
- #This may seem redundant as the pin names are already defined in the sram. However, it is difficult to extract the
- #functionality from the names, so they are recreated. As the order is static, changing the order of the pin names
- #will cause issues here.
- pin_names = []
- (addr_name, din_name, dout_name) = port_signal_names
- (total_ports, write_index, read_index) = port_info
-
- for write_input in write_index:
- for i in range(dbits):
- pin_names.append("{0}{1}_{2}".format(din_name,write_input, i))
-
- for port in range(total_ports):
- for i in range(abits):
- pin_names.append("{0}{1}_{2}".format(addr_name,port,i))
-
- #Control signals not finalized.
- for port in range(total_ports):
- pin_names.append("CSB{0}".format(port))
- for port in range(total_ports):
- if (port in read_index) and (port in write_index):
- pin_names.append("WEB{0}".format(port))
-
- for port in range(total_ports):
- pin_names.append("{0}{1}".format(tech.spice["clk"], port))
-
- for read_output in read_index:
- for i in range(dbits):
- pin_names.append("{0}{1}_{2}".format(dout_name,read_output, i))
-
- pin_names.append("{0}".format(self.vdd_name))
- pin_names.append("{0}".format(self.gnd_name))
- return pin_names
+ self.sf.write("{0}\n".format(inst_name))
def inst_model(self, pins, model_name):
""" Function to instantiate a generic model with a set of pins """
@@ -226,6 +197,13 @@ class stimuli():
trig_dir,
trig_td))
+ def gen_meas_find_voltage_at_time(self, meas_name, targ_name, time_at):
+ """ Creates the .meas statement for voltage at time"""
+ measure_string=".meas tran {0} FIND v({1}) AT={2}n \n\n"
+ self.sf.write(measure_string.format(meas_name,
+ targ_name,
+ time_at))
+
def gen_meas_power(self, meas_name, t_initial, t_final):
""" Creates the .meas statement for the measurement of avg power """
# power mea cmd is different in different spice:
diff --git a/compiler/characterizer/trim_spice.py b/compiler/characterizer/trim_spice.py
index 88195fee..ffc45a9c 100644
--- a/compiler/characterizer/trim_spice.py
+++ b/compiler/characterizer/trim_spice.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
from math import log
import re
diff --git a/compiler/characterizer/worst_case.py b/compiler/characterizer/worst_case.py
deleted file mode 100644
index 6dad95d9..00000000
--- a/compiler/characterizer/worst_case.py
+++ /dev/null
@@ -1,77 +0,0 @@
-import sys,re,shutil
-import debug
-import tech
-import math
-from .stimuli import *
-from .trim_spice import *
-from .charutils import *
-import utils
-from globals import OPTS
-from .delay import delay
-
-class worst_case(delay):
- """Functions to test for the worst case delay in a target SRAM
-
- The current worst case determines a feasible period for the SRAM then tests
- several bits and record the delay and differences between the bits.
-
- """
-
- def __init__(self, sram, spfile, corner):
- delay.__init__(self,sram,spfile,corner)
-
-
- def analyze(self,probe_address, probe_data, slews, loads):
- """
- Main function to test the delays of different bits.
- """
- debug.check(OPTS.num_rw_ports < 2 and OPTS.num_w_ports < 1 and OPTS.num_r_ports < 1 ,
- "Bit testing does not currently support multiport.")
- #Dict to hold all characterization values
- char_sram_data = {}
-
- self.set_probe(probe_address, probe_data)
- #self.prepare_netlist()
-
- self.load=max(loads)
- self.slew=max(slews)
-
- # 1) Find a feasible period and it's corresponding delays using the trimmed array.
- feasible_delays = self.find_feasible_period()
-
- # 2) Find the delays of several bits
- test_bits = self.get_test_bits()
- bit_delays = self.simulate_for_bit_delays(test_bits)
-
- for i in range(len(test_bits)):
- debug.info(1, "Bit tested: addr {0[0]} data_pos {0[1]}\n Values {1}".format(test_bits[i], bit_delays[i]))
-
- def simulate_for_bit_delays(self, test_bits):
- """Simulates the delay of the sram of over several bits."""
- bit_delays = [{} for i in range(len(test_bits))]
-
- #Assumes a bitcell with only 1 rw port. (6t, port 0)
- port = 0
- self.targ_read_ports = [self.read_ports[port]]
- self.targ_write_ports = [self.write_ports[port]]
-
- for i in range(len(test_bits)):
- (bit_addr, bit_data) = test_bits[i]
- self.set_probe(bit_addr, bit_data)
- debug.info(1,"Delay bit test: period {}, addr {}, data_pos {}".format(self.period, bit_addr, bit_data))
- (success, results)=self.run_delay_simulation()
- debug.check(success, "Bit Test Failed: period {}, addr {}, data_pos {}".format(self.period, bit_addr, bit_data))
- bit_delays[i] = results[port]
-
- return bit_delays
-
-
- def get_test_bits(self):
- """Statically determines address and bit values to test"""
- #First and last address, first middle, and last bit. Last bit is repeated twice with different data position.
- bit_addrs = ["0"*self.addr_size, "0"+"1"*(self.addr_size-1), "1"*self.addr_size, "1"*self.addr_size]
- data_positions = [0, (self.word_size-1)//2, 0, self.word_size-1]
- #Return them in a tuple form
- return [(bit_addrs[i], data_positions[i]) for i in range(len(bit_addrs))]
-
-
diff --git a/compiler/datasheet/add_db.py b/compiler/datasheet/add_db.py
new file mode 100644
index 00000000..9514cf1b
--- /dev/null
+++ b/compiler/datasheet/add_db.py
@@ -0,0 +1,48 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+from pathlib import Path
+import glob
+import os
+import sys
+
+# This is the path to the directory you would like to search
+# This directory is searched recursively for .html files
+
+path_to_files = sys.argv[1]
+
+
+def get_file_tree(path):
+ return list(Path(path).rglob("*.html"))
+
+
+def parse_html(file, comment):
+ start_tag = ''
+
+ with open(file, 'r') as f:
+
+ file_string = f.read()
+
+ with open(file, 'w') as f:
+
+ file_string = file_string.replace(start_tag,"")
+ file_string = file_string.replace(end_tag,"")
+
+ f.write(file_string)
+
+def uncomment(comments):
+ comment_files = []
+ for datasheet in datasheet_list:
+ for comment in comments:
+ if glob.glob(os.path.dirname(datasheet)+'/*' + comment):
+ parse_html(datasheet, comment)
+
+datasheet_list = get_file_tree(path_to_files)
+comments = ['.db']
+uncomment(comments)
+
diff --git a/compiler/datasheet/datasheet.py b/compiler/datasheet/datasheet.py
index a7700349..35091d36 100644
--- a/compiler/datasheet/datasheet.py
+++ b/compiler/datasheet/datasheet.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
from table_gen import *
import os
import base64
@@ -38,6 +45,9 @@ class datasheet():
with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/OpenRAM_logo.png', "rb") as image_file:
openram_logo = base64.b64encode(image_file.read())
+ #comment table rows which we may want to enable after compile time
+ comments = ['.db']
+
self.html += ''.format(str(vlsi_logo)[2:-1], str(openram_logo)[2:-1])
self.html += '
'
- self.html += self.operating_table.to_html()
+ self.html += self.operating_table.to_html(comments)
# check if analytical model is being used
self.html += '
Timing Data
'
@@ -66,13 +76,14 @@ class datasheet():
model = "spice characterizer"
# display timing data
self.html += '
Using '+model+'
'
- self.html += self.timing_table.to_html()
+ self.html += self.timing_table.to_html(comments)
# display power data
self.html += '
'
- self.html += self.dlv_table.to_html()
+ self.dlv_table.sort()
+ self.html += self.dlv_table.to_html(comments)
diff --git a/compiler/datasheet/datasheet_gen.py b/compiler/datasheet/datasheet_gen.py
index 3b4fe2ac..02ecc5d4 100644
--- a/compiler/datasheet/datasheet_gen.py
+++ b/compiler/datasheet/datasheet_gen.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
#!/usr/bin/env python3
"""
This is a script to load data from the characterization and layout processes into
@@ -154,7 +161,7 @@ def parse_characterizer_csv(f, pages):
# check current .lib file produces the slowest timing results
while(True):
col_start = col
- if(row[col].startswith('DIN')):
+ if(row[col].startswith('din')):
start = col
for item in sheet.timing_table.rows:
if item[0].startswith(row[col]):
@@ -193,7 +200,7 @@ def parse_characterizer_csv(f, pages):
col += 1
- elif(row[col].startswith('DOUT')):
+ elif(row[col].startswith('dout')):
start = col
for item in sheet.timing_table.rows:
if item[0].startswith(row[col]):
@@ -232,7 +239,7 @@ def parse_characterizer_csv(f, pages):
col += 1
- elif(row[col].startswith('CSb')):
+ elif(row[col].startswith('csb')):
start = col
for item in sheet.timing_table.rows:
if item[0].startswith(row[col]):
@@ -271,7 +278,7 @@ def parse_characterizer_csv(f, pages):
col += 1
- elif(row[col].startswith('WEb')):
+ elif(row[col].startswith('web')):
start = col
for item in sheet.timing_table.rows:
if item[0].startswith(row[col]):
@@ -310,7 +317,7 @@ def parse_characterizer_csv(f, pages):
col += 1
- elif(row[col].startswith('ADDR')):
+ elif(row[col].startswith('addr')):
start = col
for item in sheet.timing_table.rows:
if item[0].startswith(row[col]):
@@ -386,6 +393,9 @@ def parse_characterizer_csv(f, pages):
[PROC, VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')])
new_sheet.dlv_table.add_row(
['.lib', 'Synthesis models', '{1}'.format(LIB_NAME, LIB_NAME.replace(OUT_DIR, ''))])
+ new_sheet.dlv_table.add_row(
+ ['.db', 'Compiled .lib', '{1}'.format(LIB_NAME[:-3] + 'db', LIB_NAME.replace(OUT_DIR, '')[:-3] + 'db')])
+
if found == 0:
@@ -431,7 +441,7 @@ def parse_characterizer_csv(f, pages):
# parse initial timing information
while(True):
col_start = col
- if(row[col].startswith('DIN')):
+ if(row[col].startswith('din')):
start = col
new_sheet.timing_table.add_row(
@@ -455,7 +465,7 @@ def parse_characterizer_csv(f, pages):
col += 1
- elif(row[col].startswith('DOUT')):
+ elif(row[col].startswith('dout')):
start = col
new_sheet.timing_table.add_row(
@@ -479,7 +489,7 @@ def parse_characterizer_csv(f, pages):
col += 1
- elif(row[col].startswith('CSb')):
+ elif(row[col].startswith('csb')):
start = col
new_sheet.timing_table.add_row(
@@ -503,7 +513,7 @@ def parse_characterizer_csv(f, pages):
col += 1
- elif(row[col].startswith('WEb')):
+ elif(row[col].startswith('web')):
start = col
new_sheet.timing_table.add_row(
@@ -527,7 +537,7 @@ def parse_characterizer_csv(f, pages):
col += 1
- elif(row[col].startswith('ADDR')):
+ elif(row[col].startswith('addr')):
start = col
new_sheet.timing_table.add_row(
@@ -603,6 +613,8 @@ def parse_characterizer_csv(f, pages):
['.html', 'This datasheet', '{0}.{1}'.format(OPTS.output_name, 'html')])
new_sheet.dlv_table.add_row(
['.lib', 'Synthesis models', '{1}'.format(LIB_NAME, LIB_NAME.replace(OUT_DIR, ''))])
+ new_sheet.dlv_table.add_row(
+ ['.db', 'Compiled .lib', '{1}'.format(LIB_NAME[:-3] + 'db', LIB_NAME.replace(OUT_DIR, '')[:-3] + 'db')])
new_sheet.dlv_table.add_row(
['.py', 'OpenRAM configuration file', '{0}.{1}'.format(OPTS.output_name, 'py')])
new_sheet.dlv_table.add_row(
diff --git a/compiler/datasheet/table_gen.py b/compiler/datasheet/table_gen.py
index 8f94e896..85a6cfba 100644
--- a/compiler/datasheet/table_gen.py
+++ b/compiler/datasheet/table_gen.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
class table_gen:
"""small library of functions to generate the html tables"""
@@ -22,27 +29,38 @@ class table_gen:
html += ''
return html
- def gen_table_body(self):
+ def gen_table_body(self,comments):
"""generate html body (used after gen_table_head)"""
html = ''
html += ''
html += '
'
for row in self.rows[1:]:
- html += '
'
- for col in row:
- html += '
' + str(col) + '
'
- html += '
'
+
+ if row[0] not in comments:
+ html += '
'
+ for col in row:
+ html += '
' + str(col) + '
'
+ html += '
'
+
+ else:
+ html += ''
+
html += ''
html += ''
return html
+ def sort(self):
+ self.rows[1:] = sorted(self.rows[1:], key=lambda x : x[0])
- def to_html(self):
+ def to_html(self,comments):
"""writes table_gen object to inline html"""
html = ''
html += '
'
html += self.gen_table_head()
- html += self.gen_table_body()
- html += '
'
+ html += self.gen_table_body(comments)
+ html += '\n'
return html
diff --git a/compiler/debug.py b/compiler/debug.py
index 9ce1bf3f..02a28c22 100644
--- a/compiler/debug.py
+++ b/compiler/debug.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import os
import inspect
import globals
@@ -58,6 +65,8 @@ def log(str):
# in another log file if the path or name changes.
if not globals.OPTS.output_path.endswith('/'):
globals.OPTS.output_path += "/"
+ if not os.path.isdir(globals.OPTS.output_path):
+ os.mkdir(globals.OPTS.output_path)
compile_log = open(globals.OPTS.output_path +
globals.OPTS.output_name + '.log', "w+")
log.create_file = 0
@@ -76,7 +85,7 @@ def log(str):
# use a static list of strings to store messages until the global paths are set up
log.setup_output = []
-log.create_file = 1
+log.create_file = True
def info(lev, str):
diff --git a/compiler/drc/design_rules.py b/compiler/drc/design_rules.py
index 4bc2eaa6..1017aca6 100644
--- a/compiler/drc/design_rules.py
+++ b/compiler/drc/design_rules.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
from drc_value import *
from drc_lut import *
@@ -35,6 +42,7 @@ class design_rules():
return rule
else:
debug.error("Must call complex DRC rule {} with arguments.".format(b),-1)
+
diff --git a/compiler/drc/drc_lut.py b/compiler/drc/drc_lut.py
index 07e482c8..0ad0fde4 100644
--- a/compiler/drc/drc_lut.py
+++ b/compiler/drc/drc_lut.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
class drc_lut():
diff --git a/compiler/drc/drc_value.py b/compiler/drc/drc_value.py
index c4eab3d4..1649e203 100644
--- a/compiler/drc/drc_value.py
+++ b/compiler/drc/drc_value.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
class drc_value():
"""
diff --git a/compiler/example_configs/example_config_1rw_1r_scn4m_subm.py b/compiler/example_configs/example_config_1rw_1r_scn4m_subm.py
index 8703967b..5dad0207 100644
--- a/compiler/example_configs/example_config_1rw_1r_scn4m_subm.py
+++ b/compiler/example_configs/example_config_1rw_1r_scn4m_subm.py
@@ -10,6 +10,9 @@ process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]
+route_supplies = True
+check_lvsdrc = True
+
output_path = "temp"
output_name = "sram_1rw_1r_{0}_{1}_{2}".format(word_size,num_words,tech_name)
diff --git a/compiler/example_configs/example_config_1w_1r_scn4m_subm.py b/compiler/example_configs/example_config_1w_1r_scn4m_subm.py
index 56f6edfd..c698a035 100644
--- a/compiler/example_configs/example_config_1w_1r_scn4m_subm.py
+++ b/compiler/example_configs/example_config_1w_1r_scn4m_subm.py
@@ -10,6 +10,9 @@ process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]
+route_supplies = True
+check_lvsdrc = True
+
output_path = "temp"
output_name = "sram_1w_1r_{0}_{1}_{2}".format(word_size,num_words,tech_name)
diff --git a/compiler/example_configs/example_config_freepdk45.py b/compiler/example_configs/example_config_freepdk45.py
index ac02e514..73e15b6d 100644
--- a/compiler/example_configs/example_config_freepdk45.py
+++ b/compiler/example_configs/example_config_freepdk45.py
@@ -6,6 +6,9 @@ process_corners = ["TT"]
supply_voltages = [1.0]
temperatures = [25]
+route_supplies = True
+check_lvsdrc = True
+
output_path = "temp"
output_name = "sram_{0}_{1}_{2}".format(word_size,num_words,tech_name)
diff --git a/compiler/example_configs/example_config_scn4m_subm.py b/compiler/example_configs/example_config_scn4m_subm.py
index 7fafeb08..cf973225 100644
--- a/compiler/example_configs/example_config_scn4m_subm.py
+++ b/compiler/example_configs/example_config_scn4m_subm.py
@@ -6,6 +6,9 @@ process_corners = ["TT"]
supply_voltages = [5.0]
temperatures = [25]
+route_supplies = True
+check_lvsdrc = True
+
output_path = "temp"
output_name = "sram_{0}_{1}_{2}".format(word_size,num_words,tech_name)
diff --git a/compiler/example_configs/giant_config_scn4m_subm.py b/compiler/example_configs/giant_config_scn4m_subm.py
new file mode 100644
index 00000000..74d52fe6
--- /dev/null
+++ b/compiler/example_configs/giant_config_scn4m_subm.py
@@ -0,0 +1,14 @@
+word_size = 64
+num_words = 1024
+
+tech_name = "scn4m_subm"
+process_corners = ["TT"]
+supply_voltages = [ 5.0 ]
+temperatures = [ 25 ]
+
+output_path = "temp"
+output_name = "sram_{0}_{1}_{2}".format(word_size,num_words,tech_name)
+
+drc_name = "magic"
+lvs_name = "netgen"
+pex_name = "magic"
diff --git a/compiler/gdsMill/gdsMill/vlsiLayout.py b/compiler/gdsMill/gdsMill/vlsiLayout.py
index 03873ed4..f4248ebd 100644
--- a/compiler/gdsMill/gdsMill/vlsiLayout.py
+++ b/compiler/gdsMill/gdsMill/vlsiLayout.py
@@ -2,6 +2,7 @@ from .gdsPrimitives import *
from datetime import *
#from mpmath import matrix
#from numpy import matrix
+from vector import vector
import numpy as np
#import gdsPrimitives
import debug
@@ -725,12 +726,26 @@ class VlsiLayout:
self.pins[label_text] = []
self.pins[label_text].append(pin_shapes)
-
+
+ def getBlockages(self,layer):
+ """
+ Return all blockages on a given layer in [coordinate 1, coordinate 2,...] format and
+ user units.
+ """
+ blockages = []
+
+ shapes = self.getAllShapes(layer)
+ for boundary in shapes:
+ vectors = []
+ for i in range(0,len(boundary),2):
+ vectors.append(vector(boundary[i],boundary[i+1]))
+ blockages.append(vectors)
+ return blockages
def getAllShapes(self,layer):
"""
- Return all gshapes on a given layer in [llx, lly, urx, ury] format and
- user units.
+ Return all shapes on a given layer in [llx, lly, urx, ury] format and user units for rectangles
+ and [coordinate 1, coordinate 2,...] format and user units for polygons.
"""
boundaries = set()
for TreeUnit in self.xyTree:
@@ -740,42 +755,67 @@ class VlsiLayout:
# Convert to user units
user_boundaries = []
for boundary in boundaries:
- user_boundaries.append([boundary[0]*self.units[0],boundary[1]*self.units[0],
- boundary[2]*self.units[0],boundary[3]*self.units[0]])
-
+ boundaries_list = []
+ for i in range(0,len(boundary)):
+ boundaries_list.append(boundary[i]*self.units[0])
+ user_boundaries.append(boundaries_list)
return user_boundaries
def getShapesInStructure(self,layer,structure):
"""
Go through all the shapes in a structure and return the list of shapes in
- the form [llx, lly, urx, ury]
+ the form [llx, lly, urx, ury] for rectangles and [coordinate 1, coordinate 2,...] for polygons.
"""
-
(structureName,structureOrigin,structureuVector,structurevVector)=structure
#print(structureName,"u",structureuVector.transpose(),"v",structurevVector.transpose(),"o",structureOrigin.transpose())
boundaries = []
for boundary in self.structures[str(structureName)].boundaries:
- # FIXME: Right now, this only supports rectangular shapes!
- # We should trigger an error but some FreePDK45 library cells contain paths.
- # These get saved fine, but we cannot parse them as blockages...
- #debug.check(len(boundary.coordinates)==5,"Non-rectangular shapes are not supported.")
- if len(boundary.coordinates)!=5:
- continue
if layer==boundary.drawingLayer:
- left_bottom=boundary.coordinates[0]
- right_top=boundary.coordinates[2]
- # Rectangle is [leftx, bottomy, rightx, topy].
- boundaryRect=[left_bottom[0],left_bottom[1],right_top[0],right_top[1]]
- # perform the rotation
- boundaryRect=self.transformRectangle(boundaryRect,structureuVector,structurevVector)
- # add the offset and make it a tuple
- boundaryRect=(boundaryRect[0]+structureOrigin[0].item(),boundaryRect[1]+structureOrigin[1].item(),
- boundaryRect[2]+structureOrigin[0].item(),boundaryRect[3]+structureOrigin[1].item())
- boundaries.append(boundaryRect)
-
+ if len(boundary.coordinates)!=5:
+ # if shape is a polygon (used in DFF)
+ boundaryPolygon = []
+ # Polygon is a list of coordinates going ccw
+ for coord in range(0,len(boundary.coordinates)):
+ boundaryPolygon.append(boundary.coordinates[coord][0])
+ boundaryPolygon.append(boundary.coordinates[coord][1])
+ # perform the rotation
+ boundaryPolygon=self.transformPolygon(boundaryPolygon,structureuVector,structurevVector)
+ # add the offset
+ polygon = []
+ for i in range(0,len(boundaryPolygon),2):
+ polygon.append(boundaryPolygon[i]+structureOrigin[0].item())
+ polygon.append(boundaryPolygon[i+1]+structureOrigin[1].item())
+ # make it a tuple
+ polygon = tuple(polygon)
+ boundaries.append(polygon)
+ else:
+ # else shape is a rectangle
+ left_bottom=boundary.coordinates[0]
+ right_top=boundary.coordinates[2]
+ # Rectangle is [leftx, bottomy, rightx, topy].
+ boundaryRect=[left_bottom[0],left_bottom[1],right_top[0],right_top[1]]
+ # perform the rotation
+ boundaryRect=self.transformRectangle(boundaryRect,structureuVector,structurevVector)
+ # add the offset and make it a tuple
+ boundaryRect=(boundaryRect[0]+structureOrigin[0].item(),boundaryRect[1]+structureOrigin[1].item(),
+ boundaryRect[2]+structureOrigin[0].item(),boundaryRect[3]+structureOrigin[1].item())
+ boundaries.append(boundaryRect)
return boundaries
-
+
+
+ def transformPolygon(self,originalPolygon,uVector,vVector):
+ """
+ Transforms the coordinates of a polygon in space.
+ """
+ polygon = []
+ newPolygon = []
+ for i in range(0,len(originalPolygon),2):
+ polygon.append(self.transformCoordinate([originalPolygon[i],originalPolygon[i+1]],uVector,vVector))
+ newPolygon.append(polygon[int(i/2)][0])
+ newPolygon.append(polygon[int(i/2)][1])
+ return newPolygon
+
def transformRectangle(self,originalRectangle,uVector,vVector):
"""
Transforms the four coordinates of a rectangle in space
@@ -799,7 +839,7 @@ class VlsiLayout:
"""
Rotate a coordinate in space.
"""
- # MRG: 9/3/18 Incorrect matrixi multiplication!
+ # MRG: 9/3/18 Incorrect matrix multiplication!
# This is fixed to be:
# |u[0] v[0]| |x| |x'|
# |u[1] v[1]|x|y|=|y'|
diff --git a/compiler/gen_stimulus.py b/compiler/gen_stimulus.py
index 07bd1b1c..6a6be1d1 100755
--- a/compiler/gen_stimulus.py
+++ b/compiler/gen_stimulus.py
@@ -1,4 +1,11 @@
#!/usr/bin/env python
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
"""
This script will generate a stimulus file for a given period, load, and slew input
for the given dimension SRAM. It is useful for debugging after an SRAM has been
diff --git a/compiler/globals.py b/compiler/globals.py
index c1422592..e08e381f 100644
--- a/compiler/globals.py
+++ b/compiler/globals.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
"""
This is called globals.py, but it actually parses all the arguments and performs
the global OpenRAM setup as well.
@@ -12,9 +19,10 @@ import re
import copy
import importlib
-USAGE = "Usage: openram.py [options] \nUse -h for help.\n"
+VERSION = "1.1.0"
+NAME = "OpenRAM v{}".format(VERSION)
+USAGE = "openram.py [options] \nUse -h for help.\n"
-# Anonymous object that will be the options
OPTS = options.options()
CHECKPOINT_OPTS=None
@@ -50,9 +58,9 @@ def parse_args():
}
parser = optparse.OptionParser(option_list=option_list,
- description="Compile and/or characterize an SRAM.",
+ description=NAME,
usage=USAGE,
- version="OpenRAM")
+ version=VERSION)
(options, args) = parser.parse_args(values=OPTS)
# If we don't specify a tech, assume scmos.
@@ -72,17 +80,12 @@ def print_banner():
return
debug.print_raw("|==============================================================================|")
- name = "OpenRAM Compiler"
- debug.print_raw("|=========" + name.center(60) + "=========|")
+ debug.print_raw("|=========" + NAME.center(60) + "=========|")
debug.print_raw("|=========" + " ".center(60) + "=========|")
debug.print_raw("|=========" + "VLSI Design and Automation Lab".center(60) + "=========|")
debug.print_raw("|=========" + "Computer Science and Engineering Department".center(60) + "=========|")
debug.print_raw("|=========" + "University of California Santa Cruz".center(60) + "=========|")
debug.print_raw("|=========" + " ".center(60) + "=========|")
- debug.print_raw("|=========" + "VLSI Computer Architecture Research Group".center(60) + "=========|")
- debug.print_raw("|=========" + "Electrical and Computer Engineering Department".center(60) + "=========|")
- debug.print_raw("|=========" + "Oklahoma State University".center(60) + "=========|")
- debug.print_raw("|=========" + " ".center(60) + "=========|")
user_info = "Usage help: openram-user-group@ucsc.edu"
debug.print_raw("|=========" + user_info.center(60) + "=========|")
dev_info = "Development help: openram-dev-group@ucsc.edu"
@@ -128,6 +131,8 @@ def init_openram(config_file, is_unit_test=True):
import_tech()
+ set_default_corner()
+
init_paths()
from sram_factory import factory
@@ -135,10 +140,6 @@ def init_openram(config_file, is_unit_test=True):
setup_bitcell()
- # Reset the static duplicate name checker for unit tests.
- import hierarchy_design
- hierarchy_design.hierarchy_design.name_map=[]
-
global OPTS
global CHECKPOINT_OPTS
@@ -168,11 +169,12 @@ def setup_bitcell():
# If we have non-1rw ports,
# and the user didn't over-ride the bitcell manually,
# figure out the right bitcell to use
- if (OPTS.bitcell=="bitcell" and OPTS.replica_bitcell=="replica_bitcell"):
+ if (OPTS.bitcell=="bitcell"):
if (OPTS.num_rw_ports==1 and OPTS.num_w_ports==0 and OPTS.num_r_ports==0):
OPTS.bitcell = "bitcell"
OPTS.replica_bitcell = "replica_bitcell"
+ OPTS.dummy_bitcell = "dummy_bitcell"
else:
ports = ""
if OPTS.num_rw_ports>0:
@@ -184,20 +186,26 @@ def setup_bitcell():
OPTS.bitcell = "bitcell_"+ports
OPTS.replica_bitcell = "replica_bitcell_"+ports
-
- # See if a custom bitcell exists
- from importlib import find_loader
- bitcell_loader = find_loader(OPTS.bitcell)
- replica_bitcell_loader = find_loader(OPTS.replica_bitcell)
+ OPTS.dummy_bitcell = "dummy_bitcell_"+ports
+ else:
+ OPTS.replica_bitcell = "replica_" + OPTS.bitcell
+ OPTS.replica_bitcell = "dummy_" + OPTS.bitcell
+
+ # See if bitcell exists
+ from importlib import find_loader
+ try:
+ __import__(OPTS.bitcell)
+ __import__(OPTS.replica_bitcell)
+ __import__(OPTS.dummy_bitcell)
+ except ImportError:
# Use the pbitcell if we couldn't find a custom bitcell
# or its custom replica bitcell
- if bitcell_loader==None or replica_bitcell_loader==None:
- # Use the pbitcell (and give a warning if not in unit test mode)
- OPTS.bitcell = "pbitcell"
- OPTS.replica_bitcell = "replica_pbitcell"
- if not OPTS.is_unit_test:
- debug.warning("Using the parameterized bitcell which may have suboptimal density.")
-
+ # Use the pbitcell (and give a warning if not in unit test mode)
+ OPTS.bitcell = "pbitcell"
+ OPTS.replica_bitcell = "replica_pbitcell"
+ OPTS.replica_bitcell = "dummy_pbitcell"
+ if not OPTS.is_unit_test:
+ debug.warning("Using the parameterized bitcell which may have suboptimal density.")
debug.info(1,"Using bitcell: {}".format(OPTS.bitcell))
@@ -392,9 +400,20 @@ def init_paths():
except:
debug.error("Unable to make output directory.",-1)
+def set_default_corner():
+ """ Set the default corner. """
+
+ # Set some default options now based on the technology...
+ if (OPTS.process_corners == ""):
+ OPTS.process_corners = tech.spice["fet_models"].keys()
+ if (OPTS.supply_voltages == ""):
+ OPTS.supply_voltages = tech.spice["supply_voltages"]
+ if (OPTS.temperatures == ""):
+ OPTS.temperatures = tech.spice["temperatures"]
+
-# imports correct technology directories for testing
def import_tech():
+ """ Dynamically adds the tech directory to the path and imports it. """
global OPTS
debug.info(2,"Importing technology: " + OPTS.tech_name)
@@ -403,34 +422,30 @@ def import_tech():
try:
OPENRAM_TECH = os.path.abspath(os.environ.get("OPENRAM_TECH"))
except:
- debug.error("$OPENRAM_TECH is not properly defined.",1)
- debug.check(os.path.isdir(OPENRAM_TECH),"$OPENRAM_TECH does not exist: {0}".format(OPENRAM_TECH))
-
- OPTS.openram_tech = OPENRAM_TECH + "/" + OPTS.tech_name
- if not OPTS.openram_tech.endswith('/'):
- OPTS.openram_tech += "/"
- debug.info(1, "Technology path is " + OPTS.openram_tech)
+ debug.error("$OPENRAM_TECH environment variable is not defined.",1)
+ # Add all of the paths
+ for tech_path in OPENRAM_TECH.split(":"):
+ debug.check(os.path.isdir(tech_path),"$OPENRAM_TECH does not exist: {0}".format(tech_path))
+ sys.path.append(tech_path)
+ debug.info(1, "Adding technology path: {}".format(tech_path))
+
+ # Import the tech
try:
- filename = "setup_openram_{0}".format(OPTS.tech_name)
- # we assume that the setup scripts (and tech dirs) are located at the
- # same level as the compielr itself, probably not a good idea though.
- path = "{0}/setup_scripts".format(os.environ.get("OPENRAM_TECH"))
- debug.check(os.path.isdir(path),"OPENRAM_TECH does not exist: {0}".format(path))
- sys.path.append(os.path.abspath(path))
- __import__(filename)
+ tech_mod = __import__(OPTS.tech_name)
except ImportError:
- debug.error("Nonexistent technology_setup_file: {0}.py".format(filename))
- sys.exit(1)
+ debug.error("Nonexistent technology_setup_file: {0}.py".format(filename), -1)
- import tech
- # Set some default options now based on the technology...
- if (OPTS.process_corners == ""):
- OPTS.process_corners = tech.spice["fet_models"].keys()
- if (OPTS.supply_voltages == ""):
- OPTS.supply_voltages = tech.spice["supply_voltages"]
- if (OPTS.temperatures == ""):
- OPTS.temperatures = tech.spice["temperatures"]
+ OPTS.openram_tech = os.path.dirname(tech_mod.__file__) + "/"
+
+
+ # Add the tech directory
+ tech_path = OPTS.openram_tech
+ sys.path.append(tech_path)
+ try:
+ import tech
+ except ImportError:
+ debug.error("Could not load tech module.", -1)
def print_time(name, now_time, last_time=None, indentation=2):
@@ -455,6 +470,20 @@ def report_status():
debug.error("{0} is not an integer in config file.".format(OPTS.word_size))
if type(OPTS.num_words)!=int:
debug.error("{0} is not an integer in config file.".format(OPTS.sram_size))
+ if type(OPTS.write_size) is not int and OPTS.write_size is not None:
+ debug.error("{0} is not an integer in config file.".format(OPTS.write_size))
+
+ # If a write mask is specified by the user, the mask write size should be the same as
+ # the word size so that an entire word is written at once.
+ if OPTS.write_size is not None:
+ if (OPTS.word_size % OPTS.write_size != 0):
+ debug.error("Write size needs to be an integer multiple of word size.")
+ # If write size is more than half of the word size, then it doesn't need a write mask. It would be writing
+ # the whole word.
+ if (OPTS.write_size < 1 or OPTS.write_size > OPTS.word_size/2):
+ debug.error("Write size needs to be between 1 bit and {0} bits/2.".format(OPTS.word_size))
+
+
if not OPTS.tech_name:
debug.error("Tech name must be specified in config file.")
@@ -468,15 +497,30 @@ def report_status():
debug.print_raw("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size,
OPTS.num_words,
OPTS.num_banks))
+ if (OPTS.write_size != OPTS.word_size):
+ debug.print_raw("Write size: {}".format(OPTS.write_size))
debug.print_raw("RW ports: {0}\nR-only ports: {1}\nW-only ports: {2}".format(OPTS.num_rw_ports,
OPTS.num_r_ports,
OPTS.num_w_ports))
+
if OPTS.netlist_only:
- debug.print_raw("Netlist only mode (no physical design is being done).")
+ debug.print_raw("Netlist only mode (no physical design is being done, netlist_only=False to disable).")
+ if not OPTS.route_supplies:
+ debug.print_raw("Design supply routing skipped. Supplies will have multiple must-connect pins. (route_supplies=True to enable supply routing).")
+
if not OPTS.inline_lvsdrc:
- debug.print_raw("DRC/LVS/PEX is only run on the top-level design.")
+ debug.print_raw("DRC/LVS/PEX is only run on the top-level design to save run-time (inline_lvsdrc=True to do inline checking).")
if not OPTS.check_lvsdrc:
- debug.print_raw("DRC/LVS/PEX is completely disabled.")
+ debug.print_raw("DRC/LVS/PEX is disabled (check_lvsdrc=True to enable).")
+
+ if OPTS.analytical_delay:
+ debug.print_raw("Characterization is disabled (using analytical delay models) (analytical_delay=False to simulate).")
+ else:
+ if OPTS.spice_name!="":
+ debug.print_raw("Performing simulation-based characterization with {}".format(OPTS.spice_name))
+ if OPTS.trim_netlist:
+ debug.print_raw("Trimming netlist to speed up characterization (trim_netlist=False to disable).")
+
diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py
index 7eddc3bb..3e105d09 100644
--- a/compiler/modules/bank.py
+++ b/compiler/modules/bank.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import sys
from tech import drc, parameter
import debug
@@ -21,13 +28,19 @@ class bank(design.design):
def __init__(self, sram_config, name=""):
+ self.sram_config = sram_config
sram_config.set_local_config(self)
+ if self.write_size:
+ self.num_wmasks = int(self.word_size/self.write_size)
+ else:
+ self.num_wmasks = 0
if name == "":
name = "bank_{0}_{1}".format(self.word_size, self.num_words)
design.design.__init__(self, name)
debug.info(2, "create sram of size {0} with {1} words".format(self.word_size,self.num_words))
+
# The local control signals are gated when we have bank select logic,
# so this prefix will be added to all of the input signals to create
# the internal gated signals.
@@ -40,12 +53,13 @@ class bank(design.design):
if not OPTS.netlist_only:
debug.check(len(self.all_ports)<=2,"Bank layout cannot handle more than two ports.")
self.create_layout()
+ self.add_boundary()
def create_netlist(self):
self.compute_sizes()
- self.add_pins()
self.add_modules()
+ self.add_pins() # Must create the replica bitcell array first
self.create_instances()
@@ -60,17 +74,21 @@ class bank(design.design):
# Remember the bank center for further placement
self.bank_array_ll = self.offset_all_coordinates().scale(-1,-1)
self.bank_array_ur = self.bitcell_array_inst.ur()
-
+ self.bank_array_ul = self.bitcell_array_inst.ul()
+
+
self.DRC_LVS()
def add_pins(self):
""" Adding pins for Bank module"""
for port in self.read_ports:
for bit in range(self.word_size):
- self.add_pin("dout{0}_{1}".format(port,bit),"OUT")
+ self.add_pin("dout{0}_{1}".format(port,bit),"OUTPUT")
+ for port in self.all_ports:
+ self.add_pin(self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]),"OUTPUT")
for port in self.write_ports:
for bit in range(self.word_size):
- self.add_pin("din{0}_{1}".format(port,bit),"IN")
+ self.add_pin("din{0}_{1}".format(port,bit),"INPUT")
for port in self.all_ports:
for bit in range(self.addr_size):
self.add_pin("addr{0}_{1}".format(port,bit),"INPUT")
@@ -82,10 +100,12 @@ class bank(design.design):
self.add_pin("bank_sel{}".format(port),"INPUT")
for port in self.read_ports:
self.add_pin("s_en{0}".format(port), "INPUT")
- for port in self.read_ports:
+ for port in self.all_ports:
self.add_pin("p_en_bar{0}".format(port), "INPUT")
for port in self.write_ports:
self.add_pin("w_en{0}".format(port), "INPUT")
+ for bit in range(self.num_wmasks):
+ self.add_pin("bank_wmask{0}_{1}".format(port,bit),"INPUT")
for port in self.all_ports:
self.add_pin("wl_en{0}".format(port), "INPUT")
self.add_pin("vdd","POWER")
@@ -98,52 +118,45 @@ class bank(design.design):
for port in self.all_ports:
self.route_bitlines(port)
- self.route_wordline_driver(port)
- self.route_row_decoder(port)
+ self.route_rbl(port)
+ self.route_port_address(port)
self.route_column_address_lines(port)
self.route_control_lines(port)
if self.num_banks > 1:
- self.route_bank_select(port)
+ self.route_bank_select(port)
self.route_supplies()
+ def route_rbl(self,port):
+ """ Route the rbl_bl and rbl_wl """
+
+ bl_pin_name = self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port])
+ bl_pin = self.bitcell_array_inst.get_pin(bl_pin_name)
+ self.add_layout_pin(text="rbl_bl{0}".format(port),
+ layer=bl_pin.layer,
+ offset=bl_pin.ll(),
+ height=bl_pin.height(),
+ width=bl_pin.width())
+
+
+
def route_bitlines(self, port):
""" Route the bitlines depending on the port type rw, w, or r. """
+
+ if port in self.write_ports:
+ self.route_port_data_in(port)
+ if port in self.read_ports:
+ self.route_port_data_out(port)
+ self.route_port_data_to_bitcell_array(port)
- if port in self.readwrite_ports:
- # write_driver -> sense_amp -> (column_mux) -> precharge -> bitcell_array
- self.route_write_driver_in(port)
- self.route_sense_amp_out(port)
- self.route_write_driver_to_sense_amp(port)
- self.route_sense_amp_to_column_mux_or_precharge_array(port)
- self.route_column_mux_to_precharge_array(port)
- self.route_precharge_to_bitcell_array(port)
- elif port in self.read_ports:
- # sense_amp -> (column_mux) -> precharge -> bitcell_array
- self.route_sense_amp_out(port)
- self.route_sense_amp_to_column_mux_or_precharge_array(port)
- self.route_column_mux_to_precharge_array(port)
- self.route_precharge_to_bitcell_array(port)
- else:
- # write_driver -> (column_mux) -> bitcell_array
- self.route_write_driver_in(port)
- self.route_write_driver_to_column_mux_or_bitcell_array(port)
- self.route_column_mux_to_bitcell_array(port)
def create_instances(self):
""" Create the instances of the netlist. """
self.create_bitcell_array()
-
- self.create_precharge_array()
- self.create_column_mux_array()
- self.create_sense_amp_array()
- self.create_write_driver_array()
-
- self.create_row_decoder()
- self.create_wordline_driver()
+ self.create_port_data()
+ self.create_port_address()
self.create_column_decoder()
-
self.create_bank_select()
def compute_instance_offsets(self):
@@ -151,39 +164,26 @@ class bank(design.design):
Compute the empty instance offsets for port0 and port1 (if needed)
"""
- # These are created even if the port type (e.g. read only)
- # doesn't need the instance (e.g. write driver).
-
- # Create the bottom-up and left to right order of components in each port
- # which deepends on the port type rw, w, r
- self.vertical_port_order = []
- self.vertical_port_offsets = []
- for port in self.all_ports:
- self.vertical_port_order.append([])
- self.vertical_port_offsets.append([None]*4)
-
- # For later placement, these are fixed in the order: write driver,
- # sense amp, clumn mux, precharge, even if the item is not used
- # in a given port (it will be None then)
- self.vertical_port_order[port].append(self.write_driver_array_inst[port])
- self.vertical_port_order[port].append(self.sense_amp_array_inst[port])
- self.vertical_port_order[port].append(self.column_mux_array_inst[port])
- self.vertical_port_order[port].append(self.precharge_array_inst[port])
-
- # For the odd ones they will go on top, so reverse in place
- if port%2:
- self.vertical_port_order[port]=self.vertical_port_order[port][::-1]
-
- self.write_driver_offsets = [None]*len(self.all_ports)
- self.sense_amp_offsets = [None]*len(self.all_ports)
- self.column_mux_offsets = [None]*len(self.all_ports)
- self.precharge_offsets = [None]*len(self.all_ports)
-
- self.wordline_driver_offsets = [None]*len(self.all_ports)
- self.row_decoder_offsets = [None]*len(self.all_ports)
+ self.port_data_offsets = [None]*len(self.all_ports)
+ self.port_address_offsets = [None]*len(self.all_ports)
self.column_decoder_offsets = [None]*len(self.all_ports)
self.bank_select_offsets = [None]*len(self.all_ports)
+
+
+ # The center point for these cells are the upper-right corner of
+ # the bitcell array.
+ # The port address decoder/driver logic is placed on the right and mirrored on Y-axis.
+ # The port data write/sense/precharge/mux is placed on the top and mirrored on the X-axis.
+ self.bitcell_array_top = self.bitcell_array.height
+ self.bitcell_array_right = self.bitcell_array.width
+
+ # These are the offsets of the main array (excluding dummy and replica rows/cols)
+ self.main_bitcell_array_top = self.bitcell_array.bitcell_array_inst.uy()
+ # Just past the dummy column
+ self.main_bitcell_array_left = self.bitcell_array.bitcell_array_inst.lx()
+ # Just past the dummy row and replica row
+ self.main_bitcell_array_bottom = self.bitcell_array.bitcell_array_inst.by()
self.compute_instance_port0_offsets()
if len(self.all_ports)==2:
@@ -192,7 +192,7 @@ class bank(design.design):
def compute_instance_port0_offsets(self):
"""
- Compute the instance offsets for port0.
+ Compute the instance offsets for port0 on the left/bottom of the bank.
"""
port = 0
@@ -203,110 +203,71 @@ class bank(design.design):
# LOWER RIGHT QUADRANT
# Below the bitcell array
- y_height = 0
- for p in self.vertical_port_order[port]:
- if p==None:
- continue
- y_height += p.height + self.m2_gap
-
- y_offset = -y_height
- for i,p in enumerate(self.vertical_port_order[port]):
- if p==None:
- continue
- self.vertical_port_offsets[port][i]=vector(0,y_offset)
- y_offset += (p.height + self.m2_gap)
-
- self.write_driver_offsets[port] = self.vertical_port_offsets[port][0]
- self.sense_amp_offsets[port] = self.vertical_port_offsets[port][1]
- self.column_mux_offsets[port] = self.vertical_port_offsets[port][2]
- self.precharge_offsets[port] = self.vertical_port_offsets[port][3]
+ self.port_data_offsets[port] = vector(self.main_bitcell_array_left - self.bitcell_array.cell.width,0)
# UPPER LEFT QUADRANT
# To the left of the bitcell array
- # The wordline driver is placed to the right of the main decoder width.
- x_offset = self.m2_gap + self.wordline_driver.width
- self.wordline_driver_offsets[port] = vector(-x_offset,0)
- x_offset += self.row_decoder.width + self.m2_gap
- self.row_decoder_offsets[port] = vector(-x_offset,0)
+ x_offset = self.m2_gap + self.port_address.width
+ self.port_address_offsets[port] = vector(-x_offset,self.main_bitcell_array_bottom)
# LOWER LEFT QUADRANT
- # Place the col decoder left aligned with wordline driver plus halfway under row decoder
- # Place the col decoder left aligned with row decoder (x_offset doesn't change)
- # Below the bitcell array with well spacing
- x_offset = self.central_bus_width[port] + self.wordline_driver.width
+ # Place the col decoder left aligned with wordline driver
+ # This is also placed so that it's supply rails do not align with the SRAM-level
+ # control logic to allow control signals to easily pass over in M3
+ # by placing 1/2 a cell pitch down
+ x_offset = self.central_bus_width[port] + self.port_address.wordline_driver.width
if self.col_addr_size > 0:
x_offset += self.column_decoder.width + self.col_addr_bus_width
- y_offset = self.m2_gap + self.column_decoder.height
+ y_offset = 0.5*self.dff.height + self.column_decoder.height
else:
y_offset = 0
- y_offset += 2*drc("well_to_well")
self.column_decoder_offsets[port] = vector(-x_offset,-y_offset)
# Bank select gets placed below the column decoder (x_offset doesn't change)
if self.col_addr_size > 0:
- y_offset = min(self.column_decoder_offsets[port].y, self.column_mux_offsets[port].y)
+ y_offset = min(self.column_decoder_offsets[port].y, self.port_data[port].column_mux_offset.y)
else:
- y_offset = self.row_decoder_offsets[port].y
+ y_offset = self.port_address_offsets[port].y
if self.num_banks > 1:
y_offset += self.bank_select.height + drc("well_to_well")
self.bank_select_offsets[port] = vector(-x_offset,-y_offset)
def compute_instance_port1_offsets(self):
"""
- Compute the instance offsets for port1 on the top of the bank.
+ Compute the instance offsets for port1 on the right/top of the bank.
"""
port=1
- # The center point for these cells are the upper-right corner of
- # the bitcell array.
- # The decoder/driver logic is placed on the right and mirrored on Y-axis.
- # The write/sense/precharge/mux is placed on the top and mirrored on the X-axis.
-
# LOWER LEFT QUADRANT
# Bitcell array is placed at (0,0)
# UPPER LEFT QUADRANT
# Above the bitcell array
- y_offset = self.bitcell_array.height + self.m2_gap
- for i,p in enumerate(self.vertical_port_order[port]):
- if p==None:
- continue
- y_offset += (p.height + self.m2_gap)
- self.vertical_port_offsets[port][i]=vector(0,y_offset)
-
- # Reversed order
- self.write_driver_offsets[port] = self.vertical_port_offsets[port][3]
- self.sense_amp_offsets[port] = self.vertical_port_offsets[port][2]
- self.column_mux_offsets[port] = self.vertical_port_offsets[port][1]
- self.precharge_offsets[port] = self.vertical_port_offsets[port][0]
+ self.port_data_offsets[port] = vector(self.main_bitcell_array_left, self.bitcell_array_top)
# LOWER RIGHT QUADRANT
# To the left of the bitcell array
- # The wordline driver is placed to the right of the main decoder width.
- x_offset = self.bitcell_array.width + self.m2_gap + self.wordline_driver.width
- self.wordline_driver_offsets[port] = vector(x_offset,0)
- x_offset += self.row_decoder.width + self.m2_gap
- self.row_decoder_offsets[port] = vector(x_offset,0)
+ x_offset = self.bitcell_array_right + self.port_address.width + self.m2_gap
+ self.port_address_offsets[port] = vector(x_offset,self.main_bitcell_array_bottom)
# UPPER RIGHT QUADRANT
- # Place the col decoder right aligned with wordline driver plus halfway under row decoder
+ # Place the col decoder right aligned with wordline driver
# Above the bitcell array with a well spacing
- x_offset = self.bitcell_array.width + self.central_bus_width[port] + self.wordline_driver.width
+ x_offset = self.bitcell_array_right + self.central_bus_width[port] + self.port_address.wordline_driver.width
if self.col_addr_size > 0:
x_offset += self.column_decoder.width + self.col_addr_bus_width
- y_offset = self.bitcell_array.height + self.column_decoder.height + self.m2_gap
+ y_offset = self.bitcell_array_top + 0.5*self.dff.height + self.column_decoder.height
else:
- y_offset = self.bitcell_array.height
- y_offset += 2*drc("well_to_well")
+ y_offset = self.bitcell_array_top
self.column_decoder_offsets[port] = vector(x_offset,y_offset)
# Bank select gets placed above the column decoder (x_offset doesn't change)
if self.col_addr_size > 0:
y_offset = max(self.column_decoder_offsets[port].y + self.column_decoder.height,
- self.column_mux_offsets[port].y + self.column_mux_array[port].height)
+ self.port_data[port].column_mux_offset.y + self.port_data[port].column_mux_array.height)
else:
- y_offset = self.row_decoder_offsets[port].y
+ y_offset = self.port_address_offsets[port].y
self.bank_select_offsets[port] = vector(x_offset,y_offset)
def place_instances(self):
@@ -314,22 +275,12 @@ class bank(design.design):
self.compute_instance_offsets()
- # UPPER RIGHT QUADRANT
self.place_bitcell_array(self.bitcell_array_offset)
- # LOWER RIGHT QUADRANT
- # These are fixed in the order: write driver, sense amp, clumn mux, precharge,
- # even if the item is not used in a given port (it will be None then)
- self.place_write_driver_array(self.write_driver_offsets)
- self.place_sense_amp_array(self.sense_amp_offsets)
- self.place_column_mux_array(self.column_mux_offsets)
- self.place_precharge_array(self.precharge_offsets)
+ self.place_port_data(self.port_data_offsets)
- # UPPER LEFT QUADRANT
- self.place_row_decoder(self.row_decoder_offsets)
- self.place_wordline_driver(self.wordline_driver_offsets)
+ self.place_port_address(self.port_address_offsets)
- # LOWER LEFT QUADRANT
self.place_column_decoder(self.column_decoder_offsets)
self.place_bank_select(self.bank_select_offsets)
@@ -347,22 +298,17 @@ class bank(design.design):
debug.check(self.num_rows*self.num_cols==self.word_size*self.num_words,"Invalid bank sizes.")
debug.check(self.addr_size==self.col_addr_size + self.row_addr_size,"Invalid address break down.")
- # Width for the vdd/gnd rails
- self.supply_rail_width = 4*self.m2_width
- # FIXME: This spacing should be width dependent...
- self.supply_rail_pitch = self.supply_rail_width + 4*self.m2_space
-
# The order of the control signals on the control bus:
self.input_control_signals = []
port_num = 0
for port in range(OPTS.num_rw_ports):
- self.input_control_signals.append(["wl_en{}".format(port_num), "w_en{}".format(port_num), "s_en{}".format(port_num), "p_en_bar{}".format(port_num)])
+ self.input_control_signals.append(["w_en{}".format(port_num), "s_en{}".format(port_num), "p_en_bar{}".format(port_num), "wl_en{}".format(port_num)])
port_num += 1
for port in range(OPTS.num_w_ports):
- self.input_control_signals.append(["wl_en{}".format(port_num), "w_en{}".format(port_num)])
+ self.input_control_signals.append(["w_en{}".format(port_num), "p_en_bar{}".format(port_num), "wl_en{}".format(port_num)])
port_num += 1
for port in range(OPTS.num_r_ports):
- self.input_control_signals.append(["wl_en{}".format(port_num), "s_en{}".format(port_num), "p_en_bar{}".format(port_num)])
+ self.input_control_signals.append(["s_en{}".format(port_num), "p_en_bar{}".format(port_num), "wl_en{}".format(port_num)])
port_num += 1
# Number of control lines in the bus for each port
@@ -394,65 +340,40 @@ class bank(design.design):
def add_modules(self):
""" Add all the modules using the class loader """
-
- self.bitcell_array = factory.create(module_type="bitcell_array",
- cols=self.num_cols,
- rows=self.num_rows)
- self.add_mod(self.bitcell_array)
-
# create arrays of bitline and bitline_bar names for read, write, or all ports
self.bitcell = factory.create(module_type="bitcell")
- self.bl_names = self.bitcell.list_all_bl_names()
- self.br_names = self.bitcell.list_all_br_names()
- self.wl_names = self.bitcell.list_all_wl_names()
- self.bitline_names = self.bitcell.list_all_bitline_names()
+ self.bl_names = self.bitcell.get_all_bl_names()
+ self.br_names = self.bitcell.get_all_br_names()
+ self.wl_names = self.bitcell.get_all_wl_names()
+ self.bitline_names = self.bitcell.get_all_bitline_names()
- self.precharge_array = []
+ self.port_data = []
for port in self.all_ports:
- if port in self.read_ports:
- temp_pre = factory.create(module_type="precharge_array",
- columns=self.num_cols,
- bitcell_bl=self.bl_names[port],
- bitcell_br=self.br_names[port])
- self.precharge_array.append(temp_pre)
- self.add_mod(self.precharge_array[port])
- else:
- self.precharge_array.append(None)
-
- if self.col_addr_size > 0:
- self.column_mux_array = []
- for port in self.all_ports:
- temp_col = factory.create(module_type="column_mux_array",
- columns=self.num_cols,
- word_size=self.word_size,
- bitcell_bl=self.bl_names[port],
- bitcell_br=self.br_names[port])
- self.column_mux_array.append(temp_col)
- self.add_mod(self.column_mux_array[port])
+ temp_pre = factory.create(module_type="port_data",
+ sram_config=self.sram_config,
+ port=port)
+ self.port_data.append(temp_pre)
+ self.add_mod(self.port_data[port])
- self.sense_amp_array = factory.create(module_type="sense_amp_array",
- word_size=self.word_size,
- words_per_row=self.words_per_row)
- self.add_mod(self.sense_amp_array)
+ self.port_address = factory.create(module_type="port_address",
+ cols=self.num_cols,
+ rows=self.num_rows)
+ self.add_mod(self.port_address)
- self.write_driver_array = factory.create(module_type="write_driver_array",
- columns=self.num_cols,
- word_size=self.word_size)
- self.add_mod(self.write_driver_array)
- self.row_decoder = factory.create(module_type="decoder",
- rows=self.num_rows)
- self.add_mod(self.row_decoder)
+ self.port_rbl_map = self.all_ports
+ self.num_rbl = len(self.all_ports)
+
+ self.bitcell_array = factory.create(module_type="replica_bitcell_array",
+ cols=self.num_cols,
+ rows=self.num_rows,
+ left_rbl=1,
+ right_rbl=1 if len(self.all_ports)>1 else 0,
+ bitcell_ports=self.all_ports)
+ self.add_mod(self.bitcell_array)
+
- self.wordline_driver = factory.create(module_type="wordline_driver",
- rows=self.num_rows,
- cols=self.num_cols)
- self.add_mod(self.wordline_driver)
-
- self.inv = factory.create(module_type="pinv")
- self.add_mod(self.inv)
-
if(self.num_banks > 1):
self.bank_select = factory.create(module_type="bank_select")
self.add_mod(self.bank_select)
@@ -461,17 +382,23 @@ class bank(design.design):
def create_bitcell_array(self):
""" Creating Bitcell Array """
- self.bitcell_array_inst=self.add_inst(name="bitcell_array",
+ self.bitcell_array_inst=self.add_inst(name="replica_bitcell_array",
mod=self.bitcell_array)
-
temp = []
for col in range(self.num_cols):
for bitline in self.bitline_names:
- temp.append(bitline+"_{0}".format(col))
+ temp.append("{0}_{1}".format(bitline,col))
+ for rbl in range(self.num_rbl):
+ rbl_bl_name=self.bitcell_array.get_rbl_bl_name(rbl)
+ temp.append(rbl_bl_name)
+ rbl_br_name=self.bitcell_array.get_rbl_br_name(rbl)
+ temp.append(rbl_br_name)
for row in range(self.num_rows):
for wordline in self.wl_names:
- temp.append(wordline+"_{0}".format(row))
+ temp.append("{0}_{1}".format(wordline,row))
+ for port in self.all_ports:
+ temp.append("wl_en{0}".format(port))
temp.append("vdd")
temp.append("gnd")
self.connect_inst(temp)
@@ -482,161 +409,73 @@ class bank(design.design):
self.bitcell_array_inst.place(offset)
- def create_precharge_array(self):
- """ Creating Precharge """
-
- self.precharge_array_inst = [None]*len(self.all_ports)
- for port in self.read_ports:
- self.precharge_array_inst[port]=self.add_inst(name="precharge_array{}".format(port),
- mod=self.precharge_array[port])
- temp = []
- for i in range(self.num_cols):
- temp.append(self.bl_names[port]+"_{0}".format(i))
- temp.append(self.br_names[port]+"_{0}".format(i))
- temp.extend([self.prefix+"p_en_bar{0}".format(port), "vdd"])
- self.connect_inst(temp)
-
-
- def place_precharge_array(self, offsets):
- """ Placing Precharge """
-
- debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place precharge array.")
-
- for port in self.read_ports:
- if port%2 == 1:
- mirror = "MX"
- else:
- mirror = "R0"
- self.precharge_array_inst[port].place(offset=offsets[port], mirror=mirror)
-
-
- def create_column_mux_array(self):
- """ Creating Column Mux when words_per_row > 1 . """
- self.column_mux_array_inst = [None]*len(self.all_ports)
-
- if self.col_addr_size == 0:
- return
+ def create_port_data(self):
+ """ Creating Port Data """
+ self.port_data_inst = [None]*len(self.all_ports)
for port in self.all_ports:
- self.column_mux_array_inst[port] = self.add_inst(name="column_mux_array{}".format(port),
- mod=self.column_mux_array[port])
+ self.port_data_inst[port]=self.add_inst(name="port_data{}".format(port),
+ mod=self.port_data[port])
temp = []
- for col in range(self.num_cols):
- temp.append(self.bl_names[port]+"_{0}".format(col))
- temp.append(self.br_names[port]+"_{0}".format(col))
- for word in range(self.words_per_row):
- temp.append("sel{0}_{1}".format(port,word))
- for bit in range(self.word_size):
- temp.append(self.bl_names[port]+"_out_{0}".format(bit))
- temp.append(self.br_names[port]+"_out_{0}".format(bit))
- temp.append("gnd")
+ rbl_bl_name=self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port])
+ rbl_br_name=self.bitcell_array.get_rbl_br_name(self.port_rbl_map[port])
+ temp.append(rbl_bl_name)
+ temp.append(rbl_br_name)
+ for col in range(self.num_cols):
+ temp.append("{0}_{1}".format(self.bl_names[port],col))
+ temp.append("{0}_{1}".format(self.br_names[port],col))
+ if port in self.read_ports:
+ for bit in range(self.word_size):
+ temp.append("dout{0}_{1}".format(port,bit))
+ if port in self.write_ports:
+ for bit in range(self.word_size):
+ temp.append("din{0}_{1}".format(port,bit))
+ # Will be empty if no col addr lines
+ sel_names = ["sel{0}_{1}".format(port,x) for x in range(self.num_col_addr_lines)]
+ temp.extend(sel_names)
+ if port in self.read_ports:
+ temp.append("s_en{0}".format(port))
+ temp.append("p_en_bar{0}".format(port))
+ if port in self.write_ports:
+ temp.append("w_en{0}".format(port))
+ for bit in range(self.num_wmasks):
+ temp.append("bank_wmask{0}_{1}".format(port, bit))
+ temp.extend(["vdd","gnd"])
+
self.connect_inst(temp)
-
- def place_column_mux_array(self, offsets):
- """ Placing Column Mux when words_per_row > 1 . """
- if self.col_addr_size == 0:
- return
-
- debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place column mux array.")
+ def place_port_data(self, offsets):
+ """ Placing Port Data """
for port in self.all_ports:
+ # Top one is unflipped, bottom is flipped along X direction
if port%2 == 1:
- mirror = "MX"
- else:
mirror = "R0"
- self.column_mux_array_inst[port].place(offset=offsets[port], mirror=mirror)
-
-
- def create_sense_amp_array(self):
- """ Creating Sense amp """
-
- self.sense_amp_array_inst = [None]*len(self.all_ports)
- for port in self.read_ports:
- self.sense_amp_array_inst[port] = self.add_inst(name="sense_amp_array{}".format(port),
- mod=self.sense_amp_array)
-
- temp = []
- for bit in range(self.word_size):
- temp.append("dout{0}_{1}".format(port,bit))
- if self.words_per_row == 1:
- temp.append(self.bl_names[port]+"_{0}".format(bit))
- temp.append(self.br_names[port]+"_{0}".format(bit))
- else:
- temp.append(self.bl_names[port]+"_out_{0}".format(bit))
- temp.append(self.br_names[port]+"_out_{0}".format(bit))
-
- temp.extend([self.prefix+"s_en{}".format(port), "vdd", "gnd"])
- self.connect_inst(temp)
-
-
- def place_sense_amp_array(self, offsets):
- """ Placing Sense amp """
-
- debug.check(len(offsets)>=len(self.read_ports), "Insufficient offsets to place sense amp array.")
- for port in self.read_ports:
- if port%2 == 1:
- mirror = "MX"
else:
- mirror = "R0"
- self.sense_amp_array_inst[port].place(offset=offsets[port], mirror=mirror)
-
-
- def create_write_driver_array(self):
- """ Creating Write Driver """
-
- self.write_driver_array_inst = [None]*len(self.all_ports)
- for port in self.write_ports:
- self.write_driver_array_inst[port] = self.add_inst(name="write_driver_array{}".format(port),
- mod=self.write_driver_array)
-
- temp = []
- for bit in range(self.word_size):
- temp.append("din{0}_{1}".format(port,bit))
- for bit in range(self.word_size):
- if (self.words_per_row == 1):
- temp.append(self.bl_names[port]+"_{0}".format(bit))
- temp.append(self.br_names[port]+"_{0}".format(bit))
- else:
- temp.append(self.bl_names[port]+"_out_{0}".format(bit))
- temp.append(self.br_names[port]+"_out_{0}".format(bit))
- temp.extend([self.prefix+"w_en{0}".format(port), "vdd", "gnd"])
- self.connect_inst(temp)
-
-
- def place_write_driver_array(self, offsets):
- """ Placing Write Driver """
-
- debug.check(len(offsets)>=len(self.write_ports), "Insufficient offsets to place write driver array.")
-
- for port in self.write_ports:
- if port%2 == 1:
mirror = "MX"
- else:
- mirror = "R0"
- self.write_driver_array_inst[port].place(offset=offsets[port], mirror=mirror)
-
+ self.port_data_inst[port].place(offset=offsets[port], mirror=mirror)
- def create_row_decoder(self):
+ def create_port_address(self):
""" Create the hierarchical row decoder """
- self.row_decoder_inst = [None]*len(self.all_ports)
+ self.port_address_inst = [None]*len(self.all_ports)
for port in self.all_ports:
- self.row_decoder_inst[port] = self.add_inst(name="row_decoder{}".format(port),
- mod=self.row_decoder)
+ self.port_address_inst[port] = self.add_inst(name="port_address{}".format(port),
+ mod=self.port_address)
temp = []
for bit in range(self.row_addr_size):
temp.append("addr{0}_{1}".format(port,bit+self.col_addr_size))
+ temp.append("wl_en{0}".format(port))
for row in range(self.num_rows):
- temp.append("dec_out{0}_{1}".format(port,row))
+ temp.append("{0}_{1}".format(self.wl_names[port],row))
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
- def place_row_decoder(self, offsets):
+ def place_port_address(self, offsets):
""" Place the hierarchical row decoder """
debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place row decoder array.")
@@ -648,43 +487,11 @@ class bank(design.design):
# The address flop and decoder are aligned in the x coord.
for port in self.all_ports:
- if port%2 == 1:
+ if port%2:
mirror = "MY"
else:
mirror = "R0"
- self.row_decoder_inst[port].place(offset=offsets[port], mirror=mirror)
-
-
- def create_wordline_driver(self):
- """ Create the Wordline Driver """
-
- self.wordline_driver_inst = [None]*len(self.all_ports)
- for port in self.all_ports:
- self.wordline_driver_inst[port] = self.add_inst(name="wordline_driver{}".format(port),
- mod=self.wordline_driver)
-
- temp = []
- for row in range(self.num_rows):
- temp.append("dec_out{0}_{1}".format(port,row))
- for row in range(self.num_rows):
- temp.append(self.wl_names[port]+"_{0}".format(row))
- temp.append(self.prefix+"wl_en{0}".format(port))
- temp.append("vdd")
- temp.append("gnd")
- self.connect_inst(temp)
-
-
- def place_wordline_driver(self, offsets):
- """ Place the Wordline Driver """
-
- debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place wordline driver array.")
-
- for port in self.all_ports:
- if port%2 == 1:
- mirror = "MY"
- else:
- mirror = "R0"
- self.wordline_driver_inst[port].place(offset=offsets[port], mirror=mirror)
+ self.port_address_inst[port].place(offset=offsets[port], mirror=mirror)
def create_column_decoder(self):
@@ -692,16 +499,16 @@ class bank(design.design):
Create a 2:4 or 3:8 column address decoder.
"""
- dff = factory.create(module_type="dff")
+ self.dff = factory.create(module_type="dff")
if self.col_addr_size == 0:
return
elif self.col_addr_size == 1:
- self.column_decoder = factory.create(module_type="pinvbuf", height=dff.height)
+ self.column_decoder = factory.create(module_type="pinvbuf", height=self.dff.height)
elif self.col_addr_size == 2:
- self.column_decoder = factory.create(module_type="hierarchical_predecode2x4", height=dff.height)
+ self.column_decoder = factory.create(module_type="hierarchical_predecode2x4", height=self.dff.height)
elif self.col_addr_size == 3:
- self.column_decoder = factory.create(module_type="hierarchical_predecode3x8", height=dff.height)
+ self.column_decoder = factory.create(module_type="hierarchical_predecode3x8", height=self.dff.height)
else:
# No error checking before?
debug.error("Invalid column decoder?",-1)
@@ -783,8 +590,8 @@ class bank(design.design):
bank_sel_signals = ["clk_buf", "w_en", "s_en", "p_en_bar", "bank_sel"]
gated_bank_sel_signals = ["gated_clk_buf", "gated_w_en", "gated_s_en", "gated_p_en_bar"]
elif self.port_id[port] == "w":
- bank_sel_signals = ["clk_buf", "w_en", "bank_sel"]
- gated_bank_sel_signals = ["gated_clk_buf", "gated_w_en"]
+ bank_sel_signals = ["clk_buf", "w_en", "p_en_bar", "bank_sel"]
+ gated_bank_sel_signals = ["gated_clk_buf", "gated_w_en", "gated_p_en_bar"]
else:
bank_sel_signals = ["clk_buf", "s_en", "p_en_bar", "bank_sel"]
gated_bank_sel_signals = ["gated_clk_buf", "gated_s_en", "gated_p_en_bar"]
@@ -800,14 +607,11 @@ class bank(design.design):
bus_pos = vector(self.bus_xoffset[port][name].x, out_pos.y)
self.add_path("metal3",[out_pos, bus_pos])
self.add_via_center(layers=("metal2", "via2", "metal3"),
- offset=bus_pos,
- rotate=90)
+ offset=bus_pos)
self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=out_pos,
- rotate=90)
+ offset=out_pos)
self.add_via_center(layers=("metal2", "via2", "metal3"),
- offset=out_pos,
- rotate=90)
+ offset=out_pos)
def setup_routing_constraints(self):
@@ -841,9 +645,9 @@ class bank(design.design):
# Port 0
# The bank is at (0,0), so this is to the left of the y-axis.
# 2 pitches on the right for vias/jogs to access the inputs
- control_bus_offset = vector(-self.m2_pitch * self.num_control_lines[0] - self.m2_width, self.min_y_offset)
+ control_bus_offset = vector(-self.m2_pitch * self.num_control_lines[0] - self.m2_pitch, self.min_y_offset)
# The control bus is routed up to two pitches below the bitcell array
- control_bus_length = -2*self.m1_pitch - self.min_y_offset
+ control_bus_length = self.main_bitcell_array_bottom - self.min_y_offset - 2*self.m1_pitch
self.bus_xoffset[0] = self.create_bus(layer="metal2",
pitch=self.m2_pitch,
offset=control_bus_offset,
@@ -855,122 +659,52 @@ class bank(design.design):
# Port 1
if len(self.all_ports)==2:
# The other control bus is routed up to two pitches above the bitcell array
- control_bus_length = self.max_y_offset - self.bitcell_array.height - 2*self.m1_pitch
- control_bus_offset = vector(self.bitcell_array.width + self.m2_width,
+ control_bus_length = self.max_y_offset - self.main_bitcell_array_top - 2*self.m1_pitch
+ control_bus_offset = vector(self.bitcell_array_right + self.m2_pitch,
self.max_y_offset - control_bus_length)
-
+ # The bus for the right port is reversed so that the rbl_wl is closest to the array
self.bus_xoffset[1] = self.create_bus(layer="metal2",
pitch=self.m2_pitch,
offset=control_bus_offset,
- names=self.control_signals[1],
+ names=list(reversed(self.control_signals[1])),
length=control_bus_length,
vertical=True,
make_pins=(self.num_banks==1))
- def route_precharge_to_bitcell_array(self, port):
- """ Routing of BL and BR between pre-charge and bitcell array """
+ def route_port_data_to_bitcell_array(self, port):
+ """ Routing of BL and BR between port data and bitcell array """
- inst2 = self.precharge_array_inst[port]
+ # Connect the regular bitlines
+ inst2 = self.port_data_inst[port]
inst1 = self.bitcell_array_inst
inst1_bl_name = self.bl_names[port]+"_{}"
inst1_br_name = self.br_names[port]+"_{}"
+
self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.num_cols,
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
+
+ # Connect the replica bitlines
+ rbl_bl_name=self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port])
+ rbl_br_name=self.bitcell_array.get_rbl_br_name(self.port_rbl_map[port])
+ self.connect_bitline(inst1, inst2, rbl_bl_name, "rbl_bl")
+ self.connect_bitline(inst1, inst2, rbl_br_name, "rbl_br")
-
- def route_column_mux_to_precharge_array(self, port):
- """ Routing of BL and BR between col mux and precharge array """
-
- # Only do this if we have a column mux!
- if self.col_addr_size==0:
- return
- inst1 = self.column_mux_array_inst[port]
- inst2 = self.precharge_array_inst[port]
- self.connect_bitlines(inst1, inst2, self.num_cols)
+ def route_port_data_out(self, port):
+ """ Add pins for the port data out """
- def route_column_mux_to_bitcell_array(self, port):
- """ Routing of BL and BR between col mux bitcell array """
-
- # Only do this if we have a column mux!
- if self.col_addr_size==0:
- return
-
- inst2 = self.column_mux_array_inst[port]
- inst1 = self.bitcell_array_inst
- inst1_bl_name = self.bl_names[port]+"_{}"
- inst1_br_name = self.br_names[port]+"_{}"
-
- # The column mux is constructed to match the bitline pitch, so we can directly connect
- # here and not channel route the bitlines.
- self.connect_bitlines(inst1=inst1, inst2=inst2, num_bits=self.num_cols,
- inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
-
-
-
- def route_sense_amp_to_column_mux_or_precharge_array(self, port):
- """ Routing of BL and BR between sense_amp and column mux or precharge array """
- inst2 = self.sense_amp_array_inst[port]
-
- if self.col_addr_size>0:
- # Sense amp is connected to the col mux
- inst1 = self.column_mux_array_inst[port]
- inst1_bl_name = "bl_out_{}"
- inst1_br_name = "br_out_{}"
- else:
- # Sense amp is directly connected to the precharge array
- inst1 = self.precharge_array_inst[port]
- inst1_bl_name = "bl_{}"
- inst1_br_name = "br_{}"
-
- self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size,
- inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
-
- def route_write_driver_to_column_mux_or_bitcell_array(self, port):
- """ Routing of BL and BR between sense_amp and column mux or bitcell array """
- inst2 = self.write_driver_array_inst[port]
-
- if self.col_addr_size>0:
- # Write driver is connected to the col mux
- inst1 = self.column_mux_array_inst[port]
- inst1_bl_name = "bl_out_{}"
- inst1_br_name = "br_out_{}"
- else:
- # Write driver is directly connected to the bitcell array
- inst1 = self.bitcell_array_inst
- inst1_bl_name = self.bl_names[port]+"_{}"
- inst1_br_name = self.br_names[port]+"_{}"
-
- self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size,
- inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name)
-
- def route_write_driver_to_sense_amp(self, port):
- """ Routing of BL and BR between write driver and sense amp """
-
- inst1 = self.write_driver_array_inst[port]
- inst2 = self.sense_amp_array_inst[port]
-
- # These should be pitch matched in the cell library,
- # but just in case, do a channel route.
- self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size)
-
-
-
- def route_sense_amp_out(self, port):
- """ Add pins for the sense amp output """
-
for bit in range(self.word_size):
- data_pin = self.sense_amp_array_inst[port].get_pin("data_{}".format(bit))
+ data_pin = self.port_data_inst[port].get_pin("dout_{0}".format(bit))
self.add_layout_pin_rect_center(text="dout{0}_{1}".format(port,bit),
layer=data_pin.layer,
offset=data_pin.center(),
height=data_pin.height(),
width=data_pin.width())
+
-
- def route_row_decoder(self, port):
+ def route_port_address_in(self, port):
""" Routes the row decoder inputs and supplies """
# Create inputs for the row address lines
@@ -978,16 +712,25 @@ class bank(design.design):
addr_idx = row + self.col_addr_size
decoder_name = "addr_{}".format(row)
addr_name = "addr{0}_{1}".format(port,addr_idx)
- self.copy_layout_pin(self.row_decoder_inst[port], decoder_name, addr_name)
-
-
- def route_write_driver_in(self, port):
- """ Connecting write driver """
+ self.copy_layout_pin(self.port_address_inst[port], decoder_name, addr_name)
+
+
+
+ def route_port_data_in(self, port):
+ """ Connecting port data in """
for row in range(self.word_size):
- data_name = "data_{}".format(row)
+ data_name = "din_{}".format(row)
din_name = "din{0}_{1}".format(port,row)
- self.copy_layout_pin(self.write_driver_array_inst[port], data_name, din_name)
+ self.copy_layout_pin(self.port_data_inst[port], data_name, din_name)
+
+ if self.word_size:
+ for row in range(self.num_wmasks):
+ wmask_name = "bank_wmask_{}".format(row)
+ bank_wmask_name = "bank_wmask{0}_{1}".format(port, row)
+ self.copy_layout_pin(self.port_data_inst[port], wmask_name, bank_wmask_name)
+
+
def channel_route_bitlines(self, inst1, inst2, num_bits,
inst1_bl_name="bl_{}", inst1_br_name="br_{}",
@@ -1015,12 +758,9 @@ class bank(design.design):
route_map = list(zip(bottom_names, top_names))
self.create_horizontal_channel_route(route_map, offset)
-
- def connect_bitlines(self, inst1, inst2, num_bits,
- inst1_bl_name="bl_{}", inst1_br_name="br_{}",
- inst2_bl_name="bl_{}", inst2_br_name="br_{}"):
+ def connect_bitline(self, inst1, inst2, inst1_name, inst2_name):
"""
- Connect the bl and br of two modules.
+ Connect two pins of two modules.
This assumes that they have sufficient space to create a jog
in the middle between the two modules (if needed).
"""
@@ -1028,66 +768,66 @@ class bank(design.design):
# determine top and bottom automatically.
# since they don't overlap, we can just check the bottom y coordinate.
if inst1.by() < inst2.by():
- (bottom_inst, bottom_bl_name, bottom_br_name) = (inst1, inst1_bl_name, inst1_br_name)
- (top_inst, top_bl_name, top_br_name) = (inst2, inst2_bl_name, inst2_br_name)
+ (bottom_inst, bottom_name) = (inst1, inst1_name)
+ (top_inst, top_name) = (inst2, inst2_name)
else:
- (bottom_inst, bottom_bl_name, bottom_br_name) = (inst2, inst2_bl_name, inst2_br_name)
- (top_inst, top_bl_name, top_br_name) = (inst1, inst1_bl_name, inst1_br_name)
+ (bottom_inst, bottom_name) = (inst2, inst2_name)
+ (top_inst, top_name) = (inst1, inst1_name)
- for col in range(num_bits):
- bottom_bl = bottom_inst.get_pin(bottom_bl_name.format(col)).uc()
- bottom_br = bottom_inst.get_pin(bottom_br_name.format(col)).uc()
- top_bl = top_inst.get_pin(top_bl_name.format(col)).bc()
- top_br = top_inst.get_pin(top_br_name.format(col)).bc()
-
- yoffset = 0.5*(top_bl.y+bottom_bl.y)
- self.add_path("metal2",[bottom_bl, vector(bottom_bl.x,yoffset),
- vector(top_bl.x,yoffset), top_bl])
- self.add_path("metal2",[bottom_br, vector(bottom_br.x,yoffset),
- vector(top_br.x,yoffset), top_br])
+ bottom_pin = bottom_inst.get_pin(bottom_name)
+ top_pin = top_inst.get_pin(top_name)
+ debug.check(bottom_pin.layer == top_pin.layer, "Pin layers do not match.")
+
+ bottom_loc = bottom_pin.uc()
+ top_loc = top_pin.bc()
+
+ yoffset = 0.5*(top_loc.y+bottom_loc.y)
+ self.add_path(top_pin.layer,[bottom_loc, vector(bottom_loc.x,yoffset),
+ vector(top_loc.x,yoffset), top_loc])
- def route_wordline_driver(self, port):
+ def connect_bitlines(self, inst1, inst2, num_bits,
+ inst1_bl_name="bl_{}", inst1_br_name="br_{}",
+ inst2_bl_name="bl_{}", inst2_br_name="br_{}"):
+ """
+ Connect the bl and br of two modules.
+ """
+
+ for col in range(num_bits):
+ self.connect_bitline(inst1, inst2, inst1_bl_name.format(col), inst2_bl_name.format(col))
+ self.connect_bitline(inst1, inst2, inst1_br_name.format(col), inst2_br_name.format(col))
+
+
+ def route_port_address(self, port):
""" Connect Wordline driver to bitcell array wordline """
+
+ self.route_port_address_in(port)
+
if port%2:
- self.route_wordline_driver_right(port)
+ self.route_port_address_right(port)
else:
- self.route_wordline_driver_left(port)
+ self.route_port_address_left(port)
- def route_wordline_driver_left(self, port):
+ def route_port_address_left(self, port):
""" Connecting Wordline driver output to Bitcell WL connection """
for row in range(self.num_rows):
- # The pre/post is to access the pin from "outside" the cell to avoid DRCs
- decoder_out_pos = self.row_decoder_inst[port].get_pin("decode_{}".format(row)).rc()
- driver_in_pos = self.wordline_driver_inst[port].get_pin("in_{}".format(row)).lc()
- mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0)
- mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1)
- self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos])
-
# The mid guarantees we exit the input cell to the right.
- driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).rc()
+ driver_wl_pos = self.port_address_inst[port].get_pin("wl_{}".format(row)).rc()
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).lc()
- mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.wordline_driver_inst[port].rx() + 0.5*self.bitcell_array_inst.lx(),0)
+ mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.port_address_inst[port].rx() + 0.5*self.bitcell_array_inst.lx(),0)
mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0.5,1)
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
- def route_wordline_driver_right(self, port):
+ def route_port_address_right(self, port):
""" Connecting Wordline driver output to Bitcell WL connection """
for row in range(self.num_rows):
- # The pre/post is to access the pin from "outside" the cell to avoid DRCs
- decoder_out_pos = self.row_decoder_inst[port].get_pin("decode_{}".format(row)).lc()
- driver_in_pos = self.wordline_driver_inst[port].get_pin("in_{}".format(row)).rc()
- mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0)
- mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1)
- self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos])
-
# The mid guarantees we exit the input cell to the right.
- driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).lc()
+ driver_wl_pos = self.port_address_inst[port].get_pin("wl_{}".format(row)).lc()
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).rc()
- mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.wordline_driver_inst[port].lx() + 0.5*self.bitcell_array_inst.rx(),0)
+ mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.port_address_inst[port].lx() + 0.5*self.bitcell_array_inst.rx(),0)
mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0,1)
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
@@ -1122,7 +862,7 @@ class bank(design.design):
decode_pins = [self.column_decoder_inst[port].get_pin(x) for x in decode_names]
sel_names = ["sel_{}".format(x) for x in range(self.num_col_addr_lines)]
- column_mux_pins = [self.column_mux_array_inst[port].get_pin(x) for x in sel_names]
+ column_mux_pins = [self.port_data_inst[port].get_pin(x) for x in sel_names]
route_map = list(zip(decode_pins, column_mux_pins))
self.create_vertical_channel_route(route_map, offset)
@@ -1184,86 +924,61 @@ class bank(design.design):
read_inst = 0
connection = []
- if port in self.read_ports:
- connection.append((self.prefix+"p_en_bar{}".format(port), self.precharge_array_inst[port].get_pin("en_bar").lc()))
-
- if port in self.write_ports:
- connection.append((self.prefix+"w_en{}".format(port), self.write_driver_array_inst[port].get_pin("en").lc()))
-
- if port in self.read_ports:
- connection.append((self.prefix+"s_en{}".format(port), self.sense_amp_array_inst[port].get_pin("en").lc()))
-
- for (control_signal, pin_pos) in connection:
- control_pos = vector(self.bus_xoffset[port][control_signal].x ,pin_pos.y)
- self.add_path("metal1", [control_pos, pin_pos])
- self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=control_pos,
- rotate=90)
+ connection.append((self.prefix+"p_en_bar{}".format(port), self.port_data_inst[port].get_pin("p_en_bar").lc()))
+ rbl_wl_name = self.bitcell_array.get_rbl_wl_name(self.port_rbl_map[port])
+ connection.append((self.prefix+"wl_en{}".format(port), self.bitcell_array_inst.get_pin(rbl_wl_name).lc()))
+
+ if port in self.write_ports:
+ if port % 2:
+ connection.append((self.prefix+"w_en{}".format(port), self.port_data_inst[port].get_pin("w_en").rc()))
+ else:
+ connection.append((self.prefix+"w_en{}".format(port), self.port_data_inst[port].get_pin("w_en").lc()))
+
+ if port in self.read_ports:
+ connection.append((self.prefix+"s_en{}".format(port), self.port_data_inst[port].get_pin("s_en").lc()))
+
+ for (control_signal, pin_pos) in connection:
+ control_mid_pos = self.bus_xoffset[port][control_signal]
+ control_pos = vector(self.bus_xoffset[port][control_signal].x ,pin_pos.y)
+ self.add_wire(("metal1","via1","metal2"), [control_mid_pos, control_pos, pin_pos])
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=control_pos)
+
+
# clk to wordline_driver
control_signal = self.prefix+"wl_en{}".format(port)
if port%2:
- pin_pos = self.wordline_driver_inst[port].get_pin("en_bar").uc()
- mid_pos = pin_pos + vector(0,self.m2_gap) # to route down to the top of the bus
+ pin_pos = self.port_address_inst[port].get_pin("wl_en").uc()
+ mid_pos = pin_pos + vector(0,2*self.m2_gap) # to route down to the top of the bus
else:
- pin_pos = self.wordline_driver_inst[port].get_pin("en_bar").bc()
- mid_pos = pin_pos - vector(0,self.m2_gap) # to route down to the top of the bus
+ pin_pos = self.port_address_inst[port].get_pin("wl_en").bc()
+ mid_pos = pin_pos - vector(0,2*self.m2_gap) # to route down to the top of the bus
control_x_offset = self.bus_xoffset[port][control_signal].x
control_pos = vector(control_x_offset, mid_pos.y)
self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=control_pos,
- rotate=90)
-
-
- def analytical_delay(self, corner, slew, load):
- """ return analytical delay of the bank"""
- results = []
-
- decoder_delay = self.row_decoder.analytical_delay(corner, slew, self.wordline_driver.input_load())
-
- word_driver_delay = self.wordline_driver.analytical_delay(corner,
- decoder_delay.slew,
- self.bitcell_array.input_load())
-
- #FIXME: Array delay is the same for every port.
- bitcell_array_delay = self.bitcell_array.analytical_delay(corner, word_driver_delay.slew)
-
- #This also essentially creates the same delay for each port. Good structure, no substance
- for port in self.all_ports:
- if self.words_per_row > 1:
- column_mux_delay = self.column_mux_array[port].analytical_delay(corner,
- bitcell_array_delay.slew,
- self.sense_amp_array.input_load())
- else:
- column_mux_delay = self.return_delay(delay = 0.0, slew=word_driver_delay.slew)
-
- bl_t_data_out_delay = self.sense_amp_array.analytical_delay(corner,
- column_mux_delay.slew,
- self.bitcell_array.output_load())
- # output load of bitcell_array is set to be only small part of bl for sense amp.
- results.append(decoder_delay + word_driver_delay + bitcell_array_delay + column_mux_delay + bl_t_data_out_delay)
-
- return results
-
+ offset=control_pos)
+
def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True):
"""Get the all the stage efforts for each stage in the path within the bank clk_buf to a wordline"""
#Decoder is assumed to have settled before the negative edge of the clock. Delay model relies on this assumption
stage_effort_list = []
wordline_cout = self.bitcell_array.get_wordline_cin() + external_cout
- stage_effort_list += self.wordline_driver.determine_wordline_stage_efforts(wordline_cout,inp_is_rise)
+ stage_effort_list += self.port_address.wordline_driver.determine_wordline_stage_efforts(wordline_cout,inp_is_rise)
return stage_effort_list
def get_wl_en_cin(self):
"""Get the relative capacitance of all the clk connections in the bank"""
#wl_en only used in the wordline driver.
- return self.wordline_driver.get_wl_en_cin()
+ return self.port_address.wordline_driver.get_wl_en_cin()
def get_w_en_cin(self):
"""Get the relative capacitance of all the clk connections in the bank"""
#wl_en only used in the wordline driver.
- return self.write_driver.get_w_en_cin()
+ port = self.write_ports[0]
+ return self.port_data[port].write_driver.get_w_en_cin()
def get_clk_bar_cin(self):
"""Get the relative capacitance of all the clk_bar connections in the bank"""
@@ -1271,9 +986,21 @@ class bank(design.design):
#Precharges are the all the same in Mulitport, one is picked
port = self.read_ports[0]
- return self.precharge_array[port].get_en_cin()
+ return self.port_data[port].precharge_array.get_en_cin()
def get_sen_cin(self):
"""Get the relative capacitance of all the sense amp enable connections in the bank"""
#Current bank only uses sen as an enable for the sense amps.
- return self.sense_amp_array.get_en_cin()
+ port = self.read_ports[0]
+ return self.port_data[port].sense_amp_array.get_en_cin()
+
+ def graph_exclude_precharge(self):
+ """Precharge adds a loop between bitlines, can be excluded to reduce complexity"""
+ for port in self.read_ports:
+ if self.port_data[port]:
+ self.port_data[port].graph_exclude_precharge()
+
+ def get_cell_name(self, inst_name, row, col):
+ """Gets the spice name of the target bitcell."""
+ return self.bitcell_array_inst.mod.get_cell_name(inst_name+'.x'+self.bitcell_array_inst.name, row, col)
+
diff --git a/compiler/modules/bank_select.py b/compiler/modules/bank_select.py
index 8e44dfa2..296cef8b 100644
--- a/compiler/modules/bank_select.py
+++ b/compiler/modules/bank_select.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import sys
from tech import drc, parameter
import debug
@@ -35,6 +42,7 @@ class bank_select(design.design):
self.place_instances()
self.route_instances()
+ self.add_boundary()
self.DRC_LVS()
@@ -81,7 +89,7 @@ class bank_select(design.design):
self.inv4x_nor = factory.create(module_type="pinv", height=height, size=4)
self.add_mod(self.inv4x_nor)
- self.nand2 = factory.create(module_type="pnand2")
+ self.nand2 = factory.create(module_type="pnand2", height=height)
self.add_mod(self.nand2)
def calculate_module_offsets(self):
@@ -213,7 +221,7 @@ class bank_select(design.design):
end=bank_sel_pin_end)
self.add_via_center(layers=("metal2","via2","metal3"),
offset=bank_sel_pin_end,
- rotate=90)
+ directions=("H","H"))
# bank_sel_bar is vertical wire
bank_sel_bar_pin = self.bank_sel_inv.get_pin("Z")
@@ -252,7 +260,7 @@ class bank_select(design.design):
self.add_path("metal2",[logic_pos, input_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=logic_pos,
- rotate=90)
+ directions=("H","H"))
# Connect the logic A input to the input pin
@@ -260,10 +268,10 @@ class bank_select(design.design):
input_pos = vector(0,logic_pos.y)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=logic_pos,
- rotate=90)
+ directions=("H","H"))
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=logic_pos,
- rotate=90)
+ directions=("H","H"))
self.add_layout_pin_segment_center(text=input_name,
layer="metal3",
start=input_pos,
@@ -295,10 +303,10 @@ class bank_select(design.design):
pin_pos = vector(xoffset, supply_pin.cy())
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=pin_pos,
- rotate=90)
+ directions=("H","H"))
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=pin_pos,
- rotate=90)
+ directions=("H","H"))
self.add_layout_pin_rect_center(text=n,
layer="metal3",
offset=pin_pos)
diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py
index ea8fc3f2..b1b61487 100644
--- a/compiler/modules/bitcell_array.py
+++ b/compiler/modules/bitcell_array.py
@@ -1,9 +1,17 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
import design
from tech import drc, spice
from vector import vector
from globals import OPTS
from sram_factory import factory
+import logical_effort
class bitcell_array(design.design):
"""
@@ -37,8 +45,8 @@ class bitcell_array(design.design):
def create_layout(self):
# We increase it by a well enclosure so the precharges don't overlap our wells
- self.height = self.row_size*self.cell.height + drc("well_enclosure_active") + self.m1_width
- self.width = self.column_size*self.cell.width + self.m1_width
+ self.height = self.row_size*self.cell.height
+ self.width = self.column_size*self.cell.width
xoffset = 0.0
for col in range(self.column_size):
@@ -60,25 +68,45 @@ class bitcell_array(design.design):
self.add_layout_pins()
+ self.add_boundary()
+
self.DRC_LVS()
def add_pins(self):
- row_list = self.cell.list_all_wl_names()
- column_list = self.cell.list_all_bitline_names()
+ row_list = self.cell.get_all_wl_names()
+ column_list = self.cell.get_all_bitline_names()
for col in range(self.column_size):
for cell_column in column_list:
- self.add_pin(cell_column+"_{0}".format(col))
+ self.add_pin(cell_column+"_{0}".format(col), "INOUT")
for row in range(self.row_size):
for cell_row in row_list:
- self.add_pin(cell_row+"_{0}".format(row))
- self.add_pin("vdd")
- self.add_pin("gnd")
+ self.add_pin(cell_row+"_{0}".format(row), "INPUT")
+ self.add_pin("vdd", "POWER")
+ self.add_pin("gnd", "GROUND")
def add_modules(self):
""" Add the modules used in this design """
self.cell = factory.create(module_type="bitcell")
self.add_mod(self.cell)
+ def get_bitcell_pins(self, col, row):
+ """ Creates a list of connections in the bitcell,
+ indexed by column and row, for instance use in bitcell_array """
+
+ bitcell_pins = []
+
+ pin_names = self.cell.get_all_bitline_names()
+ for pin in pin_names:
+ bitcell_pins.append(pin+"_{0}".format(col))
+ pin_names = self.cell.get_all_wl_names()
+ for pin in pin_names:
+ bitcell_pins.append(pin+"_{0}".format(row))
+ bitcell_pins.append("vdd")
+ bitcell_pins.append("gnd")
+
+ return bitcell_pins
+
+
def create_instances(self):
""" Create the module instances used in this design """
self.cell_inst = {}
@@ -87,66 +115,40 @@ class bitcell_array(design.design):
name = "bit_r{0}_c{1}".format(row, col)
self.cell_inst[row,col]=self.add_inst(name=name,
mod=self.cell)
- self.connect_inst(self.cell.list_bitcell_pins(col, row))
+ self.connect_inst(self.get_bitcell_pins(col, row))
def add_layout_pins(self):
""" Add the layout pins """
- row_list = self.cell.list_all_wl_names()
- column_list = self.cell.list_all_bitline_names()
+ row_list = self.cell.get_all_wl_names()
+ column_list = self.cell.get_all_bitline_names()
- offset = vector(0.0, 0.0)
for col in range(self.column_size):
for cell_column in column_list:
bl_pin = self.cell_inst[0,col].get_pin(cell_column)
self.add_layout_pin(text=cell_column+"_{0}".format(col),
- layer="metal2",
- offset=bl_pin.ll(),
+ layer=bl_pin.layer,
+ offset=bl_pin.ll().scale(1,0),
width=bl_pin.width(),
height=self.height)
-
- # increments to the next column width
- offset.x += self.cell.width
- offset.x = 0.0
for row in range(self.row_size):
for cell_row in row_list:
wl_pin = self.cell_inst[row,0].get_pin(cell_row)
self.add_layout_pin(text=cell_row+"_{0}".format(row),
- layer="metal1",
- offset=wl_pin.ll(),
+ layer=wl_pin.layer,
+ offset=wl_pin.ll().scale(0,1),
width=self.width,
height=wl_pin.height())
- # increments to the next row height
- offset.y += self.cell.height
-
# For every second row and column, add a via for gnd and vdd
for row in range(self.row_size):
for col in range(self.column_size):
inst = self.cell_inst[row,col]
for pin_name in ["vdd", "gnd"]:
for pin in inst.get_pins(pin_name):
- self.add_power_pin(pin_name, pin.center(), 0, pin.layer)
-
+ self.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer)
- def analytical_delay(self, corner, slew, load=0):
- from tech import drc
- wl_wire = self.gen_wl_wire()
- wl_wire.return_delay_over_wire(slew)
-
- wl_to_cell_delay = wl_wire.return_delay_over_wire(slew)
- # hypothetical delay from cell to bl end without sense amp
- bl_wire = self.gen_bl_wire()
- cell_load = 2 * bl_wire.return_input_cap() # we ingore the wire r
- # hence just use the whole c
- bl_swing = 0.1
- cell_delay = self.cell.analytical_delay(corner, wl_to_cell_delay.slew, cell_load, swing = bl_swing)
-
- #we do not consider the delay over the wire for now
- return self.return_delay(cell_delay.delay+wl_to_cell_delay.delay,
- wl_to_cell_delay.slew)
-
def analytical_power(self, corner, load):
"""Power of Bitcell array and bitline in nW."""
from tech import drc, parameter
@@ -154,8 +156,8 @@ class bitcell_array(design.design):
# Dynamic Power from Bitline
bl_wire = self.gen_bl_wire()
cell_load = 2 * bl_wire.return_input_cap()
- bl_swing = parameter["rbl_height_percentage"]
- freq = spice["default_event_rate"]
+ bl_swing = OPTS.rbl_delay_percentage
+ freq = spice["default_event_frequency"]
bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing)
#Calculate the bitcell power which currently only includes leakage
@@ -185,18 +187,22 @@ class bitcell_array(design.design):
bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell
return bl_wire
- def output_load(self, bl_pos=0):
- bl_wire = self.gen_bl_wire()
- return bl_wire.wire_c # sense amp only need to charge small portion of the bl
- # set as one segment for now
-
- def input_load(self):
- wl_wire = self.gen_wl_wire()
- return wl_wire.return_input_cap()
-
def get_wordline_cin(self):
"""Get the relative input capacitance from the wordline connections in all the bitcell"""
#A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns
bitcell_wl_cin = self.cell.get_wl_cin()
total_cin = bitcell_wl_cin * self.column_size
return total_cin
+
+ def graph_exclude_bits(self, targ_row, targ_col):
+ """Excludes bits in column from being added to graph except target"""
+ #Function is not robust with column mux configurations
+ for row in range(self.row_size):
+ for col in range(self.column_size):
+ if row == targ_row and col == targ_col:
+ continue
+ self.graph_inst_exclude.add(self.cell_inst[row,col])
+
+ def get_cell_name(self, inst_name, row, col):
+ """Gets the spice name of the target bitcell."""
+ return inst_name+'.x'+self.cell_inst[row,col].name, self.cell_inst[row,col]
diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py
index b8532ee9..06883125 100644
--- a/compiler/modules/control_logic.py
+++ b/compiler/modules/control_logic.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
from math import log
import design
from tech import drc, parameter
@@ -14,7 +21,7 @@ class control_logic(design.design):
Dynamically generated Control logic for the total SRAM circuit.
"""
- def __init__(self, num_rows, words_per_row, word_size, sram=None, port_type="rw"):
+ def __init__(self, num_rows, words_per_row, word_size, sram=None, port_type="rw", name=""):
""" Constructor """
name = "control_logic_" + port_type
design.design.__init__(self, name)
@@ -32,11 +39,11 @@ class control_logic(design.design):
self.num_cols = word_size*words_per_row
self.num_words = num_rows*words_per_row
- self.enable_delay_chain_resizing = True
+ self.enable_delay_chain_resizing = False
+ self.inv_parasitic_delay = logical_effort.logical_effort.pinv
#Determines how much larger the sen delay should be. Accounts for possible error in model.
self.wl_timing_tolerance = 1
- self.parasitic_inv_delay = parameter["min_inv_para_delay"]
self.wl_stage_efforts = None
self.sen_stage_efforts = None
@@ -60,15 +67,14 @@ class control_logic(design.design):
self.place_instances()
self.route_all()
#self.add_lvs_correspondence_points()
+ self.add_boundary()
self.DRC_LVS()
def add_pins(self):
""" Add the pins to the control logic module. """
- for pin in self.input_list + ["clk"]:
- self.add_pin(pin,"INPUT")
- for pin in self.output_list:
- self.add_pin(pin,"OUTPUT")
+ self.add_pin_list(self.input_list + ["clk"] + self.rbl_list, "INPUT")
+ self.add_pin_list(self.output_list,"OUTPUT")
self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND")
@@ -88,18 +94,30 @@ class control_logic(design.design):
size=4,
height=dff_height)
self.add_mod(self.and2)
+
+ self.rbl_driver = factory.create(module_type="pbuf",
+ size=self.num_cols,
+ height=dff_height)
+ self.add_mod(self.rbl_driver)
- # clk_buf drives a flop for every address and control bit
+
+ # clk_buf drives a flop for every address
+ addr_flops = math.log(self.num_words,2) + math.log(self.words_per_row,2)
+ # plus data flops and control flops
+ num_flops = addr_flops + self.word_size + self.num_control_signals
+ # each flop internally has a FO 5 approximately
# plus about 5 fanouts for the control logic
- # each flop internally has a FO 4 approximately
- clock_fanout = 4*(math.log(self.num_words,2) + math.log(self.words_per_row,2) \
- + self.num_control_signals) + 5
+ clock_fanout = 5*num_flops + 5
self.clk_buf_driver = factory.create(module_type="pdriver",
fanout=clock_fanout,
height=dff_height)
self.add_mod(self.clk_buf_driver)
+ # We will use the maximum since this same value is used to size the wl_en
+ # and the p_en_bar drivers
+ max_fanout = max(self.num_rows,self.num_cols)
+
# wl_en drives every row in the bank
self.wl_en_driver = factory.create(module_type="pdriver",
fanout=self.num_rows,
@@ -107,70 +125,79 @@ class control_logic(design.design):
self.add_mod(self.wl_en_driver)
# w_en drives every write driver
- self.w_en_driver = factory.create(module_type="pdriver",
- fanout=self.word_size+8,
- height=dff_height)
- self.add_mod(self.w_en_driver)
+ self.wen_and = factory.create(module_type="pand3",
+ size=self.word_size+8,
+ height=dff_height)
+ self.add_mod(self.wen_and)
# s_en drives every sense amp
- self.s_en_driver = factory.create(module_type="pdriver",
- fanout=self.word_size,
- height=dff_height)
- self.add_mod(self.s_en_driver)
+ self.sen_and3 = factory.create(module_type="pand3",
+ size=self.word_size,
+ height=dff_height)
+ self.add_mod(self.sen_and3)
# used to generate inverted signals with low fanout
self.inv = factory.create(module_type="pinv",
- size=1,
- height=dff_height)
+ size=1,
+ height=dff_height)
self.add_mod(self.inv)
-
- # p_en_bar drives every column in the bicell array
+
+ # p_en_bar drives every column in the bitcell array
+ # but it is sized the same as the wl_en driver with
+ # prepended 3 inverter stages to guarantee it is slower and odd polarity
self.p_en_bar_driver = factory.create(module_type="pdriver",
- neg_polarity=True,
fanout=self.num_cols,
height=dff_height)
self.add_mod(self.p_en_bar_driver)
+
+
+ self.nand2 = factory.create(module_type="pnand2",
+ height=dff_height)
+ self.add_mod(self.nand2)
- if (self.port_type == "rw") or (self.port_type == "r"):
- from importlib import reload
- self.delay_chain_resized = False
- c = reload(__import__(OPTS.replica_bitline))
- replica_bitline = getattr(c, OPTS.replica_bitline)
- bitcell_loads = int(math.ceil(self.num_rows * parameter["rbl_height_percentage"]))
- #Use a model to determine the delays with that heuristic
- if OPTS.use_tech_delay_chain_size: #Use tech parameters if set.
- fanout_list = parameter["static_fanout_list"]
- debug.info(1, "Using tech parameters to size delay chain: fanout_list={}".format(fanout_list))
- self.replica_bitline = factory.create(module_type="replica_bitline",
- delay_fanout_list=fanout_list,
- bitcell_loads=bitcell_loads)
- if self.sram != None: #Calculate model value even for specified sizes
- self.set_sen_wl_delays()
+ # if (self.port_type == "rw") or (self.port_type == "r"):
+ # from importlib import reload
+ # self.delay_chain_resized = False
+ # c = reload(__import__(OPTS.replica_bitline))
+ # replica_bitline = getattr(c, OPTS.replica_bitline)
+ # bitcell_loads = int(math.ceil(self.num_rows * OPTS.rbl_delay_percentage))
+ # #Use a model to determine the delays with that heuristic
+ # if OPTS.use_tech_delay_chain_size: #Use tech parameters if set.
+ # fanout_list = OPTS.delay_chain_stages*[OPTS.delay_chain_fanout_per_stage]
+ # debug.info(1, "Using tech parameters to size delay chain: fanout_list={}".format(fanout_list))
+ # self.replica_bitline = factory.create(module_type="replica_bitline",
+ # delay_fanout_list=fanout_list,
+ # bitcell_loads=bitcell_loads)
+ # if self.sram != None: #Calculate model value even for specified sizes
+ # self.set_sen_wl_delays()
- else: #Otherwise, use a heuristic and/or model based sizing.
- #First use a heuristic
- delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size()
- self.replica_bitline = factory.create(module_type="replica_bitline",
- delay_fanout_list=[delay_fanout_heuristic]*delay_stages_heuristic,
- bitcell_loads=bitcell_loads)
- #Resize if necessary, condition depends on resizing method
- if self.sram != None and self.enable_delay_chain_resizing and not self.does_sen_rise_fall_timing_match():
- #This resizes to match fall and rise delays, can make the delay chain weird sizes.
- stage_list = self.get_dynamic_delay_fanout_list(delay_stages_heuristic, delay_fanout_heuristic)
- self.replica_bitline = factory.create(module_type="replica_bitline",
- delay_fanout_list=stage_list,
- bitcell_loads=bitcell_loads)
+ # else: #Otherwise, use a heuristic and/or model based sizing.
+ # #First use a heuristic
+ # delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size()
+ # self.replica_bitline = factory.create(module_type="replica_bitline",
+ # delay_fanout_list=[delay_fanout_heuristic]*delay_stages_heuristic,
+ # bitcell_loads=bitcell_loads)
+ # #Resize if necessary, condition depends on resizing method
+ # if self.sram != None and self.enable_delay_chain_resizing and not self.does_sen_rise_fall_timing_match():
+ # #This resizes to match fall and rise delays, can make the delay chain weird sizes.
+ # stage_list = self.get_dynamic_delay_fanout_list(delay_stages_heuristic, delay_fanout_heuristic)
+ # self.replica_bitline = factory.create(module_type="replica_bitline",
+ # delay_fanout_list=stage_list,
+ # bitcell_loads=bitcell_loads)
- #This resizes based on total delay.
- # delay_stages, delay_fanout = self.get_dynamic_delay_chain_size(delay_stages_heuristic, delay_fanout_heuristic)
- # self.replica_bitline = factory.create(module_type="replica_bitline",
- # delay_fanout_list=[delay_fanout]*delay_stages,
- # bitcell_loads=bitcell_loads)
+ # #This resizes based on total delay.
+ # # delay_stages, delay_fanout = self.get_dynamic_delay_chain_size(delay_stages_heuristic, delay_fanout_heuristic)
+ # # self.replica_bitline = factory.create(module_type="replica_bitline",
+ # # delay_fanout_list=[delay_fanout]*delay_stages,
+ # # bitcell_loads=bitcell_loads)
- self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen() #get the new timing
- self.delay_chain_resized = True
-
- self.add_mod(self.replica_bitline)
+ # self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen() #get the new timing
+ # self.delay_chain_resized = True
+
+ debug.check(OPTS.delay_chain_stages%2, "Must use odd number of delay chain stages for inverting delay chain.")
+ self.delay_chain=factory.create(module_type="delay_chain",
+ fanout_list = OPTS.delay_chain_stages*[OPTS.delay_chain_fanout_per_stage])
+ self.add_mod(self.delay_chain)
def get_heuristic_delay_chain_size(self):
"""Use a basic heuristic to determine the size of the delay chain used for the Sense Amp Enable """
@@ -219,7 +246,7 @@ class control_logic(design.design):
def get_dynamic_delay_chain_size(self, previous_stages, previous_fanout):
"""Determine the size of the delay chain used for the Sense Amp Enable using path delays"""
from math import ceil
- previous_delay_chain_delay = (previous_fanout+1+self.parasitic_inv_delay)*previous_stages
+ previous_delay_chain_delay = (previous_fanout+1+self.inv_parasitic_delay)*previous_stages
debug.info(2, "Previous delay chain produced {} delay units".format(previous_delay_chain_delay))
delay_fanout = 3 # This can be anything >=2
@@ -227,7 +254,7 @@ class control_logic(design.design):
#inverter adds 1 unit of delay (due to minimum size). This also depends on the pinv value
required_delay = self.wl_delay*self.wl_timing_tolerance - (self.sen_delay-previous_delay_chain_delay)
debug.check(required_delay > 0, "Cannot size delay chain to have negative delay")
- delay_stages = ceil(required_delay/(delay_fanout+1+self.parasitic_inv_delay))
+ delay_stages = ceil(required_delay/(delay_fanout+1+self.inv_parasitic_delay))
if delay_stages%2 == 1: #force an even number of stages.
delay_stages+=1
#Fanout can be varied as well but is a little more complicated but potentially optimal.
@@ -237,7 +264,7 @@ class control_logic(design.design):
def get_dynamic_delay_fanout_list(self, previous_stages, previous_fanout):
"""Determine the size of the delay chain used for the Sense Amp Enable using path delays"""
- previous_delay_chain_delay = (previous_fanout+1+self.parasitic_inv_delay)*previous_stages
+ previous_delay_chain_delay = (previous_fanout+1+self.inv_parasitic_delay)*previous_stages
debug.info(2, "Previous delay chain produced {} delay units".format(previous_delay_chain_delay))
fanout_rise = fanout_fall = 2 # This can be anything >=2
@@ -284,9 +311,9 @@ class control_logic(design.design):
def calculate_stages_with_fixed_fanout(self, required_delay, fanout):
from math import ceil
#Delay being negative is not an error. It implies that any amount of stages would have a negative effect on the overall delay
- if required_delay <= 3+self.parasitic_inv_delay: #3 is the minimum delay per stage (with pinv=0).
+ if required_delay <= 3+self.inv_parasitic_delay: #3 is the minimum delay per stage (with pinv=0).
return 1
- delay_stages = ceil(required_delay/(fanout+1+self.parasitic_inv_delay))
+ delay_stages = ceil(required_delay/(fanout+1+self.inv_parasitic_delay))
return delay_stages
def calculate_stage_list(self, total_stages, fanout_rise, fanout_fall):
@@ -304,9 +331,11 @@ class control_logic(design.design):
# List of input control signals
if self.port_type == "rw":
self.input_list = ["csb", "web"]
+ self.rbl_list = ["rbl_bl"]
else:
self.input_list = ["csb"]
-
+ self.rbl_list = ["rbl_bl"]
+
if self.port_type == "rw":
self.dff_output_list = ["cs_bar", "cs", "we_bar", "we"]
else:
@@ -314,21 +343,22 @@ class control_logic(design.design):
# list of output control signals (for making a vertical bus)
if self.port_type == "rw":
- self.internal_bus_list = ["gated_clk_bar", "gated_clk_buf", "we", "clk_buf", "we_bar", "cs"]
+ self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "gated_clk_bar", "gated_clk_buf", "we", "clk_buf", "we_bar", "cs"]
elif self.port_type == "r":
- self.internal_bus_list = ["gated_clk_bar", "gated_clk_buf", "clk_buf", "cs_bar", "cs"]
+ self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "gated_clk_bar", "gated_clk_buf", "clk_buf", "cs_bar", "cs"]
else:
- self.internal_bus_list = ["gated_clk_bar", "gated_clk_buf", "clk_buf", "cs"]
+ self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "gated_clk_bar", "gated_clk_buf", "clk_buf", "cs"]
# leave space for the bus plus one extra space
self.internal_bus_width = (len(self.internal_bus_list)+1)*self.m2_pitch
# Outputs to the bank
if self.port_type == "rw":
- self.output_list = ["s_en", "w_en", "p_en_bar"]
+ self.output_list = ["s_en", "w_en"]
elif self.port_type == "r":
- self.output_list = ["s_en", "p_en_bar"]
+ self.output_list = ["s_en"]
else:
self.output_list = ["w_en"]
+ self.output_list.append("p_en_bar")
self.output_list.append("wl_en")
self.output_list.append("clk_buf")
@@ -351,13 +381,13 @@ class control_logic(design.design):
self.create_gated_clk_buf_row()
self.create_wlen_row()
if (self.port_type == "rw") or (self.port_type == "w"):
+ self.create_rbl_delay_row()
self.create_wen_row()
- if self.port_type == "rw":
- self.create_rbl_in_row()
- if (self.port_type == "rw") or (self.port_type == "r"):
- self.create_pen_row()
+ if (self.port_type == "rw") or (self.port_type == "r"):
self.create_sen_row()
- self.create_rbl()
+ self.create_delay()
+ self.create_pen_row()
+
def place_instances(self):
@@ -384,20 +414,20 @@ class control_logic(design.design):
row += 1
if (self.port_type == "rw") or (self.port_type == "w"):
self.place_wen_row(row)
- height = self.w_en_inst.uy()
- control_center_y = self.w_en_inst.uy()
+ height = self.w_en_gate_inst.uy()
+ control_center_y = self.w_en_gate_inst.uy()
row += 1
- if self.port_type == "rw":
- self.place_rbl_in_row(row)
+ self.place_pen_row(row)
+ row += 1
+ if (self.port_type == "rw") or (self.port_type == "w"):
+ self.place_rbl_delay_row(row)
row += 1
if (self.port_type == "rw") or (self.port_type == "r"):
- self.place_pen_row(row)
- row += 1
self.place_sen_row(row)
row += 1
- self.place_rbl(row)
- height = self.rbl_inst.uy()
- control_center_y = self.rbl_inst.by()
+ self.place_delay(row)
+ height = self.delay_inst.uy()
+ control_center_y = self.delay_inst.by()
# This offset is used for placement of the control logic in the SRAM level.
self.control_logic_center = vector(self.ctrl_dff_inst.rx(), control_center_y)
@@ -407,7 +437,7 @@ class control_logic(design.design):
# Max of modules or logic rows
self.width = max([inst.rx() for inst in self.row_end_inst])
if (self.port_type == "rw") or (self.port_type == "r"):
- self.width = max(self.rbl_inst.rx() , self.width)
+ self.width = max(self.delay_inst.rx() , self.width)
self.width += self.m2_pitch
def route_all(self):
@@ -416,35 +446,48 @@ class control_logic(design.design):
self.route_dffs()
self.route_wlen()
if (self.port_type == "rw") or (self.port_type == "w"):
+ self.route_rbl_delay()
self.route_wen()
if (self.port_type == "rw") or (self.port_type == "r"):
- self.route_rbl_in()
- self.route_pen()
self.route_sen()
+ self.route_delay()
+ self.route_pen()
self.route_clk_buf()
self.route_gated_clk_bar()
self.route_gated_clk_buf()
self.route_supply()
- def create_rbl(self):
+ def create_delay(self):
""" Create the replica bitline """
- if self.port_type == "r":
- input_name = "gated_clk_bar"
- else:
- input_name = "rbl_in"
- self.rbl_inst=self.add_inst(name="replica_bitline",
- mod=self.replica_bitline)
- self.connect_inst([input_name, "pre_s_en", "vdd", "gnd"])
+ self.delay_inst=self.add_inst(name="delay_chain",
+ mod=self.delay_chain)
+ self.connect_inst(["rbl_bl", "rbl_bl_delay", "vdd", "gnd"])
- def place_rbl(self,row):
+ def place_delay(self,row):
""" Place the replica bitline """
y_off = row * self.and2.height + 2*self.m1_pitch
# Add the RBL above the rows
# Add to the right of the control rows and routing channel
- offset = vector(0, y_off)
- self.rbl_inst.place(offset)
+ offset = vector(self.delay_chain.width, y_off)
+ self.delay_inst.place(offset, mirror="MY")
+
+ def route_delay(self):
+
+ out_pos = self.delay_inst.get_pin("out").bc()
+ # Connect to the rail level with the vdd rail
+ # Use pen since it is in every type of control logic
+ vdd_ypos = self.p_en_bar_nand_inst.get_pin("vdd").by()
+ in_pos = vector(self.rail_offsets["rbl_bl_delay"].x,vdd_ypos)
+ mid1 = vector(out_pos.x,in_pos.y)
+ self.add_wire(("metal1","via1","metal2"),[out_pos, mid1, in_pos])
+ self.add_via_center(layers=("metal1","via1","metal2"),
+ offset=in_pos)
+
+
+ # Input from RBL goes to the delay line for futher delay
+ self.copy_layout_pin(self.delay_inst, "in", "rbl_bl")
def create_clk_buf_row(self):
@@ -454,12 +497,9 @@ class control_logic(design.design):
self.connect_inst(["clk","clk_buf","vdd","gnd"])
def place_clk_buf_row(self,row):
- """ Place the multistage clock buffer below the control flops """
- x_off = self.control_x_offset
- (y_off,mirror)=self.get_offset(row)
+ x_offset = self.control_x_offset
- offset = vector(x_off,y_off)
- self.clk_buf_inst.place(offset, mirror)
+ x_offset = self.place_util(self.clk_buf_inst, x_offset, row)
self.row_end_inst.append(self.clk_buf_inst)
@@ -496,17 +536,10 @@ class control_logic(design.design):
self.connect_inst(["cs","clk_bar","gated_clk_bar","vdd","gnd"])
def place_gated_clk_bar_row(self,row):
- """ Place the gated clk logic below the control flops """
- x_off = self.control_x_offset
- (y_off,mirror)=self.get_offset(row)
+ x_offset = self.control_x_offset
- offset = vector(x_off,y_off)
- self.clk_bar_inst.place(offset, mirror)
-
- x_off += self.inv.width
-
- offset = vector(x_off,y_off)
- self.gated_clk_bar_inst.place(offset, mirror)
+ x_offset = self.place_util(self.clk_bar_inst, x_offset, row)
+ x_offset = self.place_util(self.gated_clk_bar_inst, x_offset, row)
self.row_end_inst.append(self.gated_clk_bar_inst)
@@ -540,12 +573,9 @@ class control_logic(design.design):
self.connect_inst(["clk_buf", "cs","gated_clk_buf","vdd","gnd"])
def place_gated_clk_buf_row(self,row):
- """ Place the gated clk logic below the control flops """
- x_off = self.control_x_offset
- (y_off,mirror)=self.get_offset(row)
-
- offset = vector(x_off,y_off)
- self.gated_clk_buf_inst.place(offset, mirror)
+ x_offset = self.control_x_offset
+
+ x_offset = self.place_util(self.gated_clk_buf_inst, x_offset, row)
self.row_end_inst.append(self.gated_clk_buf_inst)
@@ -567,174 +597,139 @@ class control_logic(design.design):
self.connect_inst(["gated_clk_bar", "wl_en", "vdd", "gnd"])
def place_wlen_row(self, row):
- x_off = self.control_x_offset
- (y_off,mirror)=self.get_offset(row)
-
- offset = vector(x_off, y_off)
- self.wl_en_inst.place(offset, mirror)
+ x_offset = self.control_x_offset
+
+ x_offset = self.place_util(self.wl_en_inst, x_offset, row)
self.row_end_inst.append(self.wl_en_inst)
def route_wlen(self):
wlen_map = zip(["A"], ["gated_clk_bar"])
- self.connect_vertical_bus(wlen_map, self.wl_en_inst, self.rail_offsets)
+ self.connect_vertical_bus(wlen_map, self.wl_en_inst, self.rail_offsets)
+
self.connect_output(self.wl_en_inst, "Z", "wl_en")
- def create_rbl_in_row(self):
-
- # input: gated_clk_bar, we_bar, output: rbl_in
- self.rbl_in_inst=self.add_inst(name="and2_rbl_in",
- mod=self.and2)
- self.connect_inst(["gated_clk_bar", "we_bar", "rbl_in", "vdd", "gnd"])
-
- def place_rbl_in_row(self,row):
- x_off = self.control_x_offset
- (y_off,mirror)=self.get_offset(row)
-
- offset = vector(x_off, y_off)
- self.rbl_in_inst.place(offset, mirror)
-
- self.row_end_inst.append(self.rbl_in_inst)
-
- def route_rbl_in(self):
- """ Connect the logic for the rbl_in generation """
-
- if self.port_type == "rw":
- input_name = "we_bar"
- # Connect the NAND gate inputs to the bus
- rbl_in_map = zip(["A", "B"], ["gated_clk_bar", "we_bar"])
- self.connect_vertical_bus(rbl_in_map, self.rbl_in_inst, self.rail_offsets)
-
-
- # Connect the output of the precharge enable to the RBL input
- if self.port_type == "rw":
- out_pos = self.rbl_in_inst.get_pin("Z").center()
- else:
- out_pos = vector(self.rail_offsets["gated_clk_bar"].x, self.rbl_inst.by()-3*self.m2_pitch)
- in_pos = self.rbl_inst.get_pin("en").center()
- mid1 = vector(in_pos.x,out_pos.y)
- self.add_wire(("metal3","via2","metal2"),[out_pos, mid1, in_pos])
- self.add_via_center(layers=("metal1","via1","metal2"),
- offset=out_pos,
- rotate=90)
- self.add_via_center(layers=("metal2","via2","metal3"),
- offset=out_pos,
- rotate=90)
-
def create_pen_row(self):
- if self.port_type == "rw":
- # input: gated_clk_bar, we_bar, output: pre_p_en
- self.pre_p_en_inst=self.add_inst(name="and2_pre_p_en",
- mod=self.and2)
- self.connect_inst(["gated_clk_buf", "we_bar", "pre_p_en", "vdd", "gnd"])
- input_name = "pre_p_en"
- else:
- input_name = "gated_clk_buf"
+ self.p_en_bar_nand_inst=self.add_inst(name="nand_p_en_bar",
+ mod=self.nand2)
+ self.connect_inst(["gated_clk_buf", "rbl_bl_delay", "p_en_bar_unbuf", "vdd", "gnd"])
- # input: pre_p_en, output: p_en_bar
- self.p_en_bar_inst=self.add_inst(name="inv_p_en_bar",
- mod=self.p_en_bar_driver)
- self.connect_inst([input_name, "p_en_bar", "vdd", "gnd"])
-
+ self.p_en_bar_driver_inst=self.add_inst(name="buf_p_en_bar",
+ mod=self.p_en_bar_driver)
+ self.connect_inst(["p_en_bar_unbuf", "p_en_bar", "vdd", "gnd"])
def place_pen_row(self,row):
- x_off = self.control_x_offset
- (y_off,mirror)=self.get_offset(row)
-
- if self.port_type == "rw":
- offset = vector(x_off, y_off)
- self.pre_p_en_inst.place(offset, mirror)
+ x_offset = self.control_x_offset
- x_off += self.and2.width
-
- offset = vector(x_off,y_off)
- self.p_en_bar_inst.place(offset, mirror)
+ x_offset = self.place_util(self.p_en_bar_nand_inst, x_offset, row)
+ x_offset = self.place_util(self.p_en_bar_driver_inst, x_offset, row)
- self.row_end_inst.append(self.p_en_bar_inst)
+ self.row_end_inst.append(self.p_en_bar_driver_inst)
def route_pen(self):
- if self.port_type == "rw":
- # Connect the NAND gate inputs to the bus
- pre_p_en_in_map = zip(["A", "B"], ["gated_clk_buf", "we_bar"])
- self.connect_vertical_bus(pre_p_en_in_map, self.pre_p_en_inst, self.rail_offsets)
+ in_map = zip(["A", "B"], ["gated_clk_buf", "rbl_bl_delay"])
+ self.connect_vertical_bus(in_map, self.p_en_bar_nand_inst, self.rail_offsets)
- out_pos = self.pre_p_en_inst.get_pin("Z").center()
- in_pos = self.p_en_bar_inst.get_pin("A").lc()
- mid1 = vector(out_pos.x,in_pos.y)
- self.add_wire(("metal1","via1","metal2"),[out_pos,mid1,in_pos])
- else:
- in_map = zip(["A"], ["gated_clk_buf"])
- self.connect_vertical_bus(in_map, self.p_en_bar_inst, self.rail_offsets)
+ out_pos = self.p_en_bar_nand_inst.get_pin("Z").rc()
+ in_pos = self.p_en_bar_driver_inst.get_pin("A").lc()
+ mid1 = vector(out_pos.x,in_pos.y)
+ self.add_wire(("metal1","via1","metal2"),[out_pos, mid1,in_pos])
- self.connect_output(self.p_en_bar_inst, "Z", "p_en_bar")
+ self.connect_output(self.p_en_bar_driver_inst, "Z", "p_en_bar")
def create_sen_row(self):
""" Create the sense enable buffer. """
- # BUFFER FOR S_EN
- # input: pre_s_en, output: s_en
- self.s_en_inst=self.add_inst(name="buf_s_en",
- mod=self.s_en_driver)
- self.connect_inst(["pre_s_en", "s_en", "vdd", "gnd"])
+ if self.port_type=="rw":
+ input_name = "we_bar"
+ else:
+ input_name = "cs_bar"
+ # GATE FOR S_EN
+ self.s_en_gate_inst = self.add_inst(name="buf_s_en_and",
+ mod=self.sen_and3)
+ self.connect_inst(["rbl_bl_delay", "gated_clk_bar", input_name, "s_en", "vdd", "gnd"])
+
def place_sen_row(self,row):
- """
- The sense enable buffer gets placed to the far right of the
- row.
- """
- x_off = self.control_x_offset
- (y_off,mirror)=self.get_offset(row)
+ x_offset = self.control_x_offset
- offset = vector(x_off, y_off)
- self.s_en_inst.place(offset, mirror)
+ x_offset = self.place_util(self.s_en_gate_inst, x_offset, row)
- self.row_end_inst.append(self.s_en_inst)
+ self.row_end_inst.append(self.s_en_gate_inst)
def route_sen(self):
-
- out_pos = self.rbl_inst.get_pin("out").bc()
- in_pos = self.s_en_inst.get_pin("A").lc()
- mid1 = vector(out_pos.x,in_pos.y)
- self.add_wire(("metal1","via1","metal2"),[out_pos, mid1,in_pos])
- self.connect_output(self.s_en_inst, "Z", "s_en")
+ if self.port_type=="rw":
+ input_name = "we_bar"
+ else:
+ input_name = "cs_bar"
+
+ sen_map = zip(["A", "B", "C"], ["rbl_bl_delay", "gated_clk_bar", input_name])
+ self.connect_vertical_bus(sen_map, self.s_en_gate_inst, self.rail_offsets)
+ self.connect_output(self.s_en_gate_inst, "Z", "s_en")
+
+
+ def create_rbl_delay_row(self):
+
+ self.rbl_bl_delay_inv_inst = self.add_inst(name="rbl_bl_delay_inv",
+ mod=self.inv)
+ self.connect_inst(["rbl_bl_delay", "rbl_bl_delay_bar", "vdd", "gnd"])
+
+ def place_rbl_delay_row(self,row):
+ x_offset = self.control_x_offset
+
+ x_offset = self.place_util(self.rbl_bl_delay_inv_inst, x_offset, row)
+
+ self.row_end_inst.append(self.rbl_bl_delay_inv_inst)
+
+ def route_rbl_delay(self):
+ # Connect from delay line
+ # Connect to rail
+
+ rbl_map = zip(["Z"], ["rbl_bl_delay_bar"])
+ self.connect_vertical_bus(rbl_map, self.rbl_bl_delay_inv_inst, self.rail_offsets, ("metal3", "via2", "metal2"))
+ # The pin is on M1, so we need another via as well
+ self.add_via_center(layers=("metal1","via1","metal2"),
+ offset=self.rbl_bl_delay_inv_inst.get_pin("Z").center())
+
+
+ rbl_map = zip(["A"], ["rbl_bl_delay"])
+ self.connect_vertical_bus(rbl_map, self.rbl_bl_delay_inv_inst, self.rail_offsets)
def create_wen_row(self):
+
# input: we (or cs) output: w_en
if self.port_type == "rw":
input_name = "we"
else:
# No we for write-only reports, so use cs
input_name = "cs"
-
- # BUFFER FOR W_EN
- self.w_en_inst = self.add_inst(name="buf_w_en_buf",
- mod=self.w_en_driver)
- self.connect_inst([input_name, "w_en", "vdd", "gnd"])
+ # GATE THE W_EN
+ self.w_en_gate_inst = self.add_inst(name="w_en_and",
+ mod=self.wen_and)
+ self.connect_inst([input_name, "rbl_bl_delay_bar", "gated_clk_bar", "w_en", "vdd", "gnd"])
+
def place_wen_row(self,row):
- x_off = self.ctrl_dff_inst.width + self.internal_bus_width
- (y_off,mirror)=self.get_offset(row)
-
- offset = vector(x_off, y_off)
- self.w_en_inst.place(offset, mirror)
+ x_offset = self.control_x_offset
+
+ x_offset = self.place_util(self.w_en_gate_inst, x_offset, row)
- self.row_end_inst.append(self.w_en_inst)
+ self.row_end_inst.append(self.w_en_gate_inst)
def route_wen(self):
-
if self.port_type == "rw":
input_name = "we"
else:
# No we for write-only reports, so use cs
input_name = "cs"
- wen_map = zip(["A"], [input_name])
- self.connect_vertical_bus(wen_map, self.w_en_inst, self.rail_offsets)
+ wen_map = zip(["A", "B", "C"], [input_name, "rbl_bl_delay_bar", "gated_clk_bar"])
+ self.connect_vertical_bus(wen_map, self.w_en_gate_inst, self.rail_offsets)
- self.connect_output(self.w_en_inst, "Z", "w_en")
+ self.connect_output(self.w_en_gate_inst, "Z", "w_en")
def create_dffs(self):
self.ctrl_dff_inst=self.add_inst(name="ctrl_dffs",
@@ -746,7 +741,7 @@ class control_logic(design.design):
def route_dffs(self):
if self.port_type == "rw":
- dff_out_map = zip(["dout_bar_0", "dout_bar_1", "dout_1"], ["cs", "we", "we_bar"])
+ dff_out_map = zip(["dout_bar_0", "dout_bar_1", "dout_1"], ["cs", "we", "we_bar"])
elif self.port_type == "r":
dff_out_map = zip(["dout_bar_0", "dout_0"], ["cs", "cs_bar"])
else:
@@ -759,8 +754,7 @@ class control_logic(design.design):
rail_pos = vector(self.rail_offsets["clk_buf"].x, mid_pos.y)
self.add_wire(("metal1","via1","metal2"),[in_pos, mid_pos, rail_pos])
self.add_via_center(layers=("metal1","via1","metal2"),
- offset=rail_pos,
- rotate=90)
+ offset=rail_pos)
self.copy_layout_pin(self.ctrl_dff_inst, "din_0", "csb")
if (self.port_type == "rw"):
@@ -811,9 +805,8 @@ class control_logic(design.design):
self.add_power_pin("gnd", pin_loc)
self.add_path("metal1", [row_loc, pin_loc])
- if (self.port_type == "rw") or (self.port_type == "r"):
- self.copy_layout_pin(self.rbl_inst,"gnd")
- self.copy_layout_pin(self.rbl_inst,"vdd")
+ self.copy_layout_pin(self.delay_inst,"gnd")
+ self.copy_layout_pin(self.delay_inst,"vdd")
self.copy_layout_pin(self.ctrl_dff_inst,"gnd")
self.copy_layout_pin(self.ctrl_dff_inst,"vdd")
@@ -839,7 +832,7 @@ class control_logic(design.design):
# height=pin.height(),
# width=pin.width())
- pin=self.rbl_inst.get_pin("out")
+ pin=self.delay_inst.get_pin("out")
self.add_label_pin(text="out",
layer=pin.layer,
offset=pin.ll(),
@@ -850,14 +843,14 @@ class control_logic(design.design):
def get_delays_to_wl(self):
"""Get the delay (in delay units) of the clk to a wordline in the bitcell array"""
debug.check(self.sram.all_mods_except_control_done, "Cannot calculate sense amp enable delay unless all module have been added.")
- self.wl_stage_efforts = self.determine_wordline_stage_efforts()
- clk_to_wl_rise,clk_to_wl_fall = logical_effort.calculate_relative_rise_fall_delays(self.wl_stage_efforts, self.parasitic_inv_delay)
+ self.wl_stage_efforts = self.get_wordline_stage_efforts()
+ clk_to_wl_rise,clk_to_wl_fall = logical_effort.calculate_relative_rise_fall_delays(self.wl_stage_efforts)
total_delay = clk_to_wl_rise + clk_to_wl_fall
debug.info(1, "Clock to wl delay is rise={:.3f}, fall={:.3f}, total={:.3f} in delay units".format(clk_to_wl_rise, clk_to_wl_fall,total_delay))
return clk_to_wl_rise,clk_to_wl_fall
- def determine_wordline_stage_efforts(self):
+ def get_wordline_stage_efforts(self):
"""Follows the gated_clk_bar -> wl_en -> wordline signal for the total path efforts"""
stage_effort_list = []
@@ -871,7 +864,7 @@ class control_logic(design.design):
last_stage_is_rise = stage_effort_list[-1].is_rise
#Then ask the sram for the other path delays (from the bank)
- stage_effort_list += self.sram.determine_wordline_stage_efforts(last_stage_is_rise)
+ stage_effort_list += self.sram.get_wordline_stage_efforts(last_stage_is_rise)
return stage_effort_list
@@ -880,17 +873,15 @@ class control_logic(design.design):
This does not incorporate the delay of the replica bitline.
"""
debug.check(self.sram.all_mods_except_control_done, "Cannot calculate sense amp enable delay unless all module have been added.")
- self.sen_stage_efforts = self.determine_sa_enable_stage_efforts()
- clk_to_sen_rise, clk_to_sen_fall = logical_effort.calculate_relative_rise_fall_delays(self.sen_stage_efforts, self.parasitic_inv_delay)
+ self.sen_stage_efforts = self.get_sa_enable_stage_efforts()
+ clk_to_sen_rise, clk_to_sen_fall = logical_effort.calculate_relative_rise_fall_delays(self.sen_stage_efforts)
total_delay = clk_to_sen_rise + clk_to_sen_fall
debug.info(1, "Clock to s_en delay is rise={:.3f}, fall={:.3f}, total={:.3f} in delay units".format(clk_to_sen_rise, clk_to_sen_fall,total_delay))
return clk_to_sen_rise, clk_to_sen_fall
- def determine_sa_enable_stage_efforts(self):
+ def get_sa_enable_stage_efforts(self):
"""Follows the gated_clk_bar signal to the sense amp enable signal adding each stages stage effort to a list"""
stage_effort_list = []
- #Calculate the load on clk_buf_bar
- ext_clk_buf_cout = self.sram.get_clk_bar_cin()
#Initial direction of clock signal for this path
last_stage_rise = True
@@ -902,7 +893,7 @@ class control_logic(design.design):
last_stage_rise = stage_effort_list[-1].is_rise
#Replica bitline stage, rbl_in -(rbl)-> pre_s_en
- stage2_cout = self.s_en_driver.get_cin()
+ stage2_cout = self.sen_and2.get_cin()
stage_effort_list += self.replica_bitline.determine_sen_stage_efforts(stage2_cout, last_stage_rise)
last_stage_rise = stage_effort_list[-1].is_rise
@@ -915,9 +906,77 @@ class control_logic(design.design):
def get_wl_sen_delays(self):
"""Gets a list of the stages and delays in order of their path."""
+
if self.sen_stage_efforts == None or self.wl_stage_efforts == None:
debug.error("Model delays not calculated for SRAM.", 1)
- wl_delays = logical_effort.calculate_delays(self.wl_stage_efforts, self.parasitic_inv_delay)
- sen_delays = logical_effort.calculate_delays(self.sen_stage_efforts, self.parasitic_inv_delay)
+ wl_delays = logical_effort.calculate_delays(self.wl_stage_efforts)
+ sen_delays = logical_effort.calculate_delays(self.sen_stage_efforts)
return wl_delays, sen_delays
+ def analytical_delay(self, corner, slew, load):
+ """Gets the analytical delay from clk input to wl_en output"""
+
+ stage_effort_list = []
+ #Calculate the load on clk_buf_bar
+ ext_clk_buf_cout = self.sram.get_clk_bar_cin()
+
+ #Operations logic starts on negative edge
+ last_stage_rise = False
+
+ #First stage(s), clk -(pdriver)-> clk_buf.
+ #clk_buf_cout = self.replica_bitline.get_en_cin()
+ clk_buf_cout = 0
+ stage_effort_list += self.clk_buf_driver.get_stage_efforts(clk_buf_cout, last_stage_rise)
+ last_stage_rise = stage_effort_list[-1].is_rise
+
+ #Second stage, clk_buf -(inv)-> clk_bar
+ clk_bar_cout = self.and2.get_cin()
+ stage_effort_list += self.and2.get_stage_efforts(clk_bar_cout, last_stage_rise)
+ last_stage_rise = stage_effort_list[-1].is_rise
+
+ #Third stage clk_bar -(and)-> gated_clk_bar
+ gated_clk_bar_cin = self.get_gated_clk_bar_cin()
+ stage_effort_list.append(self.inv.get_stage_effort(gated_clk_bar_cin, last_stage_rise))
+ last_stage_rise = stage_effort_list[-1].is_rise
+
+ #Stages from gated_clk_bar -------> wordline
+ stage_effort_list += self.get_wordline_stage_efforts()
+ return stage_effort_list
+
+ def get_clk_buf_cin(self):
+ """
+ Get the loads that are connected to the buffered clock.
+ Includes all the DFFs and some logic.
+ """
+
+ #Control logic internal load
+ int_clk_buf_cap = self.inv.get_cin() + self.ctrl_dff_array.get_clk_cin() + self.and2.get_cin()
+
+ #Control logic external load (in the other parts of the SRAM)
+ ext_clk_buf_cap = self.sram.get_clk_bar_cin()
+
+ return int_clk_buf_cap + ext_clk_buf_cap
+
+ def get_gated_clk_bar_cin(self):
+ """Get intermediates net gated_clk_bar's capacitance"""
+
+ total_cin = 0
+ total_cin += self.wl_en_driver.get_cin()
+ if self.port_type == 'rw':
+ total_cin +=self.and2.get_cin()
+ return total_cin
+
+ def graph_exclude_dffs(self):
+ """Exclude dffs from graph as they do not represent critical path"""
+
+ self.graph_inst_exclude.add(self.ctrl_dff_inst)
+ if self.port_type=="rw" or self.port_type=="w":
+ self.graph_inst_exclude.add(self.w_en_gate_inst)
+
+ def place_util(self, inst, x_offset, row):
+ """ Utility to place a row and compute the next offset """
+
+ (y_offset,mirror)=self.get_offset(row)
+ offset = vector(x_offset, y_offset)
+ inst.place(offset, mirror)
+ return x_offset+inst.width
diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py
index f3d15ba3..bc932a26 100644
--- a/compiler/modules/delay_chain.py
+++ b/compiler/modules/delay_chain.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
import design
from tech import drc
@@ -45,14 +52,15 @@ class delay_chain(design.design):
self.place_inverters()
self.route_inverters()
self.add_layout_pins()
+ self.add_boundary()
self.DRC_LVS()
-
+
def add_pins(self):
""" Add the pins of the delay chain"""
- self.add_pin("in")
- self.add_pin("out")
- self.add_pin("vdd")
- self.add_pin("gnd")
+ self.add_pin("in", "INPUT")
+ self.add_pin("out", "OUTPUT")
+ self.add_pin("vdd", "POWER")
+ self.add_pin("gnd", "GROUND")
def add_modules(self):
self.inv = factory.create(module_type="pinv", route_output=False)
diff --git a/compiler/modules/dff.py b/compiler/modules/dff.py
index 753ae41a..3cb1bcf1 100644
--- a/compiler/modules/dff.py
+++ b/compiler/modules/dff.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import globals
import design
from math import log
@@ -11,6 +18,7 @@ class dff(design.design):
"""
pin_names = ["D", "Q", "clk", "vdd", "gnd"]
+ type_list = ["INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("dff", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "dff", GDS["unit"])
@@ -20,13 +28,14 @@ class dff(design.design):
self.width = dff.width
self.height = dff.height
self.pin_map = dff.pin_map
+ self.add_pin_types(self.type_list)
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
c_eff = self.calculate_effective_capacitance(load)
- freq = spice["default_event_rate"]
+ freq = spice["default_event_frequency"]
power_dyn = self.calc_dynamic_power(corner, c_eff, freq)
- power_leak = spice["msflop_leakage"]
+ power_leak = spice["dff_leakage"]
total_power = self.return_power(power_dyn, power_leak)
return total_power
@@ -35,18 +44,17 @@ class dff(design.design):
"""Computes effective capacitance. Results in fF"""
from tech import parameter
c_load = load
- c_para = spice["flop_para_cap"]#ff
- transition_prob = spice["flop_transition_prob"]
+ c_para = spice["dff_out_cap"]#ff
+ transition_prob = 0.5
return transition_prob*(c_load + c_para)
- def analytical_delay(self, corner, slew, load = 0.0):
- # dont know how to calculate this now, use constant in tech file
- result = self.return_delay(spice["dff_delay"], spice["dff_slew"])
- return result
-
def get_clk_cin(self):
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff"""
#This is a handmade cell so the value must be entered in the tech.py file or estimated.
#Calculated in the tech file by summing the widths of all the gates and dividing by the minimum width.
return parameter["dff_clk_cin"]
+ def build_graph(self, graph, inst_name, port_nets):
+ """Adds edges based on inputs/outputs. Overrides base class function."""
+ self.add_graph_edges(graph, port_nets)
+
diff --git a/compiler/modules/dff_array.py b/compiler/modules/dff_array.py
index 9d11b811..89b29476 100644
--- a/compiler/modules/dff_array.py
+++ b/compiler/modules/dff_array.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
import design
from tech import drc
@@ -37,6 +44,7 @@ class dff_array(design.design):
self.place_dff_array()
self.add_layout_pins()
+ self.add_boundary()
self.DRC_LVS()
def add_modules(self):
@@ -46,13 +54,13 @@ class dff_array(design.design):
def add_pins(self):
for row in range(self.rows):
for col in range(self.columns):
- self.add_pin(self.get_din_name(row,col))
+ self.add_pin(self.get_din_name(row,col), "INPUT")
for row in range(self.rows):
for col in range(self.columns):
- self.add_pin(self.get_dout_name(row,col))
- self.add_pin("clk")
- self.add_pin("vdd")
- self.add_pin("gnd")
+ self.add_pin(self.get_dout_name(row,col), "OUTPUT")
+ self.add_pin("clk", "INPUT")
+ self.add_pin("vdd", "POWER")
+ self.add_pin("gnd", "GROUND")
def create_dff_array(self):
self.dff_insts={}
@@ -152,11 +160,6 @@ class dff_array(design.design):
self.add_via_center(layers=("metal2","via2","metal3"),
offset=vector(clk_pin.cx(),clk_ypos))
-
-
- def analytical_delay(self, corner, slew, load=0.0):
- return self.dff.analytical_delay(corner, slew=slew, load=load)
-
def get_clk_cin(self):
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
dff_clk_cin = self.dff.get_clk_cin()
diff --git a/compiler/modules/dff_buf.py b/compiler/modules/dff_buf.py
index fa3285ba..f6fc1cf2 100644
--- a/compiler/modules/dff_buf.py
+++ b/compiler/modules/dff_buf.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
import design
from tech import drc,parameter
@@ -48,6 +55,7 @@ class dff_buf(design.design):
self.place_instances()
self.route_wires()
self.add_layout_pins()
+ self.add_boundary()
self.DRC_LVS()
def add_modules(self):
@@ -67,12 +75,12 @@ class dff_buf(design.design):
def add_pins(self):
- self.add_pin("D")
- self.add_pin("Q")
- self.add_pin("Qb")
- self.add_pin("clk")
- self.add_pin("vdd")
- self.add_pin("gnd")
+ self.add_pin("D", "INPUT")
+ self.add_pin("Q", "OUTPUT")
+ self.add_pin("Qb", "OUTPUT")
+ self.add_pin("clk", "INPUT")
+ self.add_pin("vdd", "POWER")
+ self.add_pin("gnd", "GROUND")
def create_instances(self):
self.dff_inst=self.add_inst(name="dff_buf_dff",
@@ -169,16 +177,7 @@ class dff_buf(design.design):
self.add_path("metal1", [self.mid_qb_pos, qb_pos])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=qb_pos)
-
-
-
- def analytical_delay(self, corner, slew, load=0.0):
- """ Calculate the analytical delay of DFF-> INV -> INV """
- dff_delay=self.dff.analytical_delay(corner, slew=slew, load=self.inv1.input_load())
- inv1_delay = self.inv1.analytical_delay(corner, slew=dff_delay.slew, load=self.inv2.input_load())
- inv2_delay = self.inv2.analytical_delay(corner, slew=inv1_delay.slew, load=load)
- return dff_delay + inv1_delay + inv2_delay
-
+
def get_clk_cin(self):
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff"""
#This is a handmade cell so the value must be entered in the tech.py file or estimated.
diff --git a/compiler/modules/dff_buf_array.py b/compiler/modules/dff_buf_array.py
index 56b20dfb..2fafee76 100644
--- a/compiler/modules/dff_buf_array.py
+++ b/compiler/modules/dff_buf_array.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
import design
from tech import drc
@@ -42,19 +49,20 @@ class dff_buf_array(design.design):
self.height = self.rows * self.dff.height
self.place_dff_array()
self.add_layout_pins()
+ self.add_boundary()
self.DRC_LVS()
def add_pins(self):
for row in range(self.rows):
for col in range(self.columns):
- self.add_pin(self.get_din_name(row,col))
+ self.add_pin(self.get_din_name(row,col), "INPUT")
for row in range(self.rows):
for col in range(self.columns):
- self.add_pin(self.get_dout_name(row,col))
- self.add_pin(self.get_dout_bar_name(row,col))
- self.add_pin("clk")
- self.add_pin("vdd")
- self.add_pin("gnd")
+ self.add_pin(self.get_dout_name(row,col), "OUTPUT")
+ self.add_pin(self.get_dout_bar_name(row,col), "OUTPUT")
+ self.add_pin("clk", "INPUT")
+ self.add_pin("vdd", "POWER")
+ self.add_pin("gnd", "GROUND")
def add_modules(self):
self.dff = factory.create(module_type="dff_buf",
@@ -185,11 +193,6 @@ class dff_buf_array(design.design):
self.add_via_center(layers=("metal2","via2","metal3"),
offset=vector(clk_pin.cx(),clk_ypos))
-
-
- def analytical_delay(self, corner, slew, load=0.0):
- return self.dff.analytical_delay(slew=slew, load=load)
-
def get_clk_cin(self):
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
dff_clk_cin = self.dff.get_clk_cin()
diff --git a/compiler/modules/dff_inv.py b/compiler/modules/dff_inv.py
index 9b901d3b..207a5ad0 100644
--- a/compiler/modules/dff_inv.py
+++ b/compiler/modules/dff_inv.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
import design
from tech import drc
@@ -46,6 +53,7 @@ class dff_inv(design.design):
self.add_wires()
self.add_layout_pins()
+ self.add_boundary()
self.DRC_LVS()
def add_pins(self):
@@ -142,15 +150,7 @@ class dff_inv(design.design):
offset=dout_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=dout_pin.center())
-
-
-
- def analytical_delay(self, corner, slew, load=0.0):
- """ Calculate the analytical delay of DFF-> INV -> INV """
- dff_delay=self.dff.analytical_delay(corner, slew=slew, load=self.inv1.input_load())
- inv1_delay = self.inv1.analytical_delay(corner, slew=dff_delay.slew, load=load)
- return dff_delay + inv1_delay
-
+
def get_clk_cin(self):
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff"""
return self.dff.get_clk_cin()
diff --git a/compiler/modules/dff_inv_array.py b/compiler/modules/dff_inv_array.py
index 624e13d0..760a2337 100644
--- a/compiler/modules/dff_inv_array.py
+++ b/compiler/modules/dff_inv_array.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
import design
from tech import drc
@@ -42,6 +49,7 @@ class dff_inv_array(design.design):
self.place_dff_array()
self.add_layout_pins()
+ self.add_boundary()
self.DRC_LVS()
def add_modules(self):
@@ -51,14 +59,14 @@ class dff_inv_array(design.design):
def add_pins(self):
for row in range(self.rows):
for col in range(self.columns):
- self.add_pin(self.get_din_name(row,col))
+ self.add_pin(self.get_din_name(row,col), "INPUT")
for row in range(self.rows):
for col in range(self.columns):
- self.add_pin(self.get_dout_name(row,col))
- self.add_pin(self.get_dout_bar_name(row,col))
- self.add_pin("clk")
- self.add_pin("vdd")
- self.add_pin("gnd")
+ self.add_pin(self.get_dout_name(row,col), "OUTPUT")
+ self.add_pin(self.get_dout_bar_name(row,col), "OUTPUT")
+ self.add_pin("clk", "INPUT")
+ self.add_pin("vdd", "POWER")
+ self.add_pin("gnd", "GROUND")
def create_dff_array(self):
self.dff_insts={}
@@ -182,12 +190,6 @@ class dff_inv_array(design.design):
self.add_via_center(layers=("metal2","via2","metal3"),
offset=vector(clk_pin.cx(),clk_ypos))
-
-
-
- def analytical_delay(self, corner, slew, load=0.0):
- return self.dff.analytical_delay(corner, slew=slew, load=load)
-
def get_clk_cin(self):
"""Return the total capacitance (in relative units) that the clock is loaded by in the dff array"""
dff_clk_cin = self.dff.get_clk_cin()
diff --git a/compiler/modules/dummy_array.py b/compiler/modules/dummy_array.py
new file mode 100644
index 00000000..f1f433ce
--- /dev/null
+++ b/compiler/modules/dummy_array.py
@@ -0,0 +1,157 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California
+# All rights reserved.
+#
+import debug
+import design
+from tech import drc
+import contact
+from sram_factory import factory
+from vector import vector
+from globals import OPTS
+
+class dummy_array(design.design):
+ """
+ Generate a dummy row/column for the replica array.
+ """
+ def __init__(self, cols, rows, mirror=0, name=""):
+ design.design.__init__(self, name)
+ debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
+ self.add_comment("rows: {0} cols: {1}".format(rows, cols))
+
+ self.column_size = cols
+ self.row_size = rows
+ self.mirror = mirror
+
+ self.create_netlist()
+ if not OPTS.netlist_only:
+ self.create_layout()
+
+
+ def create_netlist(self):
+ """ Create and connect the netlist """
+ self.add_modules()
+ self.add_pins()
+ self.create_instances()
+
+ def create_layout(self):
+
+ # We increase it by a well enclosure so the precharges don't overlap our wells
+ self.height = self.row_size*self.dummy_cell.height
+ self.width = self.column_size*self.dummy_cell.width
+
+ xoffset = 0.0
+ for col in range(self.column_size):
+ yoffset = 0.0
+ for row in range(self.row_size):
+ name = "dummy_r{0}_c{1}".format(row, col)
+
+ if (row+self.mirror) % 2:
+ tempy = yoffset + self.dummy_cell.height
+ dir_key = "MX"
+ else:
+ tempy = yoffset
+ dir_key = ""
+
+ self.cell_inst[row,col].place(offset=[xoffset, tempy],
+ mirror=dir_key)
+ yoffset += self.dummy_cell.height
+ xoffset += self.dummy_cell.width
+
+ self.add_layout_pins()
+
+ self.add_boundary()
+
+ self.DRC_LVS()
+
+ def add_pins(self):
+ row_list = self.cell.get_all_wl_names()
+ column_list = self.cell.get_all_bitline_names()
+ for col in range(self.column_size):
+ for cell_column in column_list:
+ self.add_pin(cell_column+"_{0}".format(col), "INOUT")
+ for row in range(self.row_size):
+ for cell_row in row_list:
+ self.add_pin(cell_row+"_{0}".format(row), "INPUT")
+ self.add_pin("vdd", "POWER")
+ self.add_pin("gnd", "GROUND")
+
+ def add_modules(self):
+ """ Add the modules used in this design """
+ self.dummy_cell = factory.create(module_type="dummy_bitcell")
+ self.add_mod(self.dummy_cell)
+
+ self.cell = factory.create(module_type="bitcell")
+
+ def get_bitcell_pins(self, col, row):
+ """ Creates a list of connections in the bitcell,
+ indexed by column and row, for instance use in bitcell_array """
+
+ bitcell_pins = []
+
+ pin_names = self.cell.get_all_bitline_names()
+ for pin in pin_names:
+ bitcell_pins.append(pin+"_{0}".format(col))
+ pin_names = self.cell.get_all_wl_names()
+ for pin in pin_names:
+ bitcell_pins.append(pin+"_{0}".format(row))
+ bitcell_pins.append("vdd")
+ bitcell_pins.append("gnd")
+
+ return bitcell_pins
+
+
+ def create_instances(self):
+ """ Create the module instances used in this design """
+ self.cell_inst = {}
+ for col in range(self.column_size):
+ for row in range(self.row_size):
+ name = "bit_r{0}_c{1}".format(row, col)
+ self.cell_inst[row,col]=self.add_inst(name=name,
+ mod=self.dummy_cell)
+ self.connect_inst(self.get_bitcell_pins(col, row))
+
+ def add_layout_pins(self):
+ """ Add the layout pins """
+
+ row_list = self.cell.get_all_wl_names()
+ column_list = self.cell.get_all_bitline_names()
+
+ for col in range(self.column_size):
+ for cell_column in column_list:
+ bl_pin = self.cell_inst[0,col].get_pin(cell_column)
+ self.add_layout_pin(text=cell_column+"_{0}".format(col),
+ layer="metal2",
+ offset=bl_pin.ll(),
+ width=bl_pin.width(),
+ height=self.height)
+
+ for row in range(self.row_size):
+ for cell_row in row_list:
+ wl_pin = self.cell_inst[row,0].get_pin(cell_row)
+ self.add_layout_pin(text=cell_row+"_{0}".format(row),
+ layer="metal1",
+ offset=wl_pin.ll(),
+ width=self.width,
+ height=wl_pin.height())
+
+ # For every second row and column, add a via for gnd and vdd
+ for row in range(self.row_size):
+ for col in range(self.column_size):
+ inst = self.cell_inst[row,col]
+ for pin_name in ["vdd", "gnd"]:
+ for pin in inst.get_pins(pin_name):
+ self.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer)
+
+
+ def input_load(self):
+ wl_wire = self.gen_wl_wire()
+ return wl_wire.return_input_cap()
+
+ def get_wordline_cin(self):
+ """Get the relative input capacitance from the wordline connections in all the bitcell"""
+ #A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns
+ bitcell_wl_cin = self.cell.get_wl_cin()
+ total_cin = bitcell_wl_cin * self.column_size
+ return total_cin
diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py
index bd17b37e..0e70db55 100644
--- a/compiler/modules/hierarchical_decoder.py
+++ b/compiler/modules/hierarchical_decoder.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
from tech import drc
import debug
import design
@@ -47,6 +54,7 @@ class hierarchical_decoder(design.design):
self.route_predecode_rails()
self.route_vdd_gnd()
self.offset_all_coordinates()
+ self.add_boundary()
self.DRC_LVS()
def add_modules(self):
@@ -213,11 +221,9 @@ class hierarchical_decoder(design.design):
""" Route a vertical M2 coordinate to another vertical M2 coordinate to the predecode inputs """
self.add_via_center(layers=("metal2", "via2", "metal3"),
- offset=input_offset,
- rotate=90)
+ offset=input_offset)
self.add_via_center(layers=("metal2", "via2", "metal3"),
- offset=output_offset,
- rotate=90)
+ offset=output_offset)
self.add_path(("metal3"), [input_offset, output_offset])
@@ -225,12 +231,12 @@ class hierarchical_decoder(design.design):
""" Add the module pins """
for i in range(self.num_inputs):
- self.add_pin("addr_{0}".format(i))
+ self.add_pin("addr_{0}".format(i), "INPUT")
for j in range(self.rows):
- self.add_pin("decode_{0}".format(j))
- self.add_pin("vdd")
- self.add_pin("gnd")
+ self.add_pin("decode_{0}".format(j), "OUTPUT")
+ self.add_pin("vdd", "POWER")
+ self.add_pin("gnd", "GROUND")
def create_pre_decoder(self):
@@ -575,8 +581,7 @@ class hierarchical_decoder(design.design):
rail_pos = vector(self.predecode_rails[rail_name].x,pin.lc().y)
self.add_path("metal1", [rail_pos, pin.lc()])
self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=rail_pos,
- rotate=90)
+ offset=rail_pos)
def route_predecode_rail_m3(self, rail_name, pin):
@@ -586,38 +591,15 @@ class hierarchical_decoder(design.design):
mid_point = vector(pin.cx(), pin.cy()+self.inv.height/2)
rail_pos = vector(self.predecode_rails[rail_name].x,mid_point.y)
self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=pin.center(),
- rotate=90)
+ offset=pin.center())
self.add_wire(("metal3","via2","metal2"), [rail_pos, mid_point, pin.uc()])
self.add_via_center(layers=("metal2", "via2", "metal3"),
- offset=rail_pos,
- rotate=90)
+ offset=rail_pos)
-
- def analytical_delay(self, corner, slew, load = 0.0):
- # A -> out
- if self.determine_predecodes(self.num_inputs)[1]==0:
- pre = self.pre2_4
- nand = self.nand2
- else:
- pre = self.pre3_8
- nand = self.nand3
- a_t_out_delay = pre.analytical_delay(corner, slew=slew,load = nand.input_load())
-
- # out -> z
- out_t_z_delay = nand.analytical_delay(corner, slew= a_t_out_delay.slew,
- load = self.inv.input_load())
- result = a_t_out_delay + out_t_z_delay
-
- # Z -> decode_out
- z_t_decodeout_delay = self.inv.analytical_delay(corner, slew = out_t_z_delay.slew , load = load)
- result = result + z_t_decodeout_delay
- return result
-
-
def input_load(self):
if self.determine_predecodes(self.num_inputs)[1]==0:
pre = self.pre2_4
else:
pre = self.pre3_8
return pre.input_load()
+
diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py
index 147c3018..bec0ce06 100644
--- a/compiler/modules/hierarchical_predecode.py
+++ b/compiler/modules/hierarchical_predecode.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
import design
import math
@@ -19,11 +26,11 @@ class hierarchical_predecode(design.design):
def add_pins(self):
for k in range(self.number_of_inputs):
- self.add_pin("in_{0}".format(k))
+ self.add_pin("in_{0}".format(k), "INPUT")
for i in range(self.number_of_outputs):
- self.add_pin("out_{0}".format(i))
- self.add_pin("vdd")
- self.add_pin("gnd")
+ self.add_pin("out_{0}".format(i), "OUTPUT")
+ self.add_pin("vdd", "POWER")
+ self.add_pin("gnd", "GROUND")
def add_modules(self):
""" Add the INV and NAND gate modules """
@@ -178,11 +185,9 @@ class hierarchical_predecode(design.design):
a_pos = vector(self.decode_rails[a_pin].x,y_offset)
self.add_path("metal1",[in_pos, a_pos])
self.add_via_center(layers = ("metal1", "via1", "metal2"),
- offset=[self.input_rails[in_pin].x, y_offset],
- rotate=90)
+ offset=[self.input_rails[in_pin].x, y_offset])
self.add_via_center(layers = ("metal1", "via1", "metal2"),
- offset=[self.decode_rails[a_pin].x, y_offset],
- rotate=90)
+ offset=[self.decode_rails[a_pin].x, y_offset])
def route_output_inverters(self):
"""
@@ -223,8 +228,7 @@ class hierarchical_predecode(design.design):
rail_pos = vector(self.decode_rails[out_pin].x,y_offset)
self.add_path("metal1", [inv_out_pos, right_pos, vector(right_pos.x, y_offset), rail_pos])
self.add_via_center(layers = ("metal1", "via1", "metal2"),
- offset=rail_pos,
- rotate=90)
+ offset=rail_pos)
#route input
@@ -232,8 +236,7 @@ class hierarchical_predecode(design.design):
in_pos = vector(self.input_rails[in_pin].x,inv_in_pos.y)
self.add_path("metal1", [in_pos, inv_in_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=in_pos,
- rotate=90)
+ offset=in_pos)
def route_nand_to_rails(self):
@@ -254,8 +257,8 @@ class hierarchical_predecode(design.design):
rail_pos = vector(self.decode_rails[rail_pin].x, pin_pos.y)
self.add_path("metal1", [rail_pos, pin_pos])
self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=rail_pos,
- rotate=90)
+ offset=rail_pos)
+
diff --git a/compiler/modules/hierarchical_predecode2x4.py b/compiler/modules/hierarchical_predecode2x4.py
index f50a43c1..f05f54b0 100644
--- a/compiler/modules/hierarchical_predecode2x4.py
+++ b/compiler/modules/hierarchical_predecode2x4.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
from tech import drc
import debug
import design
@@ -40,6 +47,7 @@ class hierarchical_predecode2x4(hierarchical_predecode):
self.place_output_inverters()
self.place_nand_array()
self.route()
+ self.add_boundary()
self.DRC_LVS()
def get_nand_input_line_combination(self):
@@ -48,21 +56,4 @@ class hierarchical_predecode2x4(hierarchical_predecode):
["A_0", "Abar_1"],
["Abar_0", "A_1"],
["A_0", "A_1"]]
- return combination
-
-
- def analytical_delay(self, corner, slew, load = 0.0 ):
- # in -> inbar
- a_t_b_delay = self.inv.analytical_delay(corner, slew=slew, load=self.nand.input_load())
-
- # inbar -> z
- b_t_z_delay = self.nand.analytical_delay(corner, slew=a_t_b_delay.slew, load=self.inv.input_load())
-
- # Z -> out
- a_t_out_delay = self.inv.analytical_delay(corner, slew=b_t_z_delay.slew, load=load)
-
- return a_t_b_delay + b_t_z_delay + a_t_out_delay
-
-
- def input_load(self):
- return self.nand.input_load()
+ return combination
\ No newline at end of file
diff --git a/compiler/modules/hierarchical_predecode3x8.py b/compiler/modules/hierarchical_predecode3x8.py
index 820427c7..20b629bb 100644
--- a/compiler/modules/hierarchical_predecode3x8.py
+++ b/compiler/modules/hierarchical_predecode3x8.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
from tech import drc
import debug
import design
@@ -45,6 +52,7 @@ class hierarchical_predecode3x8(hierarchical_predecode):
self.place_output_inverters()
self.place_nand_array()
self.route()
+ self.add_boundary()
self.DRC_LVS()
def get_nand_input_line_combination(self):
@@ -57,21 +65,4 @@ class hierarchical_predecode3x8(hierarchical_predecode):
["A_0", "Abar_1", "A_2"],
["Abar_0", "A_1", "A_2"],
["A_0", "A_1", "A_2"]]
- return combination
-
-
- def analytical_delay(self, corner, slew, load = 0.0 ):
- # A -> Abar
- a_t_b_delay = self.inv.analytical_delay(corner, slew=slew, load=self.nand.input_load())
-
- # Abar -> z
- b_t_z_delay = self.nand.analytical_delay(corner, slew=a_t_b_delay.slew, load=self.inv.input_load())
-
- # Z -> out
- a_t_out_delay = self.inv.analytical_delay(corner, slew=b_t_z_delay.slew, load=load)
-
- return a_t_b_delay + b_t_z_delay + a_t_out_delay
-
-
- def input_load(self):
- return self.nand.input_load()
+ return combination
\ No newline at end of file
diff --git a/compiler/modules/multibank.py b/compiler/modules/multibank.py
index 15882f8b..2f933a2d 100644
--- a/compiler/modules/multibank.py
+++ b/compiler/modules/multibank.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import sys
from tech import drc, parameter
import debug
@@ -58,11 +65,11 @@ class multibank(design.design):
def add_pins(self):
""" Adding pins for Bank module"""
for i in range(self.word_size):
- self.add_pin("DOUT_{0}".format(i),"OUT")
+ self.add_pin("dout_{0}".format(i),"OUT")
for i in range(self.word_size):
- self.add_pin("BANK_DIN_{0}".format(i),"IN")
+ self.add_pin("bank_din_{0}".format(i),"IN")
for i in range(self.addr_size):
- self.add_pin("A_{0}".format(i),"INPUT")
+ self.add_pin("a_{0}".format(i),"INPUT")
# For more than one bank, we have a bank select and name
# the signals gated_*.
@@ -180,9 +187,15 @@ class multibank(design.design):
words_per_row=self.words_per_row)
self.add_mod(self.sense_amp_array)
- self.write_driver_array = self.mod_write_driver_array(columns=self.num_cols,
- word_size=self.word_size)
- self.add_mod(self.write_driver_array)
+ if self.write_size:
+ self.write_mask_driver_array = self.mod_write_mask_driver_array(columns=self.num_cols,
+ word_size=self.word_size,
+ write_size=self.write_size)
+ self.add_mod(self.write_mask_driver_array)
+ else:
+ self.write_driver_array = self.mod_write_driver_array(columns=self.num_cols,
+ word_size=self.word_size)
+ self.add_mod(self.write_driver_array)
self.row_decoder = self.mod_decoder(rows=self.num_rows)
self.add_mod(self.row_decoder)
@@ -289,7 +302,7 @@ class multibank(design.design):
temp = []
for i in range(self.word_size):
- temp.append("BANK_DIN_{0}".format(i))
+ temp.append("bank_din_{0}".format(i))
for i in range(self.word_size):
if (self.words_per_row == 1):
temp.append("bl_{0}".format(i))
@@ -312,7 +325,7 @@ class multibank(design.design):
for i in range(self.word_size):
temp.append("sa_out_{0}".format(i))
for i in range(self.word_size):
- temp.append("DOUT_{0}".format(i))
+ temp.append("dout_{0}".format(i))
temp.extend([self.prefix+"tri_en", self.prefix+"tri_en_bar", "vdd", "gnd"])
self.connect_inst(temp)
@@ -583,7 +596,7 @@ class multibank(design.design):
""" Add pins for the sense amp output """
for i in range(self.word_size):
data_pin = self.sense_amp_array_inst.get_pin("data_{}".format(i))
- self.add_layout_pin_rect_center(text="DOUT_{}".format(i),
+ self.add_layout_pin_rect_center(text="dout_{}".format(i),
layer=data_pin.layer,
offset=data_pin.center(),
height=data_pin.height(),
@@ -593,7 +606,7 @@ class multibank(design.design):
""" Metal 3 routing of tri_gate output data """
for i in range(self.word_size):
data_pin = self.tri_gate_array_inst.get_pin("out_{}".format(i))
- self.add_layout_pin_rect_center(text="DOUT_{}".format(i),
+ self.add_layout_pin_rect_center(text="dout_{}".format(i),
layer=data_pin.layer,
offset=data_pin.center(),
height=data_pin.height(),
@@ -606,8 +619,8 @@ class multibank(design.design):
# Create inputs for the row address lines
for i in range(self.row_addr_size):
addr_idx = i + self.col_addr_size
- decoder_name = "A_{}".format(i)
- addr_name = "A_{}".format(addr_idx)
+ decoder_name = "a_{}".format(i)
+ addr_name = "a_{}".format(addr_idx)
self.copy_layout_pin(self.row_decoder_inst, decoder_name, addr_name)
@@ -616,7 +629,7 @@ class multibank(design.design):
for i in range(self.word_size):
data_name = "data_{}".format(i)
- din_name = "BANK_DIN_{}".format(i)
+ din_name = "bank_din_{}".format(i)
self.copy_layout_pin(self.write_driver_array_inst, data_name, din_name)
@@ -655,7 +668,7 @@ class multibank(design.design):
decode_names = ["Zb", "Z"]
# The Address LSB
- self.copy_layout_pin(self.col_decoder_inst, "A", "A[0]")
+ self.copy_layout_pin(self.col_decoder_inst, "A", "a[0]")
elif self.col_addr_size > 1:
decode_names = []
@@ -664,7 +677,7 @@ class multibank(design.design):
for i in range(self.col_addr_size):
decoder_name = "in_{}".format(i)
- addr_name = "A_{}".format(i)
+ addr_name = "a_{}".format(i)
self.copy_layout_pin(self.col_decoder_inst, decoder_name, addr_name)
@@ -815,21 +828,3 @@ class multibank(design.design):
self.add_via(layers=("metal2","via2","metal3"),
offset=in_pin + self.m2m3_via_offset,
rotate=90)
-
- def analytical_delay(self, corner, slew, load):
- """ return analytical delay of the bank"""
- decoder_delay = self.row_decoder.analytical_delay(corner, slew, self.wordline_driver.input_load())
-
- word_driver_delay = self.wordline_driver.analytical_delay(corner, decoder_delay.slew, self.bitcell_array.input_load())
-
- bitcell_array_delay = self.bitcell_array.analytical_delay(corner, word_driver_delay.slew)
-
- bl_t_data_out_delay = self.sense_amp_array.analytical_delay(corner, bitcell_array_delay.slew,
- self.bitcell_array.output_load())
- # output load of bitcell_array is set to be only small part of bl for sense amp.
-
- data_t_DATA_delay = self.tri_gate_array.analytical_delay(corner, bl_t_data_out_delay.slew, load)
-
- result = decoder_delay + word_driver_delay + bitcell_array_delay + bl_t_data_out_delay + data_t_DATA_delay
- return result
-
diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py
new file mode 100644
index 00000000..0a624c60
--- /dev/null
+++ b/compiler/modules/port_address.py
@@ -0,0 +1,162 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California
+# All rights reserved.
+#
+import sys
+from tech import drc, parameter
+from math import log
+import debug
+import design
+from sram_factory import factory
+from vector import vector
+
+from globals import OPTS
+
+class port_address(design.design):
+ """
+ Create the address port (row decoder and wordline driver)..
+ """
+
+ def __init__(self, cols, rows, name=""):
+
+ self.num_cols = cols
+ self.num_rows = rows
+ self.addr_size = int(log(self.num_rows, 2))
+
+ if name == "":
+ name = "port_address_{0}_{1}".format(cols,rows)
+ design.design.__init__(self, name)
+ debug.info(2, "create data port of cols {0} rows {1}".format(cols,rows))
+
+ self.create_netlist()
+ if not OPTS.netlist_only:
+ debug.check(len(self.all_ports)<=2,"Bank layout cannot handle more than two ports.")
+ self.create_layout()
+ self.add_boundary()
+
+
+ def create_netlist(self):
+ self.add_pins()
+ self.add_modules()
+ self.create_row_decoder()
+ self.create_wordline_driver()
+
+ def create_layout(self):
+ self.place_instances()
+ self.route_layout()
+ self.DRC_LVS()
+
+ def add_pins(self):
+ """ Adding pins for port address module"""
+
+ for bit in range(self.addr_size):
+ self.add_pin("addr_{0}".format(bit),"INPUT")
+
+ self.add_pin("wl_en", "INPUT")
+
+ for bit in range(self.num_rows):
+ self.add_pin("wl_{0}".format(bit),"OUTPUT")
+
+ self.add_pin("vdd","POWER")
+ self.add_pin("gnd","GROUND")
+
+
+ def route_layout(self):
+ """ Create routing amoung the modules """
+ self.route_pins()
+ self.route_internal()
+ self.route_supplies()
+
+ def route_supplies(self):
+ """ Propagate all vdd/gnd pins up to this level for all modules """
+ for inst in self.insts:
+ self.copy_power_pins(inst,"vdd")
+ self.copy_power_pins(inst,"gnd")
+
+ def route_pins(self):
+ for row in range(self.addr_size):
+ decoder_name = "addr_{}".format(row)
+ self.copy_layout_pin(self.row_decoder_inst, decoder_name)
+
+ for row in range(self.num_rows):
+ driver_name = "wl_{}".format(row)
+ self.copy_layout_pin(self.wordline_driver_inst, driver_name)
+
+ self.copy_layout_pin(self.wordline_driver_inst, "en", "wl_en")
+
+ def route_internal(self):
+ for row in range(self.num_rows):
+ # The pre/post is to access the pin from "outside" the cell to avoid DRCs
+ decoder_out_pos = self.row_decoder_inst.get_pin("decode_{}".format(row)).rc()
+ driver_in_pos = self.wordline_driver_inst.get_pin("in_{}".format(row)).lc()
+ mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0)
+ mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1)
+ self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos])
+
+
+
+
+ def add_modules(self):
+
+ self.row_decoder = factory.create(module_type="decoder",
+ rows=self.num_rows)
+ self.add_mod(self.row_decoder)
+
+ self.wordline_driver = factory.create(module_type="wordline_driver",
+ rows=self.num_rows,
+ cols=self.num_cols)
+ self.add_mod(self.wordline_driver)
+
+
+ def create_row_decoder(self):
+ """ Create the hierarchical row decoder """
+
+ self.row_decoder_inst = self.add_inst(name="row_decoder",
+ mod=self.row_decoder)
+
+ temp = []
+ for bit in range(self.addr_size):
+ temp.append("addr_{0}".format(bit))
+ for row in range(self.num_rows):
+ temp.append("dec_out_{0}".format(row))
+ temp.extend(["vdd", "gnd"])
+ self.connect_inst(temp)
+
+
+
+ def create_wordline_driver(self):
+ """ Create the Wordline Driver """
+
+ self.wordline_driver_inst = self.add_inst(name="wordline_driver",
+ mod=self.wordline_driver)
+
+ temp = []
+ for row in range(self.num_rows):
+ temp.append("dec_out_{0}".format(row))
+ for row in range(self.num_rows):
+ temp.append("wl_{0}".format(row))
+ temp.append("wl_en")
+ temp.append("vdd")
+ temp.append("gnd")
+ self.connect_inst(temp)
+
+
+
+ def place_instances(self):
+ """
+ Compute the offsets and place the instances.
+ """
+
+ # A space for wells or jogging m2
+ self.m2_gap = max(2*drc("pwell_to_nwell") + drc("well_enclosure_active"),
+ 3*self.m2_pitch)
+
+ row_decoder_offset = vector(0,0)
+ wordline_driver_offset = vector(self.row_decoder.width + self.m2_gap,0)
+
+ self.wordline_driver_inst.place(wordline_driver_offset)
+ self.row_decoder_inst.place(row_decoder_offset)
+
+ self.height = self.row_decoder.height
+ self.width = self.wordline_driver_inst.rx()
diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py
new file mode 100644
index 00000000..c3473803
--- /dev/null
+++ b/compiler/modules/port_data.py
@@ -0,0 +1,667 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California
+# All rights reserved.
+#
+import sys
+from tech import drc, parameter
+import debug
+import design
+from sram_factory import factory
+from vector import vector
+
+from globals import OPTS
+
+class port_data(design.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.
+ """
+
+ def __init__(self, sram_config, port, name=""):
+
+ sram_config.set_local_config(self)
+ self.port = port
+ if self.write_size is not None:
+ self.num_wmasks = int(self.word_size/self.write_size)
+ else:
+ self.num_wmasks = 0
+
+ if name == "":
+ name = "port_data_{0}".format(self.port)
+ design.design.__init__(self, name)
+ debug.info(2, "create data port of size {0} with {1} words per row".format(self.word_size,self.words_per_row))
+
+ self.create_netlist()
+ if not OPTS.netlist_only:
+ debug.check(len(self.all_ports)<=2,"Bank layout cannot handle more than two ports.")
+ self.create_layout()
+ self.add_boundary()
+
+
+ def create_netlist(self):
+ self.precompute_constants()
+ self.add_pins()
+ self.add_modules()
+ self.create_instances()
+
+ def create_instances(self):
+ if self.precharge_array:
+ self.create_precharge_array()
+ else:
+ self.precharge_array_inst = None
+
+ if self.sense_amp_array:
+ self.create_sense_amp_array()
+ else:
+ self.sense_amp_array_inst = None
+
+ if self.write_driver_array:
+ self.create_write_driver_array()
+ if self.write_size is not None:
+ self.create_write_mask_and_array()
+ else:
+ self.write_mask_and_array_inst = None
+ else:
+ self.write_driver_array_inst = None
+ self.write_mask_and_array_inst = None
+
+ if self.column_mux_array:
+ self.create_column_mux_array()
+ else:
+ self.column_mux_array_inst = None
+
+
+
+ def create_layout(self):
+ self.compute_instance_offsets()
+ self.place_instances()
+ self.route_layout()
+ self.DRC_LVS()
+
+ def add_pins(self):
+ """ Adding pins for port address module"""
+
+ self.add_pin("rbl_bl","INOUT")
+ self.add_pin("rbl_br","INOUT")
+ for bit in range(self.num_cols):
+ self.add_pin("{0}_{1}".format(self.bl_names[self.port], bit),"INOUT")
+ self.add_pin("{0}_{1}".format(self.br_names[self.port], bit),"INOUT")
+ if self.port in self.read_ports:
+ for bit in range(self.word_size):
+ self.add_pin("dout_{}".format(bit),"OUTPUT")
+ if self.port in self.write_ports:
+ for bit in range(self.word_size):
+ self.add_pin("din_{}".format(bit),"INPUT")
+ # Will be empty if no col addr lines
+ sel_names = ["sel_{}".format(x) for x in range(self.num_col_addr_lines)]
+ for pin_name in sel_names:
+ self.add_pin(pin_name,"INPUT")
+ if self.port in self.read_ports:
+ self.add_pin("s_en", "INPUT")
+ self.add_pin("p_en_bar", "INPUT")
+ if self.port in self.write_ports:
+ self.add_pin("w_en", "INPUT")
+ for bit in range(self.num_wmasks):
+ self.add_pin("bank_wmask_{}".format(bit),"INPUT")
+ self.add_pin("vdd","POWER")
+ self.add_pin("gnd","GROUND")
+
+
+ def route_layout(self):
+ """ Create routing among the modules """
+ self.route_data_lines()
+ self.route_layout_pins()
+ self.route_supplies()
+
+ def route_layout_pins(self):
+ """ Add the pins """
+ self.route_bitline_pins()
+ self.route_control_pins()
+
+ def route_data_lines(self):
+ """ Route the bitlines depending on the port type rw, w, or r. """
+
+ if self.port in self.readwrite_ports:
+ # (write_mask_and ->) write_driver -> sense_amp -> (column_mux ->) precharge -> bitcell_array
+ self.route_write_mask_and_array_in(self.port)
+ self.route_write_mask_and_array_to_write_driver(self.port)
+ self.route_write_driver_in(self.port)
+ self.route_sense_amp_out(self.port)
+ self.route_write_driver_to_sense_amp(self.port)
+ self.route_sense_amp_to_column_mux_or_precharge_array(self.port)
+ self.route_column_mux_to_precharge_array(self.port)
+ elif self.port in self.read_ports:
+ # sense_amp -> (column_mux) -> precharge -> bitcell_array
+ self.route_sense_amp_out(self.port)
+ self.route_sense_amp_to_column_mux_or_precharge_array(self.port)
+ self.route_column_mux_to_precharge_array(self.port)
+ else:
+ # (write_mask_and ->) write_driver -> (column_mux ->) precharge -> bitcell_array
+ self.route_write_mask_and_array_in(self.port)
+ self.route_write_mask_and_array_to_write_driver(self.port)
+ self.route_write_driver_in(self.port)
+ self.route_write_driver_to_column_mux_or_precharge_array(self.port)
+ self.route_column_mux_to_precharge_array(self.port)
+
+ def route_supplies(self):
+ """ Propagate all vdd/gnd pins up to this level for all modules """
+
+ for inst in self.insts:
+ self.copy_power_pins(inst,"vdd")
+ self.copy_power_pins(inst,"gnd")
+
+ def add_modules(self):
+
+ # Extra column +1 is for RBL
+ # Precharge will be shifted left if needed
+ self.precharge_array = factory.create(module_type="precharge_array",
+ columns=self.num_cols + 1,
+ bitcell_bl=self.bl_names[self.port],
+ bitcell_br=self.br_names[self.port])
+ self.add_mod(self.precharge_array)
+
+ if self.port in self.read_ports:
+ self.sense_amp_array = factory.create(module_type="sense_amp_array",
+ word_size=self.word_size,
+ words_per_row=self.words_per_row)
+ self.add_mod(self.sense_amp_array)
+ else:
+ self.sense_amp_array = None
+
+
+ if self.col_addr_size > 0:
+ self.column_mux_array = factory.create(module_type="column_mux_array",
+ columns=self.num_cols,
+ word_size=self.word_size,
+ bitcell_bl=self.bl_names[self.port],
+ bitcell_br=self.br_names[self.port])
+ self.add_mod(self.column_mux_array)
+ else:
+ self.column_mux_array = None
+
+
+ if self.port in self.write_ports:
+ self.write_driver_array = factory.create(module_type="write_driver_array",
+ columns=self.num_cols,
+ word_size=self.word_size,
+ write_size=self.write_size)
+ self.add_mod(self.write_driver_array)
+ if self.write_size is not None:
+ self.write_mask_and_array = factory.create(module_type="write_mask_and_array",
+ columns=self.num_cols,
+ word_size=self.word_size,
+ write_size=self.write_size,
+ port = self.port)
+ self.add_mod(self.write_mask_and_array)
+ else:
+ self.write_mask_and_array = None
+
+ else:
+ self.write_driver_array = None
+ self.write_mask_and_array = None
+
+ def precompute_constants(self):
+ """ Get some preliminary data ready """
+
+ # The central bus is the column address (one hot) and row address (binary)
+ if self.col_addr_size>0:
+ self.num_col_addr_lines = 2**self.col_addr_size
+ else:
+ self.num_col_addr_lines = 0
+
+
+ # A space for wells or jogging m2 between modules
+ self.m2_gap = max(2*drc("pwell_to_nwell") + drc("well_enclosure_active"),
+ 3*self.m2_pitch)
+
+
+ # create arrays of bitline and bitline_bar names for read, write, or all ports
+ self.bitcell = factory.create(module_type="bitcell")
+ self.bl_names = self.bitcell.get_all_bl_names()
+ self.br_names = self.bitcell.get_all_br_names()
+ self.wl_names = self.bitcell.get_all_wl_names()
+
+ def create_precharge_array(self):
+ """ Creating Precharge """
+ if not self.precharge_array:
+ self.precharge_array_inst = None
+ return
+
+ self.precharge_array_inst = self.add_inst(name="precharge_array{}".format(self.port),
+ mod=self.precharge_array)
+
+ temp = []
+ # Use left BLs for RBL
+ if self.port==0:
+ temp.append("rbl_bl")
+ temp.append("rbl_br")
+ for bit in range(self.num_cols):
+ temp.append(self.bl_names[self.port]+"_{0}".format(bit))
+ temp.append(self.br_names[self.port]+"_{0}".format(bit))
+ # Use right BLs for RBL
+ if self.port==1:
+ temp.append("rbl_bl")
+ temp.append("rbl_br")
+ temp.extend(["p_en_bar", "vdd"])
+ self.connect_inst(temp)
+
+
+ def place_precharge_array(self, offset):
+ """ Placing Precharge """
+
+ self.precharge_array_inst.place(offset=offset, mirror="MX")
+
+
+ def create_column_mux_array(self):
+ """ Creating Column Mux when words_per_row > 1 . """
+
+ self.column_mux_array_inst = self.add_inst(name="column_mux_array{}".format(self.port),
+ mod=self.column_mux_array)
+
+ temp = []
+ for col in range(self.num_cols):
+ temp.append(self.bl_names[self.port]+"_{0}".format(col))
+ temp.append(self.br_names[self.port]+"_{0}".format(col))
+ for word in range(self.words_per_row):
+ temp.append("sel_{}".format(word))
+ for bit in range(self.word_size):
+ temp.append(self.bl_names[self.port]+"_out_{0}".format(bit))
+ temp.append(self.br_names[self.port]+"_out_{0}".format(bit))
+ temp.append("gnd")
+ self.connect_inst(temp)
+
+
+ def place_column_mux_array(self, offset):
+ """ Placing Column Mux when words_per_row > 1 . """
+ if self.col_addr_size == 0:
+ return
+
+ self.column_mux_array_inst.place(offset=offset, mirror="MX")
+
+
+ def create_sense_amp_array(self):
+ """ Creating Sense amp """
+ self.sense_amp_array_inst = self.add_inst(name="sense_amp_array{}".format(self.port),
+ mod=self.sense_amp_array)
+
+ temp = []
+ for bit in range(self.word_size):
+ temp.append("dout_{}".format(bit))
+ if self.words_per_row == 1:
+ temp.append(self.bl_names[self.port]+"_{0}".format(bit))
+ temp.append(self.br_names[self.port]+"_{0}".format(bit))
+ else:
+ temp.append(self.bl_names[self.port]+"_out_{0}".format(bit))
+ temp.append(self.br_names[self.port]+"_out_{0}".format(bit))
+
+ temp.extend(["s_en", "vdd", "gnd"])
+ self.connect_inst(temp)
+
+
+ def place_sense_amp_array(self, offset):
+ """ Placing Sense amp """
+ self.sense_amp_array_inst.place(offset=offset, mirror="MX")
+
+
+ def create_write_driver_array(self):
+ """ Creating Write Driver """
+ self.write_driver_array_inst = self.add_inst(name="write_driver_array{}".format(self.port),
+ mod=self.write_driver_array)
+
+ temp = []
+ for bit in range(self.word_size):
+ temp.append("din_{}".format(bit))
+
+ for bit in range(self.word_size):
+ if (self.words_per_row == 1):
+ temp.append(self.bl_names[self.port] + "_{0}".format(bit))
+ temp.append(self.br_names[self.port] + "_{0}".format(bit))
+ else:
+ temp.append(self.bl_names[self.port] + "_out_{0}".format(bit))
+ temp.append(self.br_names[self.port] + "_out_{0}".format(bit))
+
+ if self.write_size is not None:
+ for i in range(self.num_wmasks):
+ temp.append("wdriver_sel_{}".format(i))
+ else:
+ temp.append("w_en")
+ temp.extend(["vdd", "gnd"])
+
+ self.connect_inst(temp)
+
+
+ def place_write_driver_array(self, offset):
+ """ Placing Write Driver """
+ self.write_driver_array_inst.place(offset=offset, mirror="MX")
+
+
+ def create_write_mask_and_array(self):
+ """ Creating Write Mask AND Array """
+ self.write_mask_and_array_inst = self.add_inst(name="write_mask_and_array{}".format(self.port),
+ mod=self.write_mask_and_array)
+
+ temp = []
+ for bit in range(self.num_wmasks):
+ temp.append("bank_wmask_{}".format(bit))
+ temp.extend(["w_en"])
+ for bit in range(self.num_wmasks):
+ temp.append("wdriver_sel_{}".format(bit))
+ temp.extend(["vdd", "gnd"])
+ self.connect_inst(temp)
+
+
+ def place_write_mask_and_array(self, offset):
+ """ Placing Write Mask AND array """
+ self.write_mask_and_array_inst.place(offset=offset, mirror="MX")
+
+
+ def compute_instance_offsets(self):
+ """
+ Compute the empty instance offsets for port0 and port1 (if needed)
+ """
+
+ vertical_port_order = []
+ vertical_port_order.append(self.precharge_array_inst)
+ vertical_port_order.append(self.column_mux_array_inst)
+ vertical_port_order.append(self.sense_amp_array_inst)
+ vertical_port_order.append(self.write_driver_array_inst)
+ vertical_port_order.append(self.write_mask_and_array_inst)
+
+ # Add one column for the the RBL
+ if self.port==0:
+ x_offset = self.bitcell.width
+ else:
+ x_offset = 0
+
+ vertical_port_offsets = 5 * [None]
+ self.width = x_offset
+ self.height = 0
+ for i, p in enumerate(vertical_port_order):
+ if p == None:
+ continue
+ self.height += (p.height + self.m2_gap)
+ self.width = max(self.width, p.width)
+ vertical_port_offsets[i] = vector(x_offset, self.height)
+
+ # Reversed order
+ self.write_mask_and_offset = vertical_port_offsets[4]
+ self.write_driver_offset = vertical_port_offsets[3]
+ self.sense_amp_offset = vertical_port_offsets[2]
+ self.column_mux_offset = vertical_port_offsets[1]
+ self.precharge_offset = vertical_port_offsets[0]
+ # Shift the precharge left if port 0
+ if self.precharge_offset and self.port == 0:
+ self.precharge_offset -= vector(x_offset, 0)
+
+ def place_instances(self):
+ """ Place the instances. """
+
+ # These are fixed in the order: write mask ANDs, write driver, sense amp, column mux, precharge,
+ # even if the item is not used in a given port (it will be None then)
+ if self.write_mask_and_offset:
+ self.place_write_mask_and_array(self.write_mask_and_offset)
+ if self.write_driver_offset:
+ self.place_write_driver_array(self.write_driver_offset)
+ if self.sense_amp_offset:
+ self.place_sense_amp_array(self.sense_amp_offset)
+ if self.precharge_offset:
+ self.place_precharge_array(self.precharge_offset)
+ if self.column_mux_offset:
+ self.place_column_mux_array(self.column_mux_offset)
+
+
+ def route_sense_amp_out(self, port):
+ """ Add pins for the sense amp output """
+
+ for bit in range(self.word_size):
+ data_pin = self.sense_amp_array_inst.get_pin("data_{}".format(bit))
+ self.add_layout_pin_rect_center(text="dout_{0}".format(bit),
+ layer=data_pin.layer,
+ offset=data_pin.center(),
+ height=data_pin.height(),
+ width=data_pin.width())
+
+
+ def route_write_driver_in(self, port):
+ """ Connecting write driver """
+
+ for row in range(self.word_size):
+ data_name = "data_{}".format(row)
+ din_name = "din_{}".format(row)
+ self.copy_layout_pin(self.write_driver_array_inst, data_name, din_name)
+
+
+ def route_write_mask_and_array_in(self, port):
+ """ Add pins for the write mask and array input """
+
+ for bit in range(self.num_wmasks):
+ wmask_in_name = "wmask_in_{}".format(bit)
+ bank_wmask_name = "bank_wmask_{}".format(bit)
+ self.copy_layout_pin(self.write_mask_and_array_inst, wmask_in_name, bank_wmask_name)
+
+
+ def route_write_mask_and_array_to_write_driver(self,port):
+ """ Routing of wdriver_sel_{} between write mask AND array and write driver array. Adds layout pin for write
+ mask AND array output and via for write driver enable """
+
+ inst1 = self.write_mask_and_array_inst
+ inst2 = self.write_driver_array_inst
+
+ loc = 0
+ for bit in range(self.num_wmasks):
+ # Bring write mask AND array output pin to port data level
+ self.copy_layout_pin(inst1, "wmask_out_{0}".format(bit), "wdriver_sel_{0}".format(bit))
+
+ wmask_out_pin = inst1.get_pin("wmask_out_{0}".format(bit))
+ wdriver_en_pin = inst2.get_pin("en_{0}".format(bit))
+
+ # The metal2 wdriver_sel_{} wire must hit the en_{} pin after the closest bitline pin that's right of the
+ # the wdriver_sel_{} pin in the write driver AND array.
+ if bit == 0:
+ # When the write mask output pin is right of the bitline, the target is found
+ while (wmask_out_pin.lx() + self.m2_pitch > inst2.get_pin("data_{0}".format(loc)).rx()):
+ loc += 1
+ length = inst2.get_pin("data_{0}".format(loc)).rx() + self.m2_pitch
+ debug.check(loc<=self.num_wmasks,"Couldn't route the write mask select.")
+ else:
+ # Stride by the write size rather than finding the next pin to the right
+ loc += self.write_size
+ length = inst2.get_pin("data_{0}".format(loc)).rx() + self.m2_pitch
+
+
+ beg_pos = wmask_out_pin.center()
+ middle_pos = vector(length,wmask_out_pin.cy())
+ end_pos = vector(length, wdriver_en_pin.cy())
+
+ # Add via for the write driver array's enable input
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=end_pos)
+
+ # Route between write mask AND array and write driver array
+ self.add_wire(("metal1","via1","metal2"), [beg_pos, middle_pos, end_pos])
+
+
+ def route_column_mux_to_precharge_array(self, port):
+ """ Routing of BL and BR between col mux and precharge array """
+
+ # Only do this if we have a column mux!
+ if self.col_addr_size==0:
+ return
+
+ inst1 = self.column_mux_array_inst
+ inst2 = self.precharge_array_inst
+ if self.port==0:
+ self.connect_bitlines(inst1, inst2, self.num_cols, inst2_start_bit=1)
+ else:
+ self.connect_bitlines(inst1, inst2, self.num_cols)
+
+
+ def route_sense_amp_to_column_mux_or_precharge_array(self, port):
+ """ Routing of BL and BR between sense_amp and column mux or precharge array """
+ inst2 = self.sense_amp_array_inst
+
+ if self.col_addr_size>0:
+ # Sense amp is connected to the col mux
+ inst1 = self.column_mux_array_inst
+ inst1_bl_name = "bl_out_{}"
+ inst1_br_name = "br_out_{}"
+ start_bit = 0
+ else:
+ # Sense amp is directly connected to the precharge array
+ inst1 = self.precharge_array_inst
+ inst1_bl_name = "bl_{}"
+ inst1_br_name = "br_{}"
+ if self.port==0:
+ start_bit=1
+ else:
+ start_bit=0
+
+
+ self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size,
+ inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name, inst1_start_bit=start_bit)
+
+
+ def route_write_driver_to_column_mux_or_precharge_array(self, port):
+ """ Routing of BL and BR between sense_amp and column mux or precharge array """
+ inst2 = self.write_driver_array_inst
+
+ if self.col_addr_size>0:
+ # Write driver is connected to the col mux
+ inst1 = self.column_mux_array_inst
+ inst1_bl_name = "bl_out_{}"
+ inst1_br_name = "br_out_{}"
+ start_bit = 0
+ else:
+ # Sense amp is directly connected to the precharge array
+ inst1 = self.precharge_array_inst
+ inst1_bl_name = "bl_{}"
+ inst1_br_name = "br_{}"
+ if self.port==0:
+ start_bit=1
+ else:
+ start_bit=0
+
+ self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size,
+ inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name, inst1_start_bit=start_bit)
+
+
+ def route_write_driver_to_sense_amp(self, port):
+ """ Routing of BL and BR between write driver and sense amp """
+
+ inst1 = self.write_driver_array_inst
+ inst2 = self.sense_amp_array_inst
+
+ # These should be pitch matched in the cell library,
+ # but just in case, do a channel route.
+ self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size)
+
+
+ def route_bitline_pins(self):
+ """ Add the bitline pins for the given port """
+
+ # Connect one bitline to the RBL and offset the indices for the other BLs
+ if self.port==0:
+ self.copy_layout_pin(self.precharge_array_inst, "bl_0", "rbl_bl")
+ self.copy_layout_pin(self.precharge_array_inst, "br_0", "rbl_br")
+ bit_offset=1
+ elif self.port==1:
+ self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(self.num_cols), "rbl_bl")
+ self.copy_layout_pin(self.precharge_array_inst, "br_{}".format(self.num_cols), "rbl_br")
+ bit_offset=0
+ else:
+ bit_offset=0
+
+ for bit in range(self.num_cols):
+ if self.precharge_array_inst:
+ self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(bit+bit_offset), "bl_{}".format(bit))
+ self.copy_layout_pin(self.precharge_array_inst, "br_{}".format(bit+bit_offset), "br_{}".format(bit))
+ else:
+ debug.error("Didn't find precharge array.")
+
+
+ def route_control_pins(self):
+ """ Add the control pins: s_en, p_en_bar, w_en """
+ if self.precharge_array_inst:
+ self.copy_layout_pin(self.precharge_array_inst, "en_bar", "p_en_bar")
+ if self.column_mux_array_inst:
+ sel_names = ["sel_{}".format(x) for x in range(self.num_col_addr_lines)]
+ for pin_name in sel_names:
+ self.copy_layout_pin(self.column_mux_array_inst, pin_name)
+ if self.sense_amp_array_inst:
+ self.copy_layout_pin(self.sense_amp_array_inst, "en", "s_en")
+ if self.write_driver_array_inst:
+ if self.write_mask_and_array_inst:
+ for bit in range(self.num_wmasks):
+ # Add write driver's en_{} pins
+ self.copy_layout_pin(self.write_driver_array_inst, "en_{}".format(bit), "wdriver_sel_{}".format(bit))
+ else:
+ self.copy_layout_pin(self.write_driver_array_inst, "en", "w_en")
+ if self.write_mask_and_array_inst:
+ self.copy_layout_pin(self.write_mask_and_array_inst, "en", "w_en")
+
+
+
+ def channel_route_bitlines(self, inst1, inst2, num_bits,
+ inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_start_bit=0,
+ inst2_bl_name="bl_{}", inst2_br_name="br_{}", inst2_start_bit=0):
+ """
+ Route the bl and br of two modules using the channel router.
+ """
+
+ # determine top and bottom automatically.
+ # since they don't overlap, we can just check the bottom y coordinate.
+ if inst1.by() < inst2.by():
+ (bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
+ (top_inst, top_bl_name, top_br_name, top_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
+ else:
+ (bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
+ (top_inst, top_bl_name, top_br_name, top_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
+
+
+ # Channel route each mux separately since we don't minimize the number
+ # of tracks in teh channel router yet. If we did, we could route all the bits at once!
+ offset = bottom_inst.ul() + vector(0,self.m1_pitch)
+ for bit in range(num_bits):
+ bottom_names = [bottom_inst.get_pin(bottom_bl_name.format(bit+bottom_start_bit)), bottom_inst.get_pin(bottom_br_name.format(bit+bottom_start_bit))]
+ top_names = [top_inst.get_pin(top_bl_name.format(bit+top_start_bit)), top_inst.get_pin(top_br_name.format(bit+top_start_bit))]
+ route_map = list(zip(bottom_names, top_names))
+ self.create_horizontal_channel_route(route_map, offset)
+
+
+ def connect_bitlines(self, inst1, inst2, num_bits,
+ inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_start_bit=0,
+ inst2_bl_name="bl_{}", inst2_br_name="br_{}", inst2_start_bit=0):
+
+ """
+ Connect the bl and br of two modules.
+ This assumes that they have sufficient space to create a jog
+ in the middle between the two modules (if needed).
+ """
+
+ # determine top and bottom automatically.
+ # since they don't overlap, we can just check the bottom y coordinate.
+ if inst1.by() < inst2.by():
+ (bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
+ (top_inst, top_bl_name, top_br_name, top_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
+ else:
+ (bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
+ (top_inst, top_bl_name, top_br_name, top_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
+
+ for col in range(num_bits):
+ bottom_bl = bottom_inst.get_pin(bottom_bl_name.format(col+bottom_start_bit)).uc()
+ bottom_br = bottom_inst.get_pin(bottom_br_name.format(col+bottom_start_bit)).uc()
+ top_bl = top_inst.get_pin(top_bl_name.format(col+top_start_bit)).bc()
+ top_br = top_inst.get_pin(top_br_name.format(col+top_start_bit)).bc()
+
+ yoffset = 0.5*(top_bl.y+bottom_bl.y)
+ self.add_path("metal2",[bottom_bl, vector(bottom_bl.x,yoffset),
+ vector(top_bl.x,yoffset), top_bl])
+ self.add_path("metal2",[bottom_br, vector(bottom_br.x,yoffset),
+ vector(top_br.x,yoffset), top_br])
+
+ def graph_exclude_precharge(self):
+ """Precharge adds a loop between bitlines, can be excluded to reduce complexity"""
+ if self.precharge_array_inst:
+ self.graph_inst_exclude.add(self.precharge_array_inst)
+
diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py
index 67581e1a..2d98ba14 100644
--- a/compiler/modules/precharge_array.py
+++ b/compiler/modules/precharge_array.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import design
import debug
from tech import drc
@@ -28,10 +35,11 @@ class precharge_array(design.design):
def add_pins(self):
"""Adds pins for spice file"""
for i in range(self.columns):
- self.add_pin("bl_{0}".format(i))
- self.add_pin("br_{0}".format(i))
- self.add_pin("en_bar")
- self.add_pin("vdd")
+ # These are outputs from the precharge only
+ self.add_pin("bl_{0}".format(i), "OUTPUT")
+ self.add_pin("br_{0}".format(i), "OUTPUT")
+ self.add_pin("en_bar", "INPUT")
+ self.add_pin("vdd", "POWER")
def create_netlist(self):
self.add_modules()
@@ -44,6 +52,7 @@ class precharge_array(design.design):
self.place_insts()
self.add_layout_pins()
+ self.add_boundary()
self.DRC_LVS()
def add_modules(self):
@@ -107,3 +116,4 @@ class precharge_array(design.design):
#Assume single port
precharge_en_cin = self.pc_cell.get_en_cin()
return precharge_en_cin*self.columns
+
diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py
new file mode 100644
index 00000000..639d0714
--- /dev/null
+++ b/compiler/modules/replica_bitcell_array.py
@@ -0,0 +1,425 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California
+# All rights reserved.
+#
+
+import debug
+import design
+from tech import drc, spice
+from vector import vector
+from globals import OPTS
+from sram_factory import factory
+import logical_effort
+import bitcell_array
+import replica_column
+import dummy_array
+
+class replica_bitcell_array(design.design):
+ """
+ Creates a bitcell arrow of cols x rows and then adds the replica
+ and dummy columns and rows. Replica columns are on the left and
+ right, respectively and connected to the given bitcell ports.
+ Dummy are the outside columns/rows with WL and BL tied to gnd.
+ Requires a regular bitcell array, replica bitcell, and dummy
+ bitcell (Bl/BR disconnected).
+ """
+ def __init__(self, cols, rows, left_rbl, right_rbl, bitcell_ports, name):
+ design.design.__init__(self, name)
+ debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
+ self.add_comment("rows: {0} cols: {1}".format(rows, cols))
+
+ self.column_size = cols
+ self.row_size = rows
+ self.left_rbl = left_rbl
+ self.right_rbl = right_rbl
+ self.bitcell_ports = bitcell_ports
+
+ debug.check(left_rbl+right_rbl==len(self.all_ports),"Invalid number of RBLs for port configuration.")
+ debug.check(left_rbl+right_rbl==len(self.bitcell_ports),"Bitcell ports must match total RBLs.")
+
+ # Two dummy rows/cols plus replica for each port
+ self.extra_rows = 2 + left_rbl + right_rbl
+ self.extra_cols = 2 + left_rbl + right_rbl
+
+ self.create_netlist()
+ if not OPTS.netlist_only:
+ self.create_layout()
+
+ # We don't offset this because we need to align
+ # the replica bitcell in the control logic
+ #self.offset_all_coordinates()
+
+
+ def create_netlist(self):
+ """ Create and connect the netlist """
+ self.add_modules()
+ self.add_pins()
+ self.create_instances()
+
+ def add_modules(self):
+ """ Array and dummy/replica columns
+
+ d or D = dummy cell (caps to distinguish grouping)
+ r or R = replica cell (caps to distinguish grouping)
+ b or B = bitcell
+ replica columns 1
+ v v
+ bdDDDDDDDDDDDDDDdb <- Dummy row
+ bdDDDDDDDDDDDDDDrb <- Dummy row
+ br--------------rb
+ br| Array |rb
+ br| row x col |rb
+ br--------------rb
+ brDDDDDDDDDDDDDDdb <- Dummy row
+ bdDDDDDDDDDDDDDDdb <- Dummy row
+
+ ^^^^^^^^^^^^^^^
+ dummy rows cols x 1
+
+ ^ dummy columns ^
+ 1 x (rows + 4)
+ """
+
+ # Bitcell for port names only
+ self.cell = factory.create(module_type="bitcell")
+
+ # Bitcell array
+ self.bitcell_array = factory.create(module_type="bitcell_array",
+ cols=self.column_size,
+ rows=self.row_size)
+ self.add_mod(self.bitcell_array)
+
+ # Replica bitlines
+ self.replica_columns = {}
+ for bit in range(self.left_rbl+self.right_rbl):
+ if bit1 port)
+ for port in range(self.left_rbl):
+ # Make names for all RBLs
+ wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x),port) for x in range(len(self.all_ports))]
+ # Keep track of the pin that is the RBL
+ self.rbl_wl_names[port]=wl_names[self.bitcell_ports[port]]
+ self.replica_col_wl_names.extend(wl_names)
+ # Regular WLs
+ self.replica_col_wl_names.extend(self.bitcell_array_wl_names)
+ # Right port WLs (one dummy for each port when we allow >1 port)
+ for port in range(self.left_rbl,self.left_rbl+self.right_rbl):
+ # Make names for all RBLs
+ wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x),port) for x in range(len(self.all_ports))]
+ # Keep track of the pin that is the RBL
+ self.rbl_wl_names[port]=wl_names[self.bitcell_ports[port]]
+ self.replica_col_wl_names.extend(wl_names)
+ self.replica_col_wl_names.extend(["{0}_top".format(x) for x in self.dummy_cell_wl_names])
+
+ # Left/right dummy columns are connected identically to the replica column
+ self.dummy_col_wl_names = self.replica_col_wl_names
+
+
+ # Per port bitline names
+ self.replica_bl_names = {}
+ self.replica_wl_names = {}
+ # Array of all port bitline names
+ for port in range(self.left_rbl+self.right_rbl):
+ left_names=["rbl_{0}_{1}".format(self.cell.get_bl_name(x),port) for x in range(len(self.all_ports))]
+ right_names=["rbl_{0}_{1}".format(self.cell.get_br_name(x),port) for x in range(len(self.all_ports))]
+ # Keep track of the left pins that are the RBL
+ self.rbl_bl_names[port]=left_names[self.bitcell_ports[port]]
+ self.rbl_br_names[port]=right_names[self.bitcell_ports[port]]
+ # Interleave the left and right lists
+ bl_names = [x for t in zip(left_names, right_names) for x in t]
+ self.replica_bl_names[port] = bl_names
+
+ wl_names = ["rbl_{0}_{1}".format(x,port) for x in self.cell.get_all_wl_names()]
+ #wl_names[port] = "rbl_wl{}".format(port)
+ self.replica_wl_names[port] = wl_names
+
+
+ # External pins
+ self.add_pin_list(self.bitcell_array_bl_names, "INOUT")
+ # Need to sort by port order since dictionary values may not be in order
+ bl_names = [self.rbl_bl_names[x] for x in sorted(self.rbl_bl_names.keys())]
+ br_names = [self.rbl_br_names[x] for x in sorted(self.rbl_br_names.keys())]
+ for (bl_name,br_name) in zip(bl_names,br_names):
+ self.add_pin(bl_name,"OUTPUT")
+ self.add_pin(br_name,"OUTPUT")
+ self.add_pin_list(self.bitcell_array_wl_names, "INPUT")
+ # Need to sort by port order since dictionary values may not be in order
+ wl_names = [self.rbl_wl_names[x] for x in sorted(self.rbl_wl_names.keys())]
+ for pin_name in wl_names:
+ self.add_pin(pin_name,"INPUT")
+ self.add_pin("vdd", "POWER")
+ self.add_pin("gnd", "GROUND")
+
+
+ def create_instances(self):
+ """ Create the module instances used in this design """
+
+ supplies = ["vdd", "gnd"]
+
+ # Used for names/dimensions only
+ self.cell = factory.create(module_type="bitcell")
+
+ # Main array
+ self.bitcell_array_inst=self.add_inst(name="bitcell_array",
+ mod=self.bitcell_array)
+ self.connect_inst(self.bitcell_array_bl_names + self.bitcell_array_wl_names + supplies)
+
+ # Replica columns
+ self.replica_col_inst = {}
+ for port in range(self.left_rbl+self.right_rbl):
+ self.replica_col_inst[port]=self.add_inst(name="replica_col_{}".format(port),
+ mod=self.replica_columns[port])
+ self.connect_inst(self.replica_bl_names[port] + self.replica_col_wl_names + supplies)
+
+
+ # Dummy rows under the bitcell array (connected with with the replica cell wl)
+ self.dummy_row_replica_inst = {}
+ for port in range(self.left_rbl+self.right_rbl):
+ self.dummy_row_replica_inst[port]=self.add_inst(name="dummy_row_{}".format(port),
+ mod=self.dummy_row)
+ self.connect_inst(self.dummy_row_bl_names + self.replica_wl_names[port] + supplies)
+
+
+ # Top/bottom dummy rows
+ self.dummy_row_bot_inst=self.add_inst(name="dummy_row_bot",
+ mod=self.dummy_row)
+ self.connect_inst(self.dummy_row_bl_names + [x+"_bot" for x in self.dummy_cell_wl_names] + supplies)
+ self.dummy_row_top_inst=self.add_inst(name="dummy_row_top",
+ mod=self.dummy_row)
+ self.connect_inst(self.dummy_row_bl_names + [x+"_top" for x in self.dummy_cell_wl_names] + supplies)
+
+
+ # Left/right Dummy columns
+ self.dummy_col_left_inst=self.add_inst(name="dummy_col_left",
+ mod=self.dummy_col)
+ self.connect_inst([x+"_left" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies)
+ self.dummy_col_right_inst=self.add_inst(name="dummy_col_right",
+ mod=self.dummy_col)
+ self.connect_inst([x+"_right" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies)
+
+
+
+ def create_layout(self):
+
+ self.height = (self.row_size+self.extra_rows)*self.dummy_row.height
+ self.width = (self.column_size+self.extra_cols)*self.cell.width
+
+ # This is a bitcell x bitcell offset to scale
+ offset = vector(self.cell.width, self.cell.height)
+
+ self.bitcell_array_inst.place(offset=[0,0])
+
+ # To the left of the bitcell array
+ for bit in range(self.left_rbl):
+ self.replica_col_inst[bit].place(offset=offset.scale(-bit-1,-self.left_rbl-1))
+ # To the right of the bitcell array
+ for bit in range(self.right_rbl):
+ self.replica_col_inst[self.left_rbl+bit].place(offset=offset.scale(bit,-self.left_rbl-1)+self.bitcell_array_inst.lr())
+
+
+ # Far top dummy row (first row above array is NOT flipped)
+ flip_dummy = self.right_rbl%2
+ self.dummy_row_top_inst.place(offset=offset.scale(0,self.right_rbl+flip_dummy)+self.bitcell_array_inst.ul(),
+ mirror="MX" if flip_dummy else "R0")
+ # Far bottom dummy row (first row below array IS flipped)
+ flip_dummy = (self.left_rbl+1)%2
+ self.dummy_row_bot_inst.place(offset=offset.scale(0,-self.left_rbl-1+flip_dummy),
+ mirror="MX" if flip_dummy else "R0")
+ # Far left dummy col
+ self.dummy_col_left_inst.place(offset=offset.scale(-self.left_rbl-1,-self.left_rbl-1))
+ # Far right dummy col
+ self.dummy_col_right_inst.place(offset=offset.scale(self.right_rbl,-self.left_rbl-1)+self.bitcell_array_inst.lr())
+
+ # Replica dummy rows
+ for bit in range(self.left_rbl):
+ self.dummy_row_replica_inst[bit].place(offset=offset.scale(0,-bit-bit%2),
+ mirror="R0" if bit%2 else "MX")
+ for bit in range(self.right_rbl):
+ self.dummy_row_replica_inst[self.left_rbl+bit].place(offset=offset.scale(0,bit+bit%2)+self.bitcell_array_inst.ul(),
+ mirror="MX" if bit%2 else "R0")
+
+
+ self.translate_all(offset.scale(-1-self.left_rbl,-1-self.left_rbl))
+
+ self.add_layout_pins()
+
+ self.add_boundary()
+
+ self.DRC_LVS()
+
+
+ def add_layout_pins(self):
+ """ Add the layout pins """
+
+ # Main array wl and bl/br
+ pin_names = self.bitcell_array.get_pin_names()
+ for pin_name in pin_names:
+ if pin_name.startswith("wl"):
+ pin_list = self.bitcell_array_inst.get_pins(pin_name)
+ for pin in pin_list:
+ self.add_layout_pin(text=pin_name,
+ layer=pin.layer,
+ offset=pin.ll().scale(0,1),
+ width=self.width,
+ height=pin.height())
+ elif pin_name.startswith("bl") or pin_name.startswith("br"):
+ pin_list = self.bitcell_array_inst.get_pins(pin_name)
+ for pin in pin_list:
+ self.add_layout_pin(text=pin_name,
+ layer=pin.layer,
+ offset=pin.ll().scale(1,0),
+ width=pin.width(),
+ height=self.height)
+
+
+ # Replica wordlines
+ for port in range(self.left_rbl+self.right_rbl):
+ inst = self.replica_col_inst[port]
+ for (pin_name,wl_name) in zip(self.cell.get_all_wl_names(),self.replica_wl_names[port]):
+ # +1 for dummy row
+ pin_bit = port+1
+ # +row_size if above the array
+ if port>=self.left_rbl:
+ pin_bit += self.row_size
+
+ pin_name += "_{}".format(pin_bit)
+ pin = inst.get_pin(pin_name)
+ if wl_name in self.rbl_wl_names.values():
+ self.add_layout_pin(text=wl_name,
+ layer=pin.layer,
+ offset=pin.ll().scale(0,1),
+ width=self.width,
+ height=pin.height())
+
+
+ # Replica bitlines
+ for port in range(self.left_rbl+self.right_rbl):
+ inst = self.replica_col_inst[port]
+ for (pin_name, bl_name) in zip(self.cell.get_all_bitline_names(),self.replica_bl_names[port]):
+ pin = inst.get_pin(pin_name)
+ if bl_name in self.rbl_bl_names or bl_name in self.rbl_br_names:
+ name = bl_name
+ else:
+ name = "rbl_{0}_{1}".format(pin_name,port)
+ self.add_layout_pin(text=name,
+ layer=pin.layer,
+ offset=pin.ll().scale(1,0),
+ width=pin.width(),
+ height=self.height)
+
+
+ for pin_name in ["vdd","gnd"]:
+ for inst in self.insts:
+ pin_list = inst.get_pins(pin_name)
+ for pin in pin_list:
+ self.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer)
+
+
+
+
+ def get_rbl_wl_name(self, port):
+ """ Return the WL for the given RBL port """
+ return self.rbl_wl_names[port]
+
+ def get_rbl_bl_name(self, port):
+ """ Return the BL for the given RBL port """
+ return self.rbl_bl_names[port]
+
+ def get_rbl_br_name(self, port):
+ """ Return the BR for the given RBL port """
+ return self.rbl_br_names[port]
+
+ def analytical_power(self, corner, load):
+ """Power of Bitcell array and bitline in nW."""
+ from tech import drc, parameter
+
+ # Dynamic Power from Bitline
+ bl_wire = self.gen_bl_wire()
+ cell_load = 2 * bl_wire.return_input_cap()
+ bl_swing = OPTS.rbl_delay_percentage
+ freq = spice["default_event_frequency"]
+ bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing)
+
+ #Calculate the bitcell power which currently only includes leakage
+ cell_power = self.cell.analytical_power(corner, load)
+
+ #Leakage power grows with entire array and bitlines.
+ total_power = self.return_power(cell_power.dynamic + bitline_dynamic * self.column_size,
+ cell_power.leakage * self.column_size * self.row_size)
+ return total_power
+
+ def gen_bl_wire(self):
+ if OPTS.netlist_only:
+ height = 0
+ else:
+ height = self.height
+ bl_pos = 0
+ bl_wire = self.generate_rc_net(int(self.row_size-bl_pos), height, drc("minwidth_metal1"))
+ bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell
+ return bl_wire
+
+ def get_wordline_cin(self):
+ """Get the relative input capacitance from the wordline connections in all the bitcell"""
+ #A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns
+ bitcell_wl_cin = self.cell.get_wl_cin()
+ total_cin = bitcell_wl_cin * self.column_size
+ return total_cin
+
+ def graph_exclude_bits(self, targ_row, targ_col):
+ """Excludes bits in column from being added to graph except target"""
+ self.bitcell_array.graph_exclude_bits(targ_row, targ_col)
+
+ def graph_exclude_replica_col_bits(self):
+ """Exclude all replica/dummy cells in the replica columns except the replica bit."""
+
+ for port in range(self.left_rbl+self.right_rbl):
+ self.replica_columns[port].exclude_all_but_replica()
+
+ def get_cell_name(self, inst_name, row, col):
+ """Gets the spice name of the target bitcell."""
+ return self.bitcell_array.get_cell_name(inst_name+'.x'+self.bitcell_array_inst.name, row, col)
diff --git a/compiler/modules/replica_bitline.py b/compiler/modules/replica_bitline.py
deleted file mode 100644
index 8d93b257..00000000
--- a/compiler/modules/replica_bitline.py
+++ /dev/null
@@ -1,627 +0,0 @@
-import debug
-import design
-from tech import drc
-import contact
-from sram_factory import factory
-from vector import vector
-from globals import OPTS
-
-class replica_bitline(design.design):
- """
- Generate a module that simulates the delay of control logic
- and bit line charging. Stages is the depth of the delay
- line and rows is the height of the replica bit loads.
- """
-
- def __init__(self, name, delay_fanout_list, bitcell_loads):
- design.design.__init__(self, name)
-
- self.bitcell_loads = bitcell_loads
- self.delay_fanout_list = delay_fanout_list
-
- self.create_netlist()
- if not OPTS.netlist_only:
- self.create_layout()
-
- def create_netlist(self):
- self.add_modules()
- self.add_pins()
- self.create_instances()
-
- def create_layout(self):
- self.calculate_module_offsets()
- self.place_instances()
- self.route()
- self.add_layout_pins()
-
- self.offset_all_coordinates()
-
- #self.add_lvs_correspondence_points()
-
- # Extra pitch on top and right
- self.width = self.rbl_inst.rx() - self.dc_inst.lx() + self.m2_pitch
- self.height = max(self.rbl_inst.uy(), self.dc_inst.uy()) + self.m3_pitch
-
- self.DRC_LVS()
-
- def add_pins(self):
- for pin in ["en", "out", "vdd", "gnd"]:
- self.add_pin(pin)
-
- def calculate_module_offsets(self):
- """ Calculate all the module offsets """
-
- # These aren't for instantiating, but we use them to get the dimensions
- self.poly_contact_offset = vector(0.5*contact.poly.width,0.5*contact.poly.height)
-
- # Quadrant 1: Replica bitline and such are not rotated, but they must be placed far enough
- # away from the delay chain/inverter with space for three M2 tracks
- self.bitcell_offset = vector(0,self.replica_bitcell.height)
- self.rbl_offset = self.bitcell_offset
-
- # Gap between the delay chain and RBL
- gap_width = 2*self.m2_pitch
-
- # Quadrant 4: with some space below it and tracks on the right for vdd/gnd
- self.delay_chain_offset = vector(-self.delay_chain.width-gap_width,self.replica_bitcell.height)
-
- # Will be flipped vertically below the delay chain
- # Align it with the inverters in the delay chain to simplify supply connections
- self.rbl_inv_offset = self.delay_chain_offset + vector(2*self.inv.width, 0)
-
- # Placed next to the replica bitcell
- self.access_tx_offset = vector(-gap_width-self.access_tx.width-self.inv.width, 0.5*self.inv.height)
-
-
- def add_modules(self):
- """ Add the modules for later usage """
-
- self.replica_bitcell = factory.create(module_type="replica_bitcell")
- self.add_mod(self.replica_bitcell)
-
- # This is the replica bitline load column that is the height of our array
- self.rbl = factory.create(module_type="bitcell_array",
- cols=1,
- rows=self.bitcell_loads)
- self.add_mod(self.rbl)
-
- # FIXME: The FO and depth of this should be tuned
- self.delay_chain = factory.create(module_type="delay_chain",
- fanout_list=self.delay_fanout_list)
- self.add_mod(self.delay_chain)
-
- self.inv = factory.create(module_type="pinv")
- self.add_mod(self.inv)
-
- self.access_tx = factory.create(module_type="ptx",
- tx_type="pmos")
- self.add_mod(self.access_tx)
-
- def create_instances(self):
- """ Create all of the module instances in the logical netlist """
-
- # This is the threshold detect inverter on the output of the RBL
- self.rbl_inv_inst=self.add_inst(name="rbl_inv",
- mod=self.inv)
- self.connect_inst(["bl0_0", "out", "vdd", "gnd"])
-
- self.tx_inst=self.add_inst(name="rbl_access_tx",
- mod=self.access_tx)
- # D, G, S, B
- self.connect_inst(["vdd", "delayed_en", "bl0_0", "vdd"])
- # add the well and poly contact
-
- self.dc_inst=self.add_inst(name="delay_chain",
- mod=self.delay_chain)
- self.connect_inst(["en", "delayed_en", "vdd", "gnd"])
-
- self.rbc_inst=self.add_inst(name="bitcell",
- mod=self.replica_bitcell)
- temp = []
- for port in self.all_ports:
- temp.append("bl{}_0".format(port))
- temp.append("br{}_0".format(port))
- for port in self.all_ports:
- temp.append("delayed_en")
- temp.append("vdd")
- temp.append("gnd")
- self.connect_inst(temp)
-
- self.rbl_inst=self.add_inst(name="load",
- mod=self.rbl)
-
- temp = []
- for port in self.all_ports:
- temp.append("bl{}_0".format(port))
- temp.append("br{}_0".format(port))
- for wl in range(self.bitcell_loads):
- for port in self.all_ports:
- temp.append("gnd")
- temp.append("vdd")
- temp.append("gnd")
- self.connect_inst(temp)
-
- self.wl_list = self.rbl.cell.list_all_wl_names()
- self.bl_list = self.rbl.cell.list_all_bl_names()
-
- def place_instances(self):
- """ Add all of the module instances in the logical netlist """
-
- # This is the threshold detect inverter on the output of the RBL
- self.rbl_inv_inst.place(offset=self.rbl_inv_offset,
- rotate=180)
-
- self.tx_inst.place(self.access_tx_offset)
-
- self.dc_inst.place(self.delay_chain_offset)
-
- self.rbc_inst.place(offset=self.bitcell_offset,
- mirror="MX")
-
- self.rbl_inst.place(self.rbl_offset)
-
-
- def route(self):
- """ Connect all the signals together """
- self.route_supplies()
- self.route_wl()
- self.route_access_tx()
-
- def route_wl(self):
- """ Connect the RBL word lines to gnd """
- # Connect the WL and gnd pins directly to the center and right gnd rails
- for row in range(self.bitcell_loads):
- wl = self.wl_list[0]+"_{}".format(row)
- pin = self.rbl_inst.get_pin(wl)
-
- # Route the connection to the right so that it doesn't interfere with the cells
- # Wordlines may be close to each other when tiled, so gnd connections are routed in opposite directions
- pin_right = pin.rc()
- pin_extension = pin_right + vector(self.m3_pitch,0)
-
- if pin.layer != "metal1":
- continue
- pin_width_ydir = pin.uy()-pin.by()
- #Width is set to pin y width to avoid DRC issues with m1 gaps
- self.add_path("metal1", [pin_right, pin_extension], pin_width_ydir)
- self.add_power_pin("gnd", pin_extension)
-
- # for multiport, need to short wordlines to each other so they all connect to gnd.
- wl_last = self.wl_list[-1]+"_{}".format(row)
- pin_last = self.rbl_inst.get_pin(wl_last)
- self.short_wordlines(pin, pin_last, "right", False, row, vector(self.m3_pitch,0))
-
- def short_wordlines(self, wl_pin_a, wl_pin_b, pin_side, is_replica_cell, cell_row=0, offset_x_vec=None):
- """Connects the word lines together for a single bitcell. Also requires which side of the bitcell to short the pins."""
- #Assumes input pins are wordlines. Also assumes the word lines are horizontal in metal1. Also assumes pins have same x coord.
- #This is my (Hunter) first time editing layout in openram so this function is likely not optimal.
- if len(self.all_ports) > 1:
- #1. Create vertical metal for all the bitlines to connect to
- #m1 needs to be extended in the y directions, direction needs to be determined as every other cell is flipped
- correct_y = vector(0, 0.5*drc("minwidth_metal1"))
- #x spacing depends on the side being drawn. Unknown to me (Hunter) why the size of the space differs by the side.
- #I assume this is related to how a wire is draw, but I have not investigated the issue.
- if pin_side == "right":
- correct_x = vector(0.5*drc("minwidth_metal1"), 0)
- if offset_x_vec != None:
- correct_x = offset_x_vec
- else:
- correct_x = vector(1.5*drc("minwidth_metal1"), 0)
-
- if wl_pin_a.uy() > wl_pin_b.uy():
- self.add_path("metal1", [wl_pin_a.rc()+correct_x+correct_y, wl_pin_b.rc()+correct_x-correct_y])
- else:
- self.add_path("metal1", [wl_pin_a.rc()+correct_x-correct_y, wl_pin_b.rc()+correct_x+correct_y])
- elif pin_side == "left":
- if offset_x_vec != None:
- correct_x = offset_x_vec
- else:
- correct_x = vector(1.5*drc("minwidth_metal1"), 0)
-
- if wl_pin_a.uy() > wl_pin_b.uy():
- self.add_path("metal1", [wl_pin_a.lc()-correct_x+correct_y, wl_pin_b.lc()-correct_x-correct_y])
- else:
- self.add_path("metal1", [wl_pin_a.lc()-correct_x-correct_y, wl_pin_b.lc()-correct_x+correct_y])
- else:
- debug.error("Could not connect wordlines on specified input side={}".format(pin_side),1)
-
- #2. Connect word lines horizontally. Only replica cell needs. Bitline loads currently already do this.
- for port in self.all_ports:
- if is_replica_cell:
- wl = self.wl_list[port]
- pin = self.rbc_inst.get_pin(wl)
- else:
- wl = self.wl_list[port]+"_{}".format(cell_row)
- pin = self.rbl_inst.get_pin(wl)
-
- if pin_side == "left":
- self.add_path("metal1", [pin.lc()-correct_x, pin.lc()])
- elif pin_side == "right":
- self.add_path("metal1", [pin.rc()+correct_x, pin.rc()])
-
-
-
- def route_supplies(self):
- """ Propagate all vdd/gnd pins up to this level for all modules """
-
- # These are the instances that every bank has
- top_instances = [self.rbl_inst,
- self.dc_inst]
- for inst in top_instances:
- self.copy_layout_pin(inst, "vdd")
- self.copy_layout_pin(inst, "gnd")
-
-
- # Route the inverter supply pin from M1
- # Only vdd is needed because gnd shares a rail with the delay chain
- pin = self.rbl_inv_inst.get_pin("vdd")
- self.add_power_pin("vdd", pin.lc())
-
- pin=self.rbc_inst.get_pin("vdd")
- self.add_power_pin("vdd", pin.center(), 0, pin.layer)
-
- for pin in self.rbc_inst.get_pins("gnd"):
- self.add_power_pin("gnd", pin.center())
-
-
-
- def route_access_tx(self):
- # GATE ROUTE
- # 1. Add the poly contact and nwell enclosure
- # Determines the y-coordinate of where to place the gate input poly pin
- # (middle in between the pmos and nmos)
-
- poly_pin = self.tx_inst.get_pin("G")
- poly_offset = poly_pin.uc()
- # This centers the contact above the poly by one pitch
- contact_offset = poly_offset + vector(0,self.m2_pitch)
- self.add_contact_center(layers=("poly", "contact", "metal1"),
- offset=contact_offset)
- self.add_contact_center(layers=("metal1", "via1", "metal2"),
- offset=contact_offset)
- self.add_segment_center(layer="poly",
- start=poly_offset,
- end=contact_offset)
- nwell_offset = self.rbl_inv_offset + vector(-self.inv.height,self.inv.width)
- # self.add_rect(layer="nwell",
- # offset=nwell_offset,
- # width=0.5*self.inv.height,
- # height=self.delay_chain_offset.y-nwell_offset.y)
-
- # 2. Route delay chain output to access tx gate
- delay_en_offset = self.dc_inst.get_pin("out").bc()
- self.add_path("metal2", [delay_en_offset,contact_offset])
-
- # 3. Route the contact of previous route to the bitcell WL
- # route bend of previous net to bitcell WL
- wl_offset = self.rbc_inst.get_pin(self.wl_list[0]).lc()
- wl_mid1 = wl_offset - vector(1.5*drc("minwidth_metal1"), 0)
- wl_mid2 = vector(wl_mid1.x, contact_offset.y)
- #xmid_point= 0.5*(wl_offset.x+contact_offset.x)
- #wl_mid1 = vector(xmid_point,contact_offset.y)
- #wl_mid2 = vector(xmid_point,wl_offset.y)
- self.add_path("metal1", [wl_offset, wl_mid1, wl_mid2, contact_offset])
-
- # 4. Short wodlines if multiport
- wl = self.wl_list[0]
- wl_last = self.wl_list[-1]
- pin = self.rbc_inst.get_pin(wl)
- pin_last = self.rbc_inst.get_pin(wl_last)
- x_offset = self.short_wordlines(pin, pin_last, "left", True)
-
- #correct = vector(0.5*drc("minwidth_metal1"), 0)
- #self.add_path("metal1", [pin.lc()+correct, pin_last.lc()+correct])
-
- # DRAIN ROUTE
- # Route the drain to the vdd rail
- drain_offset = self.tx_inst.get_pin("D").center()
- self.add_power_pin("vdd", drain_offset, rotate=0)
-
- # SOURCE ROUTE
- # Route the drain to the RBL inverter input
- source_offset = self.tx_inst.get_pin("S").center()
- inv_A_offset = self.rbl_inv_inst.get_pin("A").center()
- self.add_path("metal1",[source_offset, inv_A_offset])
-
- # Route the connection of the source route to the RBL bitline (left)
- # Via will go halfway down from the bitcell
- bl_offset = self.rbc_inst.get_pin(self.bl_list[0]).bc()
- # Route down a pitch so we can use M2 routing
- bl_down_offset = bl_offset - vector(0, self.m2_pitch)
- self.add_path("metal2",[source_offset, bl_down_offset, bl_offset])
- self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=source_offset)
-
- # BODY ROUTE
- # Connect it to the inverter well
- nwell_offset = self.rbl_inv_inst.lr()
- ur_offset = self.tx_inst.ur()
- self.add_rect(layer="nwell",
- offset=nwell_offset,
- width=ur_offset.x-nwell_offset.x,
- height=ur_offset.y-nwell_offset.y)
-
- def route_vdd(self):
- """ Route all signals connected to vdd """
-
- self.copy_layout_pin(self.dc_inst,"vdd")
- self.copy_layout_pin(self.rbc_inst,"vdd")
-
- # Connect the WL and vdd pins directly to the center and right vdd rails
- # Connect RBL vdd pins to center and right rails
- rbl_vdd_pins = self.rbl_inst.get_pins("vdd")
- for pin in rbl_vdd_pins:
- if pin.layer != "metal1":
- continue
- start = vector(self.center_vdd_pin.cx(),pin.cy())
- end = vector(self.right_vdd_pin.cx(),pin.cy())
- self.add_layout_pin_segment_center(text="vdd",
- layer="metal1",
- start=start,
- end=end)
- self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=start,
- rotate=90)
- self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=end,
- rotate=90)
-
- # Add via for the inverter
- pin = self.rbl_inv_inst.get_pin("vdd")
- start = vector(self.left_vdd_pin.cx(),pin.cy())
- end = vector(self.center_vdd_pin.cx(),pin.cy())
- self.add_segment_center(layer="metal1",
- start=start,
- end=end)
- self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=start,
- rotate=90)
-
- self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=end,
- rotate=90)
-
-
- # Add via for the RBC
- pin = self.rbc_inst.get_pin("vdd")
- start = pin.lc()
- end = vector(self.right_vdd_pin.cx(),pin.cy())
- self.add_segment_center(layer="metal1",
- start=start,
- end=end)
- self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=end,
- rotate=90)
-
- # Create the RBL rails too
- rbl_pins = self.rbl_inst.get_pins("vdd")
- for pin in rbl_pins:
- if pin.layer != "metal1":
- continue
- # If above the delay line, route the full width
- left = vector(self.left_vdd_pin.cx(),pin.cy())
- center = vector(self.center_vdd_pin.cx(),pin.cy())
- if pin.cy() > self.dc_inst.uy() + self.m1_pitch:
- start = left
- self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=left,
- rotate=90)
- else:
- start = center
- end = vector(self.right_vdd_pin.cx()+0.5*self.m1_width,pin.cy())
- self.add_layout_pin_segment_center(text="vdd",
- layer="metal1",
- start=start,
- end=end)
-
-
-
-
-
-
- def route_gnd(self):
- """ Route all signals connected to gnd """
-
- # Route the gnd lines from left to right
-
- # Add via for the delay chain
- left_gnd_start = self.dc_inst.ll().scale(1,0) - vector(2*self.m2_pitch,0)
- left_gnd_end = vector(left_gnd_start.x, self.rbl_inst.uy()+self.m2_pitch)
- self.left_gnd_pin=self.add_segment_center(layer="metal2",
- start=left_gnd_start,
- end=left_gnd_end)
-
- # Gnd line to the left of the replica bitline
- center_gnd_start = self.rbc_inst.ll().scale(1,0) - vector(2*self.m2_pitch,0)
- center_gnd_end = vector(center_gnd_start.x, self.rbl_inst.uy()+self.m2_pitch)
- self.center_gnd_pin=self.add_segment_center(layer="metal2",
- start=center_gnd_start,
- end=center_gnd_end)
-
- # Gnd line to the right of the replica bitline
- right_gnd_start = self.rbc_inst.lr().scale(1,0) + vector(self.m2_pitch,0)
- right_gnd_end = vector(right_gnd_start.x, self.rbl_inst.uy()+self.m2_pitch)
- self.right_gnd_pin=self.add_segment_center(layer="metal2",
- start=right_gnd_start,
- end=right_gnd_end)
-
-
-
- # Connect the WL and gnd pins directly to the center and right gnd rails
- for row in range(self.bitcell_loads):
- wl = self.wl_list[0]+"_{}".format(row)
- pin = self.rbl_inst.get_pin(wl)
- if pin.layer != "metal1":
- continue
- # If above the delay line, route the full width
- left = vector(self.left_gnd_pin.cx(),pin.cy())
- center = vector(self.center_gnd_pin.cx(),pin.cy())
- if pin.cy() > self.dc_inst.uy() + self.m1_pitch:
- start = left
- else:
- start = center
- end = vector(self.right_gnd_pin.cx(),pin.cy())
- self.add_layout_pin_segment_center(text="gnd",
- layer="metal1",
- start=start,
- end=end)
- if start == left:
- self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=left,
- rotate=90)
- self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=center,
- rotate=90)
- self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=end,
- rotate=90)
-
-
- rbl_gnd_pins = self.rbl_inst.get_pins("gnd")
- # Add L shapes to each vertical gnd rail
- for pin in rbl_gnd_pins:
- if pin.layer != "metal1":
- continue
- # If above the delay line, route the full width
- left = vector(self.left_gnd_pin.cx(),pin.cy())
- center = vector(self.center_gnd_pin.cx(),pin.cy())
- if pin.cy() > self.dc_inst.uy() + self.m1_pitch:
- start = left
- else:
- start = center
- end = vector(self.right_gnd_pin.cx(),pin.cy())
- self.add_segment_center(layer="metal1",
- start=start,
- end=end)
- if start == left:
- self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=left,
- rotate=90)
- self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=center,
- rotate=90)
- self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=end,
- rotate=90)
-
-
-
- # Connect the gnd pins of the delay chain to the left rails
- dc_gnd_pins = self.dc_inst.get_pins("gnd")
- for pin in dc_gnd_pins:
- if pin.layer != "metal1":
- continue
- start = vector(self.left_gnd_pin.cx(),pin.cy())
- # Note, we don't connect to the center rails because of
- # via conflicts with the RBL
- #end = vector(self.center_gnd_pin.cx(),pin.cy())
- end = pin.rc()
- self.add_segment_center(layer="metal1",
- start=start,
- end=end)
- self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=start,
- rotate=90)
-
- # self.add_via_center(layers=("metal1", "via1", "metal2"),
- # offset=end,
- #rotate=90)
-
-
- # Add via for the inverter
- # pin = self.rbl_inv_inst.get_pin("gnd")
- # start = vector(self.left_gnd_pin.cx(),pin.cy())
- # end = vector(self.center_gnd_pin.cx(),pin.cy())
- # self.add_segment_center(layer="metal1",
- # start=start,
- # end=end)
- # self.add_via_center(layers=("metal1", "via1", "metal2"),
- # offset=start,
- #rotate=90)
- # self.add_via_center(layers=("metal1", "via1", "metal2"),
- # offset=end,
- #rotate=90)
-
-
-
- # Create RBL rails too
- rbl_pins = self.rbl_inst.get_pins("gnd")
- for pin in rbl_pins:
- if pin.layer != "metal2":
- continue
- start = vector(pin.cx(),self.right_gnd_pin.by())
- end = vector(pin.cx(),self.right_gnd_pin.uy())
- self.add_layout_pin_segment_center(text="gnd",
- layer="metal2",
- start=start,
- end=end)
-
-
-
- def add_layout_pins(self):
- """ Route the input and output signal """
- en_offset = self.dc_inst.get_pin("in").bc()
- self.add_layout_pin_segment_center(text="en",
- layer="metal2",
- start=en_offset,
- end=en_offset.scale(1,0))
-
- out_offset = self.rbl_inv_inst.get_pin("Z").center()
- self.add_layout_pin_segment_center(text="out",
- layer="metal2",
- start=out_offset,
- end=out_offset.scale(1,0))
- self.add_via_center(layers=("metal1", "via1", "metal2"),
- offset=out_offset)
-
- def add_lvs_correspondence_points(self):
- """ This adds some points for easier debugging if LVS goes wrong.
- These should probably be turned off by default though, since extraction
- will show these as ports in the extracted netlist.
- """
-
- pin = self.rbl_inv_inst.get_pin("A")
- self.add_label_pin(text="bl[0]",
- layer=pin.layer,
- offset=pin.ll(),
- height=pin.height(),
- width=pin.width())
-
- pin = self.dc_inst.get_pin("out")
- self.add_label_pin(text="delayed_en",
- layer=pin.layer,
- offset=pin.ll(),
- height=pin.height(),
- width=pin.width())
-
- def get_en_cin(self):
- """Get the enable input relative capacitance"""
- #The enable is only connected to the delay, get the cin from that module
- en_cin = self.delay_chain.get_cin()
- return en_cin
-
- def determine_sen_stage_efforts(self, ext_cout, inp_is_rise=True):
- """Get the stage efforts from the en to s_en. Does not compute the delay for the bitline load."""
- stage_effort_list = []
- #Stage 1 is the delay chain
- stage1_cout = self.get_delayed_en_cin()
- stage1 = self.delay_chain.determine_delayed_en_stage_efforts(stage1_cout, inp_is_rise)
- stage_effort_list += stage1
-
- #There is a disconnect between the delay chain and inverter. The rise/fall of the input to the inverter
- #Will be the negation of the previous stage.
- last_stage_is_rise = not stage_effort_list[-1].is_rise
-
- #The delay chain triggers the enable on the replica bitline (rbl). This is used to track the bitline delay whereas this
- #model is intended to track every but that. Therefore, the next stage is the inverter after the rbl.
- stage2 = self.inv.get_stage_effort(ext_cout, last_stage_is_rise)
- stage_effort_list.append(stage2)
-
- return stage_effort_list
-
- def get_delayed_en_cin(self):
- """Get the fanout capacitance (relative) of the delayed enable from the delay chain."""
- access_tx_cin = self.access_tx.get_cin()
- rbc_cin = self.replica_bitcell.get_wl_cin()
- return access_tx_cin + rbc_cin
-
diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py
new file mode 100644
index 00000000..c3f63b19
--- /dev/null
+++ b/compiler/modules/replica_column.py
@@ -0,0 +1,161 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California
+# All rights reserved.
+#
+import debug
+import design
+from tech import drc
+import contact
+from sram_factory import factory
+from vector import vector
+from globals import OPTS
+
+class replica_column(design.design):
+ """
+ Generate a replica bitline column for the replica array.
+ Rows is the total number of rows i the main array.
+ Left_rbl and right_rbl are the number of left and right replica bitlines.
+ Replica bit specifies which replica column this is (to determine where to put the
+ replica cell.
+ """
+
+ def __init__(self, name, rows, left_rbl, right_rbl, replica_bit):
+ design.design.__init__(self, name)
+
+ self.rows = rows
+ self.left_rbl = left_rbl
+ self.right_rbl = right_rbl
+ self.replica_bit = replica_bit
+ # left, right, regular rows plus top/bottom dummy cells
+ self.total_size = self.left_rbl+rows+self.right_rbl+2
+
+ debug.check(replica_bit!=0 and replica_bit!=rows,"Replica bit cannot be the dummy row.")
+ debug.check(replica_bit<=left_rbl or replica_bit>=self.total_size-right_rbl-1,
+ "Replica bit cannot be in the regular array.")
+
+ self.create_netlist()
+ if not OPTS.netlist_only:
+ self.create_layout()
+
+ def create_netlist(self):
+ self.add_modules()
+ self.add_pins()
+ self.create_instances()
+
+ def create_layout(self):
+ self.height = self.total_size*self.cell.height
+ self.width = self.cell.width
+
+ self.place_instances()
+ self.add_layout_pins()
+ self.add_boundary()
+ self.DRC_LVS()
+
+ def add_pins(self):
+
+ for bl_name in self.cell.get_all_bitline_names():
+ # In the replica column, these are only outputs!
+ self.add_pin("{0}_{1}".format(bl_name,0), "OUTPUT")
+
+ for row in range(self.total_size):
+ for wl_name in self.cell.get_all_wl_names():
+ self.add_pin("{0}_{1}".format(wl_name,row), "INPUT")
+
+ self.add_pin("vdd", "POWER")
+ self.add_pin("gnd", "GROUND")
+
+ def add_modules(self):
+ self.replica_cell = factory.create(module_type="replica_bitcell")
+ self.add_mod(self.replica_cell)
+ self.dummy_cell = factory.create(module_type="dummy_bitcell")
+ self.add_mod(self.dummy_cell)
+ # Used for pin names only
+ self.cell = factory.create(module_type="bitcell")
+
+ def create_instances(self):
+ self.cell_inst = {}
+ for row in range(self.total_size):
+ name="rbc_{0}".format(row)
+ # Top/bottom cell are always dummy cells.
+ # Regular array cells are replica cells (>left_rbl and self.left_rbl and row net
- decode_t_net = self.nand2.analytical_delay(corner, slew, self.inv.input_load())
-
- # net -> wl
- net_t_wl = self.inv.analytical_delay(corner, decode_t_net.slew, load)
-
- return decode_t_net + net_t_wl
-
-
- def input_load(self):
- """Gets the capacitance of the wordline driver in absolute units (fF)"""
- return self.nand2.input_load()
-
def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True):
"""Follows the clk_buf to a wordline signal adding each stages stage effort to a list"""
stage_effort_list = []
diff --git a/compiler/modules/write_driver.py b/compiler/modules/write_driver.py
index 34c51245..85a58fd5 100644
--- a/compiler/modules/write_driver.py
+++ b/compiler/modules/write_driver.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
import design
import utils
@@ -11,7 +18,8 @@ class write_driver(design.design):
the technology library.
"""
- pin_names = ["din", "bl", "br", "en", "gnd", "vdd"]
+ pin_names = ["din", "bl", "br", "en", "vdd", "gnd"]
+ type_list = ["INPUT", "OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("write_driver", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "write_driver", GDS["unit"])
@@ -22,9 +30,13 @@ class write_driver(design.design):
self.width = write_driver.width
self.height = write_driver.height
self.pin_map = write_driver.pin_map
-
+ self.add_pin_types(self.type_list)
def get_w_en_cin(self):
"""Get the relative capacitance of a single input"""
# This is approximated from SCMOS. It has roughly 5 3x transistor gates.
return 5*3
+
+ def build_graph(self, graph, inst_name, port_nets):
+ """Adds edges based on inputs/outputs. Overrides base class function."""
+ self.add_graph_edges(graph, port_nets)
\ No newline at end of file
diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py
index 3367cc00..100ee3a2 100644
--- a/compiler/modules/write_driver_array.py
+++ b/compiler/modules/write_driver_array.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
from math import log
import design
from tech import drc
@@ -12,7 +19,7 @@ class write_driver_array(design.design):
Dynamically generated write driver array of all bitlines.
"""
- def __init__(self, name, columns, word_size):
+ def __init__(self, name, columns, word_size,write_size=None):
design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("columns: {0}".format(columns))
@@ -20,8 +27,12 @@ class write_driver_array(design.design):
self.columns = columns
self.word_size = word_size
+ self.write_size = write_size
self.words_per_row = int(columns / word_size)
+ if self.write_size:
+ self.num_wmasks = int(self.word_size/self.write_size)
+
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@@ -38,22 +49,26 @@ class write_driver_array(design.design):
self.width = self.columns * self.bitcell.width
else:
self.width = self.columns * self.driver.width
-
self.height = self.driver.height
self.place_write_array()
self.add_layout_pins()
+ self.add_boundary()
self.DRC_LVS()
def add_pins(self):
for i in range(self.word_size):
- self.add_pin("data_{0}".format(i))
+ self.add_pin("data_{0}".format(i), "INPUT")
for i in range(self.word_size):
- self.add_pin("bl_{0}".format(i))
- self.add_pin("br_{0}".format(i))
- self.add_pin("en")
- self.add_pin("vdd")
- self.add_pin("gnd")
+ self.add_pin("bl_{0}".format(i), "OUTPUT")
+ self.add_pin("br_{0}".format(i), "OUTPUT")
+ if self.write_size:
+ for i in range(self.num_wmasks):
+ self.add_pin("en_{0}".format(i), "INPUT")
+ else:
+ self.add_pin("en", "INPUT")
+ self.add_pin("vdd", "POWER")
+ self.add_pin("gnd", "GROUND")
def add_modules(self):
self.driver = factory.create(module_type="write_driver")
@@ -65,27 +80,39 @@ class write_driver_array(design.design):
def create_write_array(self):
self.driver_insts = {}
+ w = 0
+ windex=0
for i in range(0,self.columns,self.words_per_row):
name = "write_driver{}".format(i)
index = int(i/self.words_per_row)
self.driver_insts[index]=self.add_inst(name=name,
mod=self.driver)
- self.connect_inst(["data_{0}".format(index),
- "bl_{0}".format(index),
- "br_{0}".format(index),
- "en", "vdd", "gnd"])
+ if self.write_size:
+ self.connect_inst(["data_{0}".format(index),
+ "bl_{0}".format(index),
+ "br_{0}".format(index),
+ "en_{0}".format(windex), "vdd", "gnd"])
+ w+=1
+ # when w equals write size, the next en pin can be connected since we are now at the next wmask bit
+ if w == self.write_size:
+ w = 0
+ windex+=1
+ else:
+ self.connect_inst(["data_{0}".format(index),
+ "bl_{0}".format(index),
+ "br_{0}".format(index),
+ "en", "vdd", "gnd"])
def place_write_array(self):
if self.bitcell.width > self.driver.width:
- driver_spacing = self.bitcell.width
+ self.driver_spacing = self.bitcell.width
else:
- driver_spacing = self.driver.width
-
+ self.driver_spacing = self.driver.width
for i in range(0,self.columns,self.words_per_row):
- index = int(i/self.words_per_row)
- base = vector(i * driver_spacing,0)
+ index = int(i/self.words_per_row)
+ base = vector(i * self.driver_spacing, 0)
self.driver_insts[index].place(base)
@@ -121,15 +148,28 @@ class write_driver_array(design.design):
self.add_layout_pin_rect_center(text=n,
layer="metal3",
offset=pin_pos)
+ if self.write_size:
+ for bit in range(self.num_wmasks):
+ en_pin = self.driver_insts[bit*self.write_size].get_pin("en")
+ # Determine width of wmask modified en_pin with/without col mux
+ wmask_en_len = self.words_per_row*(self.write_size * self.driver_spacing)
+ if (self.words_per_row == 1):
+ en_gap = self.driver_spacing - en_pin.width()
+ else:
+ en_gap = self.driver_spacing
+
+ self.add_layout_pin(text="en_{0}".format(bit),
+ layer=en_pin.layer,
+ offset=en_pin.ll(),
+ width=wmask_en_len-en_gap,
+ height=en_pin.height())
+ else:
+ self.add_layout_pin(text="en",
+ layer="metal1",
+ offset=self.driver_insts[0].get_pin("en").ll().scale(0,1),
+ width=self.width)
-
- self.add_layout_pin(text="en",
- layer="metal1",
- offset=self.driver_insts[0].get_pin("en").ll().scale(0,1),
- width=self.width,
- height=drc('minwidth_metal1'))
-
def get_w_en_cin(self):
diff --git a/compiler/modules/write_mask_and_array.py b/compiler/modules/write_mask_and_array.py
new file mode 100644
index 00000000..258bbd8d
--- /dev/null
+++ b/compiler/modules/write_mask_and_array.py
@@ -0,0 +1,156 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+from math import log
+import design
+from tech import drc
+import debug
+from sram_factory import factory
+from vector import vector
+from globals import OPTS
+
+
+class write_mask_and_array(design.design):
+ """
+ Array of AND gates to turn write mask signal on only when w_en is on.
+ The write mask AND array goes between the write driver array and the sense amp array.
+ """
+
+ def __init__(self, name, columns, word_size, write_size, port=0):
+ design.design.__init__(self, name)
+ debug.info(1, "Creating {0}".format(self.name))
+ self.add_comment("columns: {0}".format(columns))
+ self.add_comment("word_size {0}".format(word_size))
+ self.add_comment("write_size {0}".format(write_size))
+
+ self.columns = columns
+ self.word_size = word_size
+ self.write_size = write_size
+ self.port = port
+ self.words_per_row = int(columns / word_size)
+ self.num_wmasks = int(word_size / write_size)
+
+ self.create_netlist()
+ if not OPTS.netlist_only:
+ self.create_layout()
+
+ def create_netlist(self):
+ self.add_modules()
+ self.add_pins()
+ self.create_and2_array()
+
+
+ def create_layout(self):
+ self.place_and2_array()
+ spacing = self.wmask_en_len - self.and2.width
+ self.width = (self.num_wmasks*self.and2.width) + ((self.num_wmasks-1)*spacing)
+ self.height = self.and2.height
+ self.add_layout_pins()
+ self.add_boundary()
+ self.DRC_LVS()
+
+ def add_pins(self):
+ for bit in range(self.num_wmasks):
+ self.add_pin("wmask_in_{}".format(bit),"INPUT")
+ self.add_pin("en", "INPUT")
+ for bit in range(self.num_wmasks):
+ self.add_pin("wmask_out_{}".format(bit),"OUTPUT")
+ self.add_pin("vdd","POWER")
+ self.add_pin("gnd","GROUND")
+
+ def add_modules(self):
+ # Size the AND gate for the number of write drivers it drives, which is equal to the write size.
+ # Assume stage effort of 3 to compute the size
+ self.and2 = factory.create(module_type="pand2",
+ size=self.write_size/4.0)
+ self.add_mod(self.and2)
+
+
+ def create_and2_array(self):
+ self.and2_insts = {}
+ for bit in range(self.num_wmasks):
+ name = "and2_{}".format(bit)
+ self.and2_insts[bit] = self.add_inst(name=name,
+ mod=self.and2)
+ self.connect_inst(["wmask_in_{}".format(bit),
+ "en",
+ "wmask_out_{}".format(bit),
+ "vdd", "gnd"])
+
+
+ def place_and2_array(self):
+ # Place the write mask AND array at the start of each write driver enable length.
+ # This ensures the write mask AND array will be directly under the corresponding write driver enable wire.
+
+ # This is just used for measurements, so don't add the module
+ self.bitcell = factory.create(module_type="bitcell")
+ self.driver = factory.create(module_type="write_driver")
+ if self.bitcell.width > self.driver.width:
+ self.driver_spacing = self.bitcell.width
+ else:
+ self.driver_spacing = self.driver.width
+
+ self.wmask_en_len = self.words_per_row * (self.write_size * self.driver_spacing)
+ debug.check(self.wmask_en_len >= self.and2.width,
+ "Write mask AND is wider than the corresponding write drivers {0} vs {1}.".format(self.and2.width,self.wmask_en_len))
+
+ for i in range(self.num_wmasks):
+ base = vector(i * self.wmask_en_len, 0)
+ self.and2_insts[i].place(base)
+
+
+ def add_layout_pins(self):
+ self.nand2 = factory.create(module_type="pnand2")
+ supply_pin=self.nand2.get_pin("vdd")
+
+ # Create the enable pin that connects all write mask AND array's B pins
+ beg_en_pin = self.and2_insts[0].get_pin("B")
+ end_en_pin = self.and2_insts[self.num_wmasks-1].get_pin("B")
+ if self.port % 2:
+ # Extend metal3 to edge of AND array in multiport
+ en_to_edge = self.and2.width - beg_en_pin.cx()
+ self.add_layout_pin(text="en",
+ layer="metal3",
+ offset=beg_en_pin.bc(),
+ width=end_en_pin.cx() - beg_en_pin.cx() + en_to_edge)
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=vector(end_en_pin.cx() + en_to_edge, end_en_pin.cy()))
+ self.add_via_center(layers=("metal2", "via2", "metal3"),
+ offset=vector(end_en_pin.cx() + en_to_edge, end_en_pin.cy()))
+ else:
+ self.add_layout_pin(text="en",
+ layer="metal3",
+ offset=beg_en_pin.bc(),
+ width=end_en_pin.cx() - beg_en_pin.cx())
+
+ for i in range(self.num_wmasks):
+ # Copy remaining layout pins
+ self.copy_layout_pin(self.and2_insts[i],"A","wmask_in_{0}".format(i))
+ self.copy_layout_pin(self.and2_insts[i],"Z","wmask_out_{0}".format(i))
+
+ # Add via connections to metal3 for AND array's B pin
+ en_pin = self.and2_insts[i].get_pin("B")
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=en_pin.center())
+ self.add_via_center(layers=("metal2", "via2", "metal3"),
+ offset=en_pin.center())
+
+ self.add_power_pin("gnd", vector(supply_pin.width() + i * self.wmask_en_len, 0))
+ self.add_power_pin("vdd", vector(supply_pin.width() + i * self.wmask_en_len, self.height))
+ # Route power and ground rails together
+ if i < self.num_wmasks-1:
+ for n in ["gnd","vdd"]:
+ pin = self.and2_insts[i].get_pin(n)
+ next_pin = self.and2_insts[i+1].get_pin(n)
+ self.add_path("metal1",[pin.center(),next_pin.center()])
+
+ def get_cin(self):
+ """Get the relative capacitance of all the input connections in the bank"""
+ # The enable is connected to an and2 for every row.
+ return self.and2.get_cin() * len(self.and2_insts)
+
+
diff --git a/compiler/openram.py b/compiler/openram.py
index 0fe3f7cd..97ada256 100755
--- a/compiler/openram.py
+++ b/compiler/openram.py
@@ -1,4 +1,11 @@
#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
"""
SRAM Compiler
@@ -43,13 +50,16 @@ from sram_config import sram_config
# Configure the SRAM organization
c = sram_config(word_size=OPTS.word_size,
- num_words=OPTS.num_words)
+ num_words=OPTS.num_words,
+ write_size=OPTS.write_size)
debug.print_raw("Words per row: {}".format(c.words_per_row))
#from parser import *
output_extensions = ["sp","v","lib","py","html","log"]
+# Only output lef/gds if back-end
if not OPTS.netlist_only:
- output_extensions.extend(["gds","lef"])
+ output_extensions.extend(["lef","gds"])
+
output_files = ["{0}{1}.{2}".format(OPTS.output_path,OPTS.output_name,x) for x in output_extensions]
debug.print_raw("Output files are: ")
for path in output_files:
diff --git a/compiler/options.py b/compiler/options.py
index 4d3461e6..ce974d63 100644
--- a/compiler/options.py
+++ b/compiler/options.py
@@ -1,6 +1,14 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import optparse
import getpass
import os
+#import sram_config
class options(optparse.Values):
"""
@@ -8,22 +16,82 @@ class options(optparse.Values):
that is the sole required command-line positional argument for openram.py.
"""
+ ###################
+ # Configuration options
+ ###################
# This is the technology directory.
openram_tech = ""
+
# This is the name of the technology.
tech_name = ""
+
+ # Port configuration (1-2 ports allowed)
+ num_rw_ports = 1
+ num_r_ports = 0
+ num_w_ports = 0
+
+ # Write mask size, default will be overwritten with word_size if not user specified
+ write_size = None
+
+ # These will get initialized by the user or the tech file
+ supply_voltages = ""
+ temperatures = ""
+ process_corners = ""
+
+ # Size parameters must be specified by user in config file.
+ #num_words = 0
+ #word_size = 0
+ # You can manually specify banks, but it is better to auto-detect it.
+ num_banks = 1
+
+ ###################
+ # Optimization options
+ ###################
+ rbl_delay_percentage = 0.5 #Approximate percentage of delay compared to bitlines
+
+ # Allow manual adjustment of the delay chain over automatic
+ use_tech_delay_chain_size = False
+ delay_chain_stages = 9
+ delay_chain_fanout_per_stage = 4
+
+
+
+ ###################
+ # Debug options.
+ ###################
# This is the temp directory where all intermediate results are stored.
- openram_temp = "/tmp/openram_{0}_{1}_temp/".format(getpass.getuser(),os.getpid())
- #openram_temp = "{0}/openram_temp/".format(os.getenv("HOME"))
+ try:
+ # If user defined the temporary location in their environment, use it
+ openram_temp = os.path.abspath(os.environ.get("OPENRAM_TMP"))
+ except:
+ # Else use a unique temporary directory
+ openram_temp = "/tmp/openram_{0}_{1}_temp/".format(getpass.getuser(),os.getpid())
# This is the verbosity level to control debug information. 0 is none, 1
# is minimal, etc.
debug_level = 0
+
+ ###################
+ # Run-time vs accuracy options.
+ # Default, sacrifice accuracy/completeness for speed.
+ # Must turn on options for verification, final routing, etc.
+ ###################
# When enabled, layout is not generated (and no DRC or LVS are performed)
netlist_only = False
+ # Whether we should do the final power routing
+ route_supplies = False
# This determines whether LVS and DRC is checked at all.
- check_lvsdrc = True
+ check_lvsdrc = False
# This determines whether LVS and DRC is checked for every submodule.
inline_lvsdrc = False
+ # Remove noncritical memory cells for characterization speed-up
+ trim_netlist = False
+ # Run with extracted parasitics
+ use_pex = False
+
+
+ ###################
+ # Tool options
+ ###################
# Variable to select the variant of spice
spice_name = ""
# The spice executable being used which is derived from the user PATH.
@@ -36,12 +104,9 @@ class options(optparse.Values):
drc_exe = None
lvs_exe = None
pex_exe = None
+
# Should we print out the banner at startup
print_banner = True
- # Run with extracted parasitics
- use_pex = False
- # Remove noncritical memory cells for characterization speed-up
- trim_netlist = True
# Use detailed LEF blockages
detailed_blockages = True
# Define the output file paths
@@ -53,28 +118,10 @@ class options(optparse.Values):
# Purge the temp directory after a successful run (doesn't purge on errors, anyhow)
purge_temp = True
- # These are the configuration parameters
- num_rw_ports = 1
- num_r_ports = 0
- num_w_ports = 0
-
- # These will get initialized by the the file
- supply_voltages = ""
- temperatures = ""
- process_corners = ""
- # These are the main configuration parameters that should be over-ridden
- # in a configuration file.
- #num_words = 0
- #word_size = 0
-
- # You can manually specify banks, but it is better to auto-detect it.
- num_banks = 1
-
- #Uses the delay chain size in the tech.py file rather automatic sizing.
- use_tech_delay_chain_size = False
-
+ ###################
# These are the default modules that can be over-riden
+ ###################
bank_select = "bank_select"
bitcell_array = "bitcell_array"
bitcell = "bitcell"
@@ -84,6 +131,7 @@ class options(optparse.Values):
delay_chain = "delay_chain"
dff_array = "dff_array"
dff = "dff"
+ dummy_bitcell = "dummy_bitcell"
precharge_array = "precharge_array"
ptx = "ptx"
replica_bitcell = "replica_bitcell"
@@ -95,4 +143,5 @@ class options(optparse.Values):
wordline_driver = "wordline_driver"
write_driver_array = "write_driver_array"
write_driver = "write_driver"
+ write_mask_and_array = "write_mask_and_array"
diff --git a/compiler/pgates/pand2.py b/compiler/pgates/pand2.py
index 54787282..d71b1e92 100644
--- a/compiler/pgates/pand2.py
+++ b/compiler/pgates/pand2.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
from tech import drc
from math import log
@@ -11,16 +18,13 @@ class pand2(pgate.pgate):
This is a simple buffer used for driving loads.
"""
def __init__(self, name, size=1, height=None):
- self.size = size
-
- pgate.pgate.__init__(self, name, height)
- debug.info(1, "Creating {}".format(self.name))
+ debug.info(1, "Creating pnand2 {}".format(name))
self.add_comment("size: {}".format(size))
- self.create_netlist()
- if not OPTS.netlist_only:
- self.create_layout()
-
+ self.size = size
+
+ # Creates the netlist and layout
+ pgate.pgate.__init__(self, name, height)
def create_netlist(self):
self.add_pins()
@@ -31,8 +35,8 @@ class pand2(pgate.pgate):
# Shield the cap, but have at least a stage effort of 4
self.nand = factory.create(module_type="pnand2",height=self.height)
self.add_mod(self.nand)
-
- self.inv = factory.create(module_type="pinv", size=self.size, height=self.height)
+
+ self.inv = factory.create(module_type="pdriver", neg_polarity=True, fanout=3*self.size, height=self.height)
self.add_mod(self.inv)
def create_layout(self):
@@ -40,13 +44,14 @@ class pand2(pgate.pgate):
self.place_insts()
self.add_wires()
self.add_layout_pins()
+ self.DRC_LVS()
def add_pins(self):
- self.add_pin("A")
- self.add_pin("B")
- self.add_pin("Z")
- self.add_pin("vdd")
- self.add_pin("gnd")
+ self.add_pin("A", "INPUT")
+ self.add_pin("B", "INPUT")
+ self.add_pin("Z", "OUTPUT")
+ self.add_pin("vdd", "POWER")
+ self.add_pin("gnd", "GROUND")
def create_insts(self):
self.nand_inst=self.add_inst(name="pand2_nand",
@@ -105,14 +110,6 @@ class pand2(pgate.pgate):
width=pin.width(),
height=pin.height())
-
-
- def analytical_delay(self, corner, slew, load=0.0):
- """ Calculate the analytical delay of DFF-> INV -> INV """
- nand_delay = self.nand.analytical_delay(corner, slew=slew, load=self.inv.input_load())
- inv_delay = self.inv.analytical_delay(corner, slew=nand_delay.slew, load=load)
- return nand_delay + inv_delay
-
def get_stage_efforts(self, external_cout, inp_is_rise=False):
"""Get the stage efforts of the A or B -> Z path"""
stage_effort_list = []
@@ -125,3 +122,8 @@ class pand2(pgate.pgate):
stage_effort_list.append(stage2)
return stage_effort_list
+
+ def get_cin(self):
+ """Return the relative input capacitance of a single input"""
+ return self.nand.get_cin()
+
diff --git a/compiler/pgates/pand3.py b/compiler/pgates/pand3.py
new file mode 100644
index 00000000..22864e5a
--- /dev/null
+++ b/compiler/pgates/pand3.py
@@ -0,0 +1,138 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import debug
+from tech import drc
+from math import log
+from vector import vector
+from globals import OPTS
+import pgate
+from sram_factory import factory
+
+class pand3(pgate.pgate):
+ """
+ This is a simple buffer used for driving loads.
+ """
+ def __init__(self, name, size=1, height=None):
+ debug.info(1, "Creating pand3 {}".format(name))
+ self.add_comment("size: {}".format(size))
+
+ self.size = size
+
+ # Creates the netlist and layout
+ pgate.pgate.__init__(self, name, height)
+
+ def create_netlist(self):
+ self.add_pins()
+ self.create_modules()
+ self.create_insts()
+
+ def create_modules(self):
+ # Shield the cap, but have at least a stage effort of 4
+ self.nand = factory.create(module_type="pnand3",height=self.height)
+ self.add_mod(self.nand)
+
+ self.inv = factory.create(module_type="pinv", size=self.size, height=self.height)
+ self.add_mod(self.inv)
+
+ def create_layout(self):
+ self.width = self.nand.width + self.inv.width
+ self.place_insts()
+ self.add_wires()
+ self.add_layout_pins()
+ self.DRC_LVS()
+
+ def add_pins(self):
+ self.add_pin("A", "INPUT")
+ self.add_pin("B", "INPUT")
+ self.add_pin("C", "INPUT")
+ self.add_pin("Z", "OUTPUT")
+ self.add_pin("vdd", "POWER")
+ self.add_pin("gnd", "GROUND")
+
+ def create_insts(self):
+ self.nand_inst=self.add_inst(name="pand3_nand",
+ mod=self.nand)
+ self.connect_inst(["A", "B", "C", "zb_int", "vdd", "gnd"])
+
+ self.inv_inst=self.add_inst(name="pand3_inv",
+ mod=self.inv)
+ self.connect_inst(["zb_int", "Z", "vdd", "gnd"])
+
+ def place_insts(self):
+ # Add NAND to the right
+ self.nand_inst.place(offset=vector(0,0))
+
+ # Add INV to the right
+ self.inv_inst.place(offset=vector(self.nand_inst.rx(),0))
+
+ def add_wires(self):
+ # nand Z to inv A
+ z1_pin = self.nand_inst.get_pin("Z")
+ a2_pin = self.inv_inst.get_pin("A")
+ mid1_point = vector(0.5*(z1_pin.cx()+a2_pin.cx()), z1_pin.cy())
+ mid2_point = vector(mid1_point, a2_pin.cy())
+ self.add_path("metal1", [z1_pin.center(), mid1_point, mid2_point, a2_pin.center()])
+
+
+ def add_layout_pins(self):
+ # Continous vdd rail along with label.
+ vdd_pin=self.inv_inst.get_pin("vdd")
+ self.add_layout_pin(text="vdd",
+ layer="metal1",
+ offset=vdd_pin.ll().scale(0,1),
+ width=self.width,
+ height=vdd_pin.height())
+
+ # Continous gnd rail along with label.
+ gnd_pin=self.inv_inst.get_pin("gnd")
+ self.add_layout_pin(text="gnd",
+ layer="metal1",
+ offset=gnd_pin.ll().scale(0,1),
+ width=self.width,
+ height=vdd_pin.height())
+
+ pin = self.inv_inst.get_pin("Z")
+ self.add_layout_pin_rect_center(text="Z",
+ layer=pin.layer,
+ offset=pin.center(),
+ width=pin.width(),
+ height=pin.height())
+
+ for pin_name in ["A","B", "C"]:
+ pin = self.nand_inst.get_pin(pin_name)
+ self.add_layout_pin_rect_center(text=pin_name,
+ layer=pin.layer,
+ offset=pin.center(),
+ width=pin.width(),
+ height=pin.height())
+
+
+
+ def analytical_delay(self, corner, slew, load=0.0):
+ """ Calculate the analytical delay of DFF-> INV -> INV """
+ nand_delay = self.nand.analytical_delay(corner, slew=slew, load=self.inv.input_load())
+ inv_delay = self.inv.analytical_delay(corner, slew=nand_delay.slew, load=load)
+ return nand_delay + inv_delay
+
+ def get_stage_efforts(self, external_cout, inp_is_rise=False):
+ """Get the stage efforts of the A or B -> Z path"""
+ stage_effort_list = []
+ stage1_cout = self.inv.get_cin()
+ stage1 = self.nand.get_stage_effort(stage1_cout, inp_is_rise)
+ stage_effort_list.append(stage1)
+ last_stage_is_rise = stage1.is_rise
+
+ stage2 = self.inv.get_stage_effort(external_cout, last_stage_is_rise)
+ stage_effort_list.append(stage2)
+
+ return stage_effort_list
+
+ def get_cin(self):
+ """Return the relative input capacitance of a single input"""
+ return self.nand.get_cin()
+
diff --git a/compiler/pgates/pbuf.py b/compiler/pgates/pbuf.py
index 9d73c004..fcfc6586 100644
--- a/compiler/pgates/pbuf.py
+++ b/compiler/pgates/pbuf.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
from tech import drc
from math import log
@@ -12,17 +19,15 @@ class pbuf(pgate.pgate):
"""
def __init__(self, name, size=4, height=None):
+ debug.info(1, "creating {0} with size of {1}".format(name,size))
+ self.add_comment("size: {}".format(size))
+
self.stage_effort = 4
self.size = size
self.height = height
+ # Creates the netlist and layout
pgate.pgate.__init__(self, name, height)
- debug.info(1, "creating {0} with size of {1}".format(self.name,self.size))
- self.add_comment("size: {}".format(size))
-
- self.create_netlist()
- if not OPTS.netlist_only:
- self.create_layout()
def create_netlist(self):
@@ -37,10 +42,10 @@ class pbuf(pgate.pgate):
self.add_layout_pins()
def add_pins(self):
- self.add_pin("A")
- self.add_pin("Z")
- self.add_pin("vdd")
- self.add_pin("gnd")
+ self.add_pin("A", "INPUT")
+ self.add_pin("Z", "OUTPUT")
+ self.add_pin("vdd", "POWER")
+ self.add_pin("gnd", "GROUND")
def create_modules(self):
# Shield the cap, but have at least a stage effort of 4
@@ -108,14 +113,6 @@ class pbuf(pgate.pgate):
width=a_pin.width(),
height=a_pin.height())
-
-
- def analytical_delay(self, corner, slew, load=0.0):
- """ Calculate the analytical delay of DFF-> INV -> INV """
- inv1_delay = self.inv1.analytical_delay(corner, slew=slew, load=self.inv2.input_load())
- inv2_delay = self.inv2.analytical_delay(corner, slew=inv1_delay.slew, load=load)
- return inv1_delay + inv2_delay
-
def get_stage_efforts(self, external_cout, inp_is_rise=False):
"""Get the stage efforts of the A -> Z path"""
stage_effort_list = []
diff --git a/compiler/pgates/pdriver.py b/compiler/pgates/pdriver.py
index daf4d334..ec55f0c7 100644
--- a/compiler/pgates/pdriver.py
+++ b/compiler/pgates/pdriver.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
import pgate
import math
@@ -13,27 +20,24 @@ class pdriver(pgate.pgate):
"""
def __init__(self, name, neg_polarity=False, fanout=0, size_list=None, height=None):
+ debug.info(1, "creating pdriver {}".format(name))
+
self.stage_effort = 3
self.height = height
self.neg_polarity = neg_polarity
self.size_list = size_list
self.fanout = fanout
+ if size_list == None and self.fanout == 0:
+ debug.error("Either fanout or size list must be specified.", -1)
if self.size_list and self.fanout != 0:
debug.error("Cannot specify both size_list and fanout.", -1)
if self.size_list and self.neg_polarity:
debug.error("Cannot specify both size_list and neg_polarity.", -1)
+ # Creates the netlist and layout
pgate.pgate.__init__(self, name, height)
- debug.info(1, "Creating {}".format(self.name))
- self.compute_sizes()
-
- self.add_comment("sizes: {}".format(str(self.size_list)))
-
- self.create_netlist()
- if not OPTS.netlist_only:
- self.create_layout()
def compute_sizes(self):
# size_list specified
@@ -41,7 +45,7 @@ class pdriver(pgate.pgate):
self.num_stages = len(self.size_list)
else:
# Find the optimal number of stages for the given effort
- self.num_stages = max(1,int(round(log(self.fanout)/log(self.stage_effort))))
+ self.num_stages = max(1,int(round(self.fanout**(1/self.stage_effort))))
# Increase the number of stages if we need to fix polarity
if self.neg_polarity and (self.num_stages%2==0):
@@ -49,18 +53,20 @@ class pdriver(pgate.pgate):
elif not self.neg_polarity and (self.num_stages%2):
self.num_stages += 1
- self.size_list = []
- # compute sizes backwards from the fanout
- fanout_prev = self.fanout
- for x in range(self.num_stages):
- fanout_prev = max(round(fanout_prev/self.stage_effort),1)
- self.size_list.append(fanout_prev)
+ self.size_list = []
+ # compute sizes backwards from the fanout
+ fanout_prev = self.fanout
+ for x in range(self.num_stages):
+ fanout_prev = max(round(fanout_prev/self.stage_effort),1)
+ self.size_list.append(fanout_prev)
- # reverse the sizes to be from input to output
- self.size_list.reverse()
+ # reverse the sizes to be from input to output
+ self.size_list.reverse()
def create_netlist(self):
+ self.compute_sizes()
+ self.add_comment("sizes: {}".format(str(self.size_list)))
self.add_pins()
self.add_modules()
self.create_insts()
@@ -73,13 +79,12 @@ class pdriver(pgate.pgate):
self.width = self.inv_inst_list[-1].rx()
self.height = self.inv_inst_list[0].height
- self.DRC_LVS()
def add_pins(self):
- self.add_pin("A")
- self.add_pin("Z")
- self.add_pin("vdd")
- self.add_pin("gnd")
+ self.add_pin("A", "INPUT")
+ self.add_pin("Z", "OUTPUT")
+ self.add_pin("vdd", "POWER")
+ self.add_pin("gnd", "GROUND")
def add_modules(self):
self.inv_list = []
@@ -168,34 +173,13 @@ class pdriver(pgate.pgate):
offset=a_pin.center(),
width = a_pin.width(),
height = a_pin.height())
-
- def input_load(self):
- return self.inv_list[0].input_load()
-
- def analytical_delay(self, corner, slew, load=0.0):
- """Calculate the analytical delay of INV1 -> ... -> INVn"""
-
- cout_list = []
- for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]):
- cout_list.append(inv.input_load())
- cout_list.append(load)
-
- input_slew = slew
-
- delays = []
- for inv,cout in zip(self.inv_list,cout_list):
- delays.append(inv.analytical_delay(corner, slew=input_slew, load=cout))
- input_slew = delays[-1].slew
-
- delay = delays[0]
- for i in range(len(delays)-1):
- delay += delays[i]
-
- return delay
-
+ def get_sizes(self):
+ """ Return the relative sizes of the buffers """
+ return self.size_list
+
def get_stage_efforts(self, external_cout, inp_is_rise=False):
- """Get the stage efforts of the A -> Z path"""
+ """ Get the stage efforts of the A -> Z path """
cout_list = []
for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]):
cout_list.append(inv.get_cin())
@@ -212,5 +196,5 @@ class pdriver(pgate.pgate):
return stage_effort_list
def get_cin(self):
- """Returns the relative capacitance of the input"""
+ """ Returns the relative capacitance of the input """
return self.inv_list[0].get_cin()
diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py
index 2f641da9..f974f0c4 100644
--- a/compiler/pgates/pgate.py
+++ b/compiler/pgates/pgate.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import contact
import design
import debug
@@ -21,6 +28,20 @@ class pgate(design.design):
b = factory.create(module_type="bitcell")
self.height = b.height
+ self.create_netlist()
+ if not OPTS.netlist_only:
+ self.create_layout()
+ self.add_boundary()
+ self.DRC_LVS()
+
+
+ def create_netlist(self):
+ """ Pure virtual function """
+ debug.error("Must over-ride create_netlist.",-1)
+
+ def create_layout(self):
+ """ Pure virtual function """
+ debug.error("Must over-ride create_layout.",-1)
def connect_pin_to_rail(self,inst,pin,supply):
""" Connects a ptx pin to a supply rail. """
@@ -42,7 +63,7 @@ class pgate(design.design):
height=height,
width=source_pin.width())
- def route_input_gate(self, pmos_inst, nmos_inst, ypos, name, position="left", rotate=90):
+ def route_input_gate(self, pmos_inst, nmos_inst, ypos, name, position="left", rotate=False):
""" Route the input gate to the left side of the cell for access.
Position specifies to place the contact the left, center, or right of gate. """
@@ -61,17 +82,21 @@ class pgate(design.design):
left_gate_offset = vector(nmos_gate_pin.lx(),ypos)
# Center is completely symmetric.
- if rotate==90:
+ if rotate:
contact_width = contact.poly.height
contact_m1_width = contact.poly.second_layer_height
contact_m1_height = contact.poly.second_layer_width
+ directions = ("H","V")
else:
contact_width = contact.poly.width
contact_m1_width = contact.poly.second_layer_width
contact_m1_height = contact.poly.second_layer_height
+ directions = ("V","H")
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.width, 0)
elif position=="left":
contact_offset = left_gate_offset - vector(0.5*contact_width - 0.5*self.poly_width, 0)
elif position=="right":
@@ -79,9 +104,12 @@ class pgate(design.design):
else:
debug.error("Invalid contact placement option.", -1)
- self.add_contact_center(layers=("poly", "contact", "metal1"),
- offset=contact_offset,
- rotate=rotate)
+ # Non-preferred direction via
+
+ self.add_via_center(layers=("poly", "contact", "metal1"),
+ offset=contact_offset,
+ directions=directions)
+
# self.add_layout_pin_segment_center(text=name,
# layer="metal1",
# start=left_gate_offset.scale(0,1),
@@ -145,10 +173,11 @@ 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)
- self.nwell_contact=self.add_contact_center(layers=layer_stack,
- offset=contact_offset,
- implant_type="n",
- well_type="n")
+ self.nwell_contact=self.add_via_center(layers=layer_stack,
+ offset=contact_offset,
+ directions=("H","V"),
+ implant_type="n",
+ well_type="n")
self.add_rect_center(layer="metal1",
offset=contact_offset + vector(0,0.5*(self.height-contact_offset.y)),
width=self.nwell_contact.mod.second_layer_width,
@@ -191,10 +220,11 @@ class pgate(design.design):
# Offset by half a contact
contact_offset += vector(0.5*nmos.active_contact.first_layer_width,
0.5*nmos.active_contact.first_layer_height)
- self.pwell_contact=self.add_contact_center(layers=layer_stack,
- offset=contact_offset,
- implant_type="p",
- well_type="p")
+ self.pwell_contact=self.add_via_center(layers=layer_stack,
+ offset=contact_offset,
+ directions=("H","V"),
+ implant_type="p",
+ well_type="p")
self.add_rect_center(layer="metal1",
offset=contact_offset.scale(1,0.5),
width=self.pwell_contact.mod.second_layer_width,
@@ -216,4 +246,3 @@ class pgate(design.design):
# offset=implant_offset,
# width=implant_width,
# height=implant_height)
-
diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py
index f00e9af7..275ccbe6 100644
--- a/compiler/pgates/pinv.py
+++ b/compiler/pgates/pinv.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import contact
import pgate
import debug
@@ -20,28 +27,17 @@ class pinv(pgate.pgate):
"""
def __init__(self, name, size=1, beta=parameter["beta"], height=None, route_output=True):
- # We need to keep unique names because outputting to GDSII
- # will use the last record with a given name. I.e., you will
- # over-write a design in GDS if one has and the other doesn't
- # have poly connected, for example.
- pgate.pgate.__init__(self, name, height)
- debug.info(2, "create pinv structure {0} with size of {1}".format(name, size))
+
+ debug.info(2, "creating pinv structure {0} with size of {1}".format(name, size))
self.add_comment("size: {}".format(size))
-
+
self.size = size
self.nmos_size = size
self.pmos_size = beta*size
self.beta = beta
self.route_output = False
-
- self.create_netlist()
- if not OPTS.netlist_only:
- self.create_layout()
-
- # for run-time, we won't check every transitor DRC/LVS independently
- # but this may be uncommented for debug purposes
- #self.DRC_LVS()
+ pgate.pgate.__init__(self, name, height)
def create_netlist(self):
""" Calls all functions related to the generation of the netlist """
@@ -58,12 +54,14 @@ class pinv(pgate.pgate):
self.add_well_contacts()
self.extend_wells(self.well_pos)
self.connect_rails()
- self.route_input_gate(self.pmos_inst, self.nmos_inst, self.output_pos.y, "A", rotate=0)
+ self.route_input_gate(self.pmos_inst, self.nmos_inst, self.output_pos.y, "A", position="farleft")
self.route_outputs()
def add_pins(self):
""" Adds pins for spice netlist """
- self.add_pin_list(["A", "Z", "vdd", "gnd"])
+ pin_list = ["A", "Z", "vdd", "gnd"]
+ dir_list = ["INPUT", "OUTPUT", "POWER", "GROUND"]
+ self.add_pin_list(pin_list, dir_list)
def determine_tx_mults(self):
@@ -222,8 +220,8 @@ class pinv(pgate.pgate):
pmos_drain_pin = self.pmos_inst.get_pin("D")
# Pick point at right most of NMOS and connect down to PMOS
- nmos_drain_pos = nmos_drain_pin.lr() - vector(0.5*self.m1_width,0)
- pmos_drain_pos = vector(nmos_drain_pos.x, pmos_drain_pin.bc().y)
+ nmos_drain_pos = nmos_drain_pin.bc()
+ pmos_drain_pos = vector(nmos_drain_pos.x, pmos_drain_pin.uc().y)
self.add_path("metal1",[nmos_drain_pos,pmos_drain_pos])
# Remember the mid for the output
@@ -257,19 +255,10 @@ class pinv(pgate.pgate):
self.connect_pin_to_rail(self.pmos_inst,"S","vdd")
-
- def input_load(self):
- return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
-
- def analytical_delay(self, corner, slew, load=0.0):
- r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
- c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
- return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew)
-
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
c_eff = self.calculate_effective_capacitance(load)
- freq = spice["default_event_rate"]
+ freq = spice["default_event_frequency"]
power_dyn = self.calc_dynamic_power(corner, c_eff, freq)
power_leak = spice["inv_leakage"]
@@ -280,16 +269,26 @@ class pinv(pgate.pgate):
"""Computes effective capacitance. Results in fF"""
c_load = load
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
- transition_prob = spice["inv_transition_prob"]
+ transition_prob = 0.5
return transition_prob*(c_load + c_para)
- def get_cin(self):
- """Return the capacitance of the gate connection in generic capacitive units relative to the minimum width of a transistor"""
+ def input_load(self):
+ """Return the capacitance of the gate connection in generic capacitive
+ units relative to the minimum width of a transistor"""
return self.nmos_size + self.pmos_size
-
+
def get_stage_effort(self, cout, inp_is_rise=True):
"""Returns an object representing the parameters for delay in tau units.
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
"""
parasitic_delay = 1
- return logical_effort.logical_effort(self.name, self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)
+ return logical_effort.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):
+ """Adds edges based on inputs/outputs. Overrides base class function."""
+ self.add_graph_edges(graph, port_nets)
diff --git a/compiler/pgates/pinvbuf.py b/compiler/pgates/pinvbuf.py
index 06936895..a8d2c8b8 100644
--- a/compiler/pgates/pinvbuf.py
+++ b/compiler/pgates/pinvbuf.py
@@ -1,18 +1,28 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
-import design
+import pgate
from tech import drc
from math import log
from vector import vector
from globals import OPTS
from sram_factory import factory
-class pinvbuf(design.design):
+class pinvbuf(pgate.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.
"""
def __init__(self, name, size=4, height=None):
+ debug.info(1, "creating pinvbuf {}".format(name))
+ self.add_comment("size: {}".format(size))
+
self.stage_effort = 4
self.row_height = height
# FIXME: Change the number of stages to support high drives.
@@ -23,13 +33,8 @@ class pinvbuf(design.design):
self.size = size
self.predriver_size = max(int(self.size/(self.stage_effort/2)),1)
- design.design.__init__(self, name)
- debug.info(1, "Creating {}".format(self.name))
- self.add_comment("size: {}".format(size))
-
- self.create_netlist()
- if not OPTS.netlist_only:
- self.create_layout()
+ # Creates the netlist and layout
+ pgate.pgate.__init__(self, name)
def create_netlist(self):
@@ -48,7 +53,6 @@ class pinvbuf(design.design):
self.offset_all_coordinates()
- self.DRC_LVS()
def add_pins(self):
self.add_pin("A")
@@ -174,15 +178,7 @@ class pinvbuf(design.design):
offset=a_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=a_pin.center())
-
-
-
- def analytical_delay(self, corner, slew, load=0.0):
- """ Calculate the analytical delay of DFF-> INV -> INV """
- inv1_delay = self.inv1.analytical_delay(corner, slew=slew, load=self.inv2.input_load())
- inv2_delay = self.inv2.analytical_delay(corner, slew=inv1_delay.slew, load=load)
- return inv1_delay + inv2_delay
-
+
def determine_clk_buf_stage_efforts(self, external_cout, inp_is_rise=False):
"""Get the stage efforts of the clk -> clk_buf path"""
stage_effort_list = []
diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py
index 95a9bc28..791097e5 100644
--- a/compiler/pgates/pnand2.py
+++ b/compiler/pgates/pnand2.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import contact
import pgate
import debug
@@ -14,8 +21,8 @@ class pnand2(pgate.pgate):
"""
def __init__(self, name, size=1, height=None):
""" Creates a cell for a simple 2 input nand """
- pgate.pgate.__init__(self, name, height)
- debug.info(2, "create pnand2 structure {0} with size of {1}".format(name, size))
+
+ debug.info(2, "creating pnand2 structure {0} with size of {1}".format(name, size))
self.add_comment("size: {}".format(size))
self.size = size
@@ -28,11 +35,9 @@ class pnand2(pgate.pgate):
debug.check(size==1,"Size 1 pnand2 is only supported now.")
self.tx_mults = 1
- self.create_netlist()
- if not OPTS.netlist_only:
- self.create_layout()
-
-
+ # Creates the netlist and layout
+ pgate.pgate.__init__(self, name, height)
+
def create_netlist(self):
self.add_pins()
self.add_ptx()
@@ -52,7 +57,9 @@ class pnand2(pgate.pgate):
def add_pins(self):
""" Adds pins for spice netlist """
- self.add_pin_list(["A", "B", "Z", "vdd", "gnd"])
+ pin_list = ["A", "B", "Z", "vdd", "gnd"]
+ dir_list = ["INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
+ self.add_pin_list(pin_list, dir_list)
def add_ptx(self):
@@ -203,13 +210,15 @@ class pnand2(pgate.pgate):
mid1_offset = vector(out_offset.x, top_pin_offset.y)
mid2_offset = vector(out_offset.x, bottom_pin_offset.y)
- self.add_contact_center(layers=("metal1", "via1", "metal2"),
- offset=pmos_pin.center())
- self.add_contact_center(layers=("metal1", "via1", "metal2"),
- offset=nmos_pin.center())
- self.add_contact_center(layers=("metal1", "via1", "metal2"),
- offset=out_offset,
- rotate=90)
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=pmos_pin.center(),
+ directions=("V","H"))
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=nmos_pin.center(),
+ directions=("V","H"))
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=out_offset)
+
# PMOS1 to mid-drain to NMOS2 drain
self.add_path("metal2",[top_pin_offset, mid1_offset, out_offset, mid2_offset, bottom_pin_offset])
@@ -221,21 +230,10 @@ class pnand2(pgate.pgate):
width=contact.m1m2.first_layer_height,
height=contact.m1m2.first_layer_width)
-
-
-
- def input_load(self):
- return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
-
- def analytical_delay(self, corner, slew, load=0.0):
- r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
- c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
- return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew)
-
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
c_eff = self.calculate_effective_capacitance(load)
- freq = spice["default_event_rate"]
+ freq = spice["default_event_frequency"]
power_dyn = self.calc_dynamic_power(corner, c_eff, freq)
power_leak = spice["nand2_leakage"]
@@ -246,16 +244,20 @@ class pnand2(pgate.pgate):
"""Computes effective capacitance. Results in fF"""
c_load = load
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
- transition_prob = spice["nand2_transition_prob"]
+ transition_prob = 0.1875
return transition_prob*(c_load + c_para)
- def get_cin(self):
+ def input_load(self):
"""Return the relative input capacitance of a single input"""
return self.nmos_size+self.pmos_size
-
+
def get_stage_effort(self, cout, inp_is_rise=True):
"""Returns an object representing the parameters for delay in tau units.
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
"""
parasitic_delay = 2
- return logical_effort.logical_effort(self.name, self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)
+ return logical_effort.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):
+ """Adds edges based on inputs/outputs. Overrides base class function."""
+ self.add_graph_edges(graph, port_nets)
diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py
index d0c37b55..508db024 100644
--- a/compiler/pgates/pnand3.py
+++ b/compiler/pgates/pnand3.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import contact
import pgate
import debug
@@ -14,8 +21,8 @@ class pnand3(pgate.pgate):
"""
def __init__(self, name, size=1, height=None):
""" Creates a cell for a simple 3 input nand """
- pgate.pgate.__init__(self, name, height)
- debug.info(2, "create pnand3 structure {0} with size of {1}".format(name, size))
+
+ debug.info(2, "creating pnand3 structure {0} with size of {1}".format(name, size))
self.add_comment("size: {}".format(size))
# We have trouble pitch matching a 3x sizes to the bitcell...
@@ -30,14 +37,15 @@ class pnand3(pgate.pgate):
debug.check(size==1,"Size 1 pnand3 is only supported now.")
self.tx_mults = 1
- self.create_netlist()
- if not OPTS.netlist_only:
- self.create_layout()
+ # Creates the netlist and layout
+ pgate.pgate.__init__(self, name, height)
def add_pins(self):
""" Adds pins for spice netlist """
- self.add_pin_list(["A", "B", "C", "Z", "vdd", "gnd"])
+ pin_list = ["A", "B", "C", "Z", "vdd", "gnd"]
+ dir_list = ["INPUT", "INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"]
+ self.add_pin_list(pin_list, dir_list)
def create_netlist(self):
self.add_pins()
@@ -213,12 +221,12 @@ class pnand3(pgate.pgate):
nmos3_pin = self.nmos3_inst.get_pin("D")
# Go up to metal2 for ease on all output pins
- self.add_contact_center(layers=("metal1", "via1", "metal2"),
- offset=pmos1_pin.center())
- self.add_contact_center(layers=("metal1", "via1", "metal2"),
- offset=pmos3_pin.center())
- self.add_contact_center(layers=("metal1", "via1", "metal2"),
- offset=nmos3_pin.center())
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=pmos1_pin.center())
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=pmos3_pin.center())
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=nmos3_pin.center())
# PMOS3 and NMOS3 are drain aligned
self.add_path("metal2",[pmos3_pin.bc(), nmos3_pin.uc()])
@@ -227,28 +235,18 @@ class pnand3(pgate.pgate):
self.add_path("metal2",[pmos1_pin.bc(), mid_offset, nmos3_pin.uc()])
# This extends the output to the edge of the cell
- self.add_contact_center(layers=("metal1", "via1", "metal2"),
- offset=mid_offset)
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=mid_offset)
self.add_layout_pin_rect_center(text="Z",
layer="metal1",
offset=mid_offset,
width=contact.m1m2.first_layer_width,
height=contact.m1m2.first_layer_height)
-
-
- def input_load(self):
- return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
-
- def analytical_delay(self, corner, slew, load=0.0):
- r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
- c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
- return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew)
-
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
c_eff = self.calculate_effective_capacitance(load)
- freq = spice["default_event_rate"]
+ freq = spice["default_event_frequency"]
power_dyn = self.calc_dynamic_power(corner, c_eff, freq)
power_leak = spice["nand3_leakage"]
@@ -259,10 +257,10 @@ class pnand3(pgate.pgate):
"""Computes effective capacitance. Results in fF"""
c_load = load
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
- transition_prob = spice["nand3_transition_prob"]
+ transition_prob = 0.1094
return transition_prob*(c_load + c_para)
- def get_cin(self):
+ def input_load(self):
"""Return the relative input capacitance of a single input"""
return self.nmos_size+self.pmos_size
@@ -271,4 +269,8 @@ class pnand3(pgate.pgate):
Optional is_rise refers to the input direction rise/fall. Input inverted by this stage.
"""
parasitic_delay = 3
- return logical_effort.logical_effort(self.name, self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise)
+ return logical_effort.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):
+ """Adds edges based on inputs/outputs. Overrides base class function."""
+ self.add_graph_edges(graph, port_nets)
diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py
index 8a5c80d4..ed7388e9 100644
--- a/compiler/pgates/pnor2.py
+++ b/compiler/pgates/pnor2.py
@@ -1,9 +1,17 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import contact
import pgate
import debug
from tech import drc, parameter, spice
from vector import vector
from globals import OPTS
-import contact
+import logical_effort
from sram_factory import factory
class pnor2(pgate.pgate):
@@ -13,8 +21,8 @@ class pnor2(pgate.pgate):
"""
def __init__(self, name, size=1, height=None):
""" Creates a cell for a simple 2 input nor """
- pgate.pgate.__init__(self, name, height)
- debug.info(2, "create pnor2 structure {0} with size of {1}".format(name, size))
+
+ debug.info(2, "creating pnor2 structure {0} with size of {1}".format(name, size))
self.add_comment("size: {}".format(size))
self.nmos_size = size
@@ -27,32 +35,34 @@ class pnor2(pgate.pgate):
debug.check(size==1,"Size 1 pnor2 is only supported now.")
self.tx_mults = 1
- self.create_netlist()
- self.create_layout()
- #self.DRC_LVS()
+ # Creates the netlist and layout
+ pgate.pgate.__init__(self, name, height)
- def add_pins(self):
- """ Adds pins for spice netlist """
- self.add_pin_list(["A", "B", "Z", "vdd", "gnd"])
-
def create_netlist(self):
self.add_pins()
+ self.add_ptx()
+ self.create_ptx()
def create_layout(self):
""" Calls all functions related to the generation of the layout """
-
- self.create_ptx()
+
self.setup_layout_constants()
- self.add_supply_rails()
- self.add_ptx()
+ self.route_supply_rails()
+ self.place_ptx()
self.connect_rails()
self.add_well_contacts()
self.extend_wells(self.well_pos)
self.route_inputs()
self.route_output()
- def create_ptx(self):
+ def add_pins(self):
+ """ Adds pins for spice netlist """
+ pin_list = ["A", "B", "Z", "vdd", "gnd"]
+ dir_list = ["INPUT", "INPUT", "OUTPUT", "INOUT", "INOUT"]
+ self.add_pin_list(pin_list, dir_list)
+
+ def add_ptx(self):
""" Create the PMOS and NMOS transistors. """
self.nmos = factory.create(module_type="ptx",
width=self.nmos_width,
@@ -97,7 +107,7 @@ class pnor2(pgate.pgate):
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
drc("poly_extend_active"), self.poly_space)
- def add_supply_rails(self):
+ def route_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """
self.add_layout_pin_rect_center(text="gnd",
layer="metal1",
@@ -109,7 +119,31 @@ class pnor2(pgate.pgate):
offset=vector(0.5*self.width,self.height),
width=self.width)
- def add_ptx(self):
+ def create_ptx(self):
+ """
+ Add PMOS and NMOS to the layout at the upper-most and lowest position
+ to provide maximum routing in channel
+ """
+
+ self.pmos1_inst=self.add_inst(name="pnor2_pmos1",
+ mod=self.pmos)
+ self.connect_inst(["vdd", "A", "net1", "vdd"])
+
+ self.pmos2_inst = self.add_inst(name="pnor2_pmos2",
+ mod=self.pmos)
+ self.connect_inst(["net1", "B", "Z", "vdd"])
+
+
+ self.nmos1_inst=self.add_inst(name="pnor2_nmos1",
+ mod=self.nmos)
+ self.connect_inst(["Z", "A", "gnd", "gnd"])
+
+ self.nmos2_inst=self.add_inst(name="pnor2_nmos2",
+ mod=self.nmos)
+ self.connect_inst(["Z", "B", "gnd", "gnd"])
+
+
+ def place_ptx(self):
"""
Add PMOS and NMOS to the layout at the upper-most and lowest position
to provide maximum routing in channel
@@ -117,29 +151,16 @@ class pnor2(pgate.pgate):
pmos1_pos = vector(self.pmos.active_offset.x,
self.height - self.pmos.active_height - self.top_bottom_space)
- self.pmos1_inst=self.add_inst(name="pnor2_pmos1",
- mod=self.pmos,
- offset=pmos1_pos)
- self.connect_inst(["vdd", "A", "net1", "vdd"])
+ self.pmos1_inst.place(pmos1_pos)
self.pmos2_pos = pmos1_pos + self.overlap_offset
- self.pmos2_inst = self.add_inst(name="pnor2_pmos2",
- mod=self.pmos,
- offset=self.pmos2_pos)
- self.connect_inst(["net1", "B", "Z", "vdd"])
-
+ self.pmos2_inst.place(self.pmos2_pos)
nmos1_pos = vector(self.pmos.active_offset.x, self.top_bottom_space)
- self.nmos1_inst=self.add_inst(name="pnor2_nmos1",
- mod=self.nmos,
- offset=nmos1_pos)
- self.connect_inst(["Z", "A", "gnd", "gnd"])
-
+ self.nmos1_inst.place(nmos1_pos)
+
self.nmos2_pos = nmos1_pos + self.overlap_offset
- self.nmos2_inst=self.add_inst(name="pnor2_nmos2",
- mod=self.nmos,
- offset=self.nmos2_pos)
- self.connect_inst(["Z", "B", "gnd", "gnd"])
+ self.nmos2_inst.place(self.nmos2_pos)
# Output position will be in between the PMOS and NMOS
self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height))
@@ -184,11 +205,11 @@ class pnor2(pgate.pgate):
nmos2_pin = self.nmos2_inst.get_pin("D")
# Go up to metal2 for ease on all output pins
- self.add_contact_center(layers=("metal1", "via1", "metal2"),
- offset=pmos_pin.center())
- m1m2_contact=self.add_contact_center(layers=("metal1", "via1", "metal2"),
- offset=nmos_pin.center(),
- rotate=90)
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=pmos_pin.center())
+ m1m2_contact=self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=nmos_pin.center())
+
mid1_offset = vector(pmos_pin.center().x,nmos2_pin.center().y)
mid2_offset = vector(pmos_pin.center().x,self.inputA_yoffset)
@@ -198,29 +219,18 @@ class pnor2(pgate.pgate):
self.add_path("metal2",[pmos_pin.bc(), mid2_offset, mid3_offset])
self.add_path("metal2",[nmos_pin.rc(), mid1_offset, mid2_offset])
# This extends the output to the edge of the cell
- self.add_contact_center(layers=("metal1", "via1", "metal2"),
- offset=mid3_offset,
- rotate=90)
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=mid3_offset)
self.add_layout_pin_rect_center(text="Z",
layer="metal1",
offset=mid3_offset,
width=contact.m1m2.first_layer_height,
height=contact.m1m2.first_layer_width)
-
-
- def input_load(self):
- return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
-
- def analytical_delay(self, corner, slew, load=0.0):
- r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
- c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
- return self.cal_delay_with_rc(corner, r = r, c = c_para+load, slew = slew)
-
def analytical_power(self, corner, load):
"""Returns dynamic and leakage power. Results in nW"""
c_eff = self.calculate_effective_capacitance(load)
- freq = spice["default_event_rate"]
+ freq = spice["default_event_frequency"]
power_dyn = self.calc_dynamic_power(corner, c_eff, freq)
power_leak = spice["nor2_leakage"]
@@ -231,6 +241,9 @@ class pnor2(pgate.pgate):
"""Computes effective capacitance. Results in fF"""
c_load = load
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
- transition_prob = spice["nor2_transition_prob"]
+ transition_prob = 0.1875
return transition_prob*(c_load + c_para)
+ def build_graph(self, graph, inst_name, port_nets):
+ """Adds edges based on inputs/outputs. Overrides base class function."""
+ self.add_graph_edges(graph, port_nets)
diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py
index cea9c845..b4423bed 100644
--- a/compiler/pgates/precharge.py
+++ b/compiler/pgates/precharge.py
@@ -1,31 +1,42 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import contact
-import pgate
+import design
import debug
from tech import drc, parameter
from vector import vector
from globals import OPTS
from sram_factory import factory
-class precharge(pgate.pgate):
+class precharge(design.design):
"""
Creates a single precharge cell
This module implements the precharge bitline cell used in the design.
"""
def __init__(self, name, size=1, bitcell_bl="bl", bitcell_br="br"):
- pgate.pgate.__init__(self, name)
- debug.info(2, "create single precharge cell: {0}".format(name))
+
+ debug.info(2, "creating precharge cell {0}".format(name))
+ design.design.__init__(self, name)
self.bitcell = factory.create(module_type="bitcell")
-
self.beta = parameter["beta"]
self.ptx_width = self.beta*parameter["min_tx_size"]
self.width = self.bitcell.width
self.bitcell_bl = bitcell_bl
self.bitcell_br = bitcell_br
-
+
+
+ # Creates the netlist and layout
+ # Since it has variable height, it is not a pgate.
self.create_netlist()
- if not OPTS.netlist_only:
+ if not OPTS.netlist_only:
self.create_layout()
+ self.DRC_LVS()
def create_netlist(self):
self.add_pins()
@@ -40,10 +51,9 @@ class precharge(pgate.pgate):
self.route_vdd_rail()
self.route_bitlines()
self.connect_to_bitlines()
- self.DRC_LVS()
def add_pins(self):
- self.add_pin_list(["bl", "br", "en_bar", "vdd"])
+ self.add_pin_list(["bl", "br", "en_bar", "vdd"], ["OUTPUT", "OUTPUT", "INPUT", "POWER"])
def add_ptx(self):
"""
@@ -75,7 +85,7 @@ class precharge(pgate.pgate):
self.add_path("metal1", [pmos_pin.uc(), pmos_vdd_pos])
# Add vdd pin above the transistor
- self.add_power_pin("vdd", pmos_pin.center(), rotate=0)
+ self.add_power_pin("vdd", pmos_pin.center(), vertical=True)
def create_ptx(self):
@@ -149,9 +159,8 @@ class precharge(pgate.pgate):
# adds the en contact to connect the gates to the en rail on metal1
offset = self.lower_pmos_inst.get_pin("G").ul() + vector(0,0.5*self.poly_space)
- self.add_contact_center(layers=("poly", "contact", "metal1"),
- offset=offset,
- rotate=90)
+ self.add_via_center(layers=("poly", "contact", "metal1"),
+ offset=offset)
# adds the en rail on metal1
self.add_layout_pin_segment_center(text="en_bar",
@@ -168,10 +177,10 @@ class precharge(pgate.pgate):
# adds the contact from active to metal1
well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1,0) \
+ vector(0, self.upper_pmos1_inst.uy() + contact.well.height/2 + drc("well_extend_active"))
- self.add_contact_center(layers=("active", "contact", "metal1"),
- offset=well_contact_pos,
- implant_type="n",
- well_type="n")
+ self.add_via_center(layers=("active", "contact", "metal1"),
+ offset=well_contact_pos,
+ implant_type="n",
+ well_type="n")
# leave an extra pitch for the height
self.height = well_contact_pos.y + contact.well.height + self.m1_pitch
@@ -225,16 +234,20 @@ class precharge(pgate.pgate):
lower_pin = self.lower_pmos_inst.get_pin("S")
# BL goes up to M2 at the transistor
- self.bl_contact=self.add_contact_center(layers=stack,
- offset=upper_pin.center())
- self.add_contact_center(layers=stack,
- offset=lower_pin.center())
+ self.bl_contact=self.add_via_center(layers=stack,
+ offset=upper_pin.center(),
+ directions=("V","V"))
+ self.add_via_center(layers=stack,
+ offset=lower_pin.center(),
+ directions=("V","V"))
# BR routes over on M1 first
- self.add_contact_center(layers=stack,
- offset = vector(self.br_pin.cx(), upper_pin.cy()))
- self.add_contact_center(layers=stack,
- offset = vector(self.br_pin.cx(), lower_pin.cy()))
+ self.add_via_center(layers=stack,
+ offset = vector(self.br_pin.cx(), upper_pin.cy()),
+ directions=("V","V"))
+ self.add_via_center(layers=stack,
+ offset = vector(self.br_pin.cx(), lower_pin.cy()),
+ directions=("V","V"))
def connect_pmos_m1(self, pmos_pin, bit_pin):
"""
diff --git a/compiler/pgates/ptristate_inv.py b/compiler/pgates/ptristate_inv.py
new file mode 100644
index 00000000..0564bf86
--- /dev/null
+++ b/compiler/pgates/ptristate_inv.py
@@ -0,0 +1,220 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import contact
+import pgate
+import debug
+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
+
+class ptristate_inv(pgate.pgate):
+ """
+ ptristate generates gds of a parametrically sized tristate inverter.
+
+ There is some flexibility in the size, but we do not allow multiple fingers
+ to fit in the cell height.
+
+ """
+
+ def __init__(self, name, size=1, height=None):
+
+ debug.info(2, "creating ptristate inv {0} with size of {1}".format(name, size))
+ self.add_comment("size: {}".format(size))
+
+ # We are 2x since there are two series devices
+ self.size = 2*size
+ self.nmos_size = size
+ self.beta = parameter["beta"]
+ self.pmos_size = self.beta*size
+
+ self.nmos_width = self.nmos_size * drc("minwidth_tx")
+ self.pmos_width = self.pmos_size * drc("minwidth_tx")
+
+ # Creates the netlist and layout
+ pgate.pgate.__init__(self, name, height)
+
+ def create_netlist(self):
+ """ Calls all functions related to the generation of the netlist """
+ self.add_pins()
+ self.add_ptx()
+ self.create_ptx()
+
+ def create_layout(self):
+ """ Calls all functions related to the generation of the layout """
+ self.setup_layout_constants()
+ self.route_supply_rails()
+ self.place_ptx()
+ self.add_well_contacts()
+ self.extend_wells(self.well_pos)
+ self.connect_rails()
+ self.route_inputs()
+ self.route_outputs()
+
+ def add_pins(self):
+ """ Adds pins for spice netlist """
+ self.add_pin_list(["in", "out", "en", "en_bar", "vdd", "gnd"])
+
+
+ def setup_layout_constants(self):
+ """
+ Pre-compute some handy layout parameters.
+ """
+
+ # Compute the other pmos2 location, but determining offset to overlap the
+ # source and drain pins
+ self.overlap_offset = self.pmos.get_pin("D").ll() - self.pmos.get_pin("S").ll()
+
+ # Two PMOS devices and a well contact. Separation between each.
+ # Enclosure space on the sides.
+ self.well_width = 2*self.pmos.active_width + drc("well_enclosure_active")
+
+ # Add an extra space because we route the output on the right of the S/D
+ self.width = self.well_width + 0.5*self.m1_space
+ # Height is an input parameter, so it is not recomputed.
+
+ # Make sure we can put a well above and below
+ self.top_bottom_space = max(contact.well.width, contact.well.height)
+
+
+ def add_ptx(self):
+ """ Create the PMOS and NMOS transistors. """
+ self.nmos = factory.create(module_type="ptx",
+ width=self.nmos_width,
+ mults=1,
+ tx_type="nmos")
+ self.add_mod(self.nmos)
+
+ self.pmos = factory.create(module_type="ptx",
+ width=self.pmos_width,
+ mults=1,
+ tx_type="pmos")
+
+ self.add_mod(self.pmos)
+
+ def route_supply_rails(self):
+ """ Add vdd/gnd rails to the top and bottom. """
+ self.add_layout_pin_rect_center(text="gnd",
+ layer="metal1",
+ offset=vector(0.5*self.width,0),
+ width=self.width)
+
+ self.add_layout_pin_rect_center(text="vdd",
+ layer="metal1",
+ offset=vector(0.5*self.width,self.height),
+ width=self.width)
+
+
+ def create_ptx(self):
+ """
+ Create the PMOS and NMOS netlist.
+ """
+
+ # These are the inverter PMOS/NMOS
+ self.pmos1_inst=self.add_inst(name="ptri_pmos1", mod=self.pmos)
+ self.connect_inst(["vdd", "in", "n1", "vdd"])
+ self.nmos1_inst=self.add_inst(name="ptri_nmos1", mod=self.nmos)
+ self.connect_inst(["gnd", "in", "n2", "gnd"])
+
+
+ # These are the tristate PMOS/NMOS
+ self.pmos2_inst = self.add_inst(name="ptri_pmos2", mod=self.pmos)
+ self.connect_inst(["out", "en_bar", "n1", "vdd"])
+ self.nmos2_inst=self.add_inst(name="ptri_nmos2", mod=self.nmos)
+ self.connect_inst(["out", "en", "n2", "gnd"])
+
+
+
+ def place_ptx(self):
+ """
+ Place PMOS and NMOS to the layout at the upper-most and lowest position
+ to provide maximum routing in channel
+ """
+
+ pmos_yoff = self.height - self.pmos.active_height - self.top_bottom_space - 0.5*contact.well.height
+ nmos_yoff = self.top_bottom_space + 0.5*contact.well.height
+
+ # Tristate transistors
+ pmos1_pos = vector(self.pmos.active_offset.x, pmos_yoff)
+ self.pmos1_inst.place(pmos1_pos)
+ nmos1_pos = vector(self.pmos.active_offset.x, nmos_yoff)
+ self.nmos1_inst.place(nmos1_pos)
+
+ # Inverter transistors
+ self.pmos2_pos = pmos1_pos + self.overlap_offset
+ self.pmos2_inst.place(self.pmos2_pos)
+ self.nmos2_pos = nmos1_pos + self.overlap_offset
+ self.nmos2_inst.place(self.nmos2_pos)
+
+ # Output position will be in between the PMOS and NMOS
+ self.output_pos = vector(0, 0.5*(pmos_yoff + nmos_yoff + self.nmos.height))
+
+ # This will help with the wells
+ self.well_pos = vector(0,self.nmos1_inst.uy())
+
+
+ def route_inputs(self):
+ """ Route the gates """
+
+ self.route_input_gate(self.pmos1_inst, self.nmos1_inst, self.output_pos.y, "in", position="farleft")
+ self.route_single_gate(self.pmos2_inst, "en_bar", position="left")
+ self.route_single_gate(self.nmos2_inst, "en", position="left")
+
+
+ def route_outputs(self):
+ """ Route the output (drains) together. """
+
+ nmos_drain_pin = self.nmos2_inst.get_pin("D")
+ pmos_drain_pin = self.pmos2_inst.get_pin("D")
+
+ nmos_drain_pos = nmos_drain_pin.lr()
+ pmos_drain_pos = pmos_drain_pin.ur()
+
+ self.add_layout_pin(text="out",
+ layer="metal1",
+ offset=nmos_drain_pos,
+ height=pmos_drain_pos.y-nmos_drain_pos.y)
+
+
+ def add_well_contacts(self):
+ """ Add n/p well taps to the layout and connect to supplies AFTER the wells are created """
+
+ layer_stack = ("active", "contact", "metal1")
+
+ 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")
+
+ 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")
+
+
+
+ def connect_rails(self):
+ """ Connect the nmos and pmos to its respective power rails """
+
+ self.connect_pin_to_rail(self.nmos1_inst,"S","gnd")
+ self.connect_pin_to_rail(self.pmos1_inst,"S","vdd")
+
+ def analytical_power(self, corner, load):
+ """Returns dynamic and leakage power. Results in nW"""
+ #Power in this module currently not defined. Returns 0 nW (leakage and dynamic).
+ total_power = self.return_power()
+ return total_power
+
+ def get_cin(self):
+ return 9*spice["min_tx_gate_c"]
diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py
index 3a127454..79a29d07 100644
--- a/compiler/pgates/ptx.py
+++ b/compiler/pgates/ptx.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import design
import debug
from tech import drc, spice
@@ -19,7 +26,7 @@ class ptx(design.design):
# will use the last record with a given name. I.e., you will
# over-write a design in GDS if one has and the other doesn't
# have poly connected, for example.
- name = "{0}_m{1}_w{2}".format(tx_type, mults, width)
+ name = "{0}_m{1}_w{2:.3f}".format(tx_type, mults, width)
if connect_active:
name += "_a"
if connect_poly:
@@ -28,9 +35,8 @@ class ptx(design.design):
name += "_c{}".format(num_contacts)
# replace periods with underscore for newer spice compatibility
name=name.replace('.','_')
-
+ debug.info(3, "creating ptx {0}".format(name))
design.design.__init__(self, name)
- debug.info(3, "create ptx2 structure {0}".format(name))
self.tx_type = tx_type
self.mults = mults
@@ -39,6 +45,8 @@ class ptx(design.design):
self.connect_poly = connect_poly
self.num_contacts = num_contacts
+ # Do NOT create the netlist and layout (not a pgate)
+ # Since it has variable height, it is not a pgate.
self.create_netlist()
# We must always create ptx layout for pbitcell
# some transistor sizes in other netlist depend on pbitcell
@@ -60,7 +68,13 @@ class ptx(design.design):
#self.DRC()
def create_netlist(self):
- self.add_pin_list(["D", "G", "S", "B"])
+ pin_list = ["D", "G", "S", "B"]
+ if self.tx_type=="nmos":
+ body_dir = 'GROUND'
+ else: #Assumed that the check for either pmos or nmos is done elsewhere.
+ body_dir = 'POWER'
+ dir_list = ['INOUT', 'INPUT', 'INOUT', body_dir]
+ self.add_pin_list(pin_list, dir_list)
# self.spice.append("\n.SUBCKT {0} {1}".format(self.name,
# " ".join(self.pins)))
@@ -326,11 +340,12 @@ class ptx(design.design):
[source_positions,drain_positions] = self.get_contact_positions()
for pos in source_positions:
- contact=self.add_contact_center(layers=("active", "contact", "metal1"),
- offset=pos,
- size=(1, self.num_contacts),
- implant_type=self.implant_type,
- well_type=self.well_type)
+ contact=self.add_via_center(layers=("active", "contact", "metal1"),
+ offset=pos,
+ size=(1, self.num_contacts),
+ directions=("H","V"),
+ implant_type=self.implant_type,
+ well_type=self.well_type)
self.add_layout_pin_rect_center(text="S",
layer="metal1",
offset=pos,
@@ -339,11 +354,12 @@ class ptx(design.design):
for pos in drain_positions:
- contact=self.add_contact_center(layers=("active", "contact", "metal1"),
- offset=pos,
- size=(1, self.num_contacts),
- implant_type=self.implant_type,
- well_type=self.well_type)
+ contact=self.add_via_center(layers=("active", "contact", "metal1"),
+ offset=pos,
+ size=(1, self.num_contacts),
+ directions=("H","V"),
+ implant_type=self.implant_type,
+ well_type=self.well_type)
self.add_layout_pin_rect_center(text="D",
layer="metal1",
offset=pos,
@@ -356,3 +372,8 @@ class ptx(design.design):
def get_cin(self):
"""Returns the relative gate cin of the tx"""
return self.tx_width/drc("minwidth_tx")
+
+ def build_graph(self, graph, inst_name, port_nets):
+ """Adds edges based on inputs/outputs. Overrides base class function."""
+ self.add_graph_edges(graph, port_nets)
+
\ No newline at end of file
diff --git a/compiler/pgates/single_level_column_mux.py b/compiler/pgates/single_level_column_mux.py
index f03a22e8..999d3ccd 100644
--- a/compiler/pgates/single_level_column_mux.py
+++ b/compiler/pgates/single_level_column_mux.py
@@ -1,12 +1,20 @@
-import design
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import pgate
import debug
from tech import drc
from vector import vector
import contact
from globals import OPTS
from sram_factory import factory
+import logical_effort
-class single_level_column_mux(design.design):
+class single_level_column_mux(pgate.pgate):
"""
This module implements the columnmux bitline cell used in the design.
Creates a single columnmux cell with the given integer size relative
@@ -14,18 +22,14 @@ class single_level_column_mux(design.design):
Column-mux transistors driven by the decoder must be sized for optimal speed
"""
def __init__(self, name, tx_size=8, bitcell_bl="bl", bitcell_br="br"):
+
+ debug.info(2, "creating single column mux cell: {0}".format(name))
self.tx_size = int(tx_size)
-
- design.design.__init__(self, name)
- debug.info(2, "create single column mux cell: {0}".format(name))
-
self.bitcell_bl = bitcell_bl
self.bitcell_br = bitcell_br
- self.create_netlist()
- if not OPTS.netlist_only:
- self.create_layout()
+ pgate.pgate.__init__(self, name)
def create_netlist(self):
self.add_modules()
@@ -126,13 +130,18 @@ class single_level_column_mux(design.design):
# Add vias to bl, br_out, nmos_upper/S, nmos_lower/D
self.add_via_center(layers=("metal1","via1","metal2"),
- offset=bl_pin.bc())
+ offset=bl_pin.bc(),
+ directions=("V","V"))
self.add_via_center(layers=("metal1","via1","metal2"),
- offset=br_out_pin.uc())
+ offset=br_out_pin.uc(),
+ directions=("V","V"))
self.add_via_center(layers=("metal1","via1","metal2"),
- offset=nmos_upper_s_pin.center())
+ offset=nmos_upper_s_pin.center(),
+ directions=("V","V"))
self.add_via_center(layers=("metal1","via1","metal2"),
- offset=nmos_lower_d_pin.center())
+ offset=nmos_lower_d_pin.center(),
+ directions=("V","V"))
+
# bl -> nmos_upper/D on metal1
# bl_out -> nmos_upper/S on metal2
@@ -180,5 +189,9 @@ class single_level_column_mux(design.design):
width=self.bitcell.width,
height=self.height)
-
+ def get_stage_effort(self, corner, slew, load):
+ """Returns relative delay that the column mux. Difficult to convert to LE model."""
+ parasitic_delay = 1
+ cin = 2*self.tx_size #This is not CMOS, so using this may be incorrect.
+ return logical_effort.logical_effort('column_mux', self.tx_size, cin, load, parasitic_delay, False)
diff --git a/compiler/router/direction.py b/compiler/router/direction.py
index 8a6681a7..a04fc18c 100644
--- a/compiler/router/direction.py
+++ b/compiler/router/direction.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
from enum import Enum
from vector3d import vector3d
diff --git a/compiler/router/grid.py b/compiler/router/grid.py
index 245bcb68..af182125 100644
--- a/compiler/router/grid.py
+++ b/compiler/router/grid.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import numpy as np
import string
import debug
@@ -43,7 +50,7 @@ class grid:
self.add_map(vector3d(x,y,1))
def set_blocked(self,n,value=True):
- if isinstance(n, (list,tuple,set,frozenset)):
+ if not isinstance(n, vector3d):
for item in n:
self.set_blocked(item,value)
else:
@@ -51,7 +58,7 @@ class grid:
self.map[n].blocked=value
def is_blocked(self,n):
- if isinstance(n, (list,tuple,set,frozenset)):
+ if not isinstance(n, vector3d):
for item in n:
if self.is_blocked(item):
return True
@@ -75,7 +82,7 @@ class grid:
self.map[k].blocked=False
def set_source(self,n,value=True):
- if isinstance(n, (list,tuple,set,frozenset)):
+ if not isinstance(n, vector3d):
for item in n:
self.set_source(item,value)
else:
@@ -84,7 +91,7 @@ class grid:
self.source.add(n)
def set_target(self,n,value=True):
- if isinstance(n, (list,tuple,set,frozenset)):
+ if not isinstance(n, vector3d):
for item in n:
self.set_target(item,value)
else:
@@ -118,7 +125,7 @@ class grid:
"""
Add a point to the map if it doesn't exist.
"""
- if isinstance(n, (list,tuple,set,frozenset)):
+ if not isinstance(n, vector3d):
for item in n:
self.add_map(item)
else:
diff --git a/compiler/router/grid_cell.py b/compiler/router/grid_cell.py
index cb78116c..2a09477a 100644
--- a/compiler/router/grid_cell.py
+++ b/compiler/router/grid_cell.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
class grid_cell:
"""
A single cell that can be occupied in a given layer, blocked,
@@ -29,16 +36,21 @@ class grid_cell:
def get_type(self):
+ type_string = ""
+
if self.blocked:
- return "X"
+ type_string += "X"
if self.source:
- return "S"
+ type_string += "S"
if self.target:
- return "T"
+ type_string += "T"
if self.path:
- return "P"
+ type_string += "P"
+ if type_string != "":
+ return type_string
+
return None
diff --git a/compiler/router/grid_path.py b/compiler/router/grid_path.py
index cbe739ef..e4e0995d 100644
--- a/compiler/router/grid_path.py
+++ b/compiler/router/grid_path.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
from vector3d import vector3d
from itertools import tee
diff --git a/compiler/router/grid_utils.py b/compiler/router/grid_utils.py
index 7ad864aa..a9a4c08d 100644
--- a/compiler/router/grid_utils.py
+++ b/compiler/router/grid_utils.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
"""
Some utility functions for sets of grid cells.
"""
diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py
index 13368d12..99986e76 100644
--- a/compiler/router/pin_group.py
+++ b/compiler/router/pin_group.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
from direction import direction
from pin_layout import pin_layout
from vector3d import vector3d
@@ -25,7 +32,7 @@ class pin_group:
# This is a list because we can have a pin group of disconnected sets of pins
# and these are represented by separate lists
- self.pins = [set(irredundant_pin_set)]
+ self.pins = set(irredundant_pin_set)
self.router = router
# These are the corresponding pin grids for each pin group.
@@ -55,7 +62,7 @@ class pin_group:
total_string += grids_string
if self.enclosed:
- enlosure_string = "\n enclose={}".format(self.enclosures)
+ enclosure_string = "\n enclose={}".format(self.enclosures)
total_string += enclosure_string
total_string += ")"
@@ -74,25 +81,6 @@ class pin_group:
def is_routed(self):
return self.routed
- def pins_enclosed(self):
- """
- Check if all of the pin shapes are enclosed.
- Does not check if the DRC is correct, but just touching.
- """
- for pin_list in self.pins:
- pin_is_enclosed=False
- for pin in pin_list:
- if pin_is_enclosed:
- break
- for encosure in self.enclosures:
- if pin.overlaps(enclosure):
- pin_is_enclosed=True
- break
- else:
- return False
-
- return True
-
def remove_redundant_shapes(self, pin_list):
"""
Remove any pin layout that is contained within another.
@@ -135,7 +123,6 @@ class pin_group:
return new_pin_list
- # FIXME: This relies on some technology parameters from router which is not clean.
def compute_enclosures(self):
"""
Find the minimum rectangle enclosures of the given tracks.
@@ -406,8 +393,8 @@ class pin_group:
def enclose_pin_grids(self, ll, dir1=direction.NORTH, dir2=direction.EAST):
"""
This encloses a single pin component with a rectangle
- starting with the seed and expanding right until blocked
- and then up until blocked.
+ starting with the seed and expanding dir1 until blocked
+ and then dir2 until blocked.
dir1 and dir2 should be two orthogonal directions.
"""
@@ -458,61 +445,86 @@ class pin_group:
# Compute the enclosure pin_layout list of the set of tracks
self.enclosures = self.compute_enclosures()
- for pin_list in self.pins:
- for pin in pin_list:
+ # Find a connector to every pin and add it to the enclosures
+ for pin in self.pins:
- # If it is contained, it won't need a connector
- if pin.contained_by_any(self.enclosures):
- continue
+ # If it is contained, it won't need a connector
+ if pin.contained_by_any(self.enclosures):
+ continue
- # Find a connector in the cardinal directions
- # If there is overlap, but it isn't contained, these could all be None
- # These could also be none if the pin is diagonal from the enclosure
- left_connector = self.find_left_connector(pin, self.enclosures)
- right_connector = self.find_right_connector(pin, self.enclosures)
- above_connector = self.find_above_connector(pin, self.enclosures)
- below_connector = self.find_below_connector(pin, self.enclosures)
- connector_list = [left_connector, right_connector, above_connector, below_connector]
- filtered_list = list(filter(lambda x: x!=None, connector_list))
- if (len(filtered_list)>0):
- import copy
- bbox_connector = copy.copy(pin)
- bbox_connector.bbox(filtered_list)
- self.enclosures.append(bbox_connector)
+ # Find a connector in the cardinal directions
+ # If there is overlap, but it isn't contained, these could all be None
+ # These could also be none if the pin is diagonal from the enclosure
+ left_connector = self.find_left_connector(pin, self.enclosures)
+ right_connector = self.find_right_connector(pin, self.enclosures)
+ above_connector = self.find_above_connector(pin, self.enclosures)
+ below_connector = self.find_below_connector(pin, self.enclosures)
+ connector_list = [left_connector, right_connector, above_connector, below_connector]
+ filtered_list = list(filter(lambda x: x!=None, connector_list))
+ if (len(filtered_list)>0):
+ import copy
+ bbox_connector = copy.copy(pin)
+ bbox_connector.bbox(filtered_list)
+ self.enclosures.append(bbox_connector)
# Now, make sure each pin touches an enclosure. If not, add another (diagonal) connector.
# This could only happen when there was no enclosure in any cardinal direction from a pin
- for pin_list in self.pins:
- if not self.overlap_any_shape(pin_list, self.enclosures):
- connector = self.find_smallest_connector(pin_list, self.enclosures)
- if connector==None:
- debug.error("Could not find a connector for {} with {}".format(pin_list, self.enclosures))
- self.router.write_debug_gds("no_connector.gds")
- self.enclosures.append(connector)
-
+ if not self.overlap_any_shape(self.pins, self.enclosures):
+ connector = self.find_smallest_connector(self.pins, self.enclosures)
+ if connector==None:
+ debug.error("Could not find a connector for {} with {}".format(self.pins, self.enclosures))
+ self.router.write_debug_gds("no_connector.gds")
+ self.enclosures.append(connector)
+
+ # At this point, the pins are overlapping, but there might be more than one!
+ overlap_set = set()
+ for pin in self.pins:
+ overlap_set.update(self.transitive_overlap(pin, self.enclosures))
+ # Use the new enclosures and recompute the grids that correspond to them
+ if len(overlap_set) len(old_connected_set):
+ old_connected_set = connected_set
+ connected_set = set([shape])
+ for old_shape in old_connected_set:
+ for cur_shape in augmented_shape_list:
+ if old_shape.overlaps(cur_shape):
+ connected_set.add(cur_shape)
+
+
+ # Remove the original shape
+ connected_set.remove(shape)
+
+ # if len(connected_set) {0}\n {1}".format(combined.pins,combined.grids))
+ # new_pin_groups.append(combined)
+
+ # # Add the pin groups that weren't added to the new set
+ # for index in all_indices:
+ # new_pin_groups.append(self.pin_groups[pin_name][index])
+
+ # old_size = len(self.pin_groups[pin_name])
+ # # Use the new pin group!
+ # self.pin_groups[pin_name] = new_pin_groups
+ # removed_pairs = old_size - len(new_pin_groups)
+ # debug.info(1, "Combined {0} pin groups for {1}".format(removed_pairs,pin_name))
- # Now reconstruct the new groups
- new_pin_groups = []
- for index1,index2_set in adjacent_pins.items():
- # Remove the indices if they are added to the new set
- all_indices.discard(index1)
- all_indices.difference_update(index2_set)
-
- # Create the combined group starting with the first item
- combined = self.pin_groups[pin_name][index1]
- # Add all of the other items that overlapped
- for index2 in index2_set:
- pg = self.pin_groups[pin_name][index2]
- combined.add_group(pg)
- debug.info(3,"Combining {0} {1}:".format(pin_name, index2))
- debug.info(3, " {0}\n {1}".format(combined.pins, pg.pins))
- debug.info(3," --> {0}\n {1}".format(combined.pins,combined.grids))
- new_pin_groups.append(combined)
-
- # Add the pin groups that weren't added to the new set
- for index in all_indices:
- new_pin_groups.append(self.pin_groups[pin_name][index])
-
- old_size = len(self.pin_groups[pin_name])
- # Use the new pin group!
- self.pin_groups[pin_name] = new_pin_groups
- removed_pairs = old_size - len(new_pin_groups)
- debug.info(1, "Combined {0} pin groups for {1}".format(removed_pairs,pin_name))
-
- return removed_pairs
+ # return removed_pairs
def separate_adjacent_pins(self, separation):
@@ -657,7 +668,10 @@ class router(router_tech):
track.
"""
# to scale coordinates to tracks
- x = track[0]*self.track_width - 0.5*self.track_width
+ try:
+ x = track[0]*self.track_width - 0.5*self.track_width
+ except TypeError:
+ print(track[0],type(track[0]),self.track_width,type(self.track_width))
y = track[1]*self.track_width - 0.5*self.track_width
# offset lowest corner object to to (-track halo,-track halo)
ll = snap_to_grid(vector(x,y))
@@ -748,44 +762,10 @@ class router(router_tech):
if gid not in group_map:
group_map[gid] = pin_group(name=pin_name, pin_set=[], router=self)
# We always add it to the first set since they are touching
- group_map[gid].pins[0].add(pin)
+ group_map[gid].pins.add(pin)
self.pin_groups[pin_name] = list(group_map.values())
- # This is the old O(n^2) implementation
- # def analyze_pins(self, pin_name):
- # """
- # Analyze the shapes of a pin and combine them into pin_groups which are connected.
- # """
- # debug.info(2,"Analyzing pin groups for {}.".format(pin_name))
-
- # pin_set = self.pins[pin_name]
-
- # # Put each pin in an equivalence class of it's own
- # equiv_classes = [set([x]) for x in pin_set]
- # def combine_classes(equiv_classes):
- # for class1 in equiv_classes:
- # for class2 in equiv_classes:
- # if class1 == class2:
- # continue
- # # Compare each pin in each class,
- # # and if any overlap, update equiv_classes to include the combined the class
- # for p1 in class1:
- # for p2 in class2:
- # if p1.overlaps(p2):
- # combined_class = class1 | class2
- # equiv_classes.remove(class1)
- # equiv_classes.remove(class2)
- # equiv_classes.append(combined_class)
- # return(equiv_classes)
- # return(equiv_classes)
-
- # old_length = math.inf
- # while (len(equiv_classes)1:
+ self.cell.add_route(layers=self.layers,
+ coordinates=abs_path,
+ layer_widths=self.layer_widths)
+ else:
+ self.cell.add_path(layer=self.layers[0],
+ coordinates=abs_path,
+ width=self.layer_widths[0])
def add_single_enclosure(self, track):
"""
@@ -979,12 +973,19 @@ class router(router_tech):
"""
This assumes the blockages, source, and target are all set up.
"""
+
+ # Double check source and taget are not same node, if so, we are done!
+ for k,v in self.rg.map.items():
+ if v.source and v.target:
+ debug.error("Grid cell is source and target! {}".format(k))
+ return False
+
# returns the path in tracks
(path,cost) = self.rg.route(detour_scale)
if path:
- debug.info(2,"Found path: cost={0} ".format(cost))
- debug.info(3,str(path))
-
+ debug.info(1,"Found path: cost={0} ".format(cost))
+ debug.info(1,str(path))
+
self.paths.append(path)
self.add_route(path)
@@ -1025,6 +1026,7 @@ class router(router_tech):
Write out a GDS file with the routing grid and search information annotated on it.
"""
debug.info(0,"Writing annotated router gds file to {}".format(gds_name))
+ self.del_router_info()
self.add_router_info()
self.cell.gds_write(gds_name)
@@ -1076,6 +1078,15 @@ class router(router_tech):
offset=shape[0],
zoom=0.05)
+ def del_router_info(self):
+ """
+ Erase all of the comments on the current level.
+ """
+ debug.info(0,"Erasing router info")
+ layer_num = techlayer["text"]
+ self.cell.objs = [x for x in self.cell.objs if x.layerNumber != layer_num]
+
+
def add_router_info(self):
"""
Write the routing grid and router cost, blockage, pins on
diff --git a/compiler/router/router_tech.py b/compiler/router/router_tech.py
index 02b6894f..49df06fd 100644
--- a/compiler/router/router_tech.py
+++ b/compiler/router/router_tech.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
from tech import drc,layer
from contact import contact
from pin_group import pin_group
@@ -17,19 +24,28 @@ class router_tech:
"""
self.layers = layers
self.rail_track_width = rail_track_width
-
- (self.horiz_layer_name, self.via_layer_name, self.vert_layer_name) = self.layers
- # This is the minimum routed track spacing
- via_connect = contact(self.layers, (1, 1))
- max_via_size = max(via_connect.width,via_connect.height)
- self.horiz_layer_number = layer[self.horiz_layer_name]
- self.vert_layer_number = layer[self.vert_layer_name]
-
- if self.rail_track_width>1:
+ if len(self.layers)==1:
+ self.horiz_layer_name = self.vert_layer_name = self.layers[0]
+ self.horiz_layer_number = self.vert_layer_number = layer[self.layers[0]]
+
(self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1)
(self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0)
+
+ self.horiz_track_width = self.horiz_layer_minwidth + self.horiz_layer_spacing
+ self.vert_track_width = self.vert_layer_minwidth + self.vert_layer_spacing
+ else:
+ (self.horiz_layer_name, self.via_layer_name, self.vert_layer_name) = self.layers
+ via_connect = contact(self.layers, (1, 1))
+ max_via_size = max(via_connect.width,via_connect.height)
+
+ self.horiz_layer_number = layer[self.horiz_layer_name]
+ self.vert_layer_number = layer[self.vert_layer_name]
+
+ (self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1)
+ (self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0)
+
# For supplies, we will make the wire wider than the vias
self.vert_layer_minwidth = max(self.vert_layer_minwidth, max_via_size)
self.horiz_layer_minwidth = max(self.horiz_layer_minwidth, max_via_size)
@@ -37,13 +53,6 @@ class router_tech:
self.horiz_track_width = self.horiz_layer_minwidth + self.horiz_layer_spacing
self.vert_track_width = self.vert_layer_minwidth + self.vert_layer_spacing
- else:
- (self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_layer_width_space(1)
- (self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_layer_width_space(0)
-
- self.horiz_track_width = max_via_size + self.horiz_layer_spacing
- self.vert_track_width = max_via_size + self.vert_layer_spacing
-
# We'll keep horizontal and vertical tracks the same for simplicity.
self.track_width = max(self.horiz_track_width,self.vert_track_width)
debug.info(1,"Track width: {:.3f}".format(self.track_width))
@@ -73,24 +82,6 @@ class router_tech:
else:
debug.error("Invalid zindex {}".format(zindex),-1)
- def get_layer_width_space(self, zindex, width=0, length=0):
- """
- Return the width and spacing of a given layer
- and wire of a given width and length.
- """
- if zindex==1:
- layer_name = self.vert_layer_name
- elif zindex==0:
- layer_name = self.horiz_layer_name
- else:
- debug.error("Invalid zindex for track", -1)
-
- min_width = drc("minwidth_{0}".format(layer_name), width, length)
- min_spacing = drc(str(layer_name)+"_to_"+str(layer_name), width, length)
-
- return (min_width,min_spacing)
-
-
def get_supply_layer_width_space(self, zindex):
"""
These are the width and spacing of a supply layer given a supply rail
diff --git a/compiler/router/signal_grid.py b/compiler/router/signal_grid.py
index 59d75c7a..cb012a5e 100644
--- a/compiler/router/signal_grid.py
+++ b/compiler/router/signal_grid.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
from itertools import tee
import debug
from heapq import heappush,heappop
diff --git a/compiler/router/signal_router.py b/compiler/router/signal_router.py
index eb706b5b..9390deaf 100644
--- a/compiler/router/signal_router.py
+++ b/compiler/router/signal_router.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import gdsMill
import tech
from contact import contact
diff --git a/compiler/router/supply_grid.py b/compiler/router/supply_grid.py
index 88b436af..98c6f031 100644
--- a/compiler/router/supply_grid.py
+++ b/compiler/router/supply_grid.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
from vector3d import vector3d
from grid import grid
@@ -27,7 +34,7 @@ class supply_grid(signal_grid):
p.reset()
- def find_start_wave(self, wave, width, direct):
+ def find_start_wave(self, wave, direct):
"""
Finds the first loc starting at loc and up that is open.
Returns None if it reaches max size first.
diff --git a/compiler/router/supply_router.py b/compiler/router/supply_grid_router.py
similarity index 91%
rename from compiler/router/supply_router.py
rename to compiler/router/supply_grid_router.py
index 9f2ddf57..5ddabc98 100644
--- a/compiler/router/supply_router.py
+++ b/compiler/router/supply_grid_router.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import gdsMill
import tech
import math
@@ -13,7 +20,7 @@ from datetime import datetime
import grid
import grid_utils
-class supply_router(router):
+class supply_grid_router(router):
"""
A router class to read an obstruction map from a gds and
routes a grid to connect the supply on the two layers.
@@ -81,7 +88,7 @@ class supply_router(router):
# Determine the rail locations
self.route_supply_rails(self.vdd_name,1)
print_time("Routing supply rails",datetime.now(), start_time, 3)
-
+
start_time = datetime.now()
self.route_simple_overlaps(vdd_name)
self.route_simple_overlaps(gnd_name)
@@ -94,10 +101,23 @@ class supply_router(router):
self.route_pins_to_rails(gnd_name)
print_time("Maze routing supplies",datetime.now(), start_time, 3)
#self.write_debug_gds("final.gds",False)
+
+ # Did we route everything??
+ if not self.check_all_routed(vdd_name):
+ return False
+ if not self.check_all_routed(gnd_name):
+ return False
return True
+ def check_all_routed(self, pin_name):
+ """
+ Check that all pin groups are routed.
+ """
+ for pg in self.pin_groups[pin_name]:
+ if not pg.is_routed():
+ return False
def route_simple_overlaps(self, pin_name):
"""
@@ -146,13 +166,7 @@ class supply_router(router):
# We need to move this rail to the other layer for the z indices to match
# during the intersection. This also makes a copy.
new_r1 = {vector3d(i.x,i.y,1) for i in r1}
-
- # If horizontal, subtract off the left/right track to prevent end of rail via
- #ll = grid_utils.get_lower_left(new_r1)
- #ur = grid_utils.get_upper_right(new_r1)
- grid_utils.remove_border(new_r1, direction.EAST)
- grid_utils.remove_border(new_r1, direction.WEST)
-
+
for i2,r2 in enumerate(all_rails):
# Never compare to yourself
if i1==i2:
@@ -163,16 +177,11 @@ class supply_router(router):
if e.z==0:
continue
- # Need to maek a copy to consider via overlaps to ignore the end-caps
- new_r2 = r2.copy()
- grid_utils.remove_border(new_r2, direction.NORTH)
- grid_utils.remove_border(new_r2, direction.SOUTH)
-
- # Determine if we hhave sufficient overlap and, if so,
+ # Determine if we have sufficient overlap and, if so,
# remember:
# the indices to determine a rail is connected to another
# the overlap area for placement of a via
- overlap = new_r1 & new_r2
+ overlap = new_r1 & r2
if len(overlap) >= 1:
debug.info(3,"Via overlap {0} {1}".format(len(overlap),overlap))
connections.update([i1,i2])
@@ -213,7 +222,7 @@ class supply_router(router):
ur = grid_utils.get_upper_right(rail)
z = ll.z
pin = self.compute_pin_enclosure(ll, ur, z, name)
- debug.info(2,"Adding supply rail {0} {1}->{2} {3}".format(name,ll,ur,pin))
+ debug.info(3,"Adding supply rail {0} {1}->{2} {3}".format(name,ll,ur,pin))
self.cell.add_layout_pin(text=name,
layer=pin.layer,
offset=pin.ll(),
@@ -270,7 +279,8 @@ class supply_router(router):
Find a start location, probe in the direction, and see if the rail is big enough
to contain a via, and, if so, add it.
"""
- start_wave = self.find_supply_rail_start(name, seed_wave, direct)
+ # Sweep to find an initial unblocked valid wave
+ start_wave = self.rg.find_start_wave(seed_wave, direct)
# This means there were no more unblocked grids in the row/col
if not start_wave:
@@ -284,17 +294,6 @@ class supply_router(router):
# as it will be used to find the next start location
return wave_path
- def find_supply_rail_start(self, name, seed_wave, direct):
- """
- This finds the first valid starting location and routes a supply rail
- in the given direction.
- It returns the space after the end of the rail to seed another call for multiple
- supply rails in the same "track" when there is a blockage.
- """
- # Sweep to find an initial unblocked valid wave
- start_wave = self.rg.find_start_wave(seed_wave, len(seed_wave), direct)
-
- return start_wave
def probe_supply_rail(self, name, start_wave, direct):
"""
@@ -392,7 +391,7 @@ class supply_router(router):
# Add the single component of the pin as the source
# which unmarks it as a blockage too
- self.add_pin_component_source(pin_name,index)
+ self.add_pin_component_source(pin_name, index)
# Add all of the rails as targets
# Don't add the other pins, but we could?
@@ -400,7 +399,10 @@ class supply_router(router):
# Actually run the A* router
if not self.run_router(detour_scale=5):
- self.write_debug_gds()
+ self.write_debug_gds("debug_route.gds",False)
+
+ #if index==3 and pin_name=="vdd":
+ # self.write_debug_gds("route.gds",False)
def add_supply_rail_target(self, pin_name):
diff --git a/compiler/router/supply_tree_router.py b/compiler/router/supply_tree_router.py
new file mode 100644
index 00000000..7def03e0
--- /dev/null
+++ b/compiler/router/supply_tree_router.py
@@ -0,0 +1,193 @@
+# See LICENSE for licensing information.
+#
+#Copyright (c) 2016-2019 Regents of the University of California and The Board
+#of Regents for the Oklahoma Agricultural and Mechanical College
+#(acting for and on behalf of Oklahoma State University)
+#All rights reserved.
+#
+import gdsMill
+import tech
+import math
+import debug
+from globals import OPTS,print_time
+from contact import contact
+from pin_group import pin_group
+from pin_layout import pin_layout
+from vector3d import vector3d
+from router import router
+from direction import direction
+from datetime import datetime
+import grid
+import grid_utils
+
+class supply_tree_router(router):
+ """
+ A router class to read an obstruction map from a gds and
+ routes a grid to connect the supply on the two layers.
+ """
+
+ def __init__(self, layers, design, gds_filename=None):
+ """
+ This will route on layers in design. It will get the blockages from
+ either the gds file name or the design itself (by saving to a gds file).
+ """
+ # Power rail width in minimum wire widths
+ self.rail_track_width = 3
+
+ router.__init__(self, layers, design, gds_filename, self.rail_track_width)
+
+
+ def create_routing_grid(self):
+ """
+ Create a sprase routing grid with A* expansion functions.
+ """
+ size = self.ur - self.ll
+ debug.info(1,"Size: {0} x {1}".format(size.x,size.y))
+
+ import supply_grid
+ self.rg = supply_grid.supply_grid(self.ll, self.ur, self.track_width)
+
+ def route(self, vdd_name="vdd", gnd_name="gnd"):
+ """
+ Route the two nets in a single layer)
+ """
+ debug.info(1,"Running supply router on {0} and {1}...".format(vdd_name, gnd_name))
+ self.vdd_name = vdd_name
+ self.gnd_name = gnd_name
+
+ # Clear the pins if we have previously routed
+ if (hasattr(self,'rg')):
+ self.clear_pins()
+ else:
+ # Creat a routing grid over the entire area
+ # FIXME: This could be created only over the routing region,
+ # but this is simplest for now.
+ self.create_routing_grid()
+
+ # Get the pin shapes
+ start_time = datetime.now()
+ self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
+ print_time("Finding pins and blockages",datetime.now(), start_time, 3)
+
+ # Add the supply rails in a mesh network and connect H/V with vias
+ start_time = datetime.now()
+ # Block everything
+ self.prepare_blockages(self.gnd_name)
+ self.prepare_blockages(self.vdd_name)
+
+ # Route the supply pins to the supply rails
+ # Route vdd first since we want it to be shorter
+ start_time = datetime.now()
+ self.route_pins(vdd_name)
+ self.route_pins(gnd_name)
+ print_time("Maze routing supplies",datetime.now(), start_time, 3)
+
+ #self.write_debug_gds("final.gds",False)
+
+ # Did we route everything??
+ if not self.check_all_routed(vdd_name):
+ return False
+ if not self.check_all_routed(gnd_name):
+ return False
+
+ return True
+
+
+ def check_all_routed(self, pin_name):
+ """
+ Check that all pin groups are routed.
+ """
+ for pg in self.pin_groups[pin_name]:
+ if not pg.is_routed():
+ return False
+
+ def prepare_blockages(self, pin_name):
+ """
+ Reset and add all of the blockages in the design.
+ Names is a list of pins to add as a blockage.
+ """
+ debug.info(3,"Preparing blockages.")
+
+ # Start fresh. Not the best for run-time, but simpler.
+ self.clear_blockages()
+ # This adds the initial blockges of the design
+ #print("BLOCKING:",self.blocked_grids)
+ self.set_blockages(self.blocked_grids,True)
+
+ # Block all of the pin components (some will be unblocked if they're a source/target)
+ # Also block the previous routes
+ for name in self.pin_groups:
+ blockage_grids = {y for x in self.pin_groups[name] for y in x.grids}
+ self.set_blockages(blockage_grids,True)
+ blockage_grids = {y for x in self.pin_groups[name] for y in x.blockages}
+ self.set_blockages(blockage_grids,True)
+
+ # FIXME: These duplicate a bit of work
+ # These are the paths that have already been routed.
+ self.set_blockages(self.path_blockages)
+
+ # Don't mark the other components as targets since we want to route
+ # directly to a rail, but unblock all the source components so we can
+ # route over them
+ blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids}
+ self.set_blockages(blockage_grids,False)
+
+
+
+ def route_pins(self, pin_name):
+ """
+ This will route each of the remaining pin components to the other pins.
+ After it is done, the cells are added to the pin blockage list.
+ """
+
+ remaining_components = sum(not x.is_routed() for x in self.pin_groups[pin_name])
+ debug.info(1,"Maze routing {0} with {1} pin components to connect.".format(pin_name,
+ remaining_components))
+
+ for index,pg in enumerate(self.pin_groups[pin_name]):
+ if pg.is_routed():
+ continue
+
+ debug.info(1,"Routing component {0} {1}".format(pin_name, index))
+
+ # Clear everything in the routing grid.
+ self.rg.reinit()
+
+ # This is inefficient since it is non-incremental, but it was
+ # easier to debug.
+ self.prepare_blockages(pin_name)
+
+ # Add the single component of the pin as the source
+ # which unmarks it as a blockage too
+ self.add_pin_component_source(pin_name,index)
+
+ # Marks all pin components except index as target
+ self.add_pin_component_target_except(pin_name,index)
+ # Add the prevous paths as a target too
+ self.add_path_target(self.paths)
+
+ print("SOURCE: ")
+ for k,v in self.rg.map.items():
+ if v.source:
+ print(k)
+
+ print("TARGET: ")
+ for k,v in self.rg.map.items():
+ if v.target:
+ print(k)
+
+ import pdb; pdb.set_trace()
+ if index==1:
+ self.write_debug_gds("debug{}.gds".format(pin_name),False)
+
+ # Actually run the A* router
+ if not self.run_router(detour_scale=5):
+ self.write_debug_gds("debug_route.gds",True)
+
+ #if index==3 and pin_name=="vdd":
+ # self.write_debug_gds("route.gds",False)
+
+
+
+
+
diff --git a/compiler/router/tests/01_no_blockages_test.py b/compiler/router/tests/01_no_blockages_test.py
old mode 100755
new mode 100644
index 4197f714..4a673c24
--- a/compiler/router/tests/01_no_blockages_test.py
+++ b/compiler/router/tests/01_no_blockages_test.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
#!/usr/bin/env python3
"Run a regresion test the library cells for DRC"
diff --git a/compiler/router/tests/02_blockages_test.py b/compiler/router/tests/02_blockages_test.py
old mode 100755
new mode 100644
index 6e3bee08..e317b642
--- a/compiler/router/tests/02_blockages_test.py
+++ b/compiler/router/tests/02_blockages_test.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
#!/usr/bin/env python3
"Run a regresion test the library cells for DRC"
diff --git a/compiler/router/tests/03_same_layer_pins_test.py b/compiler/router/tests/03_same_layer_pins_test.py
old mode 100755
new mode 100644
index 726cd02b..10a3544a
--- a/compiler/router/tests/03_same_layer_pins_test.py
+++ b/compiler/router/tests/03_same_layer_pins_test.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
#!/usr/bin/env python3
"Run a regresion test the library cells for DRC"
diff --git a/compiler/router/tests/04_diff_layer_pins_test.py b/compiler/router/tests/04_diff_layer_pins_test.py
old mode 100755
new mode 100644
index 2882156f..8966d2e4
--- a/compiler/router/tests/04_diff_layer_pins_test.py
+++ b/compiler/router/tests/04_diff_layer_pins_test.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
#!/usr/bin/env python3
"Run a regresion test the library cells for DRC"
diff --git a/compiler/router/tests/05_two_nets_test.py b/compiler/router/tests/05_two_nets_test.py
old mode 100755
new mode 100644
index e71920a8..ebf84745
--- a/compiler/router/tests/05_two_nets_test.py
+++ b/compiler/router/tests/05_two_nets_test.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
#!/usr/bin/env python3
"Run a regresion test the library cells for DRC"
diff --git a/compiler/router/tests/06_pin_location_test.py b/compiler/router/tests/06_pin_location_test.py
old mode 100755
new mode 100644
index f469d326..a035cc59
--- a/compiler/router/tests/06_pin_location_test.py
+++ b/compiler/router/tests/06_pin_location_test.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
#!/usr/bin/env python3
"Run a regresion test the library cells for DRC"
diff --git a/compiler/router/tests/07_big_test.py b/compiler/router/tests/07_big_test.py
old mode 100755
new mode 100644
index 8fcf2826..5410dcbf
--- a/compiler/router/tests/07_big_test.py
+++ b/compiler/router/tests/07_big_test.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
#!/usr/bin/env python3
"Run a regresion test the library cells for DRC"
diff --git a/compiler/router/tests/08_expand_region_test.py b/compiler/router/tests/08_expand_region_test.py
old mode 100755
new mode 100644
index 3e63bd51..ab4bce59
--- a/compiler/router/tests/08_expand_region_test.py
+++ b/compiler/router/tests/08_expand_region_test.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
#!/usr/bin/env python3
"Run a regresion test the library cells for DRC"
diff --git a/compiler/router/tests/10_supply_grid_test.py b/compiler/router/tests/10_supply_grid_test.py
old mode 100755
new mode 100644
index 7258ab40..73e41b86
--- a/compiler/router/tests/10_supply_grid_test.py
+++ b/compiler/router/tests/10_supply_grid_test.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
#!/usr/bin/env python3
"Run a regresion test the library cells for DRC"
diff --git a/compiler/router/tests/config_freepdk45.py b/compiler/router/tests/config_freepdk45.py
old mode 100755
new mode 100644
index aaaa4c37..bdc576bf
--- a/compiler/router/tests/config_freepdk45.py
+++ b/compiler/router/tests/config_freepdk45.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
word_size = 1
num_words = 16
diff --git a/compiler/router/tests/config_scn4m_subm.py b/compiler/router/tests/config_scn4m_subm.py
old mode 100755
new mode 100644
index e3aa1498..bfaa01f8
--- a/compiler/router/tests/config_scn4m_subm.py
+++ b/compiler/router/tests/config_scn4m_subm.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
word_size = 1
num_words = 16
diff --git a/compiler/router/tests/gds_cell.py b/compiler/router/tests/gds_cell.py
index 5c1e0f91..b93b512a 100644
--- a/compiler/router/tests/gds_cell.py
+++ b/compiler/router/tests/gds_cell.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
from design import design
class gds_cell(design):
"""
diff --git a/compiler/router/tests/regress.py b/compiler/router/tests/regress.py
old mode 100755
new mode 100644
index b40263c7..db21bbd9
--- a/compiler/router/tests/regress.py
+++ b/compiler/router/tests/regress.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
#!/usr/bin/env python3
import re
diff --git a/compiler/router/tests/testutils.py b/compiler/router/tests/testutils.py
old mode 100755
new mode 100644
index 4bea5d15..c90046f3
--- a/compiler/router/tests/testutils.py
+++ b/compiler/router/tests/testutils.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest,warnings
import sys,os,glob,copy
sys.path.append(os.path.join(sys.path[0],"../.."))
diff --git a/compiler/router/vector3d.py b/compiler/router/vector3d.py
index 1d0d083e..0d183021 100644
--- a/compiler/router/vector3d.py
+++ b/compiler/router/vector3d.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
import math
diff --git a/compiler/run_profile.sh b/compiler/run_profile.sh
index 37a130a4..1234427d 100755
--- a/compiler/run_profile.sh
+++ b/compiler/run_profile.sh
@@ -1,3 +1,3 @@
#!/bin/bash
-python3 -m cProfile -o profile.dat ./openram.py example_configs/medium_config_scn4m_subm.py -v | tee -i medium.log
+python3 -m cProfile -o profile.dat ./openram.py example_configs/giant_config_scn4m_subm.py -v | tee -i big.log
echo "Run view_profile.py to view results"
diff --git a/compiler/sram.py b/compiler/sram/sram.py
similarity index 92%
rename from compiler/sram.py
rename to compiler/sram/sram.py
index 5ff28d47..c4f41f77 100644
--- a/compiler/sram.py
+++ b/compiler/sram/sram.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import sys
import datetime
import getpass
@@ -27,7 +34,6 @@ class sram():
start_time = datetime.datetime.now()
self.name = name
-
if self.num_banks == 1:
from sram_1bank import sram_1bank as sram
@@ -62,6 +68,13 @@ class sram():
""" Save all the output files while reporting time to do it as well. """
if not OPTS.netlist_only:
+ # Create a LEF physical model
+ start_time = datetime.datetime.now()
+ lefname = OPTS.output_path + self.s.name + ".lef"
+ debug.print_raw("LEF: Writing to {0}".format(lefname))
+ self.lef_write(lefname)
+ print_time("LEF", datetime.datetime.now(), start_time)
+
# Write the layout
start_time = datetime.datetime.now()
gdsname = OPTS.output_path + self.s.name + ".gds"
@@ -69,13 +82,6 @@ class sram():
self.gds_write(gdsname)
print_time("GDS", datetime.datetime.now(), start_time)
- # Create a LEF physical model
- start_time = datetime.datetime.now()
- lefname = OPTS.output_path + self.s.name + ".lef"
- debug.print_raw("LEF: Writing to {0}".format(lefname))
- self.lef_write(lefname)
- print_time("LEF", datetime.datetime.now(), start_time)
-
# Save the spice file
start_time = datetime.datetime.now()
spname = OPTS.output_path + self.s.name + ".sp"
@@ -99,13 +105,6 @@ class sram():
start_time = datetime.datetime.now()
from characterizer import lib
debug.print_raw("LIB: Characterizing... ")
- if OPTS.analytical_delay:
- debug.print_raw("Using analytical delay models (no characterization)")
- else:
- if OPTS.spice_name!="":
- debug.print_raw("Performing simulation-based characterization with {}".format(OPTS.spice_name))
- if OPTS.trim_netlist:
- debug.print_raw("Trimming netlist to speed up characterization.")
lib(out_dir=OPTS.output_path, sram=self.s, sp_file=sp_file)
print_time("Characterization", datetime.datetime.now(), start_time)
diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py
new file mode 100644
index 00000000..9e578c7c
--- /dev/null
+++ b/compiler/sram/sram_1bank.py
@@ -0,0 +1,491 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import sys
+from tech import drc, spice
+import debug
+from math import log,sqrt,ceil
+import datetime
+import getpass
+import numpy as np
+from vector import vector
+from globals import OPTS, print_time
+
+from sram_base import sram_base
+from bank import bank
+from contact import m2m3
+from dff_buf_array import dff_buf_array
+from dff_array import dff_array
+
+
+class sram_1bank(sram_base):
+ """
+ Procedures specific to a one bank SRAM.
+ """
+ def __init__(self, name, sram_config):
+ sram_base.__init__(self, name, sram_config)
+
+ def create_modules(self):
+ """
+ This adds the modules for a single bank SRAM with control
+ logic.
+ """
+
+ self.bank_inst=self.create_bank(0)
+
+ self.control_logic_insts = self.create_control_logic()
+
+ self.row_addr_dff_insts = self.create_row_addr_dff()
+
+ if self.col_addr_dff:
+ self.col_addr_dff_insts = self.create_col_addr_dff()
+
+ if self.write_size:
+ self.wmask_dff_insts = self.create_wmask_dff()
+ self.data_dff_insts = self.create_data_dff()
+ else:
+ self.data_dff_insts = self.create_data_dff()
+
+ def place_instances(self):
+ """
+ This places the instances for a single bank SRAM with control
+ logic and up to 2 ports.
+ """
+
+ # No orientation or offset
+ self.place_bank(self.bank_inst, [0, 0], 1, 1)
+
+ # The control logic is placed such that the vertical center (between the delay/RBL and
+ # the actual control logic is aligned with the vertical center of the bank (between
+ # the sense amps/column mux and cell array)
+ # The x-coordinate is placed to allow a single clock wire (plus an extra pitch)
+ # up to the row address DFFs.
+ control_pos = [None]*len(self.all_ports)
+ row_addr_pos = [None]*len(self.all_ports)
+ col_addr_pos = [None]*len(self.all_ports)
+ wmask_pos = [None]*len(self.all_ports)
+ data_pos = [None]*len(self.all_ports)
+
+ if self.write_size:
+ max_gap_size = self.m3_pitch*self.word_size + 2*self.m1_pitch
+ max_gap_size_wmask = self.m2_pitch*max(self.num_wmasks+1,self.col_addr_size+1) + 2*self.m1_pitch
+ else:
+ # This is M2 pitch even though it is on M1 to help stem via spacings on the trunk
+ # The M1 pitch is for supply rail spacings
+ max_gap_size = self.m2_pitch*max(self.word_size+1,self.col_addr_size+1) + 2*self.m1_pitch
+
+ # Port 0
+ port = 0
+
+ if port in self.write_ports:
+ if self.write_size:
+ # Add the write mask flops below the write mask AND array.
+ wmask_pos[port] = vector(self.bank.bank_array_ll.x,
+ -max_gap_size_wmask - self.dff.height)
+ self.wmask_dff_insts[port].place(wmask_pos[port])
+
+ # Add the data flops below the write mask flops.
+ data_pos[port] = vector(self.bank.bank_array_ll.x,
+ -max_gap_size - max_gap_size_wmask - 2*self.dff.height)
+ self.data_dff_insts[port].place(data_pos[port])
+ else:
+ # Add the data flops below the bank to the right of the lower-left of bank array
+ # This relies on the lower-left of the array of the bank
+ # decoder in upper left, bank in upper right, sensing in lower right.
+ # These flops go below the sensing and leave a gap to channel route to the
+ # sense amps.
+ if port in self.write_ports:
+ data_pos[port] = vector(self.bank.bank_array_ll.x,
+ -max_gap_size - self.dff.height)
+ self.data_dff_insts[port].place(data_pos[port])
+ else:
+ wmask_pos[port] = vector(self.bank.bank_array_ll.x, 0)
+ data_pos[port] = vector(self.bank.bank_array_ll.x,0)
+
+
+ # Add the col address flops below the bank to the left of the lower-left of bank array
+ if self.col_addr_dff:
+ if self.write_size:
+ col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.m2_gap,
+ -max_gap_size_wmask - self.col_addr_dff_insts[port].height)
+ else:
+ col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.m2_gap,
+ -max_gap_size - self.col_addr_dff_insts[port].height)
+ self.col_addr_dff_insts[port].place(col_addr_pos[port])
+ else:
+ col_addr_pos[port] = vector(self.bank.bank_array_ll.x,0)
+
+ # This includes 2 M2 pitches for the row addr clock line.
+ control_pos[port] = vector(-self.control_logic_insts[port].width - 2*self.m2_pitch,
+ self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y - 2*self.bank.m2_gap )
+ self.control_logic_insts[port].place(control_pos[port])
+
+ # The row address bits are placed above the control logic aligned on the right.
+ x_offset = self.control_logic_insts[port].rx() - self.row_addr_dff_insts[port].width
+ # It is above the control logic but below the top of the bitcell array
+ y_offset = max(self.control_logic_insts[port].uy(), self.bank_inst.uy() - self.row_addr_dff_insts[port].height)
+ row_addr_pos[port] = vector(x_offset, y_offset)
+ self.row_addr_dff_insts[port].place(row_addr_pos[port])
+
+ if len(self.all_ports)>1:
+ # Port 1
+ port = 1
+
+ if port in self.write_ports:
+ if self.write_size:
+ # Add the write mask flops below the write mask AND array.
+ wmask_pos[port] = vector(self.bank.bank_array_ur.x - self.wmask_dff_insts[port].width,
+ self.bank.height + max_gap_size_wmask + self.dff.height)
+ self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX")
+
+ # Add the data flops below the write mask flops
+ data_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width,
+ self.bank.height + max_gap_size_wmask + max_gap_size + 2*self.dff.height)
+ self.data_dff_insts[port].place(data_pos[port], mirror="MX")
+ else:
+ # Add the data flops above the bank to the left of the upper-right of bank array
+ # This relies on the upper-right of the array of the bank
+ # decoder in upper left, bank in upper right, sensing in lower right.
+ # These flops go below the sensing and leave a gap to channel route to the
+ # sense amps.
+ data_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width,
+ self.bank.height + max_gap_size + self.dff.height)
+ self.data_dff_insts[port].place(data_pos[port], mirror="MX")
+
+ # Add the col address flops above the bank to the right of the upper-right of bank array
+ if self.col_addr_dff:
+ if self.write_size:
+ col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap,
+ self.bank.height + max_gap_size_wmask + self.dff.height)
+ else:
+ col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap,
+ self.bank.height + max_gap_size + self.dff.height)
+ self.col_addr_dff_insts[port].place(col_addr_pos[port], mirror="MX")
+ else:
+ col_addr_pos[port] = self.bank_inst.ur()
+
+ # This includes 2 M2 pitches for the row addr clock line
+ control_pos[port] = vector(self.bank_inst.rx() + self.control_logic_insts[port].width + 2*self.m2_pitch,
+ self.bank.bank_array_ur.y + self.control_logic_insts[port].height -
+ (self.control_logic_insts[port].height - self.control_logic_insts[port].mod.control_logic_center.y)
+ + 2*self.bank.m2_gap)
+ #import pdb; pdb.set_trace()
+ self.control_logic_insts[port].place(control_pos[port], mirror="XY")
+
+ # The row address bits are placed above the control logic aligned on the left.
+ x_offset = control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width
+ # It is below the control logic but below the bottom of the bitcell array
+ y_offset = min(self.control_logic_insts[port].by(), self.bank_inst.by() + self.row_addr_dff_insts[port].height)
+ row_addr_pos[port] = vector(x_offset, y_offset)
+ self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="XY")
+
+
+ def add_layout_pins(self):
+ """
+ Add the top-level pins for a single bank SRAM with control.
+ """
+ for port in self.all_ports:
+ # Connect the control pins as inputs
+ for signal in self.control_logic_inputs[port] + ["clk"]:
+ self.copy_layout_pin(self.control_logic_insts[port], signal, signal+"{}".format(port))
+
+ if port in self.read_ports:
+ for bit in range(self.word_size):
+ self.copy_layout_pin(self.bank_inst, "dout{0}_{1}".format(port,bit), "dout{0}[{1}]".format(port,bit))
+
+ # Lower address bits
+ for bit in range(self.col_addr_size):
+ self.copy_layout_pin(self.col_addr_dff_insts[port], "din_{}".format(bit),"addr{0}[{1}]".format(port,bit))
+ # Upper address bits
+ for bit in range(self.row_addr_size):
+ self.copy_layout_pin(self.row_addr_dff_insts[port], "din_{}".format(bit),"addr{0}[{1}]".format(port,bit+self.col_addr_size))
+
+ if port in self.write_ports:
+ for bit in range(self.word_size):
+ self.copy_layout_pin(self.data_dff_insts[port], "din_{}".format(bit), "din{0}[{1}]".format(port,bit))
+
+ if self.write_size:
+ for bit in range(self.num_wmasks):
+ self.copy_layout_pin(self.wmask_dff_insts[port], "din_{}".format(bit), "wmask{0}[{1}]".format(port,bit))
+
+
+ def route_layout(self):
+ """ Route a single bank SRAM """
+
+ self.add_layout_pins()
+
+ self.route_clk()
+
+ self.route_control_logic()
+
+ self.route_row_addr_dff()
+
+ if self.col_addr_dff:
+ self.route_col_addr_dff()
+
+ self.route_data_dff()
+
+ if self.write_size:
+ self.route_wmask_dff()
+
+ def route_clk(self):
+ """ Route the clock network """
+
+ # This is the actual input to the SRAM
+ for port in self.all_ports:
+ self.copy_layout_pin(self.control_logic_insts[port], "clk", "clk{}".format(port))
+
+ # Connect all of these clock pins to the clock in the central bus
+ # This is something like a "spine" clock distribution. The two spines
+ # are clk_buf and clk_buf_bar
+ control_clk_buf_pin = self.control_logic_insts[port].get_pin("clk_buf")
+ control_clk_buf_pos = control_clk_buf_pin.center()
+
+ # This uses a metal2 track to the right (for port0) of the control/row addr DFF
+ # to route vertically. For port1, it is to the left.
+ row_addr_clk_pin = self.row_addr_dff_insts[port].get_pin("clk")
+ if port%2:
+ control_clk_buf_pos = control_clk_buf_pin.lc()
+ row_addr_clk_pos = row_addr_clk_pin.lc()
+ mid1_pos = vector(self.row_addr_dff_insts[port].lx() - self.m2_pitch,
+ row_addr_clk_pos.y)
+ else:
+ control_clk_buf_pos = control_clk_buf_pin.rc()
+ row_addr_clk_pos = row_addr_clk_pin.rc()
+ mid1_pos = vector(self.row_addr_dff_insts[port].rx() + self.m2_pitch,
+ row_addr_clk_pos.y)
+
+ # This is the steiner point where the net branches out
+ clk_steiner_pos = vector(mid1_pos.x, control_clk_buf_pos.y)
+ self.add_path("metal1", [control_clk_buf_pos, clk_steiner_pos])
+ self.add_via_center(layers=("metal1","via1","metal2"),
+ offset=clk_steiner_pos)
+
+ # Note, the via to the control logic is taken care of above
+ self.add_wire(("metal3","via2","metal2"),[row_addr_clk_pos, mid1_pos, clk_steiner_pos])
+
+ if self.col_addr_dff:
+ dff_clk_pin = self.col_addr_dff_insts[port].get_pin("clk")
+ dff_clk_pos = dff_clk_pin.center()
+ mid_pos = vector(clk_steiner_pos.x, dff_clk_pos.y)
+ self.add_wire(("metal3","via2","metal2"),[dff_clk_pos, mid_pos, clk_steiner_pos])
+
+ if port in self.write_ports:
+ data_dff_clk_pin = self.data_dff_insts[port].get_pin("clk")
+ data_dff_clk_pos = data_dff_clk_pin.center()
+ mid_pos = vector(clk_steiner_pos.x, data_dff_clk_pos.y)
+ # In some designs, the steiner via will be too close to the mid_pos via
+ # so make the wire as wide as the contacts
+ self.add_path("metal2",[mid_pos, clk_steiner_pos], width=max(m2m3.width,m2m3.height))
+ self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, clk_steiner_pos])
+
+ if self.write_size:
+ wmask_dff_clk_pin = self.wmask_dff_insts[port].get_pin("clk")
+ wmask_dff_clk_pos = wmask_dff_clk_pin.center()
+ mid_pos = vector(clk_steiner_pos.x, wmask_dff_clk_pos.y)
+ # In some designs, the steiner via will be too close to the mid_pos via
+ # so make the wire as wide as the contacts
+ self.add_path("metal2", [mid_pos, clk_steiner_pos], width=max(m2m3.width, m2m3.height))
+ self.add_wire(("metal3", "via2", "metal2"), [wmask_dff_clk_pos, mid_pos, clk_steiner_pos])
+
+
+ def route_control_logic(self):
+ """ Route the control logic pins that are not inputs """
+
+ for port in self.all_ports:
+ for signal in self.control_logic_outputs[port]:
+ # The clock gets routed separately and is not a part of the bank
+ if "clk" in signal:
+ continue
+ src_pin = self.control_logic_insts[port].get_pin(signal)
+ dest_pin = self.bank_inst.get_pin(signal+"{}".format(port))
+ self.connect_vbus_m2m3(src_pin, dest_pin)
+
+ for port in self.all_ports:
+ # Only input (besides pins) is the replica bitline
+ src_pin = self.control_logic_insts[port].get_pin("rbl_bl")
+ dest_pin = self.bank_inst.get_pin("rbl_bl{}".format(port))
+ self.connect_vbus_m2m3(src_pin, dest_pin)
+
+
+ def route_row_addr_dff(self):
+ """ Connect the output of the row flops to the bank pins """
+ for port in self.all_ports:
+ for bit in range(self.row_addr_size):
+ flop_name = "dout_{}".format(bit)
+ bank_name = "addr{0}_{1}".format(port,bit+self.col_addr_size)
+ flop_pin = self.row_addr_dff_insts[port].get_pin(flop_name)
+ bank_pin = self.bank_inst.get_pin(bank_name)
+ flop_pos = flop_pin.center()
+ bank_pos = bank_pin.center()
+ mid_pos = vector(bank_pos.x,flop_pos.y)
+ self.add_wire(("metal3","via2","metal2"),[flop_pos, mid_pos,bank_pos])
+ self.add_via_center(layers=("metal2","via2","metal3"),
+ offset=flop_pos)
+
+ def route_col_addr_dff(self):
+ """ Connect the output of the row flops to the bank pins """
+ for port in self.all_ports:
+ if port%2:
+ offset = self.col_addr_dff_insts[port].ll() - vector(0, (self.word_size+2)*self.m1_pitch)
+ else:
+ offset = self.col_addr_dff_insts[port].ul() + vector(0, 2*self.m1_pitch)
+
+ bus_names = ["addr_{}".format(x) for x in range(self.col_addr_size)]
+ col_addr_bus_offsets = self.create_horizontal_bus(layer="metal1",
+ pitch=self.m1_pitch,
+ offset=offset,
+ names=bus_names,
+ length=self.col_addr_dff_insts[port].width)
+
+ dff_names = ["dout_{}".format(x) for x in range(self.col_addr_size)]
+ data_dff_map = zip(dff_names, bus_names)
+ self.connect_horizontal_bus(data_dff_map, self.col_addr_dff_insts[port], col_addr_bus_offsets)
+
+ bank_names = ["addr{0}_{1}".format(port,x) for x in range(self.col_addr_size)]
+ data_bank_map = zip(bank_names, bus_names)
+ self.connect_horizontal_bus(data_bank_map, self.bank_inst, col_addr_bus_offsets)
+
+
+ def route_data_dff(self):
+ """ Connect the output of the data flops to the write driver """
+ # This is where the channel will start (y-dimension at least)
+ for port in self.write_ports:
+ if self.write_size:
+ if port % 2:
+ offset = self.data_dff_insts[port].ll() - vector(0, (self.word_size + 2)*self.m3_pitch)
+ else:
+ offset = self.data_dff_insts[port].ul() + vector(0, 2 * self.m3_pitch)
+ else:
+ if port%2:
+ offset = self.data_dff_insts[port].ll() - vector(0, (self.word_size+2)*self.m1_pitch)
+ else:
+ offset = self.data_dff_insts[port].ul() + vector(0, 2*self.m1_pitch)
+
+ dff_names = ["dout_{}".format(x) for x in range(self.word_size)]
+ dff_pins = [self.data_dff_insts[port].get_pin(x) for x in dff_names]
+ if self.write_size:
+ for x in dff_names:
+ pin_offset = self.data_dff_insts[port].get_pin(x).center()
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=pin_offset,
+ directions = ("V", "V"))
+ self.add_via_center(layers=("metal2", "via2", "metal3"),
+ offset=pin_offset)
+ self.add_via_center(layers=("metal3", "via3", "metal4"),
+ offset=pin_offset)
+
+ bank_names = ["din{0}_{1}".format(port,x) for x in range(self.word_size)]
+ bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
+ if self.write_size:
+ for x in bank_names:
+ if port % 2:
+ pin_offset = self.bank_inst.get_pin(x).uc()
+ else:
+ pin_offset = self.bank_inst.get_pin(x).bc()
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=pin_offset)
+ self.add_via_center(layers=("metal2", "via2", "metal3"),
+ offset=pin_offset)
+ self.add_via_center(layers=("metal3", "via3", "metal4"),
+ offset=pin_offset)
+
+ route_map = list(zip(bank_pins, dff_pins))
+ if self.write_size:
+ self.create_horizontal_channel_route(netlist=route_map,
+ offset=offset,
+ layer_stack=("metal3", "via3", "metal4"))
+ else:
+ self.create_horizontal_channel_route(route_map, offset)
+
+ def route_wmask_dff(self):
+ """ Connect the output of the wmask flops to the write mask AND array """
+ # This is where the channel will start (y-dimension at least)
+ for port in self.write_ports:
+ if port % 2:
+ offset = self.wmask_dff_insts[port].ll() - vector(0, (self.num_wmasks+2) * self.m1_pitch)
+ else:
+ offset = self.wmask_dff_insts[port].ul() + vector(0, 2 * self.m1_pitch)
+
+ dff_names = ["dout_{}".format(x) for x in range(self.num_wmasks)]
+ dff_pins = [self.wmask_dff_insts[port].get_pin(x) for x in dff_names]
+ for x in dff_names:
+ offset_pin = self.wmask_dff_insts[port].get_pin(x).center()
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=offset_pin,
+ directions=("V", "V"))
+
+ bank_names = ["bank_wmask{0}_{1}".format(port, x) for x in range(self.num_wmasks)]
+ bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
+ for x in bank_names:
+ offset_pin = self.bank_inst.get_pin(x).center()
+ self.add_via_center(layers=("metal1", "via1", "metal2"),
+ offset=offset_pin)
+
+
+ route_map = list(zip(bank_pins, dff_pins))
+ self.create_horizontal_channel_route(route_map,offset)
+
+
+ def add_lvs_correspondence_points(self):
+ """
+ This adds some points for easier debugging if LVS goes wrong.
+ These should probably be turned off by default though, since extraction
+ will show these as ports in the extracted netlist.
+ """
+
+ for n in self.control_logic_outputs[0]:
+ pin = self.control_logic_insts[0].get_pin(n)
+ self.add_label(text=n,
+ layer=pin.layer,
+ offset=pin.center())
+
+ def graph_exclude_data_dff(self):
+ """Removes data dff and wmask dff (if applicable) from search graph. """
+ #Data dffs and wmask dffs are only for writing so are not useful for evaluating read delay.
+ for inst in self.data_dff_insts:
+ self.graph_inst_exclude.add(inst)
+ if self.write_size:
+ for inst in self.wmask_dff_insts:
+ self.graph_inst_exclude.add(inst)
+
+ def graph_exclude_addr_dff(self):
+ """Removes data dff from search graph. """
+ #Address is considered not part of the critical path, subjectively removed
+ for inst in self.row_addr_dff_insts:
+ self.graph_inst_exclude.add(inst)
+
+ if self.col_addr_dff:
+ for inst in self.col_addr_dff_insts:
+ self.graph_inst_exclude.add(inst)
+
+ def graph_exclude_ctrl_dffs(self):
+ """Exclude dffs for CSB, WEB, etc from graph"""
+ #Insts located in control logic, exclusion function called here
+ for inst in self.control_logic_insts:
+ inst.mod.graph_exclude_dffs()
+
+ def get_sen_name(self, sram_name, port=0):
+ """Returns the s_en spice name."""
+ #Naming scheme is hardcoded using this function, should be built into the
+ #graph in someway.
+ sen_name = "s_en{}".format(port)
+ control_conns = self.get_conns(self.control_logic_insts[port])
+ #Sanity checks
+ if sen_name not in control_conns:
+ debug.error("Signal={} not contained in control logic connections={}"\
+ .format(sen_name, control_conns))
+ if sen_name in self.pins:
+ debug.error("Internal signal={} contained in port list. Name defined by the parent.")
+ return "X{}.{}".format(sram_name, sen_name)
+
+ def get_cell_name(self, inst_name, row, col):
+ """Gets the spice name of the target bitcell."""
+ #Sanity check in case it was forgotten
+ if inst_name.find('x') != 0:
+ inst_name = 'x'+inst_name
+ return self.bank_inst.mod.get_cell_name(inst_name+'.x'+self.bank_inst.name, row, col)
diff --git a/compiler/sram_2bank.py b/compiler/sram/sram_2bank.py
similarity index 96%
rename from compiler/sram_2bank.py
rename to compiler/sram/sram_2bank.py
index daf02563..e1224795 100644
--- a/compiler/sram_2bank.py
+++ b/compiler/sram/sram_2bank.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import sys
from tech import drc, spice
import debug
@@ -81,7 +88,7 @@ class sram_2bank(sram_base):
mod=self.msb_address,
offset=self.msb_address_position,
rotate=270)
- self.msb_bank_sel_addr = "ADDR[{}]".format(self.addr_size-1)
+ self.msb_bank_sel_addr = "addr[{}]".format(self.addr_size-1)
self.connect_inst([self.msb_bank_sel_addr,"bank_sel[1]","bank_sel[0]","clk_buf", "vdd", "gnd"])
diff --git a/compiler/sram_base.py b/compiler/sram/sram_base.py
similarity index 81%
rename from compiler/sram_base.py
rename to compiler/sram/sram_base.py
index 611900e4..853772e8 100644
--- a/compiler/sram_base.py
+++ b/compiler/sram/sram_base.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import sys
import datetime
import getpass
@@ -11,6 +18,7 @@ from design import design
from verilog import verilog
from lef import lef
from sram_factory import factory
+import logical_effort
class sram_base(design, verilog, lef):
"""
@@ -26,19 +34,25 @@ class sram_base(design, verilog, lef):
sram_config.set_local_config(self)
self.bank_insts = []
-
+
+ if self.write_size:
+ self.num_wmasks = int(self.word_size/self.write_size)
+ else:
+ self.num_wmasks = 0
+
#For logical effort delay calculations.
self.all_mods_except_control_done = False
def add_pins(self):
""" Add pins for entire SRAM. """
+
for port in self.write_ports:
for bit in range(self.word_size):
- self.add_pin("DIN{0}[{1}]".format(port,bit),"INPUT")
+ self.add_pin("din{0}[{1}]".format(port,bit),"INPUT")
for port in self.all_ports:
for bit in range(self.addr_size):
- self.add_pin("ADDR{0}[{1}]".format(port,bit),"INPUT")
+ self.add_pin("addr{0}[{1}]".format(port,bit),"INPUT")
# These are used to create the physical pins
self.control_logic_inputs = []
@@ -60,10 +74,13 @@ class sram_base(design, verilog, lef):
self.add_pin("web{}".format(port),"INPUT")
for port in self.all_ports:
self.add_pin("clk{}".format(port),"INPUT")
-
+ # add the optional write mask pins
+ for port in self.write_ports:
+ for bit in range(self.num_wmasks):
+ self.add_pin("wmask{0}[{1}]".format(port,bit),"INPUT")
for port in self.read_ports:
for bit in range(self.word_size):
- self.add_pin("DOUT{0}[{1}]".format(port,bit),"OUTPUT")
+ self.add_pin("dout{0}[{1}]".format(port,bit),"OUTPUT")
self.add_pin("vdd","POWER")
self.add_pin("gnd","GROUND")
@@ -103,14 +120,15 @@ class sram_base(design, verilog, lef):
self.add_lvs_correspondence_points()
- self.offset_all_coordinates()
+ #self.offset_all_coordinates()
highest_coord = self.find_highest_coords()
self.width = highest_coord[0]
self.height = highest_coord[1]
start_time = datetime.now()
- self.DRC_LVS(final_verification=True)
+ # We only enable final verification if we have routed the design
+ self.DRC_LVS(final_verification=OPTS.route_supplies, top_level=True)
if not OPTS.is_unit_test:
print_time("Verification",datetime.now(), start_time)
@@ -120,18 +138,27 @@ class sram_base(design, verilog, lef):
def route_supplies(self):
""" Route the supply grid and connect the pins to them. """
+ # Copy the pins to the top level
+ # This will either be used to route or left unconnected.
for inst in self.insts:
self.copy_power_pins(inst,"vdd")
self.copy_power_pins(inst,"gnd")
+
+ import tech
+ if not OPTS.route_supplies:
+ # Do not route the power supply (leave as must-connect pins)
+ return
+ elif "metal4" in tech.layer:
+ # Route a M3/M4 grid
+ from supply_grid_router import supply_grid_router as router
+ rtr=router(("metal3","via3","metal4"), self)
+ elif "metal3" in tech.layer:
+ from supply_tree_router import supply_tree_router as router
+ rtr=router(("metal3",), self)
- from supply_router import supply_router as router
- layer_stack =("metal3","via3","metal4")
- rtr=router(layer_stack, self)
rtr.route()
-
-
def compute_bus_sizes(self):
""" Compute the independent bus widths shared between two and four bank SRAMs """
@@ -170,7 +197,7 @@ class sram_base(design, verilog, lef):
if self.port_id[port] == "r":
self.control_bus_names[port].extend([sen, pen])
elif self.port_id[port] == "w":
- self.control_bus_names[port].extend([wen])
+ self.control_bus_names[port].extend([wen, pen])
else:
self.control_bus_names[port].extend([sen, wen, pen])
self.vert_control_bus_positions = self.create_vertical_bus(layer="metal2",
@@ -241,6 +268,7 @@ class sram_base(design, verilog, lef):
def add_modules(self):
self.bitcell = factory.create(module_type=OPTS.bitcell)
+ self.dff = factory.create(module_type="dff")
# Create the address and control flops (but not the clk)
from dff_array import dff_array
@@ -255,6 +283,11 @@ class sram_base(design, verilog, lef):
self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size)
self.add_mod(self.data_dff)
+
+ if self.write_size:
+ self.wmask_dff = dff_array(name="wmask_dff", rows=1, columns=self.num_wmasks)
+ self.add_mod(self.wmask_dff)
+
# Create the bank module (up to four are instantiated)
from bank import bank
@@ -268,9 +301,6 @@ class sram_base(design, verilog, lef):
self.bank_count = 0
- self.supply_rail_width = self.bank.supply_rail_width
- self.supply_rail_pitch = self.bank.supply_rail_pitch
-
#The control logic can resize itself based on the other modules. Requires all other modules added before control logic.
self.all_mods_except_control_done = True
@@ -282,21 +312,21 @@ class sram_base(design, verilog, lef):
self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row,
word_size=self.word_size,
- sram=self,
+ sram=self,
port_type="rw")
self.add_mod(self.control_logic_rw)
if len(self.writeonly_ports)>0:
self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row,
word_size=self.word_size,
- sram=self,
+ sram=self,
port_type="w")
self.add_mod(self.control_logic_w)
if len(self.readonly_ports)>0:
self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row,
word_size=self.word_size,
- sram=self,
+ sram=self,
port_type="r")
self.add_mod(self.control_logic_r)
@@ -308,22 +338,26 @@ class sram_base(design, verilog, lef):
temp = []
for port in self.read_ports:
for bit in range(self.word_size):
- temp.append("DOUT{0}[{1}]".format(port,bit))
+ temp.append("dout{0}[{1}]".format(port,bit))
+ for port in self.all_ports:
+ temp.append("rbl_bl{0}".format(port))
for port in self.write_ports:
for bit in range(self.word_size):
- temp.append("BANK_DIN{0}[{1}]".format(port,bit))
+ temp.append("bank_din{0}[{1}]".format(port,bit))
for port in self.all_ports:
for bit in range(self.bank_addr_size):
- temp.append("A{0}[{1}]".format(port,bit))
+ temp.append("a{0}[{1}]".format(port,bit))
if(self.num_banks > 1):
for port in self.all_ports:
temp.append("bank_sel{0}[{1}]".format(port,bank_num))
for port in self.read_ports:
temp.append("s_en{0}".format(port))
- for port in self.read_ports:
+ for port in self.all_ports:
temp.append("p_en_bar{0}".format(port))
for port in self.write_ports:
temp.append("w_en{0}".format(port))
+ for bit in range(self.num_wmasks):
+ temp.append("bank_wmask{}[{}]".format(port, bit))
for port in self.all_ports:
temp.append("wl_en{0}".format(port))
temp.extend(["vdd", "gnd"])
@@ -374,8 +408,8 @@ class sram_base(design, verilog, lef):
inputs = []
outputs = []
for bit in range(self.row_addr_size):
- inputs.append("ADDR{}[{}]".format(port,bit+self.col_addr_size))
- outputs.append("A{}[{}]".format(port,bit+self.col_addr_size))
+ inputs.append("addr{}[{}]".format(port,bit+self.col_addr_size))
+ outputs.append("a{}[{}]".format(port,bit+self.col_addr_size))
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
@@ -393,8 +427,8 @@ class sram_base(design, verilog, lef):
inputs = []
outputs = []
for bit in range(self.col_addr_size):
- inputs.append("ADDR{}[{}]".format(port,bit))
- outputs.append("A{}[{}]".format(port,bit))
+ inputs.append("addr{}[{}]".format(port,bit))
+ outputs.append("a{}[{}]".format(port,bit))
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
@@ -416,13 +450,35 @@ class sram_base(design, verilog, lef):
inputs = []
outputs = []
for bit in range(self.word_size):
- inputs.append("DIN{}[{}]".format(port,bit))
- outputs.append("BANK_DIN{}[{}]".format(port,bit))
+ inputs.append("din{}[{}]".format(port,bit))
+ outputs.append("bank_din{}[{}]".format(port,bit))
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
return insts
+ def create_wmask_dff(self):
+ """ Add and place all wmask flops """
+ insts = []
+ for port in self.all_ports:
+ if port in self.write_ports:
+ insts.append(self.add_inst(name="wmask_dff{}".format(port),
+ mod=self.wmask_dff))
+ else:
+ insts.append(None)
+ continue
+
+ # inputs, outputs/output/bar
+ inputs = []
+ outputs = []
+ for bit in range(self.num_wmasks):
+ inputs.append("wmask{}[{}]".format(port, bit))
+ outputs.append("bank_wmask{}[{}]".format(port, bit))
+
+ self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
+
+ return insts
+
def create_control_logic(self):
""" Add control logic instances """
@@ -443,36 +499,45 @@ class sram_base(design, verilog, lef):
if port in self.readwrite_ports:
temp.append("web{}".format(port))
temp.append("clk{}".format(port))
+ temp.append("rbl_bl{}".format(port))
- # Ouputs
+ # Outputs
if port in self.read_ports:
temp.append("s_en{}".format(port))
if port in self.write_ports:
temp.append("w_en{}".format(port))
- if port in self.read_ports:
- temp.append("p_en_bar{}".format(port))
+ temp.append("p_en_bar{}".format(port))
temp.extend(["wl_en{}".format(port), "clk_buf{}".format(port), "vdd", "gnd"])
self.connect_inst(temp)
return insts
- def connect_rail_from_left_m2m3(self, src_pin, dest_pin):
- """ Helper routine to connect an unrotated/mirrored oriented instance to the rails """
- in_pos = src_pin.rc()
- out_pos = dest_pin.center()
+ def connect_vbus_m2m3(self, src_pin, dest_pin):
+ """ Helper routine to connect an instance to a vertical bus.
+ Routes horizontal then vertical L shape.
+ Dest pin is assumed to be on M2.
+ Src pin can be on M1/M2/M3."""
+
+ if src_pin.cx() 0:
+ total_cin += self.col_addr_dff.get_clk_cin()
+ return total_cin
diff --git a/compiler/sram_config.py b/compiler/sram/sram_config.py
similarity index 82%
rename from compiler/sram_config.py
rename to compiler/sram/sram_config.py
index 5edf9282..376bf42b 100644
--- a/compiler/sram_config.py
+++ b/compiler/sram/sram_config.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
from math import log,sqrt,ceil
from importlib import reload
@@ -7,16 +14,18 @@ from sram_factory import factory
class sram_config:
""" This is a structure that is used to hold the SRAM configuration options. """
- def __init__(self, word_size, num_words, num_banks=1, words_per_row=None):
+ def __init__(self, word_size, num_words, write_size = None, num_banks=1, words_per_row=None):
self.word_size = word_size
self.num_words = num_words
+ self.write_size = write_size
self.num_banks = num_banks
# This will get over-written when we determine the organization
self.words_per_row = words_per_row
+
self.compute_sizes()
-
+
def set_local_config(self, module):
""" Copy all of the member variables to the given module for convenience """
@@ -30,7 +39,7 @@ class sram_config:
def compute_sizes(self):
""" Computes the organization of the memory using bitcell size by trying to make it square."""
- self.bitcell = factory.create(module_type="bitcell")
+ bitcell = factory.create(module_type="bitcell")
debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.")
@@ -41,18 +50,17 @@ class sram_config:
# If this was hard coded, don't dynamically compute it!
if not self.words_per_row:
# Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry)
- self.bank_area = self.bitcell.width*self.bitcell.height*self.num_bits_per_bank
+ self.bank_area = bitcell.width*bitcell.height*self.num_bits_per_bank
self.bank_side_length = sqrt(self.bank_area)
# Estimate the words per row given the height of the bitcell and the square side length
- self.tentative_num_cols = int(self.bank_side_length/self.bitcell.width)
+ self.tentative_num_cols = int(self.bank_side_length/bitcell.width)
self.words_per_row = self.estimate_words_per_row(self.tentative_num_cols, self.word_size)
# Estimate the number of rows given the tentative words per row
self.tentative_num_rows = self.num_bits_per_bank / (self.words_per_row*self.word_size)
self.words_per_row = self.amend_words_per_row(self.tentative_num_rows, self.words_per_row)
- debug.info(1,"Words per row: {}".format(self.words_per_row))
self.recompute_sizes()
def recompute_sizes(self):
@@ -62,6 +70,8 @@ class sram_config:
SRAM for testing.
"""
+ debug.info(1,"Recomputing with words per row: {}".format(self.words_per_row))
+
# If the banks changed
self.num_words_per_bank = self.num_words/self.num_banks
self.num_bits_per_bank = self.word_size*self.num_words_per_bank
@@ -69,12 +79,16 @@ class sram_config:
# Fix the number of columns and rows
self.num_cols = int(self.words_per_row*self.word_size)
self.num_rows = int(self.num_words_per_bank/self.words_per_row)
+ debug.info(1,"Rows: {} Cols: {}".format(self.num_rows,self.num_cols))
# Compute the address and bank sizes
self.row_addr_size = int(log(self.num_rows, 2))
self.col_addr_size = int(log(self.words_per_row, 2))
self.bank_addr_size = self.col_addr_size + self.row_addr_size
self.addr_size = self.bank_addr_size + int(log(self.num_banks, 2))
+ debug.info(1,"Row addr size: {}".format(self.row_addr_size)
+ + " Col addr size: {}".format(self.col_addr_size)
+ + " Bank addr size: {}".format(self.bank_addr_size))
def estimate_words_per_row(self,tentative_num_cols, word_size):
diff --git a/compiler/sram_1bank.py b/compiler/sram_1bank.py
deleted file mode 100644
index cbfec653..00000000
--- a/compiler/sram_1bank.py
+++ /dev/null
@@ -1,307 +0,0 @@
-import sys
-from tech import drc, spice
-import debug
-from math import log,sqrt,ceil
-import datetime
-import getpass
-import numpy as np
-from vector import vector
-from globals import OPTS, print_time
-
-from sram_base import sram_base
-from bank import bank
-from contact import m2m3
-from dff_buf_array import dff_buf_array
-from dff_array import dff_array
-
-
-class sram_1bank(sram_base):
- """
- Procedures specific to a one bank SRAM.
- """
- def __init__(self, name, sram_config):
- sram_base.__init__(self, name, sram_config)
-
- def create_modules(self):
- """
- This adds the modules for a single bank SRAM with control
- logic.
- """
-
- self.bank_inst=self.create_bank(0)
-
- self.control_logic_insts = self.create_control_logic()
-
- self.row_addr_dff_insts = self.create_row_addr_dff()
-
- if self.col_addr_dff:
- self.col_addr_dff_insts = self.create_col_addr_dff()
-
- self.data_dff_insts = self.create_data_dff()
-
- def place_instances(self):
- """
- This places the instances for a single bank SRAM with control
- logic and up to 2 ports.
- """
-
- # No orientation or offset
- self.place_bank(self.bank_inst, [0, 0], 1, 1)
-
- # The control logic is placed such that the vertical center (between the delay/RBL and
- # the actual control logic is aligned with the vertical center of the bank (between
- # the sense amps/column mux and cell array)
- # The x-coordinate is placed to allow a single clock wire (plus an extra pitch)
- # up to the row address DFFs.
- control_pos = [None]*len(self.all_ports)
- row_addr_pos = [None]*len(self.all_ports)
- col_addr_pos = [None]*len(self.all_ports)
- data_pos = [None]*len(self.all_ports)
-
- # This is M2 pitch even though it is on M1 to help stem via spacings on the trunk
- # The M1 pitch is for supply rail spacings
- max_gap_size = self.m2_pitch*max(self.word_size+1,self.col_addr_size+1) + 2*self.m1_pitch
-
- # Port 0
- port = 0
-
- # This includes 2 M2 pitches for the row addr clock line.
- # It is also placed to align with the column decoder (if it exists hence the bank gap)
- control_pos[port] = vector(-self.control_logic_insts[port].width - 2*self.m2_pitch,
- self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y - self.bank.m2_gap)
- self.control_logic_insts[port].place(control_pos[port])
-
- # The row address bits are placed above the control logic aligned on the right.
- x_offset = self.control_logic_insts[port].rx() - self.row_addr_dff_insts[port].width
- # It is aove the control logic but below the top of the bitcell array
- y_offset = max(self.control_logic_insts[port].uy(), self.bank.bank_array_ur.y - self.row_addr_dff_insts[port].height)
- row_addr_pos[port] = vector(x_offset, y_offset)
- self.row_addr_dff_insts[port].place(row_addr_pos[port])
-
- # Add the col address flops below the bank to the left of the lower-left of bank array
- if self.col_addr_dff:
- col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.m2_gap,
- -max_gap_size - self.col_addr_dff_insts[port].height)
- self.col_addr_dff_insts[port].place(col_addr_pos[port])
-
- # Add the data flops below the bank to the right of the lower-left of bank array
- # This relies on the lower-left of the array of the bank
- # decoder in upper left, bank in upper right, sensing in lower right.
- # These flops go below the sensing and leave a gap to channel route to the
- # sense amps.
- if port in self.write_ports:
- data_pos[port] = vector(self.bank.bank_array_ll.x,
- -max_gap_size - self.data_dff_insts[port].height)
- self.data_dff_insts[port].place(data_pos[port])
-
-
- if len(self.all_ports)>1:
- # Port 1
- port = 1
-
- # This includes 2 M2 pitches for the row addr clock line
- # It is also placed to align with the column decoder (if it exists hence the bank gap)
- control_pos[port] = vector(self.bank_inst.rx() + self.control_logic_insts[port].width + 2*self.m2_pitch,
- self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y + self.bank.m2_gap)
- self.control_logic_insts[port].place(control_pos[port], mirror="MY")
-
- # The row address bits are placed above the control logic aligned on the left.
- x_offset = control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width
- # It is above the control logic but below the top of the bitcell array
- y_offset = max(self.control_logic_insts[port].uy(), self.bank.bank_array_ur.y - self.row_addr_dff_insts[port].height)
- row_addr_pos[port] = vector(x_offset, y_offset)
- self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="MY")
-
- # Add the col address flops above the bank to the right of the upper-right of bank array
- if self.col_addr_dff:
- col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap,
- self.bank.height + max_gap_size + self.col_addr_dff_insts[port].height)
- self.col_addr_dff_insts[port].place(col_addr_pos[port], mirror="MX")
-
- # Add the data flops above the bank to the left of the upper-right of bank array
- # This relies on the upper-right of the array of the bank
- # decoder in upper left, bank in upper right, sensing in lower right.
- # These flops go below the sensing and leave a gap to channel route to the
- # sense amps.
- if port in self.write_ports:
- data_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width,
- self.bank.height + max_gap_size + self.data_dff_insts[port].height)
- self.data_dff_insts[port].place(data_pos[port], mirror="MX")
-
-
- def add_layout_pins(self):
- """
- Add the top-level pins for a single bank SRAM with control.
- """
- for port in self.all_ports:
- # Connect the control pins as inputs
- for signal in self.control_logic_inputs[port] + ["clk"]:
- self.copy_layout_pin(self.control_logic_insts[port], signal, signal+"{}".format(port))
-
- if port in self.read_ports:
- for bit in range(self.word_size):
- self.copy_layout_pin(self.bank_inst, "dout{0}_{1}".format(port,bit), "DOUT{0}[{1}]".format(port,bit))
-
- # Lower address bits
- for bit in range(self.col_addr_size):
- self.copy_layout_pin(self.col_addr_dff_insts[port], "din_{}".format(bit),"ADDR{0}[{1}]".format(port,bit))
- # Upper address bits
- for bit in range(self.row_addr_size):
- self.copy_layout_pin(self.row_addr_dff_insts[port], "din_{}".format(bit),"ADDR{0}[{1}]".format(port,bit+self.col_addr_size))
-
- if port in self.write_ports:
- for bit in range(self.word_size):
- self.copy_layout_pin(self.data_dff_insts[port], "din_{}".format(bit), "DIN{0}[{1}]".format(port,bit))
-
- def route_layout(self):
- """ Route a single bank SRAM """
-
- self.add_layout_pins()
-
- self.route_clk()
-
- self.route_control_logic()
-
- self.route_row_addr_dff()
-
- if self.col_addr_dff:
- self.route_col_addr_dff()
-
- self.route_data_dff()
-
- def route_clk(self):
- """ Route the clock network """
-
- # This is the actual input to the SRAM
- for port in self.all_ports:
- self.copy_layout_pin(self.control_logic_insts[port], "clk", "clk{}".format(port))
-
- # Connect all of these clock pins to the clock in the central bus
- # This is something like a "spine" clock distribution. The two spines
- # are clk_buf and clk_buf_bar
- control_clk_buf_pin = self.control_logic_insts[port].get_pin("clk_buf")
- control_clk_buf_pos = control_clk_buf_pin.center()
-
- # This uses a metal2 track to the right (for port0) of the control/row addr DFF
- # to route vertically. For port1, it is to the left.
- row_addr_clk_pin = self.row_addr_dff_insts[port].get_pin("clk")
- if port%2:
- control_clk_buf_pos = control_clk_buf_pin.lc()
- row_addr_clk_pos = row_addr_clk_pin.lc()
- mid1_pos = vector(self.row_addr_dff_insts[port].lx() - self.m2_pitch,
- row_addr_clk_pos.y)
- else:
- control_clk_buf_pos = control_clk_buf_pin.rc()
- row_addr_clk_pos = row_addr_clk_pin.rc()
- mid1_pos = vector(self.row_addr_dff_insts[port].rx() + self.m2_pitch,
- row_addr_clk_pos.y)
-
- # This is the steiner point where the net branches out
- clk_steiner_pos = vector(mid1_pos.x, control_clk_buf_pos.y)
- self.add_path("metal1", [control_clk_buf_pos, clk_steiner_pos])
- self.add_via_center(layers=("metal1","via1","metal2"),
- offset=clk_steiner_pos,
- rotate=90)
-
- # Note, the via to the control logic is taken care of above
- self.add_wire(("metal3","via2","metal2"),[row_addr_clk_pos, mid1_pos, clk_steiner_pos])
-
- if self.col_addr_dff:
- dff_clk_pin = self.col_addr_dff_insts[port].get_pin("clk")
- dff_clk_pos = dff_clk_pin.center()
- mid_pos = vector(clk_steiner_pos.x, dff_clk_pos.y)
- self.add_wire(("metal3","via2","metal2"),[dff_clk_pos, mid_pos, clk_steiner_pos])
-
- if port in self.write_ports:
- data_dff_clk_pin = self.data_dff_insts[port].get_pin("clk")
- data_dff_clk_pos = data_dff_clk_pin.center()
- mid_pos = vector(clk_steiner_pos.x, data_dff_clk_pos.y)
- # In some designs, the steiner via will be too close to the mid_pos via
- # so make the wire as wide as the contacts
- self.add_path("metal2",[mid_pos, clk_steiner_pos], width=max(m2m3.width,m2m3.height))
- self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, clk_steiner_pos])
-
-
- def route_control_logic(self):
- """ Route the outputs from the control logic module """
- for port in self.all_ports:
- for signal in self.control_logic_outputs[port]:
- # The clock gets routed separately and is not a part of the bank
- if "clk" in signal:
- continue
- src_pin = self.control_logic_insts[port].get_pin(signal)
- dest_pin = self.bank_inst.get_pin(signal+"{}".format(port))
- self.connect_rail_from_left_m2m3(src_pin, dest_pin)
- self.add_via_center(layers=("metal1","via1","metal2"),
- offset=src_pin.rc(),
- rotate=90)
-
-
- def route_row_addr_dff(self):
- """ Connect the output of the row flops to the bank pins """
- for port in self.all_ports:
- for bit in range(self.row_addr_size):
- flop_name = "dout_{}".format(bit)
- bank_name = "addr{0}_{1}".format(port,bit+self.col_addr_size)
- flop_pin = self.row_addr_dff_insts[port].get_pin(flop_name)
- bank_pin = self.bank_inst.get_pin(bank_name)
- flop_pos = flop_pin.center()
- bank_pos = bank_pin.center()
- mid_pos = vector(bank_pos.x,flop_pos.y)
- self.add_wire(("metal3","via2","metal2"),[flop_pos, mid_pos,bank_pos])
- self.add_via_center(layers=("metal2","via2","metal3"),
- offset=flop_pos,
- rotate=90)
-
- def route_col_addr_dff(self):
- """ Connect the output of the row flops to the bank pins """
- for port in self.all_ports:
- bus_names = ["addr_{}".format(x) for x in range(self.col_addr_size)]
- col_addr_bus_offsets = self.create_horizontal_bus(layer="metal1",
- pitch=self.m1_pitch,
- offset=self.col_addr_dff_insts[port].ul() + vector(0, self.m1_pitch),
- names=bus_names,
- length=self.col_addr_dff_insts[port].width)
-
- dff_names = ["dout_{}".format(x) for x in range(self.col_addr_size)]
- data_dff_map = zip(dff_names, bus_names)
- self.connect_horizontal_bus(data_dff_map, self.col_addr_dff_insts[port], col_addr_bus_offsets)
-
- bank_names = ["addr{0}_{1}".format(port,x) for x in range(self.col_addr_size)]
- data_bank_map = zip(bank_names, bus_names)
- self.connect_horizontal_bus(data_bank_map, self.bank_inst, col_addr_bus_offsets)
-
-
- def route_data_dff(self):
- """ Connect the output of the data flops to the write driver """
- # This is where the channel will start (y-dimension at least)
- for port in self.write_ports:
- if port%2:
- offset = self.data_dff_insts[port].ll() - vector(0, (self.word_size+2)*self.m1_pitch)
- else:
- offset = self.data_dff_insts[port].ul() + vector(0, 2*self.m1_pitch)
-
-
- dff_names = ["dout_{}".format(x) for x in range(self.word_size)]
- dff_pins = [self.data_dff_insts[port].get_pin(x) for x in dff_names]
-
- bank_names = ["din{0}_{1}".format(port,x) for x in range(self.word_size)]
- bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
-
- route_map = list(zip(bank_pins, dff_pins))
- self.create_horizontal_channel_route(route_map, offset)
-
-
-
- def add_lvs_correspondence_points(self):
- """
- This adds some points for easier debugging if LVS goes wrong.
- These should probably be turned off by default though, since extraction
- will show these as ports in the extracted netlist.
- """
-
- for n in self.control_logic_outputs[0]:
- pin = self.control_logic_insts[0].get_pin(n)
- self.add_label(text=n,
- layer=pin.layer,
- offset=pin.center())
diff --git a/compiler/sram_factory.py b/compiler/sram_factory.py
index 7b420a6b..0083841d 100644
--- a/compiler/sram_factory.py
+++ b/compiler/sram_factory.py
@@ -1,7 +1,12 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import debug
from globals import OPTS
-from importlib import reload
-
class sram_factory:
"""
@@ -39,40 +44,57 @@ class sram_factory:
if hasattr(OPTS, module_type):
# Retrieve the name from OPTS if it exists,
# otherwise just use the name
- module_name = getattr(OPTS, module_type)
- else:
- module_name = module_type
-
+ module_type = getattr(OPTS, module_type)
+
# Either retrieve the already loaded module or load it
try:
mod = self.modules[module_type]
except KeyError:
- c = reload(__import__(module_name))
- mod = getattr(c, module_name)
+ import importlib
+ c = importlib.reload(__import__(module_type))
+ mod = getattr(c, module_type)
self.modules[module_type] = mod
self.module_indices[module_type] = 0
self.objects[module_type] = []
# Either retreive a previous object or create a new one
+ #print("new",kwargs)
for obj in self.objects[module_type]:
(obj_kwargs, obj_item) = obj
# Must have the same dictionary exactly (conservative)
if obj_kwargs == kwargs:
- #debug.info(1, "Existing module: type={0} name={1} kwargs={2}".format(module_type, obj_item.name, str(kwargs)))
+ #debug.info(0, "Existing module: type={0} name={1} kwargs={2}".format(module_type, obj_item.name, str(kwargs)))
return obj_item
+ #else:
+ # print("obj",obj_kwargs)
# Use the default name if there are default arguments
# This is especially for library cells so that the spice and gds files can be found.
if len(kwargs)>0:
# Create a unique name and increment the index
- module_name = "{0}_{1}".format(module_name, self.module_indices[module_type])
+ module_name = "{0}_{1}".format(module_type, self.module_indices[module_type])
self.module_indices[module_type] += 1
- #debug.info(1, "New module: type={0} name={1} kwargs={2}".format(module_type,module_name,str(kwargs)))
+ else:
+ module_name = module_type
+
+ #debug.info(0, "New module: type={0} name={1} kwargs={2}".format(module_type,module_name,str(kwargs)))
obj = mod(name=module_name,**kwargs)
self.objects[module_type].append((kwargs,obj))
return obj
-
+ def get_mods(self, module_type):
+ """Returns list of all objects of module name's type."""
+ if hasattr(OPTS, module_type):
+ # Retrieve the name from OPTS if it exists,
+ # otherwise just use the input
+ module_type = getattr(OPTS, module_type)
+ try:
+ mod_tuples = self.objects[module_type]
+ mods = [mod for kwargs,mod in mod_tuples]
+ except KeyError:
+ mods = []
+ return mods
+
# Make a factory
factory = sram_factory()
diff --git a/compiler/tests/00_code_format_check_test.py b/compiler/tests/00_code_format_check_test.py
index 98799ee8..571f4be7 100755
--- a/compiler/tests/00_code_format_check_test.py
+++ b/compiler/tests/00_code_format_check_test.py
@@ -1,9 +1,16 @@
#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os,re
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
import debug
@@ -44,7 +51,7 @@ def setup_files(path):
files = []
for (dir, _, current_files) in os.walk(path):
for f in current_files:
- files.append(os.path.join(dir, f))
+ files.append(os.getenv("OPENRAM_HOME"))
nametest = re.compile("\.py$", re.IGNORECASE)
select_files = list(filter(nametest.search, files))
return select_files
@@ -115,4 +122,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/01_library_drc_test.py b/compiler/tests/01_library_drc_test.py
index 046e6378..f8da685b 100755
--- a/compiler/tests/01_library_drc_test.py
+++ b/compiler/tests/01_library_drc_test.py
@@ -1,10 +1,15 @@
#!/usr/bin/env python3
-"Run a regression test the library cells for DRC"
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os,re
-#sys.path.append(os.path.join(sys.path[0],".."))
+#sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
import debug
@@ -12,7 +17,7 @@ import debug
class library_drc_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
import verify
(gds_dir, gds_files) = setup_files()
@@ -44,5 +49,5 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/02_library_lvs_test.py b/compiler/tests/02_library_lvs_test.py
index 4ec40dc7..ad150a2b 100755
--- a/compiler/tests/02_library_lvs_test.py
+++ b/compiler/tests/02_library_lvs_test.py
@@ -1,10 +1,15 @@
#!/usr/bin/env python3
-"Run a regression test the library cells for LVS"
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os,re
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
import debug
@@ -12,7 +17,7 @@ import debug
class library_lvs_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
import verify
(gds_dir, sp_dir, allnames) = setup_files()
@@ -67,4 +72,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/03_contact_test.py b/compiler/tests/03_contact_test.py
index 33aa45ae..3d7254c3 100755
--- a/compiler/tests/03_contact_test.py
+++ b/compiler/tests/03_contact_test.py
@@ -1,42 +1,61 @@
#!/usr/bin/env python3
-"Run a regression test for DRC on basic contacts of different array sizes"
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class contact_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import contact
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
-
- for layer_stack in [("poly", "contact", "metal1"), ("metal1", "via1", "metal2")]:
+ for layer_stack in [("metal1", "via1", "metal2"), ("poly", "contact", "metal1")]:
stack_name = ":".join(map(str, layer_stack))
# Check single 1 x 1 contact"
debug.info(2, "1 x 1 {} test".format(stack_name))
- c = contact.contact(layer_stack, (1, 1))
+ c = factory.create(module_type="contact", layer_stack=layer_stack, dimensions=(1, 1))
+ self.local_drc_check(c)
+
+ # Check single 1 x 1 contact"
+ debug.info(2, "1 x 1 {} test".format(stack_name))
+ c = factory.create(module_type="contact", layer_stack=layer_stack, dimensions=(1, 1), directions=("H","V"))
self.local_drc_check(c)
+ # Check single x 1 contact"
+ debug.info(2, "1 x 1 {} test".format(stack_name))
+ c = factory.create(module_type="contact", layer_stack=layer_stack, dimensions=(1, 1), directions=("H","H"))
+ self.local_drc_check(c)
+
+ # Check single 1 x 1 contact"
+ debug.info(2, "1 x 1 {} test".format(stack_name))
+ c = factory.create(module_type="contact", layer_stack=layer_stack, dimensions=(1, 1), directions=("V","V"))
+ self.local_drc_check(c)
+
# check vertical array with one in the middle and two ends
debug.info(2, "1 x 3 {} test".format(stack_name))
- c = contact.contact(layer_stack, (1, 3))
+ c = factory.create(module_type="contact", layer_stack=layer_stack, dimensions=(1, 3))
self.local_drc_check(c)
# check horizontal array with one in the middle and two ends
debug.info(2, "3 x 1 {} test".format(stack_name))
- c = contact.contact(layer_stack, (3, 1))
+ c = factory.create(module_type="contact", layer_stack=layer_stack, dimensions=(3, 1))
self.local_drc_check(c)
# check 3x3 array for all possible neighbors
debug.info(2, "3 x 3 {} test".format(stack_name))
- c = contact.contact(layer_stack, (3, 3))
+ c = factory.create(module_type="contact", layer_stack=layer_stack, dimensions=(3, 3))
self.local_drc_check(c)
globals.end_openram()
@@ -48,4 +67,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/03_path_test.py b/compiler/tests/03_path_test.py
index f0fc2299..21001718 100755
--- a/compiler/tests/03_path_test.py
+++ b/compiler/tests/03_path_test.py
@@ -1,10 +1,15 @@
#!/usr/bin/env python3
-"Run a regression test on a basic path"
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
import debug
@@ -12,7 +17,7 @@ import debug
class path_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
import wire_path
import tech
import design
@@ -89,4 +94,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/03_ptx_1finger_nmos_test.py b/compiler/tests/03_ptx_1finger_nmos_test.py
index 9a81810e..f436d7d0 100755
--- a/compiler/tests/03_ptx_1finger_nmos_test.py
+++ b/compiler/tests/03_ptx_1finger_nmos_test.py
@@ -1,25 +1,31 @@
#!/usr/bin/env python3
-"Run a regression test on a basic parameterized transistors"
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
-class ptx_test(openram_test):
+class ptx_1finger_nmos_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import ptx
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
import tech
debug.info(2, "Checking min size NMOS with 1 finger")
- fet = ptx.ptx(width=tech.drc["minwidth_tx"],
- mults=1,
- tx_type="nmos")
+ fet = factory.create(module_type="ptx",
+ width=tech.drc["minwidth_tx"],
+ mults=1,
+ tx_type="nmos")
self.local_drc_check(fet)
globals.end_openram()
@@ -30,4 +36,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/03_ptx_1finger_pmos_test.py b/compiler/tests/03_ptx_1finger_pmos_test.py
index a3ed99ff..ae8078e7 100755
--- a/compiler/tests/03_ptx_1finger_pmos_test.py
+++ b/compiler/tests/03_ptx_1finger_pmos_test.py
@@ -1,25 +1,31 @@
#!/usr/bin/env python3
-"Run a regression test on a basic parameterized transistors"
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
-class ptx_test(openram_test):
+class ptx_1finger_pmos_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import ptx
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
import tech
debug.info(2, "Checking min size PMOS with 1 finger")
- fet = ptx.ptx(width=tech.drc["minwidth_tx"],
- mults=1,
- tx_type="pmos")
+ fet = factory.create(module_type="ptx",
+ width=tech.drc["minwidth_tx"],
+ mults=1,
+ tx_type="pmos")
self.local_drc_check(fet)
globals.end_openram()
@@ -30,4 +36,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/03_ptx_3finger_nmos_test.py b/compiler/tests/03_ptx_3finger_nmos_test.py
index e1febdbc..c010a948 100755
--- a/compiler/tests/03_ptx_3finger_nmos_test.py
+++ b/compiler/tests/03_ptx_3finger_nmos_test.py
@@ -1,27 +1,33 @@
#!/usr/bin/env python3
-"Run a regression test on a basic parameterized transistors"
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
-class ptx_test(openram_test):
+class ptx_3finger_nmos_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import ptx
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
import tech
debug.info(2, "Checking three fingers NMOS")
- fet = ptx.ptx(width=tech.drc["minwidth_tx"],
- mults=3,
- tx_type="nmos",
- connect_active=True,
- connect_poly=True)
+ fet = factory.create(module_type="ptx",
+ width=tech.drc["minwidth_tx"],
+ mults=3,
+ tx_type="nmos",
+ connect_active=True,
+ connect_poly=True)
self.local_drc_check(fet)
globals.end_openram()
@@ -32,4 +38,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/03_ptx_3finger_pmos_test.py b/compiler/tests/03_ptx_3finger_pmos_test.py
index af9a5d42..85cca9e2 100755
--- a/compiler/tests/03_ptx_3finger_pmos_test.py
+++ b/compiler/tests/03_ptx_3finger_pmos_test.py
@@ -1,27 +1,33 @@
#!/usr/bin/env python3
-"Run a regression test on a basic parameterized transistors"
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
-class ptx_test(openram_test):
+class ptx_3finger_pmos_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import ptx
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
import tech
debug.info(2, "Checking three fingers PMOS")
- fet = ptx.ptx(width=tech.drc["minwidth_tx"],
- mults=3,
- tx_type="pmos",
- connect_active=True,
- connect_poly=True)
+ fet = factory.create(module_type="ptx",
+ width=tech.drc["minwidth_tx"],
+ mults=3,
+ tx_type="pmos",
+ connect_active=True,
+ connect_poly=True)
self.local_drc_check(fet)
globals.end_openram()
@@ -32,4 +38,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/03_ptx_4finger_nmos_test.py b/compiler/tests/03_ptx_4finger_nmos_test.py
index 08a20898..4a410d51 100755
--- a/compiler/tests/03_ptx_4finger_nmos_test.py
+++ b/compiler/tests/03_ptx_4finger_nmos_test.py
@@ -1,27 +1,33 @@
#!/usr/bin/env python3
-"Run a regression test on a basic parameterized transistors"
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
-class ptx_test(openram_test):
+class ptx_4finger_nmos_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import ptx
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
import tech
debug.info(2, "Checking three fingers NMOS")
- fet = ptx.ptx(width=tech.drc["minwidth_tx"],
- mults=4,
- tx_type="nmos",
- connect_active=True,
- connect_poly=True)
+ fet = factory.create(module_type="ptx",
+ width= tech.drc["minwidth_tx"],
+ mults=4,
+ tx_type="nmos",
+ connect_active=True,
+ connect_poly=True)
self.local_drc_check(fet)
globals.end_openram()
@@ -32,4 +38,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/03_ptx_4finger_pmos_test.py b/compiler/tests/03_ptx_4finger_pmos_test.py
index 01857eda..34fbaf9f 100755
--- a/compiler/tests/03_ptx_4finger_pmos_test.py
+++ b/compiler/tests/03_ptx_4finger_pmos_test.py
@@ -1,27 +1,33 @@
#!/usr/bin/env python3
-"Run a regression test on a basic parameterized transistors"
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class ptx_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import ptx
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
import tech
debug.info(2, "Checking three fingers PMOS")
- fet = ptx.ptx(width=tech.drc["minwidth_tx"],
- mults=4,
- tx_type="pmos",
- connect_active=True,
- connect_poly=True)
+ fet = factory.create(module_type="ptx",
+ width=tech.drc["minwidth_tx"],
+ mults=4,
+ tx_type="pmos",
+ connect_active=True,
+ connect_poly=True)
self.local_drc_check(fet)
globals.end_openram()
@@ -32,4 +38,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/03_wire_test.py b/compiler/tests/03_wire_test.py
index 1b18e14b..4ee360ce 100755
--- a/compiler/tests/03_wire_test.py
+++ b/compiler/tests/03_wire_test.py
@@ -1,10 +1,15 @@
#!/usr/bin/env python3
-"Run a regression test on a basic wire"
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
import debug
@@ -12,7 +17,7 @@ import debug
class wire_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
import wire
import tech
import design
@@ -126,4 +131,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/04_dummy_pbitcell_test.py b/compiler/tests/04_dummy_pbitcell_test.py
new file mode 100755
index 00000000..e8e3cc1c
--- /dev/null
+++ b/compiler/tests/04_dummy_pbitcell_test.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys,os
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+class replica_pbitcell_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ import dummy_pbitcell
+
+ OPTS.bitcell = "pbitcell"
+ OPTS.num_rw_ports = 1
+ OPTS.num_r_ports = 0
+ OPTS.num_w_ports = 0
+
+ factory.reset()
+ debug.info(2, "Checking dummy bitcell using pbitcell (small cell)")
+ tx = dummy_pbitcell.dummy_pbitcell(name="rpbc")
+ self.local_check(tx)
+
+ OPTS.num_rw_ports = 1
+ OPTS.num_r_ports = 1
+ OPTS.num_w_ports = 1
+
+ factory.reset()
+ debug.info(2, "Checking dummy bitcell using pbitcell (large cell)")
+ tx = dummy_pbitcell.dummy_pbitcell(name="rpbc")
+ self.local_check(tx)
+
+ globals.end_openram()
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/04_pand2_test.py b/compiler/tests/04_pand2_test.py
index 91b3458e..42045b43 100755
--- a/compiler/tests/04_pand2_test.py
+++ b/compiler/tests/04_pand2_test.py
@@ -1,20 +1,24 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a pand2 cell
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class pand2_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
global verify
import verify
@@ -31,4 +35,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/04_pand3_test.py b/compiler/tests/04_pand3_test.py
new file mode 100755
index 00000000..4408f6e8
--- /dev/null
+++ b/compiler/tests/04_pand3_test.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys,os
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+class pand3_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ global verify
+ import verify
+
+ import pand3
+
+ debug.info(2, "Testing pand3 gate 4x")
+ a = pand3.pand3(name="pand3x4", size=4)
+ self.local_check(a)
+
+ globals.end_openram()
+
+# instantiate a copdsay of the class to actually run the test
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/04_pbitcell_test.py b/compiler/tests/04_pbitcell_test.py
index c78b3284..0f14c4c5 100755
--- a/compiler/tests/04_pbitcell_test.py
+++ b/compiler/tests/04_pbitcell_test.py
@@ -1,12 +1,15 @@
#!/usr/bin/env python3
-"""
-Run regresion tests on a parameterized bitcell
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
import debug
@@ -16,15 +19,14 @@ from sram_factory import factory
class pbitcell_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from pbitcell import pbitcell
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.num_rw_ports=1
OPTS.num_w_ports=1
OPTS.num_r_ports=1
factory.reset()
debug.info(2, "Bitcell with 1 of each port: read/write, write, and read")
- tx = pbitcell(name="pbc")
+ tx = factory.create(module_type="pbitcell")
self.local_check(tx)
OPTS.num_rw_ports=0
@@ -32,7 +34,7 @@ class pbitcell_test(openram_test):
OPTS.num_r_ports=1
factory.reset()
debug.info(2, "Bitcell with 0 read/write ports")
- tx = pbitcell(name="pbc")
+ tx = factory.create(module_type="pbitcell")
self.local_check(tx)
OPTS.num_rw_ports=1
@@ -40,7 +42,7 @@ class pbitcell_test(openram_test):
OPTS.num_r_ports=1
factory.reset()
debug.info(2, "Bitcell with 0 write ports")
- tx = pbitcell(name="pbc")
+ tx = factory.create(module_type="pbitcell")
self.local_check(tx)
OPTS.num_rw_ports=1
@@ -48,7 +50,7 @@ class pbitcell_test(openram_test):
OPTS.num_r_ports=0
factory.reset()
debug.info(2, "Bitcell with 0 read ports")
- tx = pbitcell(name="pbc")
+ tx = factory.create(module_type="pbitcell")
self.local_check(tx)
OPTS.num_rw_ports=1
@@ -56,7 +58,7 @@ class pbitcell_test(openram_test):
OPTS.num_r_ports=0
factory.reset()
debug.info(2, "Bitcell with 0 read ports and 0 write ports")
- tx = pbitcell(name="pbc")
+ tx = factory.create(module_type="pbitcell")
self.local_check(tx)
OPTS.num_rw_ports=2
@@ -64,7 +66,7 @@ class pbitcell_test(openram_test):
OPTS.num_r_ports=2
factory.reset()
debug.info(2, "Bitcell with 2 of each port: read/write, write, and read")
- tx = pbitcell(name="pbc")
+ tx = factory.create(module_type="pbitcell")
self.local_check(tx)
OPTS.num_rw_ports=0
@@ -72,7 +74,7 @@ class pbitcell_test(openram_test):
OPTS.num_r_ports=2
factory.reset()
debug.info(2, "Bitcell with 0 read/write ports")
- tx = pbitcell(name="pbc")
+ tx = factory.create(module_type="pbitcell")
self.local_check(tx)
OPTS.num_rw_ports=2
@@ -80,7 +82,7 @@ class pbitcell_test(openram_test):
OPTS.num_r_ports=2
factory.reset()
debug.info(2, "Bitcell with 0 write ports")
- tx = pbitcell(name="pbc")
+ tx = factory.create(module_type="pbitcell")
self.local_check(tx)
OPTS.num_rw_ports=2
@@ -88,7 +90,7 @@ class pbitcell_test(openram_test):
OPTS.num_r_ports=0
factory.reset()
debug.info(2, "Bitcell with 0 read ports")
- tx = pbitcell(name="pbc")
+ tx = factory.create(module_type="pbitcell")
self.local_check(tx)
OPTS.num_rw_ports=2
@@ -96,7 +98,7 @@ class pbitcell_test(openram_test):
OPTS.num_r_ports=0
factory.reset()
debug.info(2, "Bitcell with 0 read ports and 0 write ports")
- tx = pbitcell(name="pbc")
+ tx = factory.create(module_type="pbitcell")
self.local_check(tx)
globals.end_openram()
@@ -108,4 +110,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/04_pbuf_test.py b/compiler/tests/04_pbuf_test.py
index ed5b8627..35db8ccf 100755
--- a/compiler/tests/04_pbuf_test.py
+++ b/compiler/tests/04_pbuf_test.py
@@ -1,27 +1,27 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a 2-row buffer cell
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class pbuf_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- global verify
- import verify
-
- import pbuf
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Testing inverter/buffer 4x 8x")
- a = pbuf.pbuf(name="pbufx8", size=8)
+ a = factory.create(module_type="pbuf", size=8)
self.local_check(a)
globals.end_openram()
@@ -31,4 +31,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/04_pdriver_test.py b/compiler/tests/04_pdriver_test.py
index ba89961f..abaab4a0 100755
--- a/compiler/tests/04_pdriver_test.py
+++ b/compiler/tests/04_pdriver_test.py
@@ -1,43 +1,43 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a 2-row buffer cell
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class pdriver_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- global verify
- import verify
-
- import pdriver
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Testing inverter/buffer 4x 8x")
# a tests the error message for specifying conflicting conditions
#a = pdriver.pdriver(fanout = 4,size_list = [1,2,4,8])
#self.local_check(a)
- b = pdriver.pdriver(name="pdriver1", size_list = [1,2,4,8])
+ b = factory.create(module_type="pdriver", size_list = [1,2,4,8])
self.local_check(b)
- c = pdriver.pdriver(name="pdriver2", fanout = 50)
+ c = factory.create(module_type="pdriver", fanout = 50)
self.local_check(c)
- d = pdriver.pdriver(name="pdriver3", fanout = 50, neg_polarity = True)
+ d = factory.create(module_type="pdriver", fanout = 50, neg_polarity = True)
self.local_check(d)
- e = pdriver.pdriver(name="pdriver4", fanout = 64)
+ e = factory.create(module_type="pdriver", fanout = 64)
self.local_check(e)
- f = pdriver.pdriver(name="pdriver5", fanout = 64, neg_polarity = True)
+ f = factory.create(module_type="pdriver", fanout = 64, neg_polarity = True)
self.local_check(f)
globals.end_openram()
@@ -47,4 +47,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/04_pinv_10x_test.py b/compiler/tests/04_pinv_10x_test.py
index 42c38ca1..2ccce34a 100755
--- a/compiler/tests/04_pinv_10x_test.py
+++ b/compiler/tests/04_pinv_10x_test.py
@@ -1,25 +1,27 @@
#!/usr/bin/env python3
-"""
-Run regression tests on a parameterized inverter
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class pinv_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import pinv
- import tech
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
- debug.info(2, "Checking 10x inverter")
- tx = pinv.pinv(name="pinvx10",size=8)
+ debug.info(2, "Checking 8x inverter")
+ tx = factory.create(module_type="pinv", size=8)
self.local_check(tx)
globals.end_openram()
@@ -30,4 +32,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/04_pinv_1x_beta_test.py b/compiler/tests/04_pinv_1x_beta_test.py
index 9ac66a65..2f96020c 100755
--- a/compiler/tests/04_pinv_1x_beta_test.py
+++ b/compiler/tests/04_pinv_1x_beta_test.py
@@ -1,25 +1,27 @@
#!/usr/bin/env python3
-"""
-Run regression tests on a parameterized inverter
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class pinv_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import pinv
- import tech
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Checking 1x beta=3 size inverter")
- tx = pinv.pinv(name="pinvx1b", size=1, beta=3)
+ tx = factory.create(module_type="pinv", size=1, beta=3)
self.local_check(tx)
globals.end_openram()
@@ -29,4 +31,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/04_pinv_1x_test.py b/compiler/tests/04_pinv_1x_test.py
index 850aa78e..9b0f1bc6 100755
--- a/compiler/tests/04_pinv_1x_test.py
+++ b/compiler/tests/04_pinv_1x_test.py
@@ -1,24 +1,27 @@
#!/usr/bin/env python3
-"""
-Run regression tests on a parameterized inverter
-"""
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class pinv_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import pinv
- import tech
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Checking 1x size inverter")
- tx = pinv.pinv(name="pinvx1", size=1)
+ tx = factory.create(module_type="pinv", size=1)
self.local_check(tx)
globals.end_openram()
@@ -28,4 +31,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/04_pinv_2x_test.py b/compiler/tests/04_pinv_2x_test.py
index 33950da9..d8a7598f 100755
--- a/compiler/tests/04_pinv_2x_test.py
+++ b/compiler/tests/04_pinv_2x_test.py
@@ -1,25 +1,27 @@
#!/usr/bin/env python3
-"""
-Run regression tests on a parameterized inverter
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class pinv_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import pinv
- import tech
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Checking 2x size inverter")
- tx = pinv.pinv(name="pinvx2", size=2)
+ tx = factory.create(module_type="pinv", size=2)
self.local_check(tx)
globals.end_openram()
@@ -30,4 +32,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/04_pinvbuf_test.py b/compiler/tests/04_pinvbuf_test.py
index 53814628..86af0708 100755
--- a/compiler/tests/04_pinvbuf_test.py
+++ b/compiler/tests/04_pinvbuf_test.py
@@ -1,24 +1,27 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a 2-row buffer cell
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class pinvbuf_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import pinvbuf
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Testing inverter/buffer 4x 8x")
- a = pinvbuf.pinvbuf(name="pinvufx8", size=8)
+ a = factory.create(module_type="pinvbuf", size=8)
self.local_check(a)
globals.end_openram()
@@ -28,4 +31,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/04_pnand2_test.py b/compiler/tests/04_pnand2_test.py
index cb0b65c6..bc066cfc 100755
--- a/compiler/tests/04_pnand2_test.py
+++ b/compiler/tests/04_pnand2_test.py
@@ -1,27 +1,27 @@
#!/usr/bin/env python3
-"""
-Run regression tests on a parameterized nand 2. This module doesn't
-generate a multi_finger 2-input nand gate. It generates only a minimum
-size 2-input nand gate.
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class pnand2_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import pnand2
- import tech
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Checking 2-input nand gate")
- tx = pnand2.pnand2(name="pnand2", size=1)
+ tx = factory.create(module_type="pnand2", size=1)
self.local_check(tx)
globals.end_openram()
@@ -32,4 +32,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/04_pnand3_test.py b/compiler/tests/04_pnand3_test.py
index f3bbdb73..8bf5098f 100755
--- a/compiler/tests/04_pnand3_test.py
+++ b/compiler/tests/04_pnand3_test.py
@@ -1,27 +1,27 @@
#!/usr/bin/env python3
-"""
-Run regression tests on a parameterized pnand3.
-This module doesn't generate a multi-finger 3-input nand gate.
-It generates only a minimum size 3-input nand gate.
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class pnand3_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import pnand3
- import tech
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Checking 3-input nand gate")
- tx = pnand3.pnand3(name="pnand3", size=1)
+ tx = factory.create(module_type="pnand3", size=1)
self.local_check(tx)
globals.end_openram()
@@ -32,4 +32,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/04_pnor2_test.py b/compiler/tests/04_pnor2_test.py
index 32214ded..0e524506 100755
--- a/compiler/tests/04_pnor2_test.py
+++ b/compiler/tests/04_pnor2_test.py
@@ -1,27 +1,27 @@
#!/usr/bin/env python3
-"""
-Run regression tests on a parameterized nor 2. This module doesn't
-generate a multi_finger 2-input nor gate. It generates only a minimum
-size 2-input nor gate.
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class pnor2_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import pnor2
- import tech
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Checking 2-input nor gate")
- tx = pnor2.pnor2(name="pnor2", size=1)
+ tx = factory.create(module_type="pnor2", size=1)
self.local_check(tx)
globals.end_openram()
@@ -31,4 +31,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/04_precharge_test.py b/compiler/tests/04_precharge_test.py
index a73595eb..9b2addd5 100755
--- a/compiler/tests/04_precharge_test.py
+++ b/compiler/tests/04_precharge_test.py
@@ -1,27 +1,28 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a precharge cell
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
-import debug
from sram_factory import factory
+import debug
class precharge_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import precharge
- import tech
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
# check precharge in single port
debug.info(2, "Checking precharge for handmade bitcell")
- tx = precharge.precharge(name="precharge_driver", size=1)
+ tx = factory.create(module_type="precharge", size=1)
self.local_check(tx)
# check precharge in multi-port
@@ -32,15 +33,17 @@ class precharge_test(openram_test):
factory.reset()
debug.info(2, "Checking precharge for pbitcell (innermost connections)")
- tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl0", bitcell_br="br0")
+ tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(tx)
+ factory.reset()
debug.info(2, "Checking precharge for pbitcell (innermost connections)")
- tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl1", bitcell_br="br1")
+ tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl1", bitcell_br="br1")
self.local_check(tx)
+ factory.reset()
debug.info(2, "Checking precharge for pbitcell (outermost connections)")
- tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl2", bitcell_br="br2")
+ tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl2", bitcell_br="br2")
self.local_check(tx)
globals.end_openram()
@@ -50,4 +53,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/04_replica_pbitcell_test.py b/compiler/tests/04_replica_pbitcell_test.py
index 9a672419..65ce5ecf 100755
--- a/compiler/tests/04_replica_pbitcell_test.py
+++ b/compiler/tests/04_replica_pbitcell_test.py
@@ -1,21 +1,24 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a replica pbitcell
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
-import debug
from sram_factory import factory
+import debug
class replica_pbitcell_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
import replica_pbitcell
OPTS.bitcell = "pbitcell"
@@ -44,4 +47,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/04_single_level_column_mux_test.py b/compiler/tests/04_single_level_column_mux_test.py
index 2a107b9a..3ecbbe9d 100755
--- a/compiler/tests/04_single_level_column_mux_test.py
+++ b/compiler/tests/04_single_level_column_mux_test.py
@@ -1,29 +1,30 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a wordline_driver array
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
-import debug
from sram_factory import factory
+import debug
#@unittest.skip("SKIPPING 04_driver_test")
class single_level_column_mux_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import single_level_column_mux
- import tech
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
# check single level column mux in single port
debug.info(2, "Checking column mux")
- tx = single_level_column_mux.single_level_column_mux(name="mux8", tx_size=8)
+ tx = factory.create(module_type="single_level_column_mux", tx_size=8)
self.local_check(tx)
# check single level column mux in multi-port
@@ -34,12 +35,12 @@ class single_level_column_mux_test(openram_test):
factory.reset()
debug.info(2, "Checking column mux for pbitcell (innermost connections)")
- tx = single_level_column_mux.single_level_column_mux(name="mux8_2", tx_size=8, bitcell_bl="bl0", bitcell_br="br0")
+ tx = factory.create(module_type="single_level_column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(tx)
factory.reset()
debug.info(2, "Checking column mux for pbitcell (outermost connections)")
- tx = single_level_column_mux.single_level_column_mux(name="mux8_3", tx_size=8, bitcell_bl="bl2", bitcell_br="br2")
+ tx = factory.create(module_type="single_level_column_mux",tx_size=8, bitcell_bl="bl2", bitcell_br="br2")
self.local_check(tx)
globals.end_openram()
@@ -49,4 +50,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/05_bitcell_1rw_1r_array_test.py b/compiler/tests/05_bitcell_1rw_1r_array_test.py
index 1223085e..972fb8e6 100755
--- a/compiler/tests/05_bitcell_1rw_1r_array_test.py
+++ b/compiler/tests/05_bitcell_1rw_1r_array_test.py
@@ -1,14 +1,18 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a basic array
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 05_bitcell_1rw_1r_array_test")
@@ -16,17 +20,20 @@ import debug
class bitcell_1rw_1r_array_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import bitcell_array
- debug.info(2, "Testing 4x4 array for cell_1rw_1r")
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+
OPTS.bitcell = "bitcell_1rw_1r"
+ OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
+ OPTS.dummy_bitcell="dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
- a = bitcell_array.bitcell_array(name="bitcell_1rw_1r_array", cols=4, rows=4)
+
+ debug.info(2, "Testing 4x4 array for cell_1rw_1r")
+ a = factory.create(module_type="bitcell_array", cols=4, rows=4)
self.local_check(a)
-
+
globals.end_openram()
# run the test from the command line
@@ -34,4 +41,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/05_bitcell_array_test.py b/compiler/tests/05_bitcell_array_test.py
index 93668e05..6a561019 100755
--- a/compiler/tests/05_bitcell_array_test.py
+++ b/compiler/tests/05_bitcell_array_test.py
@@ -1,14 +1,18 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a basic array
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 05_array_test")
@@ -16,13 +20,12 @@ import debug
class array_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import bitcell_array
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Testing 4x4 array for 6t_cell")
- a = bitcell_array.bitcell_array(name="bitcell_array", cols=4, rows=4)
+ a = factory.create(module_type="bitcell_array", cols=4, rows=4)
self.local_check(a)
-
+
globals.end_openram()
# run the test from the command line
@@ -30,4 +33,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/05_dummy_array_test.py b/compiler/tests/05_dummy_array_test.py
new file mode 100755
index 00000000..de379a97
--- /dev/null
+++ b/compiler/tests/05_dummy_array_test.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys,os
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+class dummy_row_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+
+ debug.info(2, "Testing dummy row for 6t_cell")
+ a = factory.create(module_type="dummy_array", rows=1, cols=4)
+ self.local_check(a)
+
+ debug.info(2, "Testing dummy column for 6t_cell")
+ a = factory.create(module_type="dummy_array", rows=4, cols=1)
+ self.local_check(a)
+
+ globals.end_openram()
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/05_pbitcell_array_test.py b/compiler/tests/05_pbitcell_array_test.py
index 4da5bec9..91bf7522 100755
--- a/compiler/tests/05_pbitcell_array_test.py
+++ b/compiler/tests/05_pbitcell_array_test.py
@@ -1,29 +1,32 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a basic array
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 05_pbitcell_array_test")
class pbitcell_array_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import bitcell_array
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Testing 4x4 array for multiport bitcell, with read ports at the edge of the bit cell")
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 2
OPTS.num_r_ports = 2
OPTS.num_w_ports = 2
- a = bitcell_array.bitcell_array(name="pbitcell_array_Rport_edge", cols=4, rows=4)
+ a = factory.create(module_type="bitcell_array", cols=4, rows=4)
self.local_check(a)
debug.info(2, "Testing 4x4 array for multiport bitcell, with write ports at the edge of the bit cell")
@@ -31,7 +34,7 @@ class pbitcell_array_test(openram_test):
OPTS.num_rw_ports = 2
OPTS.num_r_ports = 0
OPTS.num_w_ports = 2
- a = bitcell_array.bitcell_array(name="pbitcell_array_Wport_edge", cols=4, rows=4)
+ a = factory.create(module_type="bitcell_array", cols=4, rows=4)
self.local_check(a)
debug.info(2, "Testing 4x4 array for multiport bitcell, with read/write ports at the edge of the bit cell")
@@ -39,7 +42,7 @@ class pbitcell_array_test(openram_test):
OPTS.num_rw_ports = 2
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
- a = bitcell_array.bitcell_array(name="pbitcell_array_RWport_edge", cols=4, rows=4)
+ a = factory.create(module_type="bitcell_array", cols=4, rows=4)
self.local_check(a)
globals.end_openram()
@@ -49,4 +52,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/05_replica_pbitcell_array_test.py b/compiler/tests/05_replica_pbitcell_array_test.py
new file mode 100755
index 00000000..2bc4a0d2
--- /dev/null
+++ b/compiler/tests/05_replica_pbitcell_array_test.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys,os
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+class replica_bitcell_array_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+
+ OPTS.bitcell = "pbitcell"
+ OPTS.replica_bitcell = "replica_pbitcell"
+ OPTS.dummy_bitcell = "dummy_pbitcell"
+ OPTS.num_rw_ports = 1
+ OPTS.num_r_ports = 1
+ OPTS.num_w_ports = 0
+
+ debug.info(2, "Testing 4x4 array for pbitcell")
+ a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=1, bitcell_ports=[0,1])
+ self.local_check(a)
+
+ OPTS.bitcell = "pbitcell"
+ OPTS.replica_bitcell = "replica_pbitcell"
+ OPTS.dummy_bitcell = "dummy_pbitcell"
+ OPTS.num_rw_ports = 1
+ OPTS.num_r_ports = 0
+ OPTS.num_w_ports = 0
+
+ factory.reset()
+ debug.info(2, "Testing 4x4 array for pbitcell")
+ a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=0, bitcell_ports=[0])
+ self.local_check(a)
+
+ globals.end_openram()
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/06_hierarchical_decoder_test.py b/compiler/tests/06_hierarchical_decoder_test.py
index 2400d3c2..c349e889 100755
--- a/compiler/tests/06_hierarchical_decoder_test.py
+++ b/compiler/tests/06_hierarchical_decoder_test.py
@@ -1,24 +1,24 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a hierarchical_decoder.
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
-import debug
from sram_factory import factory
+import debug
class hierarchical_decoder_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import hierarchical_decoder
- import tech
-
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
# Doesn't require hierarchical decoder
# debug.info(1, "Testing 4 row sample for hierarchical_decoder")
# a = hierarchical_decoder.hierarchical_decoder(name="hd1, rows=4)
@@ -31,19 +31,19 @@ class hierarchical_decoder_test(openram_test):
# check hierarchical decoder for single port
debug.info(1, "Testing 16 row sample for hierarchical_decoder")
- a = hierarchical_decoder.hierarchical_decoder(name="hd3", rows=16)
+ a = factory.create(module_type="hierarchical_decoder", rows=16)
self.local_check(a)
debug.info(1, "Testing 32 row sample for hierarchical_decoder")
- a = hierarchical_decoder.hierarchical_decoder(name="hd4", rows=32)
+ a = factory.create(module_type="hierarchical_decoder", rows=32)
self.local_check(a)
debug.info(1, "Testing 128 row sample for hierarchical_decoder")
- a = hierarchical_decoder.hierarchical_decoder(name="hd5", rows=128)
+ a = factory.create(module_type="hierarchical_decoder", rows=128)
self.local_check(a)
debug.info(1, "Testing 512 row sample for hierarchical_decoder")
- a = hierarchical_decoder.hierarchical_decoder(name="hd6", rows=512)
+ a = factory.create(module_type="hierarchical_decoder", rows=512)
self.local_check(a)
# check hierarchical decoder for multi-port
@@ -54,19 +54,19 @@ class hierarchical_decoder_test(openram_test):
factory.reset()
debug.info(1, "Testing 16 row sample for hierarchical_decoder (multi-port case)")
- a = hierarchical_decoder.hierarchical_decoder(name="hd7", rows=16)
+ a = factory.create(module_type="hierarchical_decoder", rows=16)
self.local_check(a)
debug.info(1, "Testing 32 row sample for hierarchical_decoder (multi-port case)")
- a = hierarchical_decoder.hierarchical_decoder(name="hd8", rows=32)
+ a = factory.create(module_type="hierarchical_decoder", rows=32)
self.local_check(a)
debug.info(1, "Testing 128 row sample for hierarchical_decoder (multi-port case)")
- a = hierarchical_decoder.hierarchical_decoder(name="hd9", rows=128)
+ a = factory.create(module_type="hierarchical_decoder", rows=128)
self.local_check(a)
debug.info(1, "Testing 512 row sample for hierarchical_decoder (multi-port case)")
- a = hierarchical_decoder.hierarchical_decoder(name="hd10", rows=512)
+ a = factory.create(module_type="hierarchical_decoder", rows=512)
self.local_check(a)
globals.end_openram()
@@ -76,4 +76,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/06_hierarchical_predecode2x4_test.py b/compiler/tests/06_hierarchical_predecode2x4_test.py
index 6fbba350..0a5363ab 100755
--- a/compiler/tests/06_hierarchical_predecode2x4_test.py
+++ b/compiler/tests/06_hierarchical_predecode2x4_test.py
@@ -1,26 +1,28 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a hierarchical_predecode2x4.
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class hierarchical_predecode2x4_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import hierarchical_predecode2x4 as pre
- import tech
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
# checking hierarchical precode 2x4 for single port
debug.info(1, "Testing sample for hierarchy_predecode2x4")
- a = pre.hierarchical_predecode2x4(name="pre1")
+ a = factory.create(module_type="hierarchical_predecode2x4")
self.local_check(a)
# checking hierarchical precode 2x4 for multi-port
@@ -30,7 +32,7 @@ class hierarchical_predecode2x4_test(openram_test):
OPTS.num_r_ports = 0
debug.info(1, "Testing sample for hierarchy_predecode2x4 (multi-port case)")
- a = pre.hierarchical_predecode2x4(name="pre2")
+ a = factory.create(module_type="hierarchical_predecode2x4")
self.local_check(a)
globals.end_openram()
@@ -40,4 +42,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/06_hierarchical_predecode3x8_test.py b/compiler/tests/06_hierarchical_predecode3x8_test.py
index b704a50d..b2a8d438 100755
--- a/compiler/tests/06_hierarchical_predecode3x8_test.py
+++ b/compiler/tests/06_hierarchical_predecode3x8_test.py
@@ -1,26 +1,28 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a hierarchical_predecode3x8.
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class hierarchical_predecode3x8_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import hierarchical_predecode3x8 as pre
- import tech
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
# checking hierarchical precode 3x8 for single port
debug.info(1, "Testing sample for hierarchy_predecode3x8")
- a = pre.hierarchical_predecode3x8(name="pre1")
+ a = factory.create(module_type="hierarchical_predecode3x8")
self.local_check(a)
# checking hierarchical precode 3x8 for multi-port
@@ -30,7 +32,7 @@ class hierarchical_predecode3x8_test(openram_test):
OPTS.num_r_ports = 0
debug.info(1, "Testing sample for hierarchy_predecode3x8 (multi-port case)")
- a = pre.hierarchical_predecode3x8(name="pre2")
+ a = factory.create(module_type="hierarchical_predecode3x8")
self.local_check(a)
globals.end_openram()
@@ -40,4 +42,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/07_single_level_column_mux_array_test.py b/compiler/tests/07_single_level_column_mux_array_test.py
index 8cc16f56..c6cd7ed2 100755
--- a/compiler/tests/07_single_level_column_mux_array_test.py
+++ b/compiler/tests/07_single_level_column_mux_array_test.py
@@ -1,33 +1,36 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a single transistor column_mux.
-"""
-
-from testutils import header,openram_test,unittest
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
-import debug
from sram_factory import factory
+import debug
class single_level_column_mux_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
import single_level_column_mux_array
# check single level column mux array in single port
debug.info(1, "Testing sample for 2-way column_mux_array")
- a = single_level_column_mux_array.single_level_column_mux_array(name="mux1", columns=16, word_size=8)
+ a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=8)
self.local_check(a)
debug.info(1, "Testing sample for 4-way column_mux_array")
- a = single_level_column_mux_array.single_level_column_mux_array(name="mux2", columns=16, word_size=4)
+ a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=4)
self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array")
- a = single_level_column_mux_array.single_level_column_mux_array(name="mux3", columns=32, word_size=4)
+ a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4)
self.local_check(a)
# check single level column mux array in multi-port
@@ -38,19 +41,19 @@ class single_level_column_mux_test(openram_test):
factory.reset()
debug.info(1, "Testing sample for 2-way column_mux_array in multi-port")
- a = single_level_column_mux_array.single_level_column_mux_array(name="mux4", columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0")
+ a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a)
debug.info(1, "Testing sample for 4-way column_mux_array in multi-port")
- a = single_level_column_mux_array.single_level_column_mux_array(name="mux5", columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
+ a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (innermost connections)")
- a = single_level_column_mux_array.single_level_column_mux_array(name="mux6", columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
+ a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (outermost connections)")
- a = single_level_column_mux_array.single_level_column_mux_array(name="mux7", columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2")
+ a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2")
self.local_check(a)
globals.end_openram()
@@ -61,4 +64,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/08_precharge_array_test.py b/compiler/tests/08_precharge_array_test.py
index c31f133a..ee29211b 100755
--- a/compiler/tests/08_precharge_array_test.py
+++ b/compiler/tests/08_precharge_array_test.py
@@ -1,26 +1,28 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a precharge array
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
-import debug
from sram_factory import factory
+import debug
class precharge_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import precharge_array
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
# check precharge array in single port
debug.info(2, "Checking 3 column precharge")
- pc = precharge_array.precharge_array(name="pre1", columns=3)
+ pc = factory.create(module_type="precharge_array", columns=3)
self.local_check(pc)
# check precharge array in multi-port
@@ -31,7 +33,7 @@ class precharge_test(openram_test):
factory.reset()
debug.info(2, "Checking 3 column precharge array for 1RW/1R bitcell")
- pc = precharge_array.precharge_array(name="pre2", columns=3, bitcell_bl="bl0", bitcell_br="br0")
+ pc = factory.create(module_type="precharge_array", columns=3, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(pc)
# debug.info(2, "Checking 3 column precharge array for pbitcell (innermost connections)")
@@ -49,4 +51,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/08_wordline_driver_test.py b/compiler/tests/08_wordline_driver_test.py
index bc69c776..31415a6c 100755
--- a/compiler/tests/08_wordline_driver_test.py
+++ b/compiler/tests/08_wordline_driver_test.py
@@ -1,28 +1,30 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a wordline_driver array
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
-import debug
from sram_factory import factory
+import debug
#@unittest.skip("SKIPPING 04_driver_test")
class wordline_driver_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import wordline_driver
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
# check wordline driver for single port
debug.info(2, "Checking driver")
- tx = wordline_driver.wordline_driver(name="wld1", rows=8, cols=32)
+ tx = factory.create(module_type="wordline_driver", rows=8, cols=32)
self.local_check(tx)
# check wordline driver for multi-port
@@ -33,7 +35,7 @@ class wordline_driver_test(openram_test):
factory.reset()
debug.info(2, "Checking driver (multi-port case)")
- tx = wordline_driver.wordline_driver(name="wld2", rows=8, cols=64)
+ tx = factory.create(module_type="wordline_driver", rows=8, cols=64)
self.local_check(tx)
globals.end_openram()
@@ -43,4 +45,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/09_sense_amp_array_test.py b/compiler/tests/09_sense_amp_array_test.py
index c144b12b..e35ea3c3 100755
--- a/compiler/tests/09_sense_amp_array_test.py
+++ b/compiler/tests/09_sense_amp_array_test.py
@@ -1,30 +1,32 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a sense amp array
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
-import debug
from sram_factory import factory
+import debug
class sense_amp_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import sense_amp_array
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
# check sense amp array for single port
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2")
- a = sense_amp_array.sense_amp_array(name="sa1", word_size=4, words_per_row=2)
+ a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=2)
self.local_check(a)
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4")
- a = sense_amp_array.sense_amp_array(name="sa2", word_size=4, words_per_row=4)
+ a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=4)
self.local_check(a)
# check sense amp array for multi-port
@@ -35,11 +37,11 @@ class sense_amp_test(openram_test):
factory.reset()
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2 (multi-port case)")
- a = sense_amp_array.sense_amp_array(name="sa3", word_size=4, words_per_row=2)
+ a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=2)
self.local_check(a)
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4 (multi-port case)")
- a = sense_amp_array.sense_amp_array(name="sa4", word_size=4, words_per_row=4)
+ a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=4)
self.local_check(a)
globals.end_openram()
@@ -49,4 +51,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/10_write_driver_array_test.py b/compiler/tests/10_write_driver_array_test.py
index 98507b60..20dacca6 100755
--- a/compiler/tests/10_write_driver_array_test.py
+++ b/compiler/tests/10_write_driver_array_test.py
@@ -1,30 +1,32 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a write driver array
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
-import debug
from sram_factory import factory
+import debug
class write_driver_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import write_driver_array
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
# check write driver array for single port
debug.info(2, "Testing write_driver_array for columns=8, word_size=8")
- a = write_driver_array.write_driver_array(name="wd1", columns=8, word_size=8)
+ a = factory.create(module_type="write_driver_array", columns=8, word_size=8)
self.local_check(a)
debug.info(2, "Testing write_driver_array for columns=16, word_size=8")
- a = write_driver_array.write_driver_array(name="wd2", columns=16, word_size=8)
+ a = factory.create(module_type="write_driver_array", columns=16, word_size=8)
self.local_check(a)
# check write driver array for multi-port
@@ -35,11 +37,11 @@ class write_driver_test(openram_test):
factory.reset()
debug.info(2, "Testing write_driver_array for columns=8, word_size=8 (multi-port case)")
- a = write_driver_array.write_driver_array(name="wd3", columns=8, word_size=8)
+ a = factory.create(module_type="write_driver_array", columns=8, word_size=8)
self.local_check(a)
debug.info(2, "Testing write_driver_array for columns=16, word_size=8 (multi-port case)")
- a = write_driver_array.write_driver_array(name="wd4", columns=16, word_size=8)
+ a = factory.create(module_type="write_driver_array", columns=16, word_size=8)
self.local_check(a)
globals.end_openram()
@@ -49,4 +51,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/10_write_driver_array_wmask_test.py b/compiler/tests/10_write_driver_array_wmask_test.py
new file mode 100755
index 00000000..d09286b5
--- /dev/null
+++ b/compiler/tests/10_write_driver_array_wmask_test.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys, os
+
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+
+class write_driver_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+
+ # check write driver array for single port
+ debug.info(2, "Testing write_driver_array for columns=8, word_size=8, write_size=4")
+ a = factory.create(module_type="write_driver_array", columns=8, word_size=8, write_size=4)
+ self.local_check(a)
+
+ debug.info(2, "Testing write_driver_array for columns=16, word_size=16, write_size=2")
+ a = factory.create(module_type="write_driver_array", columns=16, word_size=16, write_size=2)
+ self.local_check(a)
+
+ debug.info(2, "Testing write_driver_array for columns=16, word_size=8, write_size=4")
+ a = factory.create(module_type="write_driver_array", columns=16, word_size=8, write_size=4)
+ self.local_check(a)
+
+ # check write driver array for multi-port
+ OPTS.bitcell = "pbitcell"
+ OPTS.num_rw_ports = 1
+ OPTS.num_w_ports = 0
+ OPTS.num_r_ports = 0
+
+ factory.reset()
+ debug.info(2, "Testing write_driver_array for columns=8, word_size=8, write_size=4 (multi-port case)")
+ a = factory.create(module_type="write_driver_array", columns=8, word_size=8, write_size=4)
+ self.local_check(a)
+
+ debug.info(2, "Testing write_driver_array for columns=16, word_size=8, write_size=4 (multi-port case)")
+ a = factory.create(module_type="write_driver_array", columns=16, word_size=8, write_size=4)
+ self.local_check(a)
+
+ globals.end_openram()
+
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
\ No newline at end of file
diff --git a/compiler/tests/10_write_mask_and_array_test.py b/compiler/tests/10_write_mask_and_array_test.py
new file mode 100755
index 00000000..91155467
--- /dev/null
+++ b/compiler/tests/10_write_mask_and_array_test.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys, os
+
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+
+class write_mask_and_array_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+
+ # check write driver array for single port
+ debug.info(2, "Testing write_mask_and_array for columns=8, word_size=8, write_size=4")
+ a = factory.create(module_type="write_mask_and_array", columns=8, word_size=8, write_size=4)
+ self.local_check(a)
+
+ debug.info(2, "Testing write_mask_and_array for columns=16, word_size=16, write_size=4")
+ a = factory.create(module_type="write_mask_and_array", columns=16, word_size=16, write_size=4)
+ self.local_check(a)
+
+ debug.info(2, "Testing write_mask_and_array for columns=16, word_size=8, write_size=2")
+ a = factory.create(module_type="write_mask_and_array", columns=16, word_size=8, write_size=2)
+ self.local_check(a)
+
+ # check write driver array for multi-port
+ OPTS.bitcell = "pbitcell"
+ OPTS.num_rw_ports = 1
+ OPTS.num_w_ports = 0
+ OPTS.num_r_ports = 0
+
+ factory.reset()
+ debug.info(2, "Testing write_mask_and_array for columns=8, word_size=8, write_size=4 (multi-port case)")
+ a = factory.create(module_type="write_mask_and_array", columns=8, word_size=8, write_size=4)
+ self.local_check(a)
+
+ debug.info(2, "Testing write_mask_and_array for columns=16, word_size=8, write_size=2 (multi-port case)")
+ a = factory.create(module_type="write_mask_and_array", columns=16, word_size=8, write_size=2)
+ self.local_check(a)
+
+ globals.end_openram()
+
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/11_dff_array_test.py b/compiler/tests/11_dff_array_test.py
index eed41dda..b843a6bb 100755
--- a/compiler/tests/11_dff_array_test.py
+++ b/compiler/tests/11_dff_array_test.py
@@ -1,32 +1,35 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a dff_array.
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class dff_array_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import dff_array
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Testing dff_array for 3x3")
- a = dff_array.dff_array(rows=3, columns=3)
+ a = factory.create(module_type="dff_array", rows=3, columns=3)
self.local_check(a)
debug.info(2, "Testing dff_array for 1x3")
- a = dff_array.dff_array(rows=1, columns=3)
+ a = factory.create(module_type="dff_array", rows=1, columns=3)
self.local_check(a)
debug.info(2, "Testing dff_array for 3x1")
- a = dff_array.dff_array(rows=3, columns=1)
+ a = factory.create(module_type="dff_array", rows=3, columns=1)
self.local_check(a)
globals.end_openram()
@@ -36,4 +39,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/11_dff_buf_array_test.py b/compiler/tests/11_dff_buf_array_test.py
index d2932cac..ec0e7742 100755
--- a/compiler/tests/11_dff_buf_array_test.py
+++ b/compiler/tests/11_dff_buf_array_test.py
@@ -1,32 +1,35 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a dff_array.
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class dff_buf_array_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import dff_buf_array
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Testing dff_buf_array for 3x3")
- a = dff_buf_array.dff_buf_array(rows=3, columns=3)
+ a = factory.create(module_type="dff_buf_array", rows=3, columns=3)
self.local_check(a)
debug.info(2, "Testing dff_buf_array for 1x3")
- a = dff_buf_array.dff_buf_array(rows=1, columns=3)
+ a = factory.create(module_type="dff_buf_array", rows=1, columns=3)
self.local_check(a)
debug.info(2, "Testing dff_buf_array for 3x1")
- a = dff_buf_array.dff_buf_array(rows=3, columns=1)
+ a = factory.create(module_type="dff_buf_array", rows=3, columns=1)
self.local_check(a)
globals.end_openram()
@@ -36,4 +39,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/11_dff_buf_test.py b/compiler/tests/11_dff_buf_test.py
index c9c25f16..161deaa2 100755
--- a/compiler/tests/11_dff_buf_test.py
+++ b/compiler/tests/11_dff_buf_test.py
@@ -1,24 +1,27 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a dff_buf.
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class dff_buf_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import dff_buf
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Testing dff_buf 4x 8x")
- a = dff_buf.dff_buf(4, 8)
+ a = factory.create(module_type="dff_buf", inv1_size=4, inv2_size=8)
self.local_check(a)
globals.end_openram()
@@ -28,4 +31,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/12_tri_gate_array_test.py b/compiler/tests/12_tri_gate_array_test.py
index cb789155..0bd5f60c 100755
--- a/compiler/tests/12_tri_gate_array_test.py
+++ b/compiler/tests/12_tri_gate_array_test.py
@@ -1,28 +1,31 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a tri_gate_array.
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class tri_gate_array_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import tri_gate_array
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(1, "Testing tri_gate_array for columns=8, word_size=8")
- a = tri_gate_array.tri_gate_array(columns=8, word_size=8)
+ a = factory.create(module_type="tri_gate_array", columns=8, word_size=8)
self.local_check(a)
-
+
debug.info(1, "Testing tri_gate_array for columns=16, word_size=8")
- a = tri_gate_array.tri_gate_array(columns=16, word_size=8)
+ a = factory.create(module_type="tri_gate_array", columns=16, word_size=8)
self.local_check(a)
globals.end_openram()
@@ -32,4 +35,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/13_delay_chain_test.py b/compiler/tests/13_delay_chain_test.py
index bfe2b3ff..9dc8faeb 100755
--- a/compiler/tests/13_delay_chain_test.py
+++ b/compiler/tests/13_delay_chain_test.py
@@ -1,24 +1,27 @@
#!/usr/bin/env python3
-"""
-Run a test on a delay chain
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class delay_chain_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import delay_chain
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(2, "Testing delay_chain")
- a = delay_chain.delay_chain(name="dc", fanout_list=[4, 4, 4, 4])
+ a = factory.create(module_type="delay_chain", fanout_list=[4, 4, 4, 4])
self.local_check(a)
globals.end_openram()
@@ -28,4 +31,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/14_replica_bitcell_1rw_1r_array_test.py b/compiler/tests/14_replica_bitcell_1rw_1r_array_test.py
new file mode 100755
index 00000000..bae7edde
--- /dev/null
+++ b/compiler/tests/14_replica_bitcell_1rw_1r_array_test.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys,os
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+class replica_bitcell_array_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+
+ OPTS.bitcell = "bitcell_1rw_1r"
+ OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
+ OPTS.dummy_bitcell="dummy_bitcell_1rw_1r"
+ OPTS.num_rw_ports = 1
+ OPTS.num_r_ports = 1
+ OPTS.num_w_ports = 0
+
+ debug.info(2, "Testing 4x4 array for cell_1rw_1r")
+ a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=2, right_rbl=0, bitcell_ports=[0,1])
+ self.local_check(a)
+
+ debug.info(2, "Testing 4x4 array for cell_1rw_1r")
+ a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=1, bitcell_ports=[0,1])
+ self.local_check(a)
+
+ globals.end_openram()
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/14_replica_bitcell_array_test.py b/compiler/tests/14_replica_bitcell_array_test.py
new file mode 100755
index 00000000..2b446758
--- /dev/null
+++ b/compiler/tests/14_replica_bitcell_array_test.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys,os
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+class replica_bitcell_array_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+
+ debug.info(2, "Testing 4x4 array for 6t_cell")
+ a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=0, bitcell_ports=[0])
+ self.local_check(a)
+
+ globals.end_openram()
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/14_replica_bitline_multiport_test.py b/compiler/tests/14_replica_bitline_multiport_test.py
deleted file mode 100755
index f379e0d2..00000000
--- a/compiler/tests/14_replica_bitline_multiport_test.py
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/usr/bin/env python3
-"""
-Run a test on a multiport replica bitline
-"""
-
-import unittest
-from testutils import header,openram_test
-import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
-import globals
-from globals import OPTS
-import debug
-from sram_factory import factory
-
-class replica_bitline_multiport_test(openram_test):
-
- def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import replica_bitline
-
- stages=4
- fanout=4
- rows=13
-
- OPTS.bitcell = "bitcell_1rw_1r"
- OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
- OPTS.num_rw_ports = 1
- OPTS.num_r_ports = 1
- OPTS.num_w_ports = 0
-
- factory.reset()
- debug.info(2, "Testing 1rw 1r RBL with {0} FO4 stages, {1} rows".format(stages,rows))
- a = replica_bitline.replica_bitline(name="rbl1", delay_fanout_list=stages*[fanout], bitcell_loads=rows)
- self.local_check(a)
-
- # check replica bitline in pbitcell multi-port
- OPTS.bitcell = "pbitcell"
- OPTS.replica_bitcell = "replica_pbitcell"
- OPTS.num_rw_ports = 1
- OPTS.num_w_ports = 0
- OPTS.num_r_ports = 0
-
- factory.reset()
- debug.info(2, "Testing RBL pbitcell 1rw with {0} FO4 stages, {1} rows".format(stages,rows))
- a = replica_bitline.replica_bitline(name="rbl2", delay_fanout_list=stages*[fanout], bitcell_loads=rows)
- self.local_check(a)
-
- OPTS.num_rw_ports = 1
- OPTS.num_w_ports = 1
- OPTS.num_r_ports = 1
-
- factory.reset()
- debug.info(2, "Testing RBL pbitcell 1rw 1w 1r with {0} FO4 stages, {1} rows".format(stages,rows))
- a = replica_bitline.replica_bitline(name="rbl3", delay_fanout_list=stages*[fanout], bitcell_loads=rows)
- self.local_check(a)
-
- globals.end_openram()
-
-# run the test from the command line
-if __name__ == "__main__":
- (OPTS, args) = globals.parse_args()
- del sys.argv[1:]
- header(__file__, OPTS.tech_name)
- unittest.main()
diff --git a/compiler/tests/14_replica_bitline_test.py b/compiler/tests/14_replica_bitline_test.py
deleted file mode 100755
index ca213d5c..00000000
--- a/compiler/tests/14_replica_bitline_test.py
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env python3
-"""
-Run a test on a replica bitline
-"""
-
-import unittest
-from testutils import header,openram_test
-import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
-import globals
-from globals import OPTS
-import debug
-
-class replica_bitline_test(openram_test):
-
- def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import replica_bitline
-
- # check replica bitline in single port
- stages=4
- fanout=4
- rows=13
- debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
- a = replica_bitline.replica_bitline(name="rbl1", delay_fanout_list=stages*[fanout], bitcell_loads=rows)
- self.local_check(a)
- #debug.error("Exiting...", 1)
-
- stages=8
- rows=100
- debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
- a = replica_bitline.replica_bitline(name="rbl2", delay_fanout_list=stages*[fanout], bitcell_loads=rows)
- self.local_check(a)
-
-
- globals.end_openram()
-
-# run the test from the command line
-if __name__ == "__main__":
- (OPTS, args) = globals.parse_args()
- del sys.argv[1:]
- header(__file__, OPTS.tech_name)
- unittest.main()
diff --git a/compiler/tests/14_replica_column_test.py b/compiler/tests/14_replica_column_test.py
new file mode 100755
index 00000000..c0db4d17
--- /dev/null
+++ b/compiler/tests/14_replica_column_test.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys,os
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+class replica_column_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+
+ debug.info(2, "Testing replica column for 6t_cell")
+ a = factory.create(module_type="replica_column", rows=4, left_rbl=1, right_rbl=0, replica_bit=1)
+ self.local_check(a)
+
+ debug.info(2, "Testing replica column for 6t_cell")
+ a = factory.create(module_type="replica_column", rows=4, left_rbl=1, right_rbl=1, replica_bit=6)
+ self.local_check(a)
+
+ debug.info(2, "Testing replica column for 6t_cell")
+ a = factory.create(module_type="replica_column", rows=4, left_rbl=2, right_rbl=0, replica_bit=2)
+ self.local_check(a)
+
+ globals.end_openram()
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/16_control_logic_multiport_test.py b/compiler/tests/16_control_logic_multiport_test.py
new file mode 100755
index 00000000..66c34d24
--- /dev/null
+++ b/compiler/tests/16_control_logic_multiport_test.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+#Copyright (c) 2016-2019 Regents of the University of California and The Board
+#of Regents for the Oklahoma Agricultural and Mechanical College
+#(acting for and on behalf of Oklahoma State University)
+#All rights reserved.
+#
+"""
+Run a regression test on a control_logic
+"""
+
+import unittest
+from testutils import header,openram_test
+import sys,os
+sys.path.append(os.path.join(sys.path[0],".."))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+class control_logic_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ import control_logic
+ import tech
+
+ # check control logic for multi-port
+ OPTS.bitcell = "pbitcell"
+ OPTS.replica_bitcell = "replica_pbitcell"
+ OPTS.num_rw_ports = 1
+ OPTS.num_w_ports = 1
+ OPTS.num_r_ports = 1
+
+ debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
+ a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, port_type="rw")
+ self.local_check(a)
+
+ # OPTS.num_rw_ports = 0
+ # OPTS.num_w_ports = 1
+ debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
+ a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, port_type="w")
+ self.local_check(a)
+
+ # OPTS.num_w_ports = 0
+ # OPTS.num_r_ports = 1
+ debug.info(1, "Testing sample for control_logic for multiport, only read control logic")
+ a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, port_type="r")
+ self.local_check(a)
+
+ globals.end_openram()
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main()
diff --git a/compiler/tests/16_control_logic_test.py b/compiler/tests/16_control_logic_test.py
index e0545af4..92d5c94b 100755
--- a/compiler/tests/16_control_logic_test.py
+++ b/compiler/tests/16_control_logic_test.py
@@ -1,65 +1,42 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a control_logic
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class control_logic_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
import control_logic
import tech
- # check control logic for single port
- debug.info(1, "Testing sample for control_logic")
- a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=32)
- self.local_check(a)
-
- # check control logic for multi-port
- OPTS.bitcell = "pbitcell"
- OPTS.replica_bitcell = "replica_pbitcell"
- OPTS.num_rw_ports = 1
- OPTS.num_w_ports = 0
- OPTS.num_r_ports = 0
-
- debug.info(1, "Testing sample for control_logic for multiport")
- a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8)
- self.local_check(a)
-
- # Check port specific control logic
- OPTS.num_rw_ports = 1
- OPTS.num_w_ports = 0
- OPTS.num_r_ports = 0
-
- debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
- a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="rw")
- self.local_check(a)
-
- OPTS.num_rw_ports = 0
- OPTS.num_w_ports = 1
- debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
- a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="w")
- self.local_check(a)
-
- OPTS.num_w_ports = 0
- OPTS.num_r_ports = 1
- debug.info(1, "Testing sample for control_logic for multiport, only read control logic")
- a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="r")
+ debug.info(1, "Testing sample for control_logic_rw")
+ a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=32)
self.local_check(a)
- globals.end_openram()
+ debug.info(1, "Testing sample for control_logic_r")
+ a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=32, port_type="r")
+ self.local_check(a)
+
+ debug.info(1, "Testing sample for control_logic_w")
+ a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=32, port_type="w")
+ self.local_check(a)
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/18_port_address_test.py b/compiler/tests/18_port_address_test.py
new file mode 100755
index 00000000..c8db6ec2
--- /dev/null
+++ b/compiler/tests/18_port_address_test.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys,os
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+class port_address_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+
+ debug.info(1, "Port address 16 rows")
+ a = factory.create("port_address", cols=16, rows=16)
+ self.local_check(a)
+
+ globals.end_openram()
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/18_port_data_test.py b/compiler/tests/18_port_data_test.py
new file mode 100755
index 00000000..e5f94329
--- /dev/null
+++ b/compiler/tests/18_port_data_test.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys,os
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+class port_data_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ from sram_config import sram_config
+
+ c = sram_config(word_size=4,
+ num_words=16)
+
+ c.words_per_row=1
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "No column mux")
+ a = factory.create("port_data", sram_config=c, port=0)
+ self.local_check(a)
+
+ c.num_words=32
+ c.words_per_row=2
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "Two way column mux")
+ a = factory.create("port_data", sram_config=c, port=0)
+ self.local_check(a)
+
+ c.num_words=64
+ c.words_per_row=4
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "Four way column mux")
+ a = factory.create("port_data", sram_config=c, port=0)
+ self.local_check(a)
+
+ c.word_size=2
+ c.num_words=128
+ c.words_per_row=8
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "Eight way column mux")
+ a = factory.create("port_data", sram_config=c, port=0)
+ self.local_check(a)
+
+ OPTS.bitcell = "bitcell_1w_1r"
+ OPTS.num_rw_ports = 0
+ OPTS.num_r_ports = 1
+ OPTS.num_w_ports = 1
+
+ c.num_words=16
+ c.words_per_row=1
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "No column mux")
+ a = factory.create("port_data", sram_config=c, port=0)
+ self.local_check(a)
+ a = factory.create("port_data", sram_config=c, port=1)
+ self.local_check(a)
+
+ c.num_words=32
+ c.words_per_row=2
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "Two way column mux")
+ a = factory.create("port_data", sram_config=c, port=0)
+ self.local_check(a)
+ a = factory.create("port_data", sram_config=c, port=1)
+ self.local_check(a)
+
+ c.num_words=64
+ c.words_per_row=4
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "Four way column mux")
+ a = factory.create("port_data", sram_config=c, port=0)
+ self.local_check(a)
+ a = factory.create("port_data", sram_config=c, port=1)
+ self.local_check(a)
+
+ c.word_size=2
+ c.num_words=128
+ c.words_per_row=8
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "Eight way column mux")
+ a = factory.create("port_data", sram_config=c, port=0)
+ self.local_check(a)
+ a = factory.create("port_data", sram_config=c, port=1)
+ self.local_check(a)
+
+ globals.end_openram()
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/18_port_data_wmask_test.py b/compiler/tests/18_port_data_wmask_test.py
new file mode 100755
index 00000000..e9b70337
--- /dev/null
+++ b/compiler/tests/18_port_data_wmask_test.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys, os
+
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+
+class port_data_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ from sram_config import sram_config
+
+ c = sram_config(word_size=16,
+ write_size=4,
+ num_words=16)
+
+ c.words_per_row = 1
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "No column mux")
+ a = factory.create("port_data", sram_config=c, port=0)
+ self.local_check(a)
+
+ c.num_words = 32
+ c.words_per_row = 2
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "Two way column mux")
+ a = factory.create("port_data", sram_config=c, port=0)
+ self.local_check(a)
+
+ c.num_words = 64
+ c.words_per_row = 4
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "Four way column mux")
+ a = factory.create("port_data", sram_config=c, port=0)
+ self.local_check(a)
+
+ c.num_words = 128
+ c.words_per_row = 8
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "Eight way column mux")
+ a = factory.create("port_data", sram_config=c, port=0)
+ self.local_check(a)
+
+ OPTS.bitcell = "bitcell_1w_1r"
+ OPTS.num_rw_ports = 0
+ OPTS.num_r_ports = 1
+ OPTS.num_w_ports = 1
+
+ c.num_words = 16
+ c.words_per_row = 1
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "No column mux")
+ a = factory.create("port_data", sram_config=c, port=0)
+ self.local_check(a)
+ a = factory.create("port_data", sram_config=c, port=1)
+ self.local_check(a)
+ #
+ c.num_words = 32
+ c.words_per_row = 2
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "Two way column mux")
+ a = factory.create("port_data", sram_config=c, port=0)
+ self.local_check(a)
+ a = factory.create("port_data", sram_config=c, port=1)
+ self.local_check(a)
+
+ c.num_words = 64
+ c.words_per_row = 4
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "Four way column mux")
+ a = factory.create("port_data", sram_config=c, port=0)
+ self.local_check(a)
+ a = factory.create("port_data", sram_config=c, port=1)
+ self.local_check(a)
+
+ c.word_size = 8
+ c.num_words = 128
+ c.words_per_row = 8
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "Eight way column mux")
+ a = factory.create("port_data", sram_config=c, port=0)
+ self.local_check(a)
+ a = factory.create("port_data", sram_config=c, port=1)
+ self.local_check(a)
+
+ globals.end_openram()
+
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/19_bank_select_test.py b/compiler/tests/19_bank_select_test.py
index 1245926b..e2f5a9a8 100755
--- a/compiler/tests/19_bank_select_test.py
+++ b/compiler/tests/19_bank_select_test.py
@@ -1,29 +1,32 @@
#!/usr/bin/env python3
-"""
-Run a regression test on various srams
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class bank_select_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- import bank_select
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
debug.info(1, "No column mux, rw control logic")
- a = bank_select.bank_select(port="rw")
+ a = factory.create(module_type="bank_select", port="rw")
self.local_check(a)
OPTS.bitcell = "pbitcell"
debug.info(1, "No column mux, rw control logic")
- a = bank_select.bank_select(port="rw")
+ a = factory.create(module_type="bank_select", port="rw")
self.local_check(a)
OPTS.num_rw_ports = 0
@@ -31,11 +34,11 @@ class bank_select_test(openram_test):
OPTS.num_r_ports = 1
debug.info(1, "No column mux, w control logic")
- a = bank_select.bank_select(port="w")
+ a = factory.create(module_type="bank_select", port="w")
self.local_check(a)
debug.info(1, "No column mux, r control logic")
- a = bank_select.bank_select(port="r")
+ a = factory.create(module_type="bank_select", port="r")
self.local_check(a)
globals.end_openram()
@@ -45,4 +48,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/19_multi_bank_test.py b/compiler/tests/19_multi_bank_test.py
index 0eff040d..1816cd61 100755
--- a/compiler/tests/19_multi_bank_test.py
+++ b/compiler/tests/19_multi_bank_test.py
@@ -1,22 +1,25 @@
#!/usr/bin/env python3
-"""
-Run a regression test on various srams
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
@unittest.skip("SKIPPING 19_multi_bank_test")
class multi_bank_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from bank import bank
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
c = sram_config(word_size=4,
@@ -24,31 +27,35 @@ class multi_bank_test(openram_test):
c.num_banks=2
c.words_per_row=1
+ factory.reset()
c.recompute_sizes()
debug.info(1, "No column mux")
- a = bank(c, name="bank1_multi")
+ a = factory.create("bank", sram_config=c)
self.local_check(a)
c.num_words=32
c.words_per_row=2
+ factory.reset()
c.recompute_sizes()
debug.info(1, "Two way column mux")
- a = bank(c, name="bank2_multi")
+ a = factory.create("bank", sram_config=c)
self.local_check(a)
c.num_words=64
c.words_per_row=4
+ factory.reset()
c.recompute_sizes()
debug.info(1, "Four way column mux")
- a = bank(c, name="bank3_multi")
+ a = factory.create("bank", sram_config=c)
self.local_check(a)
c.word_size=2
c.num_words=128
c.words_per_row=8
+ factory.reset()
c.recompute_sizes()
debug.info(1, "Eight way column mux")
- a = bank(c, name="bank4_multi")
+ a = factory.create("bank", sram_config=c)
self.local_check(a)
globals.end_openram()
@@ -58,4 +65,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/19_pmulti_bank_test.py b/compiler/tests/19_pmulti_bank_test.py
index 32d3917a..749460fa 100755
--- a/compiler/tests/19_pmulti_bank_test.py
+++ b/compiler/tests/19_pmulti_bank_test.py
@@ -1,22 +1,25 @@
#!/usr/bin/env python3
-"""
-Run a regression test on various srams
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
@unittest.skip("SKIPPING 19_pmulti_bank_test")
class multi_bank_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from bank import bank
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
OPTS.bitcell = "pbitcell"
@@ -29,27 +32,35 @@ class multi_bank_test(openram_test):
c.num_banks=2
c.words_per_row=1
+ factory.reset()
+ c.recompute_sizes()
debug.info(1, "No column mux")
- a = bank(c, name="bank1_multi")
+ a = factory.create("bank", sram_config=c)
self.local_check(a)
c.num_words=32
c.words_per_row=2
+ factory.reset()
+ c.recompute_sizes()
debug.info(1, "Two way column mux")
- a = bank(c, name="bank2_multi")
+ a = factory.create("bank", sram_config=c)
self.local_check(a)
c.num_words=64
c.words_per_row=4
+ factory.reset()
+ c.recompute_sizes()
debug.info(1, "Four way column mux")
- a = bank(c, name="bank3_multi")
+ a = factory.create("bank", sram_config=c)
self.local_check(a)
c.word_size=2
c.num_words=128
c.words_per_row=8
+ factory.reset()
+ c.recompute_sizes()
debug.info(1, "Eight way column mux")
- a = bank(c, name="bank4_multi")
+ a = factory.create("bank", sram_config=c)
self.local_check(a)
globals.end_openram()
@@ -59,4 +70,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/19_psingle_bank_test.py b/compiler/tests/19_psingle_bank_test.py
index 8e462318..90e886f4 100755
--- a/compiler/tests/19_psingle_bank_test.py
+++ b/compiler/tests/19_psingle_bank_test.py
@@ -1,30 +1,35 @@
#!/usr/bin/env python3
-"""
-Run a regression test on various srams
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
-import debug
from sram_factory import factory
+import debug
#@unittest.skip("SKIPPING 19_psingle_bank_test")
class psingle_bank_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from bank import bank
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
- OPTS.bitcell = "pbitcell"
- # testing layout of bank using pbitcell with 1 RW port (a 6T-cell equivalent)
+ OPTS.bitcell = "pbitcell"
+ OPTS.replica_bitcell="replica_pbitcell"
+ OPTS.dummy_bitcell="dummy_pbitcell"
+
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
+
c = sram_config(word_size=4,
num_words=16)
@@ -32,8 +37,7 @@ class psingle_bank_test(openram_test):
factory.reset()
c.recompute_sizes()
debug.info(1, "No column mux")
- name = "bank1_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports)
- a = bank(c, name=name)
+ a = factory.create(module_type="bank", sram_config=c)
self.local_check(a)
c.num_words=32
@@ -41,8 +45,7 @@ class psingle_bank_test(openram_test):
factory.reset()
c.recompute_sizes()
debug.info(1, "Two way column mux")
- name = "bank2_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports)
- a = bank(c, name=name)
+ a = factory.create(module_type="bank", sram_config=c)
self.local_check(a)
c.num_words=64
@@ -50,8 +53,7 @@ class psingle_bank_test(openram_test):
factory.reset()
c.recompute_sizes()
debug.info(1, "Four way column mux")
- name = "bank3_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports)
- a = bank(c, name=name)
+ a = factory.create(module_type="bank", sram_config=c)
self.local_check(a)
c.word_size=2
@@ -60,93 +62,9 @@ class psingle_bank_test(openram_test):
factory.reset()
c.recompute_sizes()
debug.info(1, "Four way column mux")
- name = "bank4_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports)
- a = bank(c, name=name)
+ a = factory.create(module_type="bank", sram_config=c)
self.local_check(a)
-
- # testing bank using pbitcell in various port combinations
- # layout for multiple ports does not work yet
- """
- OPTS.netlist_only = True
-
- c.num_words=16
- c.words_per_row=1
-
- OPTS.num_rw_ports = c.num_rw_ports = 2
- OPTS.num_w_ports = c.num_w_ports = 2
- OPTS.num_r_ports = c.num_r_ports = 2
-
- debug.info(1, "No column mux")
- name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
- a = bank(c, name=name)
- self.local_check(a)
-
- OPTS.num_rw_ports = c.num_rw_ports = 0
- OPTS.num_w_ports = c.num_w_ports = 2
- OPTS.num_r_ports = c.num_r_ports = 2
-
- debug.info(1, "No column mux")
- name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
- a = bank(c, name=name)
- self.local_check(a)
-
- OPTS.num_rw_ports = c.num_rw_ports = 2
- OPTS.num_w_ports = c.num_w_ports = 0
- OPTS.num_r_ports = c.num_r_ports = 2
-
- debug.info(1, "No column mux")
- name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
- a = bank(c, name=name)
- self.local_check(a)
-
- OPTS.num_rw_ports = c.num_rw_ports = 2
- OPTS.num_w_ports = c.num_w_ports = 2
- OPTS.num_r_ports = c.num_r_ports = 0
-
- debug.info(1, "No column mux")
- name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
- a = bank(c, name=name)
- self.local_check(a)
-
- OPTS.num_rw_ports = c.num_rw_ports = 2
- OPTS.num_w_ports = c.num_w_ports = 0
- OPTS.num_r_ports = c.num_r_ports = 0
-
- debug.info(1, "No column mux")
- name = "bank1_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
- a = bank(c, name=name)
- self.local_check(a)
-
- # testing with various column muxes
- OPTS.num_rw_ports = c.num_rw_ports = 2
- OPTS.num_w_ports = c.num_w_ports = 2
- OPTS.num_r_ports = c.num_r_ports = 2
-
- c.num_words=32
- c.words_per_row=2
- debug.info(1, "Two way column mux")
- name = "bank2_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
- a = bank(c, name=name)
- self.local_check(a)
-
- c.num_words=64
- c.words_per_row=4
- debug.info(1, "Four way column mux")
- name = "bank3_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
- a = bank(c, name=name)
- self.local_check(a)
-
- # Eight way has a short circuit of one column mux select to gnd rail
- c.word_size=2
- c.num_words=128
- c.words_per_row=8
- debug.info(1, "Eight way column mux")
- name = "bank4_{0}rw_{1}w_{2}r_single".format(c.num_rw_ports, c.num_w_ports, c.num_r_ports)
- a = bank(c, name=name)
- self.local_check(a)
- """
-
globals.end_openram()
# run the test from the command line
@@ -154,4 +72,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/19_single_bank_1rw_1r_test.py b/compiler/tests/19_single_bank_1rw_1r_test.py
index 93bfd35a..ab5ce041 100755
--- a/compiler/tests/19_single_bank_1rw_1r_test.py
+++ b/compiler/tests/19_single_bank_1rw_1r_test.py
@@ -1,53 +1,66 @@
#!/usr/bin/env python3
-"""
-Run a regression test on 1rw 1r sram bank
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class single_bank_1rw_1r_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from bank import bank
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ from sram_config import sram_config
OPTS.bitcell = "bitcell_1rw_1r"
+ OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
+ OPTS.dummy_bitcell="dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
- from sram_config import sram_config
c = sram_config(word_size=4,
num_words=16)
c.words_per_row=1
+ factory.reset()
+ c.recompute_sizes()
debug.info(1, "No column mux")
- a = bank(c, name="bank1_single")
+ a = factory.create(module_type="bank", sram_config=c)
self.local_check(a)
c.num_words=32
c.words_per_row=2
+ factory.reset()
+ c.recompute_sizes()
debug.info(1, "Two way column mux")
- a = bank(c, name="bank2_single")
+ a = factory.create(module_type="bank", sram_config=c)
self.local_check(a)
c.num_words=64
c.words_per_row=4
+ factory.reset()
+ c.recompute_sizes()
debug.info(1, "Four way column mux")
- a = bank(c, name="bank3_single")
+ a = factory.create(module_type="bank", sram_config=c)
self.local_check(a)
c.word_size=2
c.num_words=128
c.words_per_row=8
+ factory.reset()
+ c.recompute_sizes()
debug.info(1, "Eight way column mux")
- a = bank(c, name="bank4_single")
+ a = factory.create(module_type="bank", sram_config=c)
self.local_check(a)
globals.end_openram()
@@ -57,4 +70,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/19_single_bank_1w_1r_test.py b/compiler/tests/19_single_bank_1w_1r_test.py
new file mode 100755
index 00000000..12b9f3a0
--- /dev/null
+++ b/compiler/tests/19_single_bank_1w_1r_test.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys,os
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+class single_bank_1w_1r_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ from sram_config import sram_config
+
+ OPTS.bitcell = "bitcell_1w_1r"
+ OPTS.replica_bitcell = "replica_bitcell_1w_1r"
+ OPTS.dummy_bitcell="dummy_bitcell_1w_1r"
+
+ OPTS.num_rw_ports = 0
+ OPTS.num_r_ports = 1
+ OPTS.num_w_ports = 1
+
+ c = sram_config(word_size=4,
+ num_words=16)
+
+ c.words_per_row=1
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "No column mux")
+ a = factory.create(module_type="bank", sram_config=c)
+ self.local_check(a)
+
+ c.num_words=32
+ c.words_per_row=2
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "Two way column mux")
+ a = factory.create(module_type="bank", sram_config=c)
+ self.local_check(a)
+
+ c.num_words=64
+ c.words_per_row=4
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "Four way column mux")
+ a = factory.create(module_type="bank", sram_config=c)
+ self.local_check(a)
+
+ c.word_size=2
+ c.num_words=128
+ c.words_per_row=8
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "Eight way column mux")
+ a = factory.create(module_type="bank", sram_config=c)
+ self.local_check(a)
+
+ globals.end_openram()
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/19_single_bank_test.py b/compiler/tests/19_single_bank_test.py
index e7179d96..1d010db5 100755
--- a/compiler/tests/19_single_bank_test.py
+++ b/compiler/tests/19_single_bank_test.py
@@ -1,48 +1,59 @@
#!/usr/bin/env python3
-"""
-Run a regression test on various srams
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class single_bank_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from bank import bank
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=16)
c.words_per_row=1
+ factory.reset()
+ c.recompute_sizes()
debug.info(1, "No column mux")
- a = bank(c, name="bank1_single")
+ a = factory.create("bank", sram_config=c)
self.local_check(a)
c.num_words=32
c.words_per_row=2
+ factory.reset()
+ c.recompute_sizes()
debug.info(1, "Two way column mux")
- a = bank(c, name="bank2_single")
+ a = factory.create("bank", sram_config=c)
self.local_check(a)
c.num_words=64
c.words_per_row=4
+ factory.reset()
+ c.recompute_sizes()
debug.info(1, "Four way column mux")
- a = bank(c, name="bank3_single")
+ a = factory.create("bank", sram_config=c)
self.local_check(a)
c.word_size=2
c.num_words=128
c.words_per_row=8
+ factory.reset()
+ c.recompute_sizes()
debug.info(1, "Eight way column mux")
- a = bank(c, name="bank4_single")
+ a = factory.create("bank", sram_config=c)
self.local_check(a)
globals.end_openram()
@@ -52,4 +63,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/19_single_bank_wmask_test.py b/compiler/tests/19_single_bank_wmask_test.py
new file mode 100755
index 00000000..439ffeba
--- /dev/null
+++ b/compiler/tests/19_single_bank_wmask_test.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys,os
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+class single_bank_wmask_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ from sram_config import sram_config
+
+
+ c = sram_config(word_size=8,
+ write_size=4,
+ num_words=16,
+ num_banks=1)
+
+ c.words_per_row=1
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "No column mux")
+ a = factory.create("bank", sram_config=c)
+ self.local_check(a)
+
+ c.num_words=32
+ c.words_per_row=2
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "Two way column mux")
+ a = factory.create("bank", sram_config=c)
+ self.local_check(a)
+
+ c.num_words=64
+ c.words_per_row=4
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "Four way column mux")
+ a = factory.create("bank", sram_config=c)
+ self.local_check(a)
+
+ c.num_words=128
+ c.words_per_row=8
+ factory.reset()
+ c.recompute_sizes()
+ debug.info(1, "Eight way column mux")
+ a = factory.create("bank", sram_config=c)
+ self.local_check(a)
+
+ globals.end_openram()
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/20_psram_1bank_2mux_1rw_1w_test.py b/compiler/tests/20_psram_1bank_2mux_1rw_1w_test.py
index f2f6386c..fdeae56f 100755
--- a/compiler/tests/20_psram_1bank_2mux_1rw_1w_test.py
+++ b/compiler/tests/20_psram_1bank_2mux_1rw_1w_test.py
@@ -1,26 +1,30 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a 1 bank SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 20_psram_1bank_test, multiport layout not complete")
class psram_1bank_2mux_1rw_1w_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from sram import sram
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
+
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell"
-
+ OPTS.dummy_bitcell="dummy_pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 1
OPTS.num_r_ports = 0
@@ -31,14 +35,16 @@ class psram_1bank_2mux_1rw_1w_test(openram_test):
c.num_words=32
c.words_per_row=2
c.recompute_sizes()
- debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
- OPTS.num_r_ports,
- OPTS.num_w_ports,
- c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- a = sram(c, "sram")
+ debug.info(1, "Layout test for {}rw,{}r,{}w psram "
+ "with {} bit words, {} words, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
globals.end_openram()
@@ -48,4 +54,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/20_psram_1bank_2mux_1rw_1w_wmask_test.py b/compiler/tests/20_psram_1bank_2mux_1rw_1w_wmask_test.py
new file mode 100755
index 00000000..20fbd8e6
--- /dev/null
+++ b/compiler/tests/20_psram_1bank_2mux_1rw_1w_wmask_test.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys, os
+
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+
+# @unittest.skip("SKIPPING psram_1bank_2mux_1rw_1w_wmask_test, multiport layout not complete")
+class psram_1bank_2mux_1rw_1w_wmask_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ from sram_config import sram_config
+
+ OPTS.bitcell = "pbitcell"
+ OPTS.replica_bitcell = "replica_pbitcell"
+ OPTS.dummy_bitcell = "dummy_pbitcell"
+ OPTS.num_rw_ports = 1
+ OPTS.num_w_ports = 1
+ OPTS.num_r_ports = 0
+
+ c = sram_config(word_size=8,
+ write_size=4,
+ num_words=32,
+ num_banks=1)
+ c.num_words = 32
+ c.words_per_row = 2
+ c.recompute_sizes()
+ debug.info(1, "Layout test for {}rw,{}r,{}w psram "
+ "with {} bit words, {} words, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ a = factory.create(module_type="sram", sram_config=c)
+ self.local_check(a, final_verification=True)
+
+ globals.end_openram()
+
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
\ No newline at end of file
diff --git a/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py b/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py
index 3d049aef..a5c01d8f 100755
--- a/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py
+++ b/compiler/tests/20_psram_1bank_2mux_1w_1r_test.py
@@ -1,26 +1,30 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a 1 bank SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 20_psram_1bank_2mux_1w_1r_test, odd supply routing error")
class psram_1bank_2mux_1w_1r_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from sram import sram
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
+
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell"
-
+ OPTS.dummy_bitcell="dummy_pbitcell"
OPTS.num_rw_ports = 0
OPTS.num_w_ports = 1
OPTS.num_r_ports = 1
@@ -38,7 +42,7 @@ class psram_1bank_2mux_1w_1r_test(openram_test):
c.num_words,
c.words_per_row,
c.num_banks))
- a = sram(c, "sram")
+ a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
globals.end_openram()
@@ -48,4 +52,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/20_psram_1bank_2mux_test.py b/compiler/tests/20_psram_1bank_2mux_test.py
index 3afd2c9b..64fa72ca 100755
--- a/compiler/tests/20_psram_1bank_2mux_test.py
+++ b/compiler/tests/20_psram_1bank_2mux_test.py
@@ -1,25 +1,29 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a 1 bank SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 20_psram_1bank_2mux_test, wide metal supply routing error")
class psram_1bank_2mux_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from sram import sram
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell"
+ OPTS.dummy_bitcell="dummy_pbitcell"
# testing layout of sram using pbitcell with 1 RW port (a 6T-cell equivalent)
OPTS.num_rw_ports = 1
@@ -32,14 +36,16 @@ class psram_1bank_2mux_test(openram_test):
c.num_words=32
c.words_per_row=2
c.recompute_sizes()
- debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
- OPTS.num_r_ports,
- OPTS.num_w_ports,
- c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- a = sram(c, "sram")
+ debug.info(1, "Layout test for {}rw,{}r,{}w psram "
+ "with {} bit words, {} words, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
globals.end_openram()
@@ -49,4 +55,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/20_psram_1bank_4mux_1rw_1r_test.py b/compiler/tests/20_psram_1bank_4mux_1rw_1r_test.py
index 1be26ca7..7779b794 100755
--- a/compiler/tests/20_psram_1bank_4mux_1rw_1r_test.py
+++ b/compiler/tests/20_psram_1bank_4mux_1rw_1r_test.py
@@ -1,25 +1,29 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a 1 bank SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class psram_1bank_4mux_1rw_1r_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from sram import sram
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
+
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell"
-
+ OPTS.dummy_bitcell="dummy_pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 1
@@ -30,14 +34,16 @@ class psram_1bank_4mux_1rw_1r_test(openram_test):
c.num_words=64
c.words_per_row=4
c.recompute_sizes()
- debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
- OPTS.num_r_ports,
- OPTS.num_w_ports,
- c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- a = sram(c, "sram")
+ debug.info(1, "Layout test for {}rw,{}r,{}w psram "
+ "with {} bit words, {} words, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
globals.end_openram()
@@ -47,4 +53,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/20_sram_1bank_2mux_1rw_1r_test.py b/compiler/tests/20_sram_1bank_2mux_1rw_1r_test.py
index ea5fba78..60192759 100755
--- a/compiler/tests/20_sram_1bank_2mux_1rw_1r_test.py
+++ b/compiler/tests/20_sram_1bank_2mux_1rw_1r_test.py
@@ -1,25 +1,29 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a 1 bank, 2 port SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class sram_1bank_2mux_1rw_1r_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from sram import sram
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
+ OPTS.dummy_bitcell="dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
@@ -30,14 +34,16 @@ class sram_1bank_2mux_1rw_1r_test(openram_test):
c.words_per_row=2
c.recompute_sizes()
- debug.info(1, "Layout test for {}rw,{}r,{}w sram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
- OPTS.num_r_ports,
- OPTS.num_w_ports,
- c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- a = sram(c, "sram")
+ debug.info(1, "Layout test for {}rw,{}r,{}w sram "
+ "with {} bit words, {} words, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
globals.end_openram()
@@ -47,4 +53,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/20_sram_1bank_2mux_1w_1r_test.py b/compiler/tests/20_sram_1bank_2mux_1w_1r_test.py
index 2954ffbc..2e1e848f 100755
--- a/compiler/tests/20_sram_1bank_2mux_1w_1r_test.py
+++ b/compiler/tests/20_sram_1bank_2mux_1w_1r_test.py
@@ -1,26 +1,30 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a 1 bank SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 20_psram_1bank_2mux_1w_1r_test, odd supply routing error")
class psram_1bank_2mux_1w_1r_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from sram import sram
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
+
OPTS.bitcell = "bitcell_1w_1r"
OPTS.replica_bitcell="replica_bitcell_1w_1r"
-
+ OPTS.dummy_bitcell="dummy_bitcell_1w_1r"
OPTS.num_rw_ports = 0
OPTS.num_w_ports = 1
OPTS.num_r_ports = 1
@@ -31,14 +35,16 @@ class psram_1bank_2mux_1w_1r_test(openram_test):
c.num_words=32
c.words_per_row=2
c.recompute_sizes()
- debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
- OPTS.num_r_ports,
- OPTS.num_w_ports,
- c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- a = sram(c, "sram")
+ debug.info(1, "Layout test for {}rw,{}r,{}w sram "
+ "with {} bit words, {} words, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
globals.end_openram()
@@ -48,4 +54,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/20_sram_1bank_2mux_test.py b/compiler/tests/20_sram_1bank_2mux_test.py
index 26a7755f..7e5a4f3a 100755
--- a/compiler/tests/20_sram_1bank_2mux_test.py
+++ b/compiler/tests/20_sram_1bank_2mux_test.py
@@ -1,22 +1,25 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a 1 bank SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 20_sram_1bank_2mux_test")
class sram_1bank_2mux_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from sram import sram
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=32,
@@ -24,14 +27,16 @@ class sram_1bank_2mux_test(openram_test):
c.words_per_row=2
c.recompute_sizes()
- debug.info(1, "Layout test for {}rw,{}r,{}w sram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
- OPTS.num_r_ports,
- OPTS.num_w_ports,
- c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- a = sram(c, "sram")
+ debug.info(1, "Layout test for {}rw,{}r,{}w sram "
+ "with {} bit words, {} words, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
globals.end_openram()
@@ -41,4 +46,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/20_sram_1bank_2mux_wmask_test.py b/compiler/tests/20_sram_1bank_2mux_wmask_test.py
new file mode 100755
index 00000000..65f025a7
--- /dev/null
+++ b/compiler/tests/20_sram_1bank_2mux_wmask_test.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys, os
+
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+
+# @unittest.skip("SKIPPING 20_sram_1bank_2mux_wmask_test")
+class sram_1bank_2mux_wmask_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ from sram_config import sram_config
+ c = sram_config(word_size=8,
+ write_size=4,
+ num_words=64,
+ num_banks=1)
+
+ c.words_per_row = 2
+ c.recompute_sizes()
+ debug.info(1, "Layout test for {}rw,{}r,{}w sram "
+ "with {} bit words, {} words, {} bit writes, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.write_size,
+ c.words_per_row,
+ c.num_banks))
+ a = factory.create(module_type="sram", sram_config=c)
+ self.local_check(a, final_verification=True)
+
+ globals.end_openram()
+
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
\ No newline at end of file
diff --git a/compiler/tests/20_sram_1bank_32b_1024_wmask_test.py b/compiler/tests/20_sram_1bank_32b_1024_wmask_test.py
new file mode 100755
index 00000000..a5232267
--- /dev/null
+++ b/compiler/tests/20_sram_1bank_32b_1024_wmask_test.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys, os
+
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+
+@unittest.skip("SKIPPING sram_1bank_32b_1024_wmask_test")
+class sram_1bank_32b_1024_wmask_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ from sram_config import sram_config
+ c = sram_config(word_size=32,
+ write_size=8,
+ num_words=1024,
+ num_banks=1)
+
+ c.recompute_sizes()
+ debug.info(1, "Layout test for {}rw,{}r,{}w sram "
+ "with {} bit words, {} words, {} bit writes, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.write_size,
+ c.words_per_row,
+ c.num_banks))
+ a = factory.create(module_type="sram", sram_config=c)
+ self.local_check(a, final_verification=True)
+
+ globals.end_openram()
+
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
\ No newline at end of file
diff --git a/compiler/tests/20_sram_1bank_4mux_test.py b/compiler/tests/20_sram_1bank_4mux_test.py
index 16654be5..34af86a1 100755
--- a/compiler/tests/20_sram_1bank_4mux_test.py
+++ b/compiler/tests/20_sram_1bank_4mux_test.py
@@ -1,22 +1,25 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a 1 bank SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 20_sram_1bank_4mux_test")
class sram_1bank_4mux_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from sram import sram
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=64,
@@ -24,14 +27,16 @@ class sram_1bank_4mux_test(openram_test):
c.words_per_row=4
c.recompute_sizes()
- debug.info(1, "Layout test for {}rw,{}r,{}w sram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
- OPTS.num_r_ports,
- OPTS.num_w_ports,
- c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- a = sram(c, "sram")
+ debug.info(1, "Layout test for {}rw,{}r,{}w sram "
+ "with {} bit words, {} words, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
globals.end_openram()
@@ -41,4 +46,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/20_sram_1bank_8mux_1rw_1r_test.py b/compiler/tests/20_sram_1bank_8mux_1rw_1r_test.py
index dfd8a6a1..48a42106 100755
--- a/compiler/tests/20_sram_1bank_8mux_1rw_1r_test.py
+++ b/compiler/tests/20_sram_1bank_8mux_1rw_1r_test.py
@@ -1,25 +1,29 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a 1 bank SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class sram_1bank_8mux_1rw_1r_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from sram import sram
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
+ OPTS.dummy_bitcell="dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
@@ -30,14 +34,16 @@ class sram_1bank_8mux_1rw_1r_test(openram_test):
c.words_per_row=8
c.recompute_sizes()
- debug.info(1, "Layout test for {}rw,{}r,{}w sram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
- OPTS.num_r_ports,
- OPTS.num_w_ports,
- c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- a = sram(c, "sram")
+ debug.info(1, "Layout test for {}rw,{}r,{}w sram "
+ "with {} bit words, {} words, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
globals.end_openram()
@@ -47,4 +53,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/20_sram_1bank_8mux_test.py b/compiler/tests/20_sram_1bank_8mux_test.py
index dde1a448..c5eaea75 100755
--- a/compiler/tests/20_sram_1bank_8mux_test.py
+++ b/compiler/tests/20_sram_1bank_8mux_test.py
@@ -1,22 +1,25 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a 1 bank SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 20_sram_1bank_8mux_test")
class sram_1bank_8mux_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from sram import sram
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
c = sram_config(word_size=2,
num_words=128,
@@ -24,14 +27,16 @@ class sram_1bank_8mux_test(openram_test):
c.words_per_row=8
c.recompute_sizes()
- debug.info(1, "Layout test for {}rw,{}r,{}w sram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
- OPTS.num_r_ports,
- OPTS.num_w_ports,
- c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- a = sram(c, "sram")
+ debug.info(1, "Layout test for {}rw,{}r,{}w sram "
+ "with {} bit words, {} words, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
globals.end_openram()
@@ -41,4 +46,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/20_sram_1bank_nomux_1rw_1r_test.py b/compiler/tests/20_sram_1bank_nomux_1rw_1r_test.py
index 02e82687..f6bccc13 100755
--- a/compiler/tests/20_sram_1bank_nomux_1rw_1r_test.py
+++ b/compiler/tests/20_sram_1bank_nomux_1rw_1r_test.py
@@ -1,25 +1,29 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a 1 bank, 2 port SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class sram_1bank_nomux_1rw_1r_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from sram import sram
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
+ OPTS.dummy_bitcell = "dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
@@ -30,14 +34,16 @@ class sram_1bank_nomux_1rw_1r_test(openram_test):
c.words_per_row=1
c.recompute_sizes()
- debug.info(1, "Layout test for {}rw,{}r,{}w sram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
- OPTS.num_r_ports,
- OPTS.num_w_ports,
- c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- a = sram(c, "sram")
+ debug.info(1, "Layout test for {}rw,{}r,{}w sram "
+ "with {} bit words, {} words, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
globals.end_openram()
@@ -47,4 +53,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/20_sram_1bank_nomux_test.py b/compiler/tests/20_sram_1bank_nomux_test.py
index 7a03ce1e..650d2ac2 100755
--- a/compiler/tests/20_sram_1bank_nomux_test.py
+++ b/compiler/tests/20_sram_1bank_nomux_test.py
@@ -1,22 +1,25 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a 1 bank SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 20_sram_1bank_nomux_test")
class sram_1bank_nomux_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from sram import sram
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=16,
@@ -24,14 +27,16 @@ class sram_1bank_nomux_test(openram_test):
c.words_per_row=1
c.recompute_sizes()
- debug.info(1, "Layout test for {}rw,{}r,{}w sram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
- OPTS.num_r_ports,
- OPTS.num_w_ports,
- c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- a = sram(c, "sram")
+ debug.info(1, "Layout test for {}rw,{}r,{}w sram "
+ "with {} bit words, {} words, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
globals.end_openram()
@@ -41,4 +46,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/20_sram_1bank_nomux_wmask_test.py b/compiler/tests/20_sram_1bank_nomux_wmask_test.py
new file mode 100755
index 00000000..e0292e95
--- /dev/null
+++ b/compiler/tests/20_sram_1bank_nomux_wmask_test.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys, os
+
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+
+# @unittest.skip("SKIPPING 20_sram_1bank_nomux_wmask_test")
+class sram_1bank_nomux_wmask_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ from sram_config import sram_config
+ c = sram_config(word_size=8,
+ write_size=4,
+ num_words=16,
+ num_banks=1)
+
+ c.words_per_row = 1
+ c.recompute_sizes()
+ debug.info(1, "Layout test for {}rw,{}r,{}w sram "
+ "with {} bit words, {} words, {} bit writes, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.write_size,
+ c.words_per_row,
+ c.num_banks))
+ a = factory.create(module_type="sram", sram_config=c)
+ self.local_check(a, final_verification=True)
+
+ globals.end_openram()
+
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
\ No newline at end of file
diff --git a/compiler/tests/20_sram_2bank_test.py b/compiler/tests/20_sram_2bank_test.py
index 59db981d..c5d9d3d0 100755
--- a/compiler/tests/20_sram_2bank_test.py
+++ b/compiler/tests/20_sram_2bank_test.py
@@ -1,22 +1,25 @@
#!/usr/bin/env python3
-"""
-Run a regression test on a 2 bank SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
@unittest.skip("Multibank is not working yet.")
class sram_2bank_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- from sram import sram
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram_config import sram_config
c = sram_config(word_size=16,
num_words=32,
@@ -24,30 +27,66 @@ class sram_2bank_test(openram_test):
c.words_per_row=1
c.recompute_sizes()
- debug.info(1, "Two bank, no column mux with control logic")
- a = sram(c, "sram1")
+ debug.info(1, "Layout test for {}rw,{}r,{}w sram "
+ "with {} bit words, {} words, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ factory.reset()
+ a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
c.num_words=64
c.words_per_row=2
c.recompute_sizes()
- debug.info(1, "Two bank two way column mux with control logic")
- a = sram(c, "sram2")
+ debug.info(1, "Layout test for {}rw,{}r,{}w sram "
+ "with {} bit words, {} words, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ factory.reset()
+ a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
c.num_words=128
c.words_per_row=4
c.recompute_sizes()
- debug.info(1, "Two bank, four way column mux with control logic")
- a = sram(c, "sram3")
+ debug.info(1, "Layout test for {}rw,{}r,{}w sram "
+ "with {} bit words, {} words, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ factory.reset()
+ a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
c.word_size=2
c.num_words=256
c.words_per_row=8
c.recompute_sizes()
- debug.info(1, "Two bank, eight way column mux with control logic")
- a = sram(c, "sram4")
+ debug.info(1, "Layout test for {}rw,{}r,{}w sram "
+ "with {} bit words, {} words, {} words per "
+ "row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ factory.reset()
+ a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
globals.end_openram()
@@ -57,4 +96,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/21_hspice_delay_test.py b/compiler/tests/21_hspice_delay_test.py
index fa7fc35f..e2222fcf 100755
--- a/compiler/tests/21_hspice_delay_test.py
+++ b/compiler/tests/21_hspice_delay_test.py
@@ -1,20 +1,24 @@
#!/usr/bin/env python3
-"""
-Run a regression test on various srams
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class timing_sram_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.spice_name="hspice"
OPTS.analytical_delay = False
OPTS.netlist_only = True
@@ -24,16 +28,22 @@ class timing_sram_test(openram_test):
import characterizer
reload(characterizer)
from characterizer import delay
- from sram import sram
from sram_config import sram_config
c = sram_config(word_size=1,
num_words=16,
num_banks=1)
c.words_per_row=1
+ # c = sram_config(word_size=32,
+ # num_words=256,
+ # num_banks=1)
+ # c.words_per_row=2
+ # OPTS.use_tech_delay_chain_size = True
c.recompute_sizes()
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
- s = sram(c, name="sram1")
-
+ s = factory.create(module_type="sram", sram_config=c)
+ #import sys
+ #sys.exit(1)
+
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
@@ -44,43 +54,34 @@ class timing_sram_test(openram_test):
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
d = delay(s.s, tempspice, corner)
import tech
- loads = [tech.spice["msflop_in_cap"]*4]
+ loads = [tech.spice["dff_in_cap"]*4]
slews = [tech.spice["rise_time"]*2]
data, port_data = d.analyze(probe_address, probe_data, slews, loads)
#Combine info about port into all data
data.update(port_data[0])
if OPTS.tech_name == "freepdk45":
- golden_data = {'delay_bl': [0.1980959],
- 'delay_br': [0.1946091],
- 'delay_hl': [0.2121267],
- 'delay_lh': [0.2121267],
- 'leakage_power': 0.0023761999999999998,
- 'min_period': 0.43,
- 'read0_power': [0.5139368],
- 'read1_power': [0.48940979999999995],
- 'slew_hl': [0.0516745],
- 'slew_lh': [0.0516745],
- 'volt_bl': [0.5374525],
- 'volt_br': [1.1058],
- 'write0_power': [0.46267169999999996],
- 'write1_power': [0.4670826]}
+ golden_data = {'delay_hl': [0.2181231],
+ 'delay_lh': [0.2181231],
+ 'leakage_power': 0.0025453999999999997,
+ 'min_period': 0.781,
+ 'read0_power': [0.34664159999999994],
+ 'read1_power': [0.32656349999999995],
+ 'slew_hl': [0.21136519999999998],
+ 'slew_lh': [0.21136519999999998],
+ 'write0_power': [0.37980179999999997],
+ 'write1_power': [0.3532026]}
elif OPTS.tech_name == "scn4m_subm":
- golden_data = {'delay_bl': [1.1029],
- 'delay_br': [0.9656455999999999],
- 'delay_hl': [1.288],
- 'delay_lh': [1.288],
- 'leakage_power': 0.0273896,
- 'min_period': 2.578,
- 'read0_power': [16.9996],
- 'read1_power': [16.2616],
- 'slew_hl': [0.47891700000000004],
- 'slew_lh': [0.47891700000000004],
- 'volt_bl': [4.2155],
- 'volt_br': [5.8142],
- 'write0_power': [16.0656],
- 'write1_power': [16.2616]}
-
+ golden_data = {'delay_hl': [1.4082],
+ 'delay_lh': [1.4082],
+ 'leakage_power': 0.0267388,
+ 'min_period': 4.688,
+ 'read0_power': [11.5255],
+ 'read1_power': [10.9406],
+ 'slew_hl': [1.2979],
+ 'slew_lh': [1.2979],
+ 'write0_power': [12.9458],
+ 'write1_power': [11.7444]}
else:
self.assertTrue(False) # other techs fail
# Check if no too many or too few results
@@ -95,4 +96,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/21_hspice_setuphold_test.py b/compiler/tests/21_hspice_setuphold_test.py
index c003f54a..ef5cf1a8 100755
--- a/compiler/tests/21_hspice_setuphold_test.py
+++ b/compiler/tests/21_hspice_setuphold_test.py
@@ -1,20 +1,24 @@
#!/usr/bin/env python3
-"""
-Run a regression test on various srams
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class timing_setup_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.spice_name="hspice"
OPTS.analytical_delay = False
OPTS.netlist_only = True
@@ -57,4 +61,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/21_model_delay_test.py b/compiler/tests/21_model_delay_test.py
new file mode 100755
index 00000000..a4de4c2a
--- /dev/null
+++ b/compiler/tests/21_model_delay_test.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys,os
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+# @unittest.skip("SKIPPING 21_model_delay_test")
+class model_delay_test(openram_test):
+ """ Compare the accuracy of the analytical model with a spice simulation. """
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ OPTS.analytical_delay = False
+ OPTS.netlist_only = True
+
+ # This is a hack to reload the characterizer __init__ with the spice version
+ from importlib import reload
+ import characterizer
+ reload(characterizer)
+ from characterizer import delay
+ from sram import sram
+ from sram_config import sram_config
+ c = sram_config(word_size=1,
+ num_words=16,
+ num_banks=1)
+ c.words_per_row=1
+ c.recompute_sizes()
+ debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
+ s = factory.create(module_type="sram", sram_config=c)
+
+ tempspice = OPTS.openram_temp + "temp.sp"
+ s.sp_write(tempspice)
+
+ probe_address = "1" * s.s.addr_size
+ probe_data = s.s.word_size - 1
+ debug.info(1, "Probe address {0} probe data bit {1}".format(probe_address, probe_data))
+
+ corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
+ d = delay(s.s, tempspice, corner)
+ import tech
+ loads = [tech.spice["dff_in_cap"]*4]
+ slews = [tech.spice["rise_time"]*2]
+
+ # Run a spice characterization
+ spice_data, port_data = d.analyze(probe_address, probe_data, slews, loads)
+ spice_data.update(port_data[0])
+
+ # Run analytical characterization
+ model_data, port_data = d.analytical_delay(slews, loads)
+ model_data.update(port_data[0])
+
+ # Only compare the delays
+ spice_delays = {key:value for key, value in spice_data.items() if 'delay' in key}
+ model_delays = {key:value for key, value in model_data.items() if 'delay' in key}
+ debug.info(1,"Spice Delays={}".format(spice_delays))
+ debug.info(1,"Model Delays={}".format(model_delays))
+
+ if OPTS.tech_name == "freepdk45":
+ error_tolerance = 0.25
+ elif OPTS.tech_name == "scn4m_subm":
+ error_tolerance = 0.25
+ else:
+ self.assertTrue(False) # other techs fail
+
+ # Check if no too many or too few results
+ self.assertTrue(len(spice_delays.keys())==len(model_delays.keys()))
+
+ self.assertTrue(self.check_golden_data(spice_delays,model_delays,error_tolerance))
+
+ globals.end_openram()
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/21_ngspice_delay_test.py b/compiler/tests/21_ngspice_delay_test.py
index 5af44e69..0fe5dfdd 100755
--- a/compiler/tests/21_ngspice_delay_test.py
+++ b/compiler/tests/21_ngspice_delay_test.py
@@ -1,20 +1,24 @@
#!/usr/bin/env python3
-"""
-Run a regression test on various srams
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class timing_sram_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.spice_name="ngspice"
OPTS.analytical_delay = False
OPTS.netlist_only = True
@@ -24,7 +28,6 @@ class timing_sram_test(openram_test):
import characterizer
reload(characterizer)
from characterizer import delay
- from sram import sram
from sram_config import sram_config
c = sram_config(word_size=1,
num_words=16,
@@ -32,7 +35,7 @@ class timing_sram_test(openram_test):
c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
- s = sram(c, name="sram1")
+ s = factory.create(module_type="sram", sram_config=c)
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
@@ -44,43 +47,34 @@ class timing_sram_test(openram_test):
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
d = delay(s.s, tempspice, corner)
import tech
- loads = [tech.spice["msflop_in_cap"]*4]
+ loads = [tech.spice["dff_in_cap"]*4]
slews = [tech.spice["rise_time"]*2]
data, port_data = d.analyze(probe_address, probe_data, slews, loads)
#Combine info about port into all data
data.update(port_data[0])
if OPTS.tech_name == "freepdk45":
- golden_data = {'delay_bl': [0.2003652],
- 'delay_br': [0.198698],
- 'delay_hl': [0.2108836],
- 'delay_lh': [0.2108836],
- 'leakage_power': 0.001564799,
- 'min_period': 0.508,
- 'read0_power': [0.43916689999999997],
- 'read1_power': [0.4198608],
- 'slew_hl': [0.0455126],
- 'slew_lh': [0.0455126],
- 'volt_bl': [0.6472883],
- 'volt_br': [1.114024],
- 'write0_power': [0.40681890000000004],
- 'write1_power': [0.4198608]}
+ golden_data = {'delay_hl': [0.2264205],
+ 'delay_lh': [0.2264205],
+ 'leakage_power': 0.0021017429999999997,
+ 'min_period': 0.859,
+ 'read0_power': [0.3339161],
+ 'read1_power': [0.31329440000000003],
+ 'slew_hl': [0.2590786],
+ 'slew_lh': [0.2590786],
+ 'write0_power': [0.36360849999999995],
+ 'write1_power': [0.3486931]}
elif OPTS.tech_name == "scn4m_subm":
- golden_data = {'delay_bl': [1.3937359999999999],
- 'delay_br': [1.2596429999999998],
- 'delay_hl': [1.5747600000000002],
- 'delay_lh': [1.5747600000000002],
- 'leakage_power': 0.00195795,
- 'min_period': 3.281,
- 'read0_power': [14.92874],
- 'read1_power': [14.369810000000001],
- 'slew_hl': [0.49631959999999997],
- 'slew_lh': [0.49631959999999997],
- 'volt_bl': [4.132618],
- 'volt_br': [5.573099],
- 'write0_power': [13.79953],
- 'write1_power': [14.369810000000001]}
-
+ golden_data = {'delay_hl': [1.7083549999999998],
+ 'delay_lh': [1.7083549999999998],
+ 'leakage_power': 0.001119657,
+ 'min_period': 7.812,
+ 'read0_power': [8.013845],
+ 'read1_power': [7.6889389999999995],
+ 'slew_hl': [1.31918],
+ 'slew_lh': [1.31918],
+ 'write0_power': [8.791557000000001],
+ 'write1_power': [8.70443]}
else:
self.assertTrue(False) # other techs fail
@@ -96,4 +90,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/21_ngspice_setuphold_test.py b/compiler/tests/21_ngspice_setuphold_test.py
index 924d05a5..4a289812 100755
--- a/compiler/tests/21_ngspice_setuphold_test.py
+++ b/compiler/tests/21_ngspice_setuphold_test.py
@@ -1,20 +1,24 @@
#!/usr/bin/env python3
-"""
-Run a regression test on various srams
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
class timing_setup_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.spice_name="ngspice"
OPTS.analytical_delay = False
OPTS.netlist_only = True
@@ -58,4 +62,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/22_psram_1bank_2mux_func_test.py b/compiler/tests/22_psram_1bank_2mux_func_test.py
index 87c8db48..f986c3e7 100755
--- a/compiler/tests/22_psram_1bank_2mux_func_test.py
+++ b/compiler/tests/22_psram_1bank_2mux_func_test.py
@@ -1,28 +1,34 @@
#!/usr/bin/env python3
-"""
-Run a regression test on various srams
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
-#@unittest.skip("SKIPPING 22_psram_1bank_2mux_1rw_1r_1w_func_test, third port reads are broken?")
-class psram_1bank_2mux_1rw_1r_1w_func_test(openram_test):
+class psram_1bank_2mux_func_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
+
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell"
+ OPTS.dummy_bitcell="dummy_pbitcell"
+
OPTS.num_rw_ports = 1
- OPTS.num_r_ports = 1
+ OPTS.num_r_ports = 0
OPTS.num_w_ports = 1
# This is a hack to reload the characterizer __init__ with the spice version
@@ -30,30 +36,26 @@ class psram_1bank_2mux_1rw_1r_1w_func_test(openram_test):
import characterizer
reload(characterizer)
from characterizer import functional, delay
- from sram import sram
from sram_config import sram_config
- c = sram_config(word_size=4,
- num_words=64,
+ c = sram_config(word_size=2,
+ num_words=32,
num_banks=1)
c.words_per_row=2
c.recompute_sizes()
- debug.info(1, "Functional test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
- OPTS.num_r_ports,
- OPTS.num_w_ports,
- c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- s = sram(c, name="sram")
- tempspice = OPTS.openram_temp + "temp.sp"
+ debug.info(1, "Functional test for {}rw,{}r,{}w psram with"
+ "{} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ s = factory.create(module_type="sram", sram_config=c)
+ tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner)
- d = delay(s.s, tempspice, corner)
- feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
-
- f.num_cycles = 10
(fail, error) = f.run()
self.assertTrue(fail,error)
@@ -64,4 +66,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/22_psram_1bank_4mux_func_test.py b/compiler/tests/22_psram_1bank_4mux_func_test.py
index 16661483..c5fd8945 100755
--- a/compiler/tests/22_psram_1bank_4mux_func_test.py
+++ b/compiler/tests/22_psram_1bank_4mux_func_test.py
@@ -1,28 +1,35 @@
#!/usr/bin/env python3
-"""
-Run a regression test on various srams
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 22_psram_1bank_4mux_func_test, third port reads are broken?")
class psram_1bank_4mux_func_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
+
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell"
+ OPTS.dummy_bitcell="dummy_pbitcell"
+
OPTS.num_rw_ports = 1
- OPTS.num_r_ports = 1
+ OPTS.num_r_ports = 0
OPTS.num_w_ports = 1
# This is a hack to reload the characterizer __init__ with the spice version
@@ -30,30 +37,26 @@ class psram_1bank_4mux_func_test(openram_test):
import characterizer
reload(characterizer)
from characterizer import functional, delay
- from sram import sram
from sram_config import sram_config
- c = sram_config(word_size=4,
+ c = sram_config(word_size=2,
num_words=256,
num_banks=1)
c.words_per_row=4
c.recompute_sizes()
- debug.info(1, "Functional test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
- OPTS.num_r_ports,
- OPTS.num_w_ports,
- c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- s = sram(c, name="sram")
- tempspice = OPTS.openram_temp + "temp.sp"
+ debug.info(1, "Functional test for {}rw,{}r,{}w psram with"
+ "{} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ s = factory.create(module_type="sram", sram_config=c)
+ tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner)
- d = delay(s.s, tempspice, corner)
- feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
-
- f.num_cycles = 10
(fail, error) = f.run()
self.assertTrue(fail,error)
@@ -64,4 +67,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/22_psram_1bank_8mux_func_test.py b/compiler/tests/22_psram_1bank_8mux_func_test.py
index 86cfd16f..acb168c0 100755
--- a/compiler/tests/22_psram_1bank_8mux_func_test.py
+++ b/compiler/tests/22_psram_1bank_8mux_func_test.py
@@ -1,28 +1,35 @@
#!/usr/bin/env python3
-"""
-Run a regression test on various srams
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 22_psram_1bank_8mux_func_test")
class psram_1bank_8mux_func_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
+
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell"
+ OPTS.dummy_bitcell="dummy_pbitcell"
+
OPTS.num_rw_ports = 1
- OPTS.num_r_ports = 1
+ OPTS.num_r_ports = 0
OPTS.num_w_ports = 1
# This is a hack to reload the characterizer __init__ with the spice version
@@ -30,30 +37,26 @@ class psram_1bank_8mux_func_test(openram_test):
import characterizer
reload(characterizer)
from characterizer import functional, delay
- from sram import sram
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=256,
num_banks=1)
c.words_per_row=8
c.recompute_sizes()
- debug.info(1, "Functional test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
- OPTS.num_r_ports,
- OPTS.num_w_ports,
- c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- s = sram(c, name="sram")
- tempspice = OPTS.openram_temp + "temp.sp"
+ debug.info(1, "Functional test for {}rw,{}r,{}w psram with"
+ "{} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ s = factory.create(module_type="sram", sram_config=c)
+ tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner)
- d = delay(s.s, tempspice, corner)
- feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
-
- f.num_cycles = 10
(fail, error) = f.run()
self.assertTrue(fail,error)
@@ -64,4 +67,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/22_psram_1bank_nomux_func_test.py b/compiler/tests/22_psram_1bank_nomux_func_test.py
index 3133eb03..a2a2b41c 100755
--- a/compiler/tests/22_psram_1bank_nomux_func_test.py
+++ b/compiler/tests/22_psram_1bank_nomux_func_test.py
@@ -1,28 +1,35 @@
#!/usr/bin/env python3
-"""
-Run a functioal test on 1 bank SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 22_psram_1bank_nomux_func_test")
class psram_1bank_nomux_func_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
+
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell"
+ OPTS.dummy_bitcell="dummy_pbitcell"
+
OPTS.num_rw_ports = 1
- OPTS.num_r_ports = 1
+ OPTS.num_r_ports = 0
OPTS.num_w_ports = 1
# This is a hack to reload the characterizer __init__ with the spice version
@@ -30,30 +37,26 @@ class psram_1bank_nomux_func_test(openram_test):
import characterizer
reload(characterizer)
from characterizer import functional, delay
- from sram import sram
from sram_config import sram_config
- c = sram_config(word_size=4,
+ c = sram_config(word_size=2,
num_words=32,
num_banks=1)
c.words_per_row=1
c.recompute_sizes()
- debug.info(1, "Functional test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
- OPTS.num_r_ports,
- OPTS.num_w_ports,
- c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- s = sram(c, name="sram")
- tempspice = OPTS.openram_temp + "temp.sp"
+ debug.info(1, "Functional test for {}rw,{}r,{}w psram with"
+ "{} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
+ OPTS.num_r_ports,
+ OPTS.num_w_ports,
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ s = factory.create(module_type="sram", sram_config=c)
+ tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner)
- d = delay(s.s, tempspice, corner)
- feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
-
- f.num_cycles = 10
(fail, error) = f.run()
self.assertTrue(fail,error)
@@ -64,4 +67,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/22_sram_1bank_2mux_func_test.py b/compiler/tests/22_sram_1bank_2mux_func_test.py
index f163216e..2037169e 100755
--- a/compiler/tests/22_sram_1bank_2mux_func_test.py
+++ b/compiler/tests/22_sram_1bank_2mux_func_test.py
@@ -1,21 +1,25 @@
#!/usr/bin/env python3
-"""
-Run a regression test on various srams
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 22_sram_1bank_2mux_func_test")
class sram_1bank_2mux_func_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
@@ -25,28 +29,24 @@ class sram_1bank_2mux_func_test(openram_test):
import characterizer
reload(characterizer)
from characterizer import functional, delay
- from sram import sram
from sram_config import sram_config
c = sram_config(word_size=4,
- num_words=64,
+ num_words=32,
num_banks=1)
c.words_per_row=2
c.recompute_sizes()
- debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- s = sram(c, name="sram")
- tempspice = OPTS.openram_temp + "temp.sp"
+ debug.info(1, "Functional test for sram with "
+ "{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ s = factory.create(module_type="sram", sram_config=c)
+ tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner)
- d = delay(s.s, tempspice, corner)
- feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
-
- f.num_cycles = 10
- (fail, error) = f.run(feasible_period)
+ (fail, error) = f.run()
self.assertTrue(fail,error)
globals.end_openram()
@@ -56,4 +56,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/22_sram_1bank_4mux_func_test.py b/compiler/tests/22_sram_1bank_4mux_func_test.py
index 049d8459..178f955b 100755
--- a/compiler/tests/22_sram_1bank_4mux_func_test.py
+++ b/compiler/tests/22_sram_1bank_4mux_func_test.py
@@ -1,21 +1,25 @@
#!/usr/bin/env python3
-"""
-Run a regression test on various srams
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 22_sram_1bank_4mux_func_test")
class sram_1bank_4mux_func_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
@@ -25,27 +29,23 @@ class sram_1bank_4mux_func_test(openram_test):
import characterizer
reload(characterizer)
from characterizer import functional, delay
- from sram import sram
from sram_config import sram_config
c = sram_config(word_size=4,
- num_words=256,
+ num_words=128,
num_banks=1)
c.words_per_row=4
c.recompute_sizes()
- debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- s = sram(c, name="sram")
- tempspice = OPTS.openram_temp + "temp.sp"
+ debug.info(1, "Functional test for sram with "
+ "{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ s = factory.create(module_type="sram", sram_config=c)
+ tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner)
- d = delay(s.s, tempspice, corner)
- feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
-
- f.num_cycles = 10
(fail, error) = f.run()
self.assertTrue(fail,error)
@@ -56,4 +56,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/22_sram_1bank_8mux_func_test.py b/compiler/tests/22_sram_1bank_8mux_func_test.py
index d159f265..d531163a 100755
--- a/compiler/tests/22_sram_1bank_8mux_func_test.py
+++ b/compiler/tests/22_sram_1bank_8mux_func_test.py
@@ -1,21 +1,25 @@
#!/usr/bin/env python3
-"""
-Run a regression test on various srams
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 22_sram_1bank_8mux_func_test")
class sram_1bank_8mux_func_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
@@ -28,27 +32,23 @@ class sram_1bank_8mux_func_test(openram_test):
if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
- from sram import sram
from sram_config import sram_config
c = sram_config(word_size=4,
- num_words=256,
+ num_words=128,
num_banks=1)
c.words_per_row=8
c.recompute_sizes()
- debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- s = sram(c, name="sram")
- tempspice = OPTS.openram_temp + "temp.sp"
+ debug.info(1, "Functional test for sram with "
+ "{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ s = factory.create(module_type="sram", sram_config=c)
+ tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner)
- d = delay(s.s, tempspice, corner)
- feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
-
- f.num_cycles = 10
(fail, error) = f.run()
self.assertTrue(fail,error)
@@ -59,4 +59,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/22_sram_1bank_nomux_func_test.py b/compiler/tests/22_sram_1bank_nomux_func_test.py
index 08a21d92..eb6d2412 100755
--- a/compiler/tests/22_sram_1bank_nomux_func_test.py
+++ b/compiler/tests/22_sram_1bank_nomux_func_test.py
@@ -1,21 +1,25 @@
#!/usr/bin/env python3
-"""
-Run a functioal test on 1 bank SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 22_sram_func_test")
class sram_1bank_nomux_func_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.analytical_delay = False
OPTS.netlist_only = True
@@ -24,25 +28,23 @@ class sram_1bank_nomux_func_test(openram_test):
import characterizer
reload(characterizer)
from characterizer import functional
- from sram import sram
from sram_config import sram_config
c = sram_config(word_size=4,
- num_words=32,
+ num_words=16,
num_banks=1)
c.words_per_row=1
c.recompute_sizes()
- debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- s = sram(c, name="sram")
- tempspice = OPTS.openram_temp + "temp.sp"
+ debug.info(1, "Functional test for sram with "
+ "{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ s = factory.create(module_type="sram", sram_config=c)
+ tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
-
f = functional(s.s, tempspice, corner)
- f.num_cycles = 10
(fail, error) = f.run()
self.assertTrue(fail,error)
@@ -53,4 +55,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/22_sram_1rw_1r_1bank_nomux_func_test.py b/compiler/tests/22_sram_1rw_1r_1bank_nomux_func_test.py
index a609460b..169e34d0 100755
--- a/compiler/tests/22_sram_1rw_1r_1bank_nomux_func_test.py
+++ b/compiler/tests/22_sram_1rw_1r_1bank_nomux_func_test.py
@@ -1,26 +1,31 @@
#!/usr/bin/env python3
-"""
-Run a functioal test on 1 bank SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 22_sram_1rw_1r_1bank_nomux_func_test")
class psram_1bank_nomux_func_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.analytical_delay = False
OPTS.netlist_only = True
OPTS.trim_netlist = False
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
+ OPTS.dummy_bitcell="dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 1
@@ -30,27 +35,23 @@ class psram_1bank_nomux_func_test(openram_test):
import characterizer
reload(characterizer)
from characterizer import functional, delay
- from sram import sram
from sram_config import sram_config
c = sram_config(word_size=4,
num_words=32,
num_banks=1)
c.words_per_row=1
c.recompute_sizes()
- debug.info(1, "Functional test for sram 1rw,1r with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
- c.num_words,
- c.words_per_row,
- c.num_banks))
- s = sram(c, name="sram")
- tempspice = OPTS.openram_temp + "temp.sp"
+ debug.info(1, "Functional test for sram 1rw,1r with "
+ "{} bit words, {} words, {} words per row, {} banks".format(c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.num_banks))
+ s = factory.create(module_type="sram", sram_config=c)
+ tempspice = OPTS.openram_temp + "sram.sp"
s.sp_write(tempspice)
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
f = functional(s.s, tempspice, corner)
- d = delay(s.s, tempspice, corner)
- feasible_period = self.find_feasible_test_period(d, s.s, f.load, f.slew)
-
- f.num_cycles = 10
(fail, error) = f.run()
self.assertTrue(fail,error)
@@ -61,4 +62,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/22_sram_wmask_1w_1r_func_test.py b/compiler/tests/22_sram_wmask_1w_1r_func_test.py
new file mode 100755
index 00000000..2ee79750
--- /dev/null
+++ b/compiler/tests/22_sram_wmask_1w_1r_func_test.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys, os
+
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+
+# @unittest.skip("SKIPPING sram_wmask_1w_1r_func_test")
+class sram_wmask_1w_1r_func_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ OPTS.analytical_delay = False
+ OPTS.netlist_only = True
+ OPTS.trim_netlist = False
+ OPTS.bitcell = "bitcell_1w_1r"
+ OPTS.replica_bitcell = "replica_bitcell_1w_1r"
+ OPTS.dummy_bitcell = "dummy_bitcell_1w_1r"
+
+ OPTS.num_rw_ports = 0
+ OPTS.num_w_ports = 1
+ OPTS.num_r_ports = 1
+
+ # This is a hack to reload the characterizer __init__ with the spice version
+ from importlib import reload
+ import characterizer
+ reload(characterizer)
+ from characterizer import functional, delay
+ from sram_config import sram_config
+ c = sram_config(word_size=8,
+ num_words=16,
+ write_size=2,
+ num_banks=1)
+ c.words_per_row = 1
+ c.recompute_sizes()
+ debug.info(1,
+ "Functional test for sram with {} bit words, {} words, {} words per row, {} bit writes, {} banks".format(
+ c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.write_size,
+ c.num_banks))
+ s = factory.create(module_type="sram", sram_config=c)
+ tempspice = OPTS.openram_temp + "sram.sp"
+ s.sp_write(tempspice)
+
+ corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
+ f = functional(s.s, tempspice, corner)
+ (fail, error) = f.run()
+ self.assertTrue(fail, error)
+
+ globals.end_openram()
+
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/22_sram_wmask_func_test.py b/compiler/tests/22_sram_wmask_func_test.py
new file mode 100755
index 00000000..c390f030
--- /dev/null
+++ b/compiler/tests/22_sram_wmask_func_test.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys,os
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+
+#@unittest.skip("SKIPPING sram_wmask_func_test")
+class sram_wmask_func_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ OPTS.analytical_delay = False
+ OPTS.netlist_only = True
+ OPTS.trim_netlist = False
+
+ # This is a hack to reload the characterizer __init__ with the spice version
+ from importlib import reload
+ import characterizer
+ reload(characterizer)
+ from characterizer import functional, delay
+ from sram_config import sram_config
+ c = sram_config(word_size=8,
+ num_words=16,
+ write_size=4,
+ num_banks=1)
+ c.words_per_row=1
+ c.recompute_sizes()
+ debug.info(1, "Functional test for sram with "
+ "{} bit words, {} words, {} words per row, {} bit writes, {} banks".format(c.word_size,
+ c.num_words,
+ c.words_per_row,
+ c.write_size,
+ c.num_banks))
+ s = factory.create(module_type="sram", sram_config=c)
+ tempspice = OPTS.openram_temp + "sram.sp"
+ s.sp_write(tempspice)
+
+ corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
+ f = functional(s.s, tempspice, corner)
+ (fail, error) = f.run()
+ self.assertTrue(fail, error)
+
+ globals.end_openram()
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/23_lib_sram_model_corners_test.py b/compiler/tests/23_lib_sram_model_corners_test.py
index 431555bc..5840c05d 100755
--- a/compiler/tests/23_lib_sram_model_corners_test.py
+++ b/compiler/tests/23_lib_sram_model_corners_test.py
@@ -1,20 +1,25 @@
#!/usr/bin/env python3
-"""
-Check the .lib file for an SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os,re
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
import debug
-class model_corners_lib_test(openram_test):
+#@unittest.skip("SKIPPING 23_lib_sram_model_corners_test")
+class lib_model_corners_lib_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ OPTS.netlist_only = True
from characterizer import lib
from sram import sram
@@ -25,7 +30,10 @@ class model_corners_lib_test(openram_test):
c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Testing analytical timing for sample 2 bit, 16 words SRAM with 1 bank")
- s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
+
+ # This doesn't have to use the factory since worst case
+ # it will just replaece the top-level module of the same name
+ s = sram(c, name="sram_2_16_1_{0}".format(OPTS.tech_name))
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
@@ -60,7 +68,7 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/23_lib_sram_model_test.py b/compiler/tests/23_lib_sram_model_test.py
index 8a996cb4..75e73f71 100755
--- a/compiler/tests/23_lib_sram_model_test.py
+++ b/compiler/tests/23_lib_sram_model_test.py
@@ -1,21 +1,26 @@
#!/usr/bin/env python3
-"""
-Check the .lib file for an SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os,re
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
import debug
-class lib_test(openram_test):
+#@unittest.skip("SKIPPING 23_lib_sram_model_test")
+class lib_sram_model_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
-
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ OPTS.netlist_only = True
+
from characterizer import lib
from sram import sram
from sram_config import sram_config
@@ -25,6 +30,9 @@ class lib_test(openram_test):
c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Testing analytical timing for sample 2 bit, 16 words SRAM with 1 bank")
+
+ # This doesn't have to use the factory since worst case
+ # it will just replaece the top-level module of the same name
s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
@@ -50,7 +58,7 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/23_lib_sram_prune_test.py b/compiler/tests/23_lib_sram_prune_test.py
index 1b93d1fd..1fc5a66b 100755
--- a/compiler/tests/23_lib_sram_prune_test.py
+++ b/compiler/tests/23_lib_sram_prune_test.py
@@ -1,20 +1,24 @@
#!/usr/bin/env python3
-"""
-Check the .lib file for an SRAM with pruning
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os,re
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
import debug
-class lib_test(openram_test):
+@unittest.skip("SKIPPING 23_lib_sram_prune_test")
+class lib_sram_prune_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.analytical_delay = False
OPTS.trim_netlist = True
@@ -34,6 +38,9 @@ class lib_test(openram_test):
c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Testing pruned timing for sample 2 bit, 16 words SRAM with 1 bank")
+
+ # This doesn't have to use the factory since worst case
+ # it will just replaece the top-level module of the same name
s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
tempspice = OPTS.openram_temp + "temp.sp"
@@ -61,7 +68,7 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/23_lib_sram_test.py b/compiler/tests/23_lib_sram_test.py
index 1c26fd45..0ababf32 100755
--- a/compiler/tests/23_lib_sram_test.py
+++ b/compiler/tests/23_lib_sram_test.py
@@ -1,12 +1,15 @@
#!/usr/bin/env python3
-"""
-Check the .lib file for an SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os,re
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
import debug
@@ -14,7 +17,7 @@ import debug
class lib_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.analytical_delay = False
OPTS.trim_netlist = False
@@ -34,6 +37,9 @@ class lib_test(openram_test):
c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank")
+
+ # This doesn't have to use the factory since worst case
+ # it will just replaece the top-level module of the same name
s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
tempspice = OPTS.openram_temp + "temp.sp"
@@ -60,7 +66,7 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/24_lef_sram_test.py b/compiler/tests/24_lef_sram_test.py
index 983038a2..5f7fdc60 100755
--- a/compiler/tests/24_lef_sram_test.py
+++ b/compiler/tests/24_lef_sram_test.py
@@ -1,12 +1,15 @@
#!/usr/bin/env python3
-"""
-Check the LEF file for an SRMA
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
import debug
@@ -15,7 +18,7 @@ import debug
class lef_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram import sram
from sram_config import sram_config
@@ -25,6 +28,8 @@ class lef_test(openram_test):
c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Testing LEF for sample 2 bit, 16 words SRAM with 1 bank")
+ # This doesn't have to use the factory since worst case
+ # it will just replaece the top-level module of the same name
s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
gdsfile = s.name + ".gds"
@@ -45,4 +50,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/25_verilog_sram_test.py b/compiler/tests/25_verilog_sram_test.py
index f98475b4..da6a2682 100755
--- a/compiler/tests/25_verilog_sram_test.py
+++ b/compiler/tests/25_verilog_sram_test.py
@@ -1,12 +1,15 @@
#!/usr/bin/env python3
-"""
-Check the .v file for an SRAM
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
import debug
@@ -14,7 +17,7 @@ import debug
class verilog_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
from sram import sram
from sram_config import sram_config
@@ -24,6 +27,8 @@ class verilog_test(openram_test):
c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Testing Verilog for sample 2 bit, 16 words SRAM with 1 bank")
+ # This doesn't have to use the factory since worst case
+ # it will just replaece the top-level module of the same name
s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
vfile = s.name + ".v"
@@ -42,4 +47,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/26_hspice_pex_pinv_test.py b/compiler/tests/26_hspice_pex_pinv_test.py
new file mode 100755
index 00000000..f0cccba3
--- /dev/null
+++ b/compiler/tests/26_hspice_pex_pinv_test.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California
+# All rights reserved.
+#
+"""
+Run regression tests/pex test on an extracted pinv to ensure pex functionality
+with HSPICE.
+"""
+import unittest
+from testutils import header,openram_test
+import sys,os
+sys.path.append(os.path.join(sys.path[0],".."))
+import globals
+from globals import OPTS
+import debug
+
+
+class hspice_pex_pinv_test(openram_test):
+
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ import pinv
+
+ # load the hspice
+ OPTS.spice_name="hspice"
+ OPTS.analytical_delay = False
+
+ # This is a hack to reload the characterizer __init__ with the spice version
+ from importlib import reload
+ import characterizer
+ reload(characterizer)
+
+ # generate the pinv
+ prev_purge_value = OPTS.purge_temp
+ OPTS.purge_temp = False # force set purge to false to save the sp file
+ debug.info(2, "Checking 1x size inverter")
+ tx = pinv.pinv(name="pinv", size=1)
+ tempgds = "{0}{1}.gds".format(OPTS.openram_temp,tx.name)
+ tx.gds_write(tempgds)
+ tempsp = "{0}{1}.sp".format(OPTS.openram_temp,tx.name)
+ tx.sp_write(tempsp)
+
+ # make sure that the library simulation is successful\
+ sp_delay = self.simulate_delay(test_module = tempsp,
+ top_level_name = tx.name)
+ if sp_delay is "Failed":
+ self.fail('Library Spice module did not behave as expected')
+
+ # now generate its pex file
+ pex_file = self.run_pex(tx)
+ OPTS.purge_temp = prev_purge_value # restore the old purge value
+ # generate simulation for pex, make sure the simulation is successful
+ pex_delay = self.simulate_delay(test_module = pex_file,
+ top_level_name = tx.name)
+ # make sure the extracted spice simulated
+ if pex_delay is "Failed":
+ self.fail('Pex file did not behave as expected')
+
+ # if pex data is bigger than original spice file then result is ok
+ # However this may not always be true depending on the netlist provided
+ # comment out for now
+ #debug.info(2,"pex_delay: {0}".format(pex_delay))
+ #debug.info(2,"sp_delay: {0}".format(sp_delay))
+
+ #assert pex_delay > sp_delay, "pex delay {0} is smaller than sp_delay {1}"\
+ #.format(pex_delay,sp_delay)
+
+ globals.end_openram()
+
+ def simulate_delay(self, test_module, top_level_name):
+ from characterizer import charutils
+ from charutils import parse_spice_list
+ # setup simulation
+ sim_file = OPTS.openram_temp + "stim.sp"
+ log_file_name = "timing"
+ test_sim = self.write_simulation(sim_file, test_module, top_level_name)
+ test_sim.run_sim()
+ delay = parse_spice_list(log_file_name, "pinv_delay")
+ return delay
+
+ def write_simulation(self, sim_file, cir_file, top_module_name):
+ """ write pex spice simulation for a pinv test"""
+ import tech
+ from characterizer import measurements, stimuli
+ corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
+ sim_file = open(sim_file, "w")
+ simulation = stimuli(sim_file,corner)
+
+ # library files
+ simulation.write_include(cir_file)
+
+ # supply voltages
+ simulation.gen_constant(sig_name ="vdd",
+ v_val = tech.spice["nom_supply_voltage"])
+ simulation.gen_constant(sig_name = "gnd",
+ v_val = "0v")
+
+ run_time = tech.spice["feasible_period"] * 4
+ # input voltage
+ clk_period = tech.spice["feasible_period"]
+ simulation.gen_pwl(sig_name ="input",
+ clk_times = [clk_period,clk_period],
+ data_values = [1,0],
+ period = clk_period,
+ slew = 0.001*tech.spice["feasible_period"],
+ setup = 0)
+
+ # instantiation of simulated pinv
+ simulation.inst_model(pins = ["input", "output", "vdd", "gnd"],
+ model_name = top_module_name)
+
+ # delay measurement
+ delay_measure = measurements.delay_measure(measure_name = "pinv_delay",
+ trig_name = "input",
+ targ_name = "output",
+ trig_dir_str = "FALL",
+ targ_dir_str = "RISE",
+ has_port = False)
+ trig_td = trag_td = 0.01 * run_time
+ rest_info = trig_td,trag_td,tech.spice["nom_supply_voltage"]
+ delay_measure.write_measure(simulation, rest_info)
+
+ simulation.write_control(end_time = run_time)
+ sim_file.close()
+ return simulation
+
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main()
diff --git a/compiler/tests/26_ngspice_pex_pinv_test.py b/compiler/tests/26_ngspice_pex_pinv_test.py
new file mode 100755
index 00000000..2eb95948
--- /dev/null
+++ b/compiler/tests/26_ngspice_pex_pinv_test.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California
+# All rights reserved.
+#
+"""
+Run regression tests/pex test on an extracted pinv to ensure pex functionality
+with Ngspice.
+"""
+import unittest
+from testutils import header,openram_test
+import sys,os
+sys.path.append(os.path.join(sys.path[0],".."))
+import globals
+from globals import OPTS
+import debug
+
+
+class ngspice_pex_pinv_test(openram_test):
+ def runTest(self):
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
+ import pinv
+
+ # load the ngspice
+ OPTS.spice_name="ngspice"
+ OPTS.analytical_delay = False
+
+ # This is a hack to reload the characterizer __init__ with the spice version
+ from importlib import reload
+ import characterizer
+ reload(characterizer)
+
+ # generate the pinv module
+ prev_purge_value = OPTS.purge_temp
+ OPTS.purge_temp = False # force set purge to false to save the sp file
+ debug.info(2, "Checking 1x size inverter")
+ tx = pinv.pinv(name="pinv", size=1)
+ tempgds = "{0}{1}.gds".format(OPTS.openram_temp,tx.name)
+ tx.gds_write(tempgds)
+ tempsp = "{0}{1}.sp".format(OPTS.openram_temp,tx.name)
+ tx.sp_write(tempsp)
+
+ # make sure that the library simulation is successful
+ sp_delay = self.simulate_delay(test_module = tempsp,
+ top_level_name = tx.name)
+ if sp_delay is "Failed":
+ self.fail('Library Spice module did not behave as expected')
+
+ # now generate its pex file
+ pex_file = self.run_pex(tx)
+ OPTS.purge_temp = prev_purge_value # restore the old purge value
+ # generate simulation for pex, make sure the simulation is successful
+ pex_delay = self.simulate_delay(test_module = pex_file,
+ top_level_name = tx.name)
+ # make sure the extracted spice simulated
+ if pex_delay is "Failed":
+ self.fail('Pex file did not behave as expected')
+
+ # if pex data is bigger than original spice file then result is ok
+ # However this may not always be true depending on the netlist provided
+ # comment out for now
+ #debug.info(2,"pex_delay: {0}".format(pex_delay))
+ #debug.info(2,"sp_delay: {0}".format(sp_delay))
+
+ #assert pex_delay > sp_delay, "pex delay {0} is smaller than sp_delay {1}"\
+ #.format(pex_delay,sp_delay)
+
+ globals.end_openram()
+
+ def simulate_delay(self, test_module, top_level_name):
+ from characterizer import charutils
+ from charutils import parse_spice_list
+ # setup simulation
+ sim_file = OPTS.openram_temp + "stim.sp"
+ log_file_name = "timing"
+ test_sim = self.write_simulation(sim_file, test_module, top_level_name)
+ test_sim.run_sim()
+ delay = parse_spice_list(log_file_name, "pinv_delay")
+ return delay
+
+ def write_simulation(self, sim_file, cir_file, top_module_name):
+ """ write pex spice simulation for a pinv test"""
+ import tech
+ from characterizer import measurements, stimuli
+ corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
+ sim_file = open(sim_file, "w")
+ simulation = stimuli(sim_file,corner)
+
+ # library files
+ simulation.write_include(cir_file)
+
+ # supply voltages
+ simulation.gen_constant(sig_name ="vdd",
+ v_val = tech.spice["nom_supply_voltage"])
+ # The scn4m_subm and ngspice combination will have a gnd source error:
+ # "Fatal error: instance vgnd is a shorted VSRC"
+ # However, remove gnd power for all techa pass for this test
+ # simulation.gen_constant(sig_name = "gnd",
+ # v_val = "0v")
+
+
+ run_time = tech.spice["feasible_period"] * 4
+ # input voltage
+ clk_period = tech.spice["feasible_period"]
+ simulation.gen_pwl(sig_name ="input",
+ clk_times = [clk_period,clk_period],
+ data_values = [1,0],
+ period = clk_period,
+ slew = 0.001*tech.spice["feasible_period"],
+ setup = 0)
+
+ # instantiation of simulated pinv
+ simulation.inst_model(pins = ["input", "output", "vdd", "gnd"],
+ model_name = top_module_name)
+
+ # delay measurement
+ delay_measure = measurements.delay_measure(measure_name = "pinv_delay",
+ trig_name = "input",
+ targ_name = "output",
+ trig_dir_str = "FALL",
+ targ_dir_str = "RISE",
+ has_port = False)
+ trig_td = trag_td = 0.01 * run_time
+ rest_info = trig_td,trag_td,tech.spice["nom_supply_voltage"]
+ delay_measure.write_measure(simulation, rest_info)
+
+ simulation.write_control(end_time = run_time)
+ sim_file.close()
+ return simulation
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main()
diff --git a/compiler/tests/26_pex_test.py b/compiler/tests/26_pex_test.py
index d374e485..78409249 100755
--- a/compiler/tests/26_pex_test.py
+++ b/compiler/tests/26_pex_test.py
@@ -1,21 +1,25 @@
#!/usr/bin/env python3
-"""
-Run a regression test on an extracted SRAM to ensure functionality.
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
@unittest.skip("SKIPPING 26_pex_test")
class sram_func_test(openram_test):
def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
+ globals.init_openram("config_{0}".format(OPTS.tech_name))
OPTS.use_pex = True
@@ -311,4 +315,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/27_worst_case_delay_test.py b/compiler/tests/27_worst_case_delay_test.py
deleted file mode 100755
index 834c6b69..00000000
--- a/compiler/tests/27_worst_case_delay_test.py
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/usr/bin/env python3
-"""
-Run a regression test on various srams
-"""
-
-import unittest
-from testutils import header,openram_test
-import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
-import globals
-from globals import OPTS
-import debug
-
-@unittest.skip("SKIPPING 27_worst_case_delay_test")
-class worst_case_timing_sram_test(openram_test):
-
- def runTest(self):
- OPTS.tech_name = "freepdk45"
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- OPTS.spice_name="hspice"
- OPTS.analytical_delay = False
- OPTS.netlist_only = True
- OPTS.trim_netlist = False
- OPTS.check_lvsdrc = True
-
-
- # This is a hack to reload the characterizer __init__ with the spice version
- from importlib import reload
- import characterizer
- reload(characterizer)
- from characterizer import worst_case
- if not OPTS.spice_exe:
- debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
-
- word_size, num_words, num_banks = 2, 16, 1
- from sram import sram
- from sram_config import sram_config
- c = sram_config(word_size=word_size,
- num_words=num_words,
- num_banks=num_banks)
- c.words_per_row=1
- c.recompute_sizes()
- debug.info(1, "Testing the timing different bitecells inside a {}bit, {} words SRAM with {} bank".format(
- word_size, num_words, num_banks))
- s = sram(c, name="sram1")
-
- sp_netlist_file = OPTS.openram_temp + "temp.sp"
- s.sp_write(sp_netlist_file)
-
- if OPTS.use_pex:
- gdsname = OPTS.output_path + s.name + ".gds"
- s.gds_write(gdsname)
-
- import verify
- reload(verify)
- # Output the extracted design if requested
- sp_pex_file = OPTS.output_path + s.name + "_pex.sp"
- verify.run_pex(s.name, gdsname, sp_netlist_file, output=sp_pex_file)
- sp_sim_file = sp_pex_file
- debug.info(1, "Performing spice simulations with backannotated spice file.")
- else:
- sp_sim_file = sp_netlist_file
- debug.info(1, "Performing spice simulations with spice netlist.")
-
- corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
- wc = worst_case(s.s, sp_sim_file, corner)
- import tech
- loads = [tech.spice["msflop_in_cap"]*4]
- slews = [tech.spice["rise_time"]*2]
- probe_address = "1" * s.s.addr_size
- probe_data = s.s.word_size - 1
- wc.analyze(probe_address, probe_data, slews, loads)
-
- globals.end_openram()
-
-# run the test from the command line
-if __name__ == "__main__":
- (OPTS, args) = globals.parse_args()
- del sys.argv[1:]
- header(__file__, OPTS.tech_name)
- unittest.main()
diff --git a/compiler/tests/28_delay_model_test.py b/compiler/tests/28_delay_model_test.py
deleted file mode 100755
index a02a42e9..00000000
--- a/compiler/tests/28_delay_model_test.py
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/usr/bin/env python3
-"""
-Run a regression test on various srams
-"""
-
-import unittest
-from testutils import header,openram_test
-import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
-import globals
-from globals import OPTS
-import debug
-
-class delay_model_test(openram_test):
-
- def runTest(self):
- globals.init_openram("config_20_{0}".format(OPTS.tech_name))
- OPTS.spice_name="hspice"
- OPTS.analytical_delay = False
- OPTS.netlist_only = True
- OPTS.trim_netlist = False
- debug.info(1, "Trimming disabled for this test. Simulation could be slow.")
-
- # This is a hack to reload the characterizer __init__ with the spice version
- from importlib import reload
- import characterizer
- reload(characterizer)
-
- from characterizer import model_check
- from sram import sram
- from sram_config import sram_config
- c = sram_config(word_size=4,
- num_words=16,
- num_banks=1)
- c.words_per_row=1
- c.recompute_sizes()
- debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
- s = sram(c, name="sram1")
-
- tempspice = OPTS.openram_temp + "temp.sp"
- s.sp_write(tempspice)
-
- probe_address = "1" * s.s.addr_size
- probe_data = s.s.word_size - 1
- debug.info(1, "Probe address {0} probe data bit {1}".format(probe_address, probe_data))
-
- corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
- mc = model_check(s.s, tempspice, corner)
- import tech
- loads = [tech.spice["msflop_in_cap"]*4]
- slews = [tech.spice["rise_time"]*2]
- sram_data = mc.analyze(probe_address, probe_data, slews, loads)
- #Combine info about port into all data
-
- #debug.info(1,"Data:\n{}".format(wl_data))
-
- globals.end_openram()
-
-# run the test from the command line
-if __name__ == "__main__":
- (OPTS, args) = globals.parse_args()
- del sys.argv[1:]
- header(__file__, OPTS.tech_name)
- unittest.main()
diff --git a/compiler/tests/30_openram_test.py b/compiler/tests/30_openram_back_end_test.py
similarity index 73%
rename from compiler/tests/30_openram_test.py
rename to compiler/tests/30_openram_back_end_test.py
index 55ab9457..de1bec05 100755
--- a/compiler/tests/30_openram_test.py
+++ b/compiler/tests/30_openram_back_end_test.py
@@ -1,28 +1,29 @@
#!/usr/bin/env python3
-"""
-This tests the top-level executable. It checks that it generates the
-appropriate files: .lef, .lib, .sp, .gds, .v. It DOES NOT, however,
-check that these files are right.
-"""
-
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest
-from testutils import header,openram_test
+from testutils import *
import sys,os,re,shutil
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
+from sram_factory import factory
import debug
import getpass
-class openram_test(openram_test):
+class openram_back_end_test(openram_test):
def runTest(self):
OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME"))
- globals.init_openram("{0}/tests/config_20_{1}".format(OPENRAM_HOME,OPTS.tech_name))
-
- debug.info(1, "Testing top-level openram.py with 2-bit, 16 word SRAM.")
+ globals.init_openram("{0}/tests/config_{1}".format(OPENRAM_HOME,OPTS.tech_name))
+
+ debug.info(1, "Testing top-level back-end openram.py with 2-bit, 16 word SRAM.")
out_file = "testsram"
- # make a temp directory for output
out_path = "/tmp/testsram_{0}_{1}_{2}/".format(OPTS.tech_name,getpass.getuser(),os.getpid())
# make sure we start without the files existing
@@ -37,10 +38,12 @@ class openram_test(openram_test):
os.chmod(out_path, 0o0750)
# specify the same verbosity for the system call
- verbosity = ""
+ options = ""
for i in range(OPTS.debug_level):
- verbosity += " -v"
+ options += " -v"
+ if OPTS.spice_name:
+ options += " -s {}".format(OPTS.spice_name)
# Always perform code coverage
if OPTS.coverage == 0:
@@ -48,11 +51,11 @@ class openram_test(openram_test):
exe_name = "{0}/openram.py ".format(OPENRAM_HOME)
else:
exe_name = "coverage run -p {0}/openram.py ".format(OPENRAM_HOME)
- config_name = "{0}config_20_{1}.py".format(OPENRAM_HOME + "/tests/",OPTS.tech_name)
+ config_name = "{0}config_{1}_back_end.py".format(OPENRAM_HOME + "/tests/",OPTS.tech_name)
cmd = "{0} -n -o {1} -p {2} {3} {4} 2>&1 > {5}/output.log".format(exe_name,
out_file,
out_path,
- verbosity,
+ options,
config_name,
out_path)
debug.info(1, cmd)
@@ -83,10 +86,11 @@ class openram_test(openram_test):
# now clean up the directory
- if os.path.exists(out_path):
- shutil.rmtree(out_path, ignore_errors=True)
- self.assertEqual(os.path.exists(out_path),False)
-
+ if OPTS.purge_temp:
+ if os.path.exists(out_path):
+ shutil.rmtree(out_path, ignore_errors=True)
+ self.assertEqual(os.path.exists(out_path),False)
+
globals.end_openram()
# run the test from the command line
@@ -94,4 +98,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
- unittest.main()
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/30_openram_front_end_test.py b/compiler/tests/30_openram_front_end_test.py
new file mode 100755
index 00000000..dbe7fcb9
--- /dev/null
+++ b/compiler/tests/30_openram_front_end_test.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+import unittest
+from testutils import *
+import sys,os,re,shutil
+sys.path.append(os.getenv("OPENRAM_HOME"))
+import globals
+from globals import OPTS
+from sram_factory import factory
+import debug
+import getpass
+
+#@unittest.skip("SKIPPING 30_openram_front_end_test")
+class openram_front_end_test(openram_test):
+
+ def runTest(self):
+ OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME"))
+ globals.init_openram("{0}/tests/config_{1}".format(OPENRAM_HOME,OPTS.tech_name))
+
+ debug.info(1, "Testing top-level front-end openram.py with 2-bit, 16 word SRAM.")
+ out_file = "testsram"
+ out_path = "/tmp/testsram_{0}_{1}_{2}".format(OPTS.tech_name,getpass.getuser(),os.getpid())
+
+ # make sure we start without the files existing
+ if os.path.exists(out_path):
+ shutil.rmtree(out_path, ignore_errors=True)
+ self.assertEqual(os.path.exists(out_path),False)
+
+ try:
+ os.makedirs(out_path, 0o0750)
+ except OSError as e:
+ if e.errno == 17: # errno.EEXIST
+ os.chmod(out_path, 0o0750)
+
+ # specify the same verbosity for the system call
+ options = ""
+ for i in range(OPTS.debug_level):
+ options += " -v"
+
+ if OPTS.spice_name:
+ options += " -s {}".format(OPTS.spice_name)
+
+ # Always perform code coverage
+ if OPTS.coverage == 0:
+ debug.warning("Failed to find coverage installation. This can be installed with pip3 install coverage")
+ exe_name = "{0}/openram.py ".format(OPENRAM_HOME)
+ else:
+ exe_name = "coverage run -p {0}/openram.py ".format(OPENRAM_HOME)
+ config_name = "{0}config_{1}_front_end.py".format(OPENRAM_HOME + "/tests/",OPTS.tech_name)
+ cmd = "{0} -n -o {1} -p {2} {3} {4} 2>&1 > {5}/output.log".format(exe_name,
+ out_file,
+ out_path,
+ options,
+ config_name,
+ out_path)
+ debug.info(1, cmd)
+ os.system(cmd)
+
+ # assert an error until we actually check a result
+ for extension in ["v", "lef", "sp", "gds"]:
+ filename = "{0}/{1}.{2}".format(out_path,out_file,extension)
+ debug.info(1,"Checking for file: " + filename)
+ self.assertEqual(os.path.exists(filename),True)
+
+ # Make sure there is any .lib file
+ import glob
+ files = glob.glob('{0}/*.lib'.format(out_path))
+ self.assertTrue(len(files)>0)
+
+ # Make sure there is any .html file
+ if os.path.exists(out_path):
+ datasheets = glob.glob('{0}/*html'.format(out_path))
+ self.assertTrue(len(datasheets)>0)
+
+ # grep any errors from the output
+ output_log = open("{0}/output.log".format(out_path),"r")
+ output = output_log.read()
+ output_log.close()
+ self.assertEqual(len(re.findall('ERROR',output)),0)
+ self.assertEqual(len(re.findall('WARNING',output)),0)
+
+
+ # now clean up the directory
+ if OPTS.purge_temp:
+ if os.path.exists(out_path):
+ shutil.rmtree(out_path, ignore_errors=True)
+ self.assertEqual(os.path.exists(out_path),False)
+
+ globals.end_openram()
+
+# run the test from the command line
+if __name__ == "__main__":
+ (OPTS, args) = globals.parse_args()
+ del sys.argv[1:]
+ header(__file__, OPTS.tech_name)
+ unittest.main(testRunner=debugTestRunner())
diff --git a/compiler/tests/config_20_freepdk45.py b/compiler/tests/config_20_freepdk45.py
deleted file mode 100755
index aaaa4c37..00000000
--- a/compiler/tests/config_20_freepdk45.py
+++ /dev/null
@@ -1,9 +0,0 @@
-word_size = 1
-num_words = 16
-
-tech_name = "freepdk45"
-process_corners = ["TT"]
-supply_voltages = [1.0]
-temperatures = [25]
-
-
diff --git a/compiler/tests/config_20_scn3me_subm.py b/compiler/tests/config_20_scn3me_subm.py
deleted file mode 100755
index 330d463b..00000000
--- a/compiler/tests/config_20_scn3me_subm.py
+++ /dev/null
@@ -1,8 +0,0 @@
-word_size = 1
-num_words = 16
-
-tech_name = "scn3me_subm"
-process_corners = ["TT"]
-supply_voltages = [5.0]
-temperatures = [25]
-
diff --git a/compiler/tests/config_20_scn4m_subm.py b/compiler/tests/config_20_scn4m_subm.py
deleted file mode 100755
index e847745b..00000000
--- a/compiler/tests/config_20_scn4m_subm.py
+++ /dev/null
@@ -1,12 +0,0 @@
-word_size = 1
-num_words = 16
-
-tech_name = "scn4m_subm"
-process_corners = ["TT"]
-supply_voltages = [5.0]
-temperatures = [25]
-
-drc_name = "magic"
-lvs_name = "netgen"
-pex_name = "magic"
-
diff --git a/compiler/tests/config_freepdk45.py b/compiler/tests/config_freepdk45.py
new file mode 100644
index 00000000..3103217f
--- /dev/null
+++ b/compiler/tests/config_freepdk45.py
@@ -0,0 +1,18 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+word_size = 1
+num_words = 16
+
+tech_name = "freepdk45"
+process_corners = ["TT"]
+supply_voltages = [1.0]
+temperatures = [25]
+
+route_supplies = True
+check_lvsdrc = True
+
diff --git a/compiler/tests/config_freepdk45_back_end.py b/compiler/tests/config_freepdk45_back_end.py
new file mode 100644
index 00000000..68417a3b
--- /dev/null
+++ b/compiler/tests/config_freepdk45_back_end.py
@@ -0,0 +1,20 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+word_size = 1
+num_words = 16
+
+tech_name = "freepdk45"
+process_corners = ["TT"]
+supply_voltages = [1.0]
+temperatures = [25]
+
+inline_lvsdrc = True
+route_supplies = True
+check_lvsdrc = True
+analytical_delay = False
+
diff --git a/compiler/tests/config_freepdk45_front_end.py b/compiler/tests/config_freepdk45_front_end.py
new file mode 100644
index 00000000..1886d808
--- /dev/null
+++ b/compiler/tests/config_freepdk45_front_end.py
@@ -0,0 +1,18 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+word_size = 1
+num_words = 16
+
+tech_name = "freepdk45"
+process_corners = ["TT"]
+supply_voltages = [1.0]
+temperatures = [25]
+
+analytical_delay = False
+
+
diff --git a/compiler/tests/config_scn3me_subm.py b/compiler/tests/config_scn3me_subm.py
new file mode 100644
index 00000000..7b5b5e15
--- /dev/null
+++ b/compiler/tests/config_scn3me_subm.py
@@ -0,0 +1,22 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+word_size = 1
+num_words = 16
+
+tech_name = "scn3me_subm"
+process_corners = ["TT"]
+supply_voltages = [5.0]
+temperatures = [25]
+
+route_supplies = True
+check_lvsdrc = True
+
+drc_name = "magic"
+lvs_name = "netgen"
+pex_name = "magic"
+
diff --git a/compiler/tests/config_scn3me_subm_back_end.py b/compiler/tests/config_scn3me_subm_back_end.py
new file mode 100644
index 00000000..f9c23417
--- /dev/null
+++ b/compiler/tests/config_scn3me_subm_back_end.py
@@ -0,0 +1,23 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+word_size = 1
+num_words = 16
+
+tech_name = "scn3me_subm"
+process_corners = ["TT"]
+supply_voltages = [5.0]
+temperatures = [25]
+
+route_supplies = True
+check_lvsdrc = True
+inline_lvsdrc = True
+analytical_delay = False
+
+drc_name = "magic"
+lvs_name = "netgen"
+pex_name = "magic"
diff --git a/compiler/tests/config_scn3me_subm_front_end.py b/compiler/tests/config_scn3me_subm_front_end.py
new file mode 100644
index 00000000..40504a18
--- /dev/null
+++ b/compiler/tests/config_scn3me_subm_front_end.py
@@ -0,0 +1,21 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+word_size = 1
+num_words = 16
+
+tech_name = "scn3me_subm"
+process_corners = ["TT"]
+supply_voltages = [5.0]
+temperatures = [25]
+
+analytical_delay = False
+
+drc_name = "magic"
+lvs_name = "netgen"
+pex_name = "magic"
+
diff --git a/compiler/tests/config_scn4m_subm.py b/compiler/tests/config_scn4m_subm.py
new file mode 100644
index 00000000..abb31435
--- /dev/null
+++ b/compiler/tests/config_scn4m_subm.py
@@ -0,0 +1,22 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+word_size = 1
+num_words = 16
+
+tech_name = "scn4m_subm"
+process_corners = ["TT"]
+supply_voltages = [5.0]
+temperatures = [25]
+
+route_supplies = True
+check_lvsdrc = True
+
+drc_name = "magic"
+lvs_name = "netgen"
+pex_name = "magic"
+
diff --git a/compiler/tests/config_scn4m_subm_back_end.py b/compiler/tests/config_scn4m_subm_back_end.py
new file mode 100644
index 00000000..35e4cd91
--- /dev/null
+++ b/compiler/tests/config_scn4m_subm_back_end.py
@@ -0,0 +1,23 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+word_size = 1
+num_words = 16
+
+tech_name = "scn4m_subm"
+process_corners = ["TT"]
+supply_voltages = [5.0]
+temperatures = [25]
+
+route_supplies = True
+check_lvsdrc = True
+inline_lvsdrc = True
+analytical_delay = False
+
+drc_name = "magic"
+lvs_name = "netgen"
+pex_name = "magic"
diff --git a/compiler/tests/config_scn4m_subm_front_end.py b/compiler/tests/config_scn4m_subm_front_end.py
new file mode 100644
index 00000000..142191a0
--- /dev/null
+++ b/compiler/tests/config_scn4m_subm_front_end.py
@@ -0,0 +1,19 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+word_size = 1
+num_words = 16
+
+tech_name = "scn4m_subm"
+process_corners = ["TT"]
+supply_voltages = [5.0]
+temperatures = [25]
+
+drc_name = "magic"
+lvs_name = "netgen"
+pex_name = "magic"
+
diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45.lef b/compiler/tests/golden/sram_2_16_1_freepdk45.lef
index 5a80802d..15ad3a88 100644
--- a/compiler/tests/golden/sram_2_16_1_freepdk45.lef
+++ b/compiler/tests/golden/sram_2_16_1_freepdk45.lef
@@ -3,7 +3,7 @@ NAMESCASESENSITIVE ON ;
BUSBITCHARS "[]" ;
DIVIDERCHAR "/" ;
UNITS
- DATABASE MICRONS 1000 ;
+ dataBASE MICRONS 1000 ;
END UNITS
SITE MacroSite
CLASS Core ;
@@ -14,48 +14,48 @@ MACRO sram_2_16_1_freepdk45
SIZE 12145.0 BY 43967.5 ;
SYMMETRY X Y R90 ;
SITE MacroSite ;
- PIN DATA[0]
+ PIN data[0]
DIRECTION INOUT ;
PORT
LAYER metal2 ;
RECT 10260.0 67.5 10330.0 207.5 ;
END
- END DATA[0]
- PIN DATA[1]
+ END data[0]
+ PIN data[1]
DIRECTION INOUT ;
PORT
LAYER metal2 ;
RECT 10965.0 67.5 11035.0 207.5 ;
END
- END DATA[1]
- PIN ADDR[0]
+ END data[1]
+ PIN addr[0]
DIRECTION INPUT ;
PORT
LAYER metal3 ;
RECT 67.5 8370.0 837.5 8440.0 ;
END
- END ADDR[0]
- PIN ADDR[1]
+ END addr[0]
+ PIN addr[1]
DIRECTION INPUT ;
PORT
LAYER metal3 ;
RECT 67.5 7665.0 837.5 7735.0 ;
END
- END ADDR[1]
- PIN ADDR[2]
+ END addr[1]
+ PIN addr[2]
DIRECTION INPUT ;
PORT
LAYER metal3 ;
RECT 67.5 6960.0 837.5 7030.0 ;
END
- END ADDR[2]
- PIN ADDR[3]
+ END addr[2]
+ PIN addr[3]
DIRECTION INPUT ;
PORT
LAYER metal3 ;
RECT 67.5 6255.0 837.5 6325.0 ;
END
- END ADDR[3]
+ END addr[3]
PIN CSb
DIRECTION INPUT ;
PORT
diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45.sp b/compiler/tests/golden/sram_2_16_1_freepdk45.sp
index 90500f05..c499390e 100644
--- a/compiler/tests/golden/sram_2_16_1_freepdk45.sp
+++ b/compiler/tests/golden/sram_2_16_1_freepdk45.sp
@@ -136,10 +136,10 @@ Xpmos1 vdd A net1 vdd nor_2_pmos121
Xpmos2 net1 B Z vdd nor_2_pmos222
.ENDS nor2
-.SUBCKT msf_control DATA[0] DATA[1] DATA[2] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] data_in[2] data_in_bar[2] clk vdd gnd
-XXdff0 DATA[0] data_in[0] data_in_bar[0] clk vdd gnd ms_flop
-XXdff1 DATA[1] data_in[1] data_in_bar[1] clk vdd gnd ms_flop
-XXdff2 DATA[2] data_in[2] data_in_bar[2] clk vdd gnd ms_flop
+.SUBCKT msf_control data[0] data[1] data[2] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] data_in[2] data_in_bar[2] clk vdd gnd
+XXdff0 data[0] data_in[0] data_in_bar[0] clk vdd gnd ms_flop
+XXdff1 data[1] data_in[1] data_in_bar[1] clk vdd gnd ms_flop
+XXdff2 data[2] data_in[2] data_in_bar[2] clk vdd gnd ms_flop
.ENDS msf_control
.SUBCKT replica_cell_6t bl br wl vdd gnd
@@ -524,16 +524,16 @@ XINVERTER_[14] Z[14] decode_out[14] vdd gnd INVERTER
XINVERTER_[15] Z[15] decode_out[15] vdd gnd INVERTER
.ENDS hierarchical_decoder
-.SUBCKT msf_address ADDR[0] ADDR[1] ADDR[2] ADDR[3] A[0] A_bar[0] A[1] A_bar[1] A[2] A_bar[2] A[3] A_bar[3] addr_clk vdd gnd
-XXdff0 ADDR[0] A[0] A_bar[0] addr_clk vdd gnd ms_flop
-XXdff1 ADDR[1] A[1] A_bar[1] addr_clk vdd gnd ms_flop
-XXdff2 ADDR[2] A[2] A_bar[2] addr_clk vdd gnd ms_flop
-XXdff3 ADDR[3] A[3] A_bar[3] addr_clk vdd gnd ms_flop
+.SUBCKT msf_address addr[0] addr[1] addr[2] addr[3] A[0] A_bar[0] A[1] A_bar[1] A[2] A_bar[2] A[3] A_bar[3] addr_clk vdd gnd
+XXdff0 addr[0] A[0] A_bar[0] addr_clk vdd gnd ms_flop
+XXdff1 addr[1] A[1] A_bar[1] addr_clk vdd gnd ms_flop
+XXdff2 addr[2] A[2] A_bar[2] addr_clk vdd gnd ms_flop
+XXdff3 addr[3] A[3] A_bar[3] addr_clk vdd gnd ms_flop
.ENDS msf_address
-.SUBCKT msf_data_in DATA[0] DATA[1] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] clk vdd gnd
-XXdff0 DATA[0] data_in[0] data_in_bar[0] clk vdd gnd ms_flop
-XXdff1 DATA[1] data_in[1] data_in_bar[1] clk vdd gnd ms_flop
+.SUBCKT msf_data_in data[0] data[1] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] clk vdd gnd
+XXdff0 data[0] data_in[0] data_in_bar[0] clk vdd gnd ms_flop
+XXdff1 data[1] data_in[1] data_in_bar[1] clk vdd gnd ms_flop
.ENDS msf_data_in
.SUBCKT msf_data_out data_out[0] data_out[1] tri_in[0] tri_in_bar[0] tri_in[1] tri_in_bar[1] sclk vdd gnd
@@ -551,9 +551,9 @@ M_6 in_inv in gnd gnd NMOS_VTG W=90.000000n L=50.000000n
.ENDS
-.SUBCKT tri_gate_array tri_in[0] tri_in[1] DATA[0] DATA[1] en en_bar vdd gnd
-XXtri_gate0 tri_in[0] DATA[0] en en_bar vdd gnd tri_gate
-XXtri_gate1 tri_in[1] DATA[1] en en_bar vdd gnd tri_gate
+.SUBCKT tri_gate_array tri_in[0] tri_in[1] data[0] data[1] en en_bar vdd gnd
+XXtri_gate0 tri_in[0] data[0] en en_bar vdd gnd tri_gate
+XXtri_gate1 tri_in[1] data[1] en en_bar vdd gnd tri_gate
.ENDS tri_gate_array
.SUBCKT wordline_driver decode_out[0] decode_out[1] decode_out[2] decode_out[3] decode_out[4] decode_out[5] decode_out[6] decode_out[7] decode_out[8] decode_out[9] decode_out[10] decode_out[11] decode_out[12] decode_out[13] decode_out[14] decode_out[15] wl[0] wl[1] wl[2] wl[3] wl[4] wl[5] wl[6] wl[7] wl[8] wl[9] wl[10] wl[11] wl[12] wl[13] wl[14] wl[15] clk vdd gnd
@@ -643,19 +643,19 @@ Xpmos1 vdd A net1 vdd nor_2_pmos185
Xpmos2 net1 B Z vdd nor_2_pmos286
.ENDS NOR2
-.SUBCKT test_bank1 DATA[0] DATA[1] ADDR[0] ADDR[1] ADDR[2] ADDR[3] s_en w_en tri_en_bar tri_en clk_bar clk vdd gnd
+.SUBCKT test_bank1 data[0] data[1] addr[0] addr[1] addr[2] addr[3] s_en w_en tri_en_bar tri_en clk_bar clk vdd gnd
Xbitcell_array bl[0] br[0] bl[1] br[1] wl[0] wl[1] wl[2] wl[3] wl[4] wl[5] wl[6] wl[7] wl[8] wl[9] wl[10] wl[11] wl[12] wl[13] wl[14] wl[15] vdd gnd bitcell_array
Xprecharge_array bl[0] br[0] bl[1] br[1] clk_bar vdd precharge_array
Xsense_amp_array bl[0] br[0] bl[1] br[1] data_out[0] data_out[1] s_en vdd gnd sense_amp_array
Xwrite_driver_array data_in[0] data_in[1] bl[0] br[0] bl[1] br[1] w_en vdd gnd write_driver_array
-Xdata_in_flop_array DATA[0] DATA[1] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] clk_bar vdd gnd msf_data_in
-Xtrigate_data_array data_out[0] data_out[1] DATA[0] DATA[1] tri_en tri_en_bar vdd gnd tri_gate_array
+Xdata_in_flop_array data[0] data[1] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] clk_bar vdd gnd msf_data_in
+Xtrigate_data_array data_out[0] data_out[1] data[0] data[1] tri_en tri_en_bar vdd gnd tri_gate_array
Xaddress_decoder A[0] A[1] A[2] A[3] decode_out[0] decode_out[1] decode_out[2] decode_out[3] decode_out[4] decode_out[5] decode_out[6] decode_out[7] decode_out[8] decode_out[9] decode_out[10] decode_out[11] decode_out[12] decode_out[13] decode_out[14] decode_out[15] vdd gnd hierarchical_decoder
Xwordline_driver decode_out[0] decode_out[1] decode_out[2] decode_out[3] decode_out[4] decode_out[5] decode_out[6] decode_out[7] decode_out[8] decode_out[9] decode_out[10] decode_out[11] decode_out[12] decode_out[13] decode_out[14] decode_out[15] wl[0] wl[1] wl[2] wl[3] wl[4] wl[5] wl[6] wl[7] wl[8] wl[9] wl[10] wl[11] wl[12] wl[13] wl[14] wl[15] clk vdd gnd wordline_driver
-Xaddress_flop_array ADDR[0] ADDR[1] ADDR[2] ADDR[3] A[0] A_bar[0] A[1] A_bar[1] A[2] A_bar[2] A[3] A_bar[3] clk vdd gnd msf_address
+Xaddress_flop_array addr[0] addr[1] addr[2] addr[3] A[0] A_bar[0] A[1] A_bar[1] A[2] A_bar[2] A[3] A_bar[3] clk vdd gnd msf_address
.ENDS test_bank1
-.SUBCKT testsram DATA[0] DATA[1] ADDR[0] ADDR[1] ADDR[2] ADDR[3] CSb WEb OEb clk vdd gnd
-Xbank0 DATA[0] DATA[1] ADDR[0] ADDR[1] ADDR[2] ADDR[3] s_en w_en tri_en_bar tri_en clk_bar clk vdd gnd test_bank1
+.SUBCKT testsram data[0] data[1] addr[0] addr[1] addr[2] addr[3] CSb WEb OEb clk vdd gnd
+Xbank0 data[0] data[1] addr[0] addr[1] addr[2] addr[3] s_en w_en tri_en_bar tri_en clk_bar clk vdd gnd test_bank1
Xcontrol CSb WEb OEb s_en w_en tri_en tri_en_bar clk_bar clk vdd gnd control_logic
.ENDS testsram
diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45.v b/compiler/tests/golden/sram_2_16_1_freepdk45.v
index 025350bc..5edd2fee 100644
--- a/compiler/tests/golden/sram_2_16_1_freepdk45.v
+++ b/compiler/tests/golden/sram_2_16_1_freepdk45.v
@@ -4,7 +4,7 @@
module sram_2_16_1_freepdk45(
// Port 0: RW
- clk0,csb0,web0,ADDR0,DIN0,DOUT0
+ clk0,csb0,web0,addr0,din0,dout0
);
parameter DATA_WIDTH = 2 ;
@@ -16,28 +16,28 @@ module sram_2_16_1_freepdk45(
input clk0; // clock
input csb0; // active low chip select
input web0; // active low write control
- input [ADDR_WIDTH-1:0] ADDR0;
- input [DATA_WIDTH-1:0] DIN0;
- output [DATA_WIDTH-1:0] DOUT0;
+ input [ADDR_WIDTH-1:0] addr0;
+ input [DATA_WIDTH-1:0] din0;
+ output [DATA_WIDTH-1:0] dout0;
reg csb0_reg;
reg web0_reg;
- reg [ADDR_WIDTH-1:0] ADDR0_reg;
- reg [DATA_WIDTH-1:0] DIN0_reg;
- reg [DATA_WIDTH-1:0] DOUT0;
+ reg [ADDR_WIDTH-1:0] addr0_reg;
+ reg [DATA_WIDTH-1:0] din0_reg;
+ reg [DATA_WIDTH-1:0] dout0;
// All inputs are registers
always @(posedge clk0)
begin
csb0_reg = csb0;
web0_reg = web0;
- ADDR0_reg = ADDR0;
- DIN0_reg = DIN0;
- DOUT0 = 2'bx;
+ addr0_reg = addr0;
+ din0_reg = din0;
+ dout0 = 2'bx;
if ( !csb0_reg && web0_reg )
- $display($time," Reading %m ADDR0=%b DOUT0=%b",ADDR0_reg,mem[ADDR0_reg]);
+ $display($time," Reading %m addr0=%b dout0=%b",addr0_reg,mem[addr0_reg]);
if ( !csb0_reg && !web0_reg )
- $display($time," Writing %m ADDR0=%b DIN0=%b",ADDR0_reg,DIN0_reg);
+ $display($time," Writing %m addr0=%b din0=%b",addr0_reg,din0_reg);
end
reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
@@ -47,7 +47,7 @@ reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
always @ (negedge clk0)
begin : MEM_WRITE0
if ( !csb0_reg && !web0_reg )
- mem[ADDR0_reg] = DIN0_reg;
+ mem[addr0_reg] = din0_reg;
end
// Memory Read Block Port 0
@@ -55,7 +55,7 @@ reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
always @ (negedge clk0)
begin : MEM_READ0
if (!csb0_reg && web0_reg)
- DOUT0 <= #(DELAY) mem[ADDR0_reg];
+ dout0 <= #(DELAY) mem[addr0_reg];
end
endmodule
diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_FF_1p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_FF_1p0V_25C_analytical.lib
index 88b54eca..a1c5a04b 100644
--- a/compiler/tests/golden/sram_2_16_1_freepdk45_FF_1p0V_25C_analytical.lib
+++ b/compiler/tests/golden/sram_2_16_1_freepdk45_FF_1p0V_25C_analytical.lib
@@ -1,10 +1,10 @@
library (sram_2_16_1_freepdk45_FF_1p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
- voltage_unit : "1v" ;
+ voltage_unit : "1V" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
- capacitive_load_unit(1 ,fF) ;
+ capacitive_load_unit(1, pF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
@@ -52,7 +52,7 @@ library (sram_2_16_1_freepdk45_FF_1p0V_25C_lib){
default_operating_conditions : OC;
- type (DATA){
+ type (data){
base_type : array;
data_type : bit;
bit_width : 2;
@@ -60,7 +60,7 @@ library (sram_2_16_1_freepdk45_FF_1p0V_25C_lib){
bit_to : 1;
}
- type (ADDR){
+ type (addr){
base_type : array;
data_type : bit;
bit_width : 4;
@@ -81,19 +81,19 @@ cell (sram_2_16_1_freepdk45){
area : 1124.88;
leakage_power () {
- when : "CSb0";
+ when : "csb0";
value : 0.000167;
}
cell_leakage_power : 0;
- bus(DIN0){
- bus_type : DATA;
+ bus(din0){
+ bus_type : data;
direction : input;
capacitance : 0.2091;
memory_write(){
- address : ADDR0;
+ address : addr0;
clocked_on : clk0;
}
- pin(DIN0[1:0]){
+ pin(din0[1:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -124,15 +124,15 @@ cell (sram_2_16_1_freepdk45){
}
}
}
- bus(DOUT0){
- bus_type : DATA;
+ bus(dout0){
+ bus_type : data;
direction : output;
max_capacitance : 1.6728;
min_capacitance : 0.052275;
memory_read(){
- address : ADDR0;
+ address : addr0;
}
- pin(DOUT0[1:0]){
+ pin(dout0[1:0]){
timing(){
timing_sense : non_unate;
related_pin : "clk0";
@@ -161,12 +161,12 @@ cell (sram_2_16_1_freepdk45){
}
}
- bus(ADDR0){
- bus_type : ADDR;
+ bus(addr0){
+ bus_type : addr;
direction : input;
capacitance : 0.2091;
max_transition : 0.04;
- pin(ADDR0[3:0]){
+ pin(addr0[3:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -198,7 +198,7 @@ cell (sram_2_16_1_freepdk45){
}
}
- pin(CSb0){
+ pin(csb0){
direction : input;
capacitance : 0.2091;
timing(){
@@ -231,7 +231,7 @@ cell (sram_2_16_1_freepdk45){
}
}
- pin(WEb0){
+ pin(web0){
direction : input;
capacitance : 0.2091;
timing(){
@@ -269,7 +269,7 @@ cell (sram_2_16_1_freepdk45){
direction : input;
capacitance : 0.2091;
internal_power(){
- when : "!CSb0 & clk0 & !WEb0";
+ when : "!csb0 & clk0 & !web0";
rise_power(scalar){
values("0.033101244168888884");
}
@@ -278,7 +278,7 @@ cell (sram_2_16_1_freepdk45){
}
}
internal_power(){
- when : "!CSb0 & !clk0 & WEb0";
+ when : "!csb0 & !clk0 & web0";
rise_power(scalar){
values("0.033101244168888884");
}
@@ -287,7 +287,7 @@ cell (sram_2_16_1_freepdk45){
}
}
internal_power(){
- when : "CSb0";
+ when : "csb0";
rise_power(scalar){
values("0");
}
diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_SS_1p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_SS_1p0V_25C_analytical.lib
index e78fe8d3..865daada 100644
--- a/compiler/tests/golden/sram_2_16_1_freepdk45_SS_1p0V_25C_analytical.lib
+++ b/compiler/tests/golden/sram_2_16_1_freepdk45_SS_1p0V_25C_analytical.lib
@@ -1,10 +1,10 @@
library (sram_2_16_1_freepdk45_SS_1p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
- voltage_unit : "1v" ;
+ voltage_unit : "1V" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
- capacitive_load_unit(1 ,fF) ;
+ capacitive_load_unit(1, pF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
@@ -52,7 +52,7 @@ library (sram_2_16_1_freepdk45_SS_1p0V_25C_lib){
default_operating_conditions : OC;
- type (DATA){
+ type (data){
base_type : array;
data_type : bit;
bit_width : 2;
@@ -60,7 +60,7 @@ library (sram_2_16_1_freepdk45_SS_1p0V_25C_lib){
bit_to : 1;
}
- type (ADDR){
+ type (addr){
base_type : array;
data_type : bit;
bit_width : 4;
@@ -81,19 +81,19 @@ cell (sram_2_16_1_freepdk45){
area : 1124.88;
leakage_power () {
- when : "CSb0";
+ when : "csb0";
value : 0.000167;
}
cell_leakage_power : 0;
- bus(DIN0){
- bus_type : DATA;
+ bus(din0){
+ bus_type : data;
direction : input;
capacitance : 0.2091;
memory_write(){
- address : ADDR0;
+ address : addr0;
clocked_on : clk0;
}
- pin(DIN0[1:0]){
+ pin(din0[1:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -124,15 +124,15 @@ cell (sram_2_16_1_freepdk45){
}
}
}
- bus(DOUT0){
- bus_type : DATA;
+ bus(dout0){
+ bus_type : data;
direction : output;
max_capacitance : 1.6728;
min_capacitance : 0.052275;
memory_read(){
- address : ADDR0;
+ address : addr0;
}
- pin(DOUT0[1:0]){
+ pin(dout0[1:0]){
timing(){
timing_sense : non_unate;
related_pin : "clk0";
@@ -161,12 +161,12 @@ cell (sram_2_16_1_freepdk45){
}
}
- bus(ADDR0){
- bus_type : ADDR;
+ bus(addr0){
+ bus_type : addr;
direction : input;
capacitance : 0.2091;
max_transition : 0.04;
- pin(ADDR0[3:0]){
+ pin(addr0[3:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -198,7 +198,7 @@ cell (sram_2_16_1_freepdk45){
}
}
- pin(CSb0){
+ pin(csb0){
direction : input;
capacitance : 0.2091;
timing(){
@@ -231,7 +231,7 @@ cell (sram_2_16_1_freepdk45){
}
}
- pin(WEb0){
+ pin(web0){
direction : input;
capacitance : 0.2091;
timing(){
@@ -269,7 +269,7 @@ cell (sram_2_16_1_freepdk45){
direction : input;
capacitance : 0.2091;
internal_power(){
- when : "!CSb0 & clk0 & !WEb0";
+ when : "!csb0 & clk0 & !web0";
rise_power(scalar){
values("0.033101244168888884");
}
@@ -278,7 +278,7 @@ cell (sram_2_16_1_freepdk45){
}
}
internal_power(){
- when : "!CSb0 & !clk0 & WEb0";
+ when : "!csb0 & !clk0 & web0";
rise_power(scalar){
values("0.033101244168888884");
}
@@ -287,7 +287,7 @@ cell (sram_2_16_1_freepdk45){
}
}
internal_power(){
- when : "CSb0";
+ when : "csb0";
rise_power(scalar){
values("0");
}
diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C.lib
index 0939b4bb..72d01a0f 100644
--- a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C.lib
+++ b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C.lib
@@ -1,10 +1,10 @@
library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
- voltage_unit : "1v" ;
+ voltage_unit : "1V" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
- capacitive_load_unit(1 ,fF) ;
+ capacitive_load_unit(1, pF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
@@ -52,7 +52,7 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){
default_operating_conditions : OC;
- type (DATA){
+ type (data){
base_type : array;
data_type : bit;
bit_width : 2;
@@ -60,7 +60,7 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){
bit_to : 1;
}
- type (ADDR){
+ type (addr){
base_type : array;
data_type : bit;
bit_width : 4;
@@ -81,19 +81,19 @@ cell (sram_2_16_1_freepdk45){
area : 977.4951374999999;
leakage_power () {
- when : "CSb0";
+ when : "csb0";
value : 0.0011164579999999999;
}
cell_leakage_power : 0;
- bus(DIN0){
- bus_type : DATA;
+ bus(din0){
+ bus_type : data;
direction : input;
capacitance : 0.2091;
memory_write(){
- address : ADDR0;
+ address : addr0;
clocked_on : clk0;
}
- pin(DIN0[1:0]){
+ pin(din0[1:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -124,15 +124,15 @@ cell (sram_2_16_1_freepdk45){
}
}
}
- bus(DOUT0){
- bus_type : DATA;
+ bus(dout0){
+ bus_type : data;
direction : output;
max_capacitance : 1.6728;
min_capacitance : 0.052275;
memory_read(){
- address : ADDR0;
+ address : addr0;
}
- pin(DOUT0[1:0]){
+ pin(dout0[1:0]){
timing(){
timing_sense : non_unate;
related_pin : "clk0";
@@ -161,12 +161,12 @@ cell (sram_2_16_1_freepdk45){
}
}
- bus(ADDR0){
- bus_type : ADDR;
+ bus(addr0){
+ bus_type : addr;
direction : input;
capacitance : 0.2091;
max_transition : 0.04;
- pin(ADDR0[3:0]){
+ pin(addr0[3:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -198,7 +198,7 @@ cell (sram_2_16_1_freepdk45){
}
}
- pin(CSb0){
+ pin(csb0){
direction : input;
capacitance : 0.2091;
timing(){
@@ -231,7 +231,7 @@ cell (sram_2_16_1_freepdk45){
}
}
- pin(WEb0){
+ pin(web0){
direction : input;
capacitance : 0.2091;
timing(){
@@ -269,7 +269,7 @@ cell (sram_2_16_1_freepdk45){
direction : input;
capacitance : 0.2091;
internal_power(){
- when : "!CSb0 & clk0 & !WEb0";
+ when : "!csb0 & clk0 & !web0";
rise_power(scalar){
values("0.03599689694444445");
}
@@ -278,7 +278,7 @@ cell (sram_2_16_1_freepdk45){
}
}
internal_power(){
- when : "!CSb0 & !clk0 & WEb0";
+ when : "!csb0 & !clk0 & web0";
rise_power(scalar){
values("0.029906643888888886");
}
@@ -287,7 +287,7 @@ cell (sram_2_16_1_freepdk45){
}
}
internal_power(){
- when : "CSb0";
+ when : "csb0";
rise_power(scalar){
values("0");
}
diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_analytical.lib
index a06ff5b5..33587063 100644
--- a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_analytical.lib
+++ b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_analytical.lib
@@ -1,10 +1,10 @@
library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
- voltage_unit : "1v" ;
+ voltage_unit : "1V" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
- capacitive_load_unit(1 ,fF) ;
+ capacitive_load_unit(1, pF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
@@ -52,7 +52,7 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){
default_operating_conditions : OC;
- type (DATA){
+ type (data){
base_type : array;
data_type : bit;
bit_width : 2;
@@ -60,7 +60,7 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){
bit_to : 1;
}
- type (ADDR){
+ type (addr){
base_type : array;
data_type : bit;
bit_width : 4;
@@ -81,19 +81,19 @@ cell (sram_2_16_1_freepdk45){
area : 977.4951374999999;
leakage_power () {
- when : "CSb0";
+ when : "csb0";
value : 0.000179;
}
cell_leakage_power : 0;
- bus(DIN0){
- bus_type : DATA;
+ bus(din0){
+ bus_type : data;
direction : input;
capacitance : 0.2091;
memory_write(){
- address : ADDR0;
+ address : addr0;
clocked_on : clk0;
}
- pin(DIN0[1:0]){
+ pin(din0[1:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -124,15 +124,15 @@ cell (sram_2_16_1_freepdk45){
}
}
}
- bus(DOUT0){
- bus_type : DATA;
+ bus(dout0){
+ bus_type : data;
direction : output;
max_capacitance : 1.6728;
min_capacitance : 0.052275;
memory_read(){
- address : ADDR0;
+ address : addr0;
}
- pin(DOUT0[1:0]){
+ pin(dout0[1:0]){
timing(){
timing_sense : non_unate;
related_pin : "clk0";
@@ -161,12 +161,12 @@ cell (sram_2_16_1_freepdk45){
}
}
- bus(ADDR0){
- bus_type : ADDR;
+ bus(addr0){
+ bus_type : addr;
direction : input;
capacitance : 0.2091;
max_transition : 0.04;
- pin(ADDR0[3:0]){
+ pin(addr0[3:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -198,7 +198,7 @@ cell (sram_2_16_1_freepdk45){
}
}
- pin(CSb0){
+ pin(csb0){
direction : input;
capacitance : 0.2091;
timing(){
@@ -231,7 +231,7 @@ cell (sram_2_16_1_freepdk45){
}
}
- pin(WEb0){
+ pin(web0){
direction : input;
capacitance : 0.2091;
timing(){
@@ -269,7 +269,7 @@ cell (sram_2_16_1_freepdk45){
direction : input;
capacitance : 0.2091;
internal_power(){
- when : "!CSb0 & clk0 & !WEb0";
+ when : "!csb0 & clk0 & !web0";
rise_power(scalar){
values("0.0747594982142222");
}
@@ -278,7 +278,7 @@ cell (sram_2_16_1_freepdk45){
}
}
internal_power(){
- when : "!CSb0 & !clk0 & WEb0";
+ when : "!csb0 & !clk0 & web0";
rise_power(scalar){
values("0.0747594982142222");
}
@@ -287,7 +287,7 @@ cell (sram_2_16_1_freepdk45){
}
}
internal_power(){
- when : "CSb0";
+ when : "csb0";
rise_power(scalar){
values("0");
}
diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_pruned.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_pruned.lib
index d7d7de7e..5817211b 100644
--- a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_pruned.lib
+++ b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_pruned.lib
@@ -1,10 +1,10 @@
library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
- voltage_unit : "1v" ;
+ voltage_unit : "1V" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
- capacitive_load_unit(1 ,fF) ;
+ capacitive_load_unit(1, pF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
@@ -52,7 +52,7 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){
default_operating_conditions : OC;
- type (DATA){
+ type (data){
base_type : array;
data_type : bit;
bit_width : 2;
@@ -60,7 +60,7 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){
bit_to : 1;
}
- type (ADDR){
+ type (addr){
base_type : array;
data_type : bit;
bit_width : 4;
@@ -81,19 +81,19 @@ cell (sram_2_16_1_freepdk45){
area : 977.4951374999999;
leakage_power () {
- when : "CSb0";
+ when : "csb0";
value : 0.0011164579999999999;
}
cell_leakage_power : 0;
- bus(DIN0){
- bus_type : DATA;
+ bus(din0){
+ bus_type : data;
direction : input;
capacitance : 0.2091;
memory_write(){
- address : ADDR0;
+ address : addr0;
clocked_on : clk0;
}
- pin(DIN0[1:0]){
+ pin(din0[1:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -124,15 +124,15 @@ cell (sram_2_16_1_freepdk45){
}
}
}
- bus(DOUT0){
- bus_type : DATA;
+ bus(dout0){
+ bus_type : data;
direction : output;
max_capacitance : 1.6728;
min_capacitance : 0.052275;
memory_read(){
- address : ADDR0;
+ address : addr0;
}
- pin(DOUT0[1:0]){
+ pin(dout0[1:0]){
timing(){
timing_sense : non_unate;
related_pin : "clk0";
@@ -161,12 +161,12 @@ cell (sram_2_16_1_freepdk45){
}
}
- bus(ADDR0){
- bus_type : ADDR;
+ bus(addr0){
+ bus_type : addr;
direction : input;
capacitance : 0.2091;
max_transition : 0.04;
- pin(ADDR0[3:0]){
+ pin(addr0[3:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -198,7 +198,7 @@ cell (sram_2_16_1_freepdk45){
}
}
- pin(CSb0){
+ pin(csb0){
direction : input;
capacitance : 0.2091;
timing(){
@@ -231,7 +231,7 @@ cell (sram_2_16_1_freepdk45){
}
}
- pin(WEb0){
+ pin(web0){
direction : input;
capacitance : 0.2091;
timing(){
@@ -269,7 +269,7 @@ cell (sram_2_16_1_freepdk45){
direction : input;
capacitance : 0.2091;
internal_power(){
- when : "!CSb0 & clk0 & !WEb0";
+ when : "!csb0 & clk0 & !web0";
rise_power(scalar){
values("0.03334771594444444");
}
@@ -278,7 +278,7 @@ cell (sram_2_16_1_freepdk45){
}
}
internal_power(){
- when : "!CSb0 & !clk0 & WEb0";
+ when : "!csb0 & !clk0 & web0";
rise_power(scalar){
values("0.028457026222222223");
}
@@ -287,7 +287,7 @@ cell (sram_2_16_1_freepdk45){
}
}
internal_power(){
- when : "CSb0";
+ when : "csb0";
rise_power(scalar){
values("0");
}
diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm.lef b/compiler/tests/golden/sram_2_16_1_scn4m_subm.lef
index 9d784677..08ebcdb2 100644
--- a/compiler/tests/golden/sram_2_16_1_scn4m_subm.lef
+++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm.lef
@@ -3,7 +3,7 @@ NAMESCASESENSITIVE ON ;
BUSBITCHARS "[]" ;
DIVIDERCHAR "/" ;
UNITS
- DATABASE MICRONS 1000 ;
+ dataBASE MICRONS 1000 ;
END UNITS
SITE MacroSite
CLASS Core ;
@@ -14,48 +14,48 @@ MACRO sram_2_16_1_scn3me_subm
SIZE 148050.0 BY 461850.0 ;
SYMMETRY X Y R90 ;
SITE MacroSite ;
- PIN DATA[0]
+ PIN data[0]
DIRECTION INOUT ;
PORT
LAYER metal2 ;
RECT 120900.0 0.0 121800.0 1800.0 ;
END
- END DATA[0]
- PIN DATA[1]
+ END data[0]
+ PIN data[1]
DIRECTION INOUT ;
PORT
LAYER metal2 ;
RECT 131100.0 0.0 132000.0 1800.0 ;
END
- END DATA[1]
- PIN ADDR[0]
+ END data[1]
+ PIN addr[0]
DIRECTION INPUT ;
PORT
LAYER metal3 ;
RECT 0.0 87600.0 10800.0 89100.0 ;
END
- END ADDR[0]
- PIN ADDR[1]
+ END addr[0]
+ PIN addr[1]
DIRECTION INPUT ;
PORT
LAYER metal3 ;
RECT 0.0 77400.0 10800.0 78900.0 ;
END
- END ADDR[1]
- PIN ADDR[2]
+ END addr[1]
+ PIN addr[2]
DIRECTION INPUT ;
PORT
LAYER metal3 ;
RECT 0.0 67200.0 10800.0 68700.0 ;
END
- END ADDR[2]
- PIN ADDR[3]
+ END addr[2]
+ PIN addr[3]
DIRECTION INPUT ;
PORT
LAYER metal3 ;
RECT 0.0 57000.0 10800.0 58500.0 ;
END
- END ADDR[3]
+ END addr[3]
PIN CSb
DIRECTION INPUT ;
PORT
diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm.sp b/compiler/tests/golden/sram_2_16_1_scn4m_subm.sp
index 258b4464..1b8d4e07 100644
--- a/compiler/tests/golden/sram_2_16_1_scn4m_subm.sp
+++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm.sp
@@ -136,10 +136,10 @@ Xpmos1 vdd A net1 vdd nor_2_pmos125
Xpmos2 net1 B Z vdd nor_2_pmos226
.ENDS nor2
-.SUBCKT msf_control DATA[0] DATA[1] DATA[2] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] data_in[2] data_in_bar[2] clk vdd gnd
-XXdff0 DATA[0] data_in[0] data_in_bar[0] clk vdd gnd ms_flop
-XXdff1 DATA[1] data_in[1] data_in_bar[1] clk vdd gnd ms_flop
-XXdff2 DATA[2] data_in[2] data_in_bar[2] clk vdd gnd ms_flop
+.SUBCKT msf_control data[0] data[1] data[2] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] data_in[2] data_in_bar[2] clk vdd gnd
+XXdff0 data[0] data_in[0] data_in_bar[0] clk vdd gnd ms_flop
+XXdff1 data[1] data_in[1] data_in_bar[1] clk vdd gnd ms_flop
+XXdff2 data[2] data_in[2] data_in_bar[2] clk vdd gnd ms_flop
.ENDS msf_control
*********************** "cell_6t" ******************************
@@ -541,16 +541,16 @@ XINVERTER_[14] Z[14] decode_out[14] vdd gnd INVERTER
XINVERTER_[15] Z[15] decode_out[15] vdd gnd INVERTER
.ENDS hierarchical_decoder
-.SUBCKT msf_address ADDR[0] ADDR[1] ADDR[2] ADDR[3] A[0] A_bar[0] A[1] A_bar[1] A[2] A_bar[2] A[3] A_bar[3] addr_clk vdd gnd
-XXdff0 ADDR[0] A[0] A_bar[0] addr_clk vdd gnd ms_flop
-XXdff1 ADDR[1] A[1] A_bar[1] addr_clk vdd gnd ms_flop
-XXdff2 ADDR[2] A[2] A_bar[2] addr_clk vdd gnd ms_flop
-XXdff3 ADDR[3] A[3] A_bar[3] addr_clk vdd gnd ms_flop
+.SUBCKT msf_address addr[0] addr[1] addr[2] addr[3] A[0] A_bar[0] A[1] A_bar[1] A[2] A_bar[2] A[3] A_bar[3] addr_clk vdd gnd
+XXdff0 addr[0] A[0] A_bar[0] addr_clk vdd gnd ms_flop
+XXdff1 addr[1] A[1] A_bar[1] addr_clk vdd gnd ms_flop
+XXdff2 addr[2] A[2] A_bar[2] addr_clk vdd gnd ms_flop
+XXdff3 addr[3] A[3] A_bar[3] addr_clk vdd gnd ms_flop
.ENDS msf_address
-.SUBCKT msf_data_in DATA[0] DATA[1] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] clk vdd gnd
-XXdff0 DATA[0] data_in[0] data_in_bar[0] clk vdd gnd ms_flop
-XXdff1 DATA[1] data_in[1] data_in_bar[1] clk vdd gnd ms_flop
+.SUBCKT msf_data_in data[0] data[1] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] clk vdd gnd
+XXdff0 data[0] data_in[0] data_in_bar[0] clk vdd gnd ms_flop
+XXdff1 data[1] data_in[1] data_in_bar[1] clk vdd gnd ms_flop
.ENDS msf_data_in
.SUBCKT msf_data_out data_out[0] data_out[1] tri_in[0] tri_in_bar[0] tri_in[1] tri_in_bar[1] sclk vdd gnd
@@ -571,9 +571,9 @@ M_6 in_inv in gnd gnd n W='1.2*1u' L=0.6u
.ENDS
-.SUBCKT tri_gate_array tri_in[0] tri_in[1] DATA[0] DATA[1] en en_bar vdd gnd
-XXtri_gate0 tri_in[0] DATA[0] en en_bar vdd gnd tri_gate
-XXtri_gate1 tri_in[1] DATA[1] en en_bar vdd gnd tri_gate
+.SUBCKT tri_gate_array tri_in[0] tri_in[1] data[0] data[1] en en_bar vdd gnd
+XXtri_gate0 tri_in[0] data[0] en en_bar vdd gnd tri_gate
+XXtri_gate1 tri_in[1] data[1] en en_bar vdd gnd tri_gate
.ENDS tri_gate_array
.SUBCKT wordline_driver decode_out[0] decode_out[1] decode_out[2] decode_out[3] decode_out[4] decode_out[5] decode_out[6] decode_out[7] decode_out[8] decode_out[9] decode_out[10] decode_out[11] decode_out[12] decode_out[13] decode_out[14] decode_out[15] wl[0] wl[1] wl[2] wl[3] wl[4] wl[5] wl[6] wl[7] wl[8] wl[9] wl[10] wl[11] wl[12] wl[13] wl[14] wl[15] clk vdd gnd
@@ -663,19 +663,19 @@ Xpmos1 vdd A net1 vdd nor_2_pmos197
Xpmos2 net1 B Z vdd nor_2_pmos298
.ENDS NOR2
-.SUBCKT test_bank1 DATA[0] DATA[1] ADDR[0] ADDR[1] ADDR[2] ADDR[3] s_en w_en tri_en_bar tri_en clk_bar clk vdd gnd
+.SUBCKT test_bank1 data[0] data[1] addr[0] addr[1] addr[2] addr[3] s_en w_en tri_en_bar tri_en clk_bar clk vdd gnd
Xbitcell_array bl[0] br[0] bl[1] br[1] wl[0] wl[1] wl[2] wl[3] wl[4] wl[5] wl[6] wl[7] wl[8] wl[9] wl[10] wl[11] wl[12] wl[13] wl[14] wl[15] vdd gnd bitcell_array
Xprecharge_array bl[0] br[0] bl[1] br[1] clk_bar vdd precharge_array
Xsense_amp_array bl[0] br[0] bl[1] br[1] data_out[0] data_out[1] s_en vdd gnd sense_amp_array
Xwrite_driver_array data_in[0] data_in[1] bl[0] br[0] bl[1] br[1] w_en vdd gnd write_driver_array
-Xdata_in_flop_array DATA[0] DATA[1] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] clk_bar vdd gnd msf_data_in
-Xtrigate_data_array data_out[0] data_out[1] DATA[0] DATA[1] tri_en tri_en_bar vdd gnd tri_gate_array
+Xdata_in_flop_array data[0] data[1] data_in[0] data_in_bar[0] data_in[1] data_in_bar[1] clk_bar vdd gnd msf_data_in
+Xtrigate_data_array data_out[0] data_out[1] data[0] data[1] tri_en tri_en_bar vdd gnd tri_gate_array
Xaddress_decoder A[0] A[1] A[2] A[3] decode_out[0] decode_out[1] decode_out[2] decode_out[3] decode_out[4] decode_out[5] decode_out[6] decode_out[7] decode_out[8] decode_out[9] decode_out[10] decode_out[11] decode_out[12] decode_out[13] decode_out[14] decode_out[15] vdd gnd hierarchical_decoder
Xwordline_driver decode_out[0] decode_out[1] decode_out[2] decode_out[3] decode_out[4] decode_out[5] decode_out[6] decode_out[7] decode_out[8] decode_out[9] decode_out[10] decode_out[11] decode_out[12] decode_out[13] decode_out[14] decode_out[15] wl[0] wl[1] wl[2] wl[3] wl[4] wl[5] wl[6] wl[7] wl[8] wl[9] wl[10] wl[11] wl[12] wl[13] wl[14] wl[15] clk vdd gnd wordline_driver
-Xaddress_flop_array ADDR[0] ADDR[1] ADDR[2] ADDR[3] A[0] A_bar[0] A[1] A_bar[1] A[2] A_bar[2] A[3] A_bar[3] clk vdd gnd msf_address
+Xaddress_flop_array addr[0] addr[1] addr[2] addr[3] A[0] A_bar[0] A[1] A_bar[1] A[2] A_bar[2] A[3] A_bar[3] clk vdd gnd msf_address
.ENDS test_bank1
-.SUBCKT testsram DATA[0] DATA[1] ADDR[0] ADDR[1] ADDR[2] ADDR[3] CSb WEb OEb clk vdd gnd
-Xbank0 DATA[0] DATA[1] ADDR[0] ADDR[1] ADDR[2] ADDR[3] s_en w_en tri_en_bar tri_en clk_bar clk vdd gnd test_bank1
+.SUBCKT testsram data[0] data[1] addr[0] addr[1] addr[2] addr[3] CSb WEb OEb clk vdd gnd
+Xbank0 data[0] data[1] addr[0] addr[1] addr[2] addr[3] s_en w_en tri_en_bar tri_en clk_bar clk vdd gnd test_bank1
Xcontrol CSb WEb OEb s_en w_en tri_en tri_en_bar clk_bar clk vdd gnd control_logic
.ENDS testsram
diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm.v b/compiler/tests/golden/sram_2_16_1_scn4m_subm.v
index 7017b8a7..cec47c19 100644
--- a/compiler/tests/golden/sram_2_16_1_scn4m_subm.v
+++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm.v
@@ -4,7 +4,7 @@
module sram_2_16_1_scn4m_subm(
// Port 0: RW
- clk0,csb0,web0,ADDR0,DIN0,DOUT0
+ clk0,csb0,web0,addr0,din0,dout0
);
parameter DATA_WIDTH = 2 ;
@@ -16,28 +16,28 @@ module sram_2_16_1_scn4m_subm(
input clk0; // clock
input csb0; // active low chip select
input web0; // active low write control
- input [ADDR_WIDTH-1:0] ADDR0;
- input [DATA_WIDTH-1:0] DIN0;
- output [DATA_WIDTH-1:0] DOUT0;
+ input [ADDR_WIDTH-1:0] addr0;
+ input [DATA_WIDTH-1:0] din0;
+ output [DATA_WIDTH-1:0] dout0;
reg csb0_reg;
reg web0_reg;
- reg [ADDR_WIDTH-1:0] ADDR0_reg;
- reg [DATA_WIDTH-1:0] DIN0_reg;
- reg [DATA_WIDTH-1:0] DOUT0;
+ reg [ADDR_WIDTH-1:0] addr0_reg;
+ reg [DATA_WIDTH-1:0] din0_reg;
+ reg [DATA_WIDTH-1:0] dout0;
// All inputs are registers
always @(posedge clk0)
begin
csb0_reg = csb0;
web0_reg = web0;
- ADDR0_reg = ADDR0;
- DIN0_reg = DIN0;
- DOUT0 = 2'bx;
+ addr0_reg = addr0;
+ din0_reg = din0;
+ dout0 = 2'bx;
if ( !csb0_reg && web0_reg )
- $display($time," Reading %m ADDR0=%b DOUT0=%b",ADDR0_reg,mem[ADDR0_reg]);
+ $display($time," Reading %m addr0=%b dout0=%b",addr0_reg,mem[addr0_reg]);
if ( !csb0_reg && !web0_reg )
- $display($time," Writing %m ADDR0=%b DIN0=%b",ADDR0_reg,DIN0_reg);
+ $display($time," Writing %m addr0=%b din0=%b",addr0_reg,din0_reg);
end
reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
@@ -47,7 +47,7 @@ reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
always @ (negedge clk0)
begin : MEM_WRITE0
if ( !csb0_reg && !web0_reg )
- mem[ADDR0_reg] = DIN0_reg;
+ mem[addr0_reg] = din0_reg;
end
// Memory Read Block Port 0
@@ -55,7 +55,7 @@ reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
always @ (negedge clk0)
begin : MEM_READ0
if (!csb0_reg && web0_reg)
- DOUT0 <= #(DELAY) mem[ADDR0_reg];
+ dout0 <= #(DELAY) mem[addr0_reg];
end
endmodule
diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm_FF_5p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_scn4m_subm_FF_5p0V_25C_analytical.lib
index 5cbecd94..c370f993 100644
--- a/compiler/tests/golden/sram_2_16_1_scn4m_subm_FF_5p0V_25C_analytical.lib
+++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm_FF_5p0V_25C_analytical.lib
@@ -1,10 +1,10 @@
library (sram_2_16_1_scn4m_subm_FF_5p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
- voltage_unit : "1v" ;
+ voltage_unit : "1V" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
- capacitive_load_unit(1 ,fF) ;
+ capacitive_load_unit(1, pF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
@@ -52,7 +52,7 @@ library (sram_2_16_1_scn4m_subm_FF_5p0V_25C_lib){
default_operating_conditions : OC;
- type (DATA){
+ type (data){
base_type : array;
data_type : bit;
bit_width : 2;
@@ -60,7 +60,7 @@ library (sram_2_16_1_scn4m_subm_FF_5p0V_25C_lib){
bit_to : 1;
}
- type (ADDR){
+ type (addr){
base_type : array;
data_type : bit;
bit_width : 4;
@@ -81,19 +81,19 @@ cell (sram_2_16_1_scn4m_subm){
area : 73068.14000000001;
leakage_power () {
- when : "CSb0";
+ when : "csb0";
value : 0.000167;
}
cell_leakage_power : 0;
- bus(DIN0){
- bus_type : DATA;
+ bus(din0){
+ bus_type : data;
direction : input;
capacitance : 9.8242;
memory_write(){
- address : ADDR0;
+ address : addr0;
clocked_on : clk0;
}
- pin(DIN0[1:0]){
+ pin(din0[1:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -124,15 +124,15 @@ cell (sram_2_16_1_scn4m_subm){
}
}
}
- bus(DOUT0){
- bus_type : DATA;
+ bus(dout0){
+ bus_type : data;
direction : output;
max_capacitance : 78.5936;
min_capacitance : 2.45605;
memory_read(){
- address : ADDR0;
+ address : addr0;
}
- pin(DOUT0[1:0]){
+ pin(dout0[1:0]){
timing(){
timing_sense : non_unate;
related_pin : "clk0";
@@ -161,12 +161,12 @@ cell (sram_2_16_1_scn4m_subm){
}
}
- bus(ADDR0){
- bus_type : ADDR;
+ bus(addr0){
+ bus_type : addr;
direction : input;
capacitance : 9.8242;
max_transition : 0.4;
- pin(ADDR0[3:0]){
+ pin(addr0[3:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -198,7 +198,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
- pin(CSb0){
+ pin(csb0){
direction : input;
capacitance : 9.8242;
timing(){
@@ -231,7 +231,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
- pin(WEb0){
+ pin(web0){
direction : input;
capacitance : 9.8242;
timing(){
@@ -269,7 +269,7 @@ cell (sram_2_16_1_scn4m_subm){
direction : input;
capacitance : 9.8242;
internal_power(){
- when : "!CSb0 & clk0 & !WEb0";
+ when : "!csb0 & clk0 & !web0";
rise_power(scalar){
values("4.99880645");
}
@@ -278,7 +278,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
internal_power(){
- when : "!CSb0 & !clk0 & WEb0";
+ when : "!csb0 & !clk0 & web0";
rise_power(scalar){
values("4.99880645");
}
@@ -287,7 +287,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
internal_power(){
- when : "CSb0";
+ when : "csb0";
rise_power(scalar){
values("0");
}
diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm_SS_5p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_scn4m_subm_SS_5p0V_25C_analytical.lib
index 3324f119..f52de676 100644
--- a/compiler/tests/golden/sram_2_16_1_scn4m_subm_SS_5p0V_25C_analytical.lib
+++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm_SS_5p0V_25C_analytical.lib
@@ -1,10 +1,10 @@
library (sram_2_16_1_scn4m_subm_SS_5p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
- voltage_unit : "1v" ;
+ voltage_unit : "1V" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
- capacitive_load_unit(1 ,fF) ;
+ capacitive_load_unit(1, pF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
@@ -52,7 +52,7 @@ library (sram_2_16_1_scn4m_subm_SS_5p0V_25C_lib){
default_operating_conditions : OC;
- type (DATA){
+ type (data){
base_type : array;
data_type : bit;
bit_width : 2;
@@ -60,7 +60,7 @@ library (sram_2_16_1_scn4m_subm_SS_5p0V_25C_lib){
bit_to : 1;
}
- type (ADDR){
+ type (addr){
base_type : array;
data_type : bit;
bit_width : 4;
@@ -81,19 +81,19 @@ cell (sram_2_16_1_scn4m_subm){
area : 73068.14000000001;
leakage_power () {
- when : "CSb0";
+ when : "csb0";
value : 0.000167;
}
cell_leakage_power : 0;
- bus(DIN0){
- bus_type : DATA;
+ bus(din0){
+ bus_type : data;
direction : input;
capacitance : 9.8242;
memory_write(){
- address : ADDR0;
+ address : addr0;
clocked_on : clk0;
}
- pin(DIN0[1:0]){
+ pin(din0[1:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -124,15 +124,15 @@ cell (sram_2_16_1_scn4m_subm){
}
}
}
- bus(DOUT0){
- bus_type : DATA;
+ bus(dout0){
+ bus_type : data;
direction : output;
max_capacitance : 78.5936;
min_capacitance : 2.45605;
memory_read(){
- address : ADDR0;
+ address : addr0;
}
- pin(DOUT0[1:0]){
+ pin(dout0[1:0]){
timing(){
timing_sense : non_unate;
related_pin : "clk0";
@@ -161,12 +161,12 @@ cell (sram_2_16_1_scn4m_subm){
}
}
- bus(ADDR0){
- bus_type : ADDR;
+ bus(addr0){
+ bus_type : addr;
direction : input;
capacitance : 9.8242;
max_transition : 0.4;
- pin(ADDR0[3:0]){
+ pin(addr0[3:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -198,7 +198,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
- pin(CSb0){
+ pin(csb0){
direction : input;
capacitance : 9.8242;
timing(){
@@ -231,7 +231,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
- pin(WEb0){
+ pin(web0){
direction : input;
capacitance : 9.8242;
timing(){
@@ -269,7 +269,7 @@ cell (sram_2_16_1_scn4m_subm){
direction : input;
capacitance : 9.8242;
internal_power(){
- when : "!CSb0 & clk0 & !WEb0";
+ when : "!csb0 & clk0 & !web0";
rise_power(scalar){
values("4.99880645");
}
@@ -278,7 +278,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
internal_power(){
- when : "!CSb0 & !clk0 & WEb0";
+ when : "!csb0 & !clk0 & web0";
rise_power(scalar){
values("4.99880645");
}
@@ -287,7 +287,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
internal_power(){
- when : "CSb0";
+ when : "csb0";
rise_power(scalar){
values("0");
}
diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C.lib b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C.lib
index f8a337d3..7447a1e2 100644
--- a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C.lib
+++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C.lib
@@ -1,10 +1,10 @@
library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
- voltage_unit : "1v" ;
+ voltage_unit : "1V" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
- capacitive_load_unit(1 ,fF) ;
+ capacitive_load_unit(1, pF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
@@ -52,7 +52,7 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){
default_operating_conditions : OC;
- type (DATA){
+ type (data){
base_type : array;
data_type : bit;
bit_width : 2;
@@ -60,7 +60,7 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){
bit_to : 1;
}
- type (ADDR){
+ type (addr){
base_type : array;
data_type : bit;
bit_width : 4;
@@ -81,19 +81,19 @@ cell (sram_2_16_1_scn4m_subm){
area : 60774.3;
leakage_power () {
- when : "CSb0";
+ when : "csb0";
value : 0.0009813788999999999;
}
cell_leakage_power : 0;
- bus(DIN0){
- bus_type : DATA;
+ bus(din0){
+ bus_type : data;
direction : input;
capacitance : 9.8242;
memory_write(){
- address : ADDR0;
+ address : addr0;
clocked_on : clk0;
}
- pin(DIN0[1:0]){
+ pin(din0[1:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -124,15 +124,15 @@ cell (sram_2_16_1_scn4m_subm){
}
}
}
- bus(DOUT0){
- bus_type : DATA;
+ bus(dout0){
+ bus_type : data;
direction : output;
max_capacitance : 78.5936;
min_capacitance : 2.45605;
memory_read(){
- address : ADDR0;
+ address : addr0;
}
- pin(DOUT0[1:0]){
+ pin(dout0[1:0]){
timing(){
timing_sense : non_unate;
related_pin : "clk0";
@@ -161,12 +161,12 @@ cell (sram_2_16_1_scn4m_subm){
}
}
- bus(ADDR0){
- bus_type : ADDR;
+ bus(addr0){
+ bus_type : addr;
direction : input;
capacitance : 9.8242;
max_transition : 0.4;
- pin(ADDR0[3:0]){
+ pin(addr0[3:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -198,7 +198,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
- pin(CSb0){
+ pin(csb0){
direction : input;
capacitance : 9.8242;
timing(){
@@ -231,7 +231,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
- pin(WEb0){
+ pin(web0){
direction : input;
capacitance : 9.8242;
timing(){
@@ -269,7 +269,7 @@ cell (sram_2_16_1_scn4m_subm){
direction : input;
capacitance : 9.8242;
internal_power(){
- when : "!CSb0 & clk0 & !WEb0";
+ when : "!csb0 & clk0 & !web0";
rise_power(scalar){
values("9.972790277777777");
}
@@ -278,7 +278,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
internal_power(){
- when : "!CSb0 & !clk0 & WEb0";
+ when : "!csb0 & !clk0 & web0";
rise_power(scalar){
values("8.899322499999998");
}
@@ -287,7 +287,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
internal_power(){
- when : "CSb0";
+ when : "csb0";
rise_power(scalar){
values("0");
}
diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_analytical.lib
index 72a106ac..4248b986 100644
--- a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_analytical.lib
+++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_analytical.lib
@@ -1,10 +1,10 @@
library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
- voltage_unit : "1v" ;
+ voltage_unit : "1V" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
- capacitive_load_unit(1 ,fF) ;
+ capacitive_load_unit(1, pF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
@@ -52,7 +52,7 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){
default_operating_conditions : OC;
- type (DATA){
+ type (data){
base_type : array;
data_type : bit;
bit_width : 2;
@@ -60,7 +60,7 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){
bit_to : 1;
}
- type (ADDR){
+ type (addr){
base_type : array;
data_type : bit;
bit_width : 4;
@@ -81,19 +81,19 @@ cell (sram_2_16_1_scn4m_subm){
area : 60774.3;
leakage_power () {
- when : "CSb0";
+ when : "csb0";
value : 0.000179;
}
cell_leakage_power : 0;
- bus(DIN0){
- bus_type : DATA;
+ bus(din0){
+ bus_type : data;
direction : input;
capacitance : 9.8242;
memory_write(){
- address : ADDR0;
+ address : addr0;
clocked_on : clk0;
}
- pin(DIN0[1:0]){
+ pin(din0[1:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -124,15 +124,15 @@ cell (sram_2_16_1_scn4m_subm){
}
}
}
- bus(DOUT0){
- bus_type : DATA;
+ bus(dout0){
+ bus_type : data;
direction : output;
max_capacitance : 78.5936;
min_capacitance : 2.45605;
memory_read(){
- address : ADDR0;
+ address : addr0;
}
- pin(DOUT0[1:0]){
+ pin(dout0[1:0]){
timing(){
timing_sense : non_unate;
related_pin : "clk0";
@@ -161,12 +161,12 @@ cell (sram_2_16_1_scn4m_subm){
}
}
- bus(ADDR0){
- bus_type : ADDR;
+ bus(addr0){
+ bus_type : addr;
direction : input;
capacitance : 9.8242;
max_transition : 0.4;
- pin(ADDR0[3:0]){
+ pin(addr0[3:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -198,7 +198,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
- pin(CSb0){
+ pin(csb0){
direction : input;
capacitance : 9.8242;
timing(){
@@ -231,7 +231,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
- pin(WEb0){
+ pin(web0){
direction : input;
capacitance : 9.8242;
timing(){
@@ -269,7 +269,7 @@ cell (sram_2_16_1_scn4m_subm){
direction : input;
capacitance : 9.8242;
internal_power(){
- when : "!CSb0 & clk0 & !WEb0";
+ when : "!csb0 & clk0 & !web0";
rise_power(scalar){
values("11.3049604371");
}
@@ -278,7 +278,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
internal_power(){
- when : "!CSb0 & !clk0 & WEb0";
+ when : "!csb0 & !clk0 & web0";
rise_power(scalar){
values("11.3049604371");
}
@@ -287,7 +287,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
internal_power(){
- when : "CSb0";
+ when : "csb0";
rise_power(scalar){
values("0");
}
diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_pruned.lib b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_pruned.lib
index 124f80ff..7b649d0d 100644
--- a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_pruned.lib
+++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_pruned.lib
@@ -1,10 +1,10 @@
library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
- voltage_unit : "1v" ;
+ voltage_unit : "1V" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
- capacitive_load_unit(1 ,fF) ;
+ capacitive_load_unit(1, pF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
@@ -52,7 +52,7 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){
default_operating_conditions : OC;
- type (DATA){
+ type (data){
base_type : array;
data_type : bit;
bit_width : 2;
@@ -60,7 +60,7 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){
bit_to : 1;
}
- type (ADDR){
+ type (addr){
base_type : array;
data_type : bit;
bit_width : 4;
@@ -81,19 +81,19 @@ cell (sram_2_16_1_scn4m_subm){
area : 60774.3;
leakage_power () {
- when : "CSb0";
+ when : "csb0";
value : 0.0009813788999999999;
}
cell_leakage_power : 0;
- bus(DIN0){
- bus_type : DATA;
+ bus(din0){
+ bus_type : data;
direction : input;
capacitance : 9.8242;
memory_write(){
- address : ADDR0;
+ address : addr0;
clocked_on : clk0;
}
- pin(DIN0[1:0]){
+ pin(din0[1:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -124,15 +124,15 @@ cell (sram_2_16_1_scn4m_subm){
}
}
}
- bus(DOUT0){
- bus_type : DATA;
+ bus(dout0){
+ bus_type : data;
direction : output;
max_capacitance : 78.5936;
min_capacitance : 2.45605;
memory_read(){
- address : ADDR0;
+ address : addr0;
}
- pin(DOUT0[1:0]){
+ pin(dout0[1:0]){
timing(){
timing_sense : non_unate;
related_pin : "clk0";
@@ -161,12 +161,12 @@ cell (sram_2_16_1_scn4m_subm){
}
}
- bus(ADDR0){
- bus_type : ADDR;
+ bus(addr0){
+ bus_type : addr;
direction : input;
capacitance : 9.8242;
max_transition : 0.4;
- pin(ADDR0[3:0]){
+ pin(addr0[3:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk0";
@@ -198,7 +198,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
- pin(CSb0){
+ pin(csb0){
direction : input;
capacitance : 9.8242;
timing(){
@@ -231,7 +231,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
- pin(WEb0){
+ pin(web0){
direction : input;
capacitance : 9.8242;
timing(){
@@ -269,7 +269,7 @@ cell (sram_2_16_1_scn4m_subm){
direction : input;
capacitance : 9.8242;
internal_power(){
- when : "!CSb0 & clk0 & !WEb0";
+ when : "!csb0 & clk0 & !web0";
rise_power(scalar){
values("9.602821763527778");
}
@@ -278,7 +278,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
internal_power(){
- when : "!CSb0 & !clk0 & WEb0";
+ when : "!csb0 & !clk0 & web0";
rise_power(scalar){
values("8.647938152416664");
}
@@ -287,7 +287,7 @@ cell (sram_2_16_1_scn4m_subm){
}
}
internal_power(){
- when : "CSb0";
+ when : "csb0";
rise_power(scalar){
values("0");
}
diff --git a/compiler/tests/regress.py b/compiler/tests/regress.py
index d97def2b..e60b010d 100755
--- a/compiler/tests/regress.py
+++ b/compiler/tests/regress.py
@@ -1,15 +1,22 @@
#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import re
import unittest
import sys,os
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
-from testutils import header,openram_test
+from testutils import *
header(__file__, OPTS.tech_name)
# get a list of all files in the tests directory
diff --git a/compiler/tests/sram_1rw_1r_tb.v b/compiler/tests/sram_1rw_1r_tb.v
index 9c212e0a..3a2194e1 100644
--- a/compiler/tests/sram_1rw_1r_tb.v
+++ b/compiler/tests/sram_1rw_1r_tb.v
@@ -19,14 +19,14 @@ module sram_1rw_1r_tb;
reg csb1;
wire [1:0] dout1;
- sram_1rw_1r_2_16_scn4m_subm U0 (.DIN0(din0),
- .DOUT0(dout0),
- .ADDR0(addr0),
+ sram_1rw_1r_2_16_scn4m_subm U0 (.din0(din0),
+ .dout0(dout0),
+ .addr0(addr0),
.csb0(csb0),
.web0(web0),
.clk0(clk),
- .DOUT1(dout1),
- .ADDR1(addr1),
+ .dout1(dout1),
+ .addr1(addr1),
.csb1(csb1),
.clk1(clk)
);
diff --git a/compiler/tests/sram_1rw_tb.v b/compiler/tests/sram_1rw_tb.v
index 31f120e8..f4f6cb33 100644
--- a/compiler/tests/sram_1rw_tb.v
+++ b/compiler/tests/sram_1rw_tb.v
@@ -13,9 +13,9 @@ module sram_1rw_tb;
reg web0;
wire [1:0] dout0;
- sram_2_16_scn4m_subm U0 (.DIN0(din0),
- .DOUT0(dout0),
- .ADDR0(addr0),
+ sram_2_16_scn4m_subm U0 (.din0(din0),
+ .dout0(dout0),
+ .addr0(addr0),
.csb0(csb0),
.web0(web0),
.clk0(clk)
diff --git a/compiler/tests/sram_1rw_wmask_tb.v b/compiler/tests/sram_1rw_wmask_tb.v
new file mode 100644
index 00000000..51d03d6b
--- /dev/null
+++ b/compiler/tests/sram_1rw_wmask_tb.v
@@ -0,0 +1,110 @@
+`define assert(signal, value) \
+if (!(signal === value)) begin \
+ $display("ASSERTION FAILED in %m: signal != value"); \
+ $finish;\
+end
+
+module sram_1rw_wmask_tb;
+ reg clk;
+
+ reg [3:0] addr0;
+ reg [1:0] din0;
+ reg csb0;
+ reg web0;
+ reg [1:0] wmask0;
+ wire [1:0] dout0;
+
+ sram_2b_16_1rw_freepdk45 U0 (.din0(din0),
+ .dout0(dout0),
+ .addr0(addr0),
+ .csb0(csb0),
+ .web0(web0),
+ .wmask0(wmask0),
+ .clk0(clk)
+ );
+
+
+ initial
+ begin
+ //$monitor("%g addr0=%b din0=%b dout0=%b",
+ // $time, addr0, din0, dout0);
+
+
+ clk = 1;
+ csb0 = 1;
+ web0 = 1;
+ wmask0 = 2'b01;
+ addr0 = 0;
+ din0 = 0;
+
+ // write
+ #10 din0=2'b10;
+ addr0=4'h1;
+ web0 = 0;
+ csb0 = 0;
+ wmask0 = 2'b10;
+
+ // read
+ #10 din0=2'b11;
+ addr0=4'h1;
+ web0 = 1;
+ csb0 = 0;
+
+ #10 `assert(dout0, 2'b1x)
+
+ // write another
+ #10 din0=2'b01;
+ addr0=4'hC;
+ web0 = 0;
+ csb0 = 0;
+ wmask0 = 2'b01;
+
+ // read undefined
+ #10 din0=2'b11;
+ addr0=4'h0;
+ web0 = 1;
+ csb0 = 0;
+ wmask0 = 2'b01;
+
+ #10 `assert(dout0, 2'bxx)
+
+ // read defined
+ din0=2'b11;
+ addr0=4'hC;
+ web0 = 1;
+ csb0 = 0;
+ wmask0 = 2'b01;
+
+ #10 `assert(dout0, 2'bx1)
+
+ // write another
+ din0=2'b01;
+ addr0=4'h1;
+ web0 = 0;
+ csb0 = 0;
+
+ // read defined
+ #10 din0=2'b11;
+ addr0=4'h1;
+ web0 = 1;
+ csb0 = 0;
+
+
+ #10 `assert(dout0, 2'b11)
+
+ // read undefined
+ din0=2'b11;
+ addr0=4'h0;
+ web0 = 1;
+ csb0 = 0;
+
+ #10 `assert(dout0, 2'bxx)
+
+ #10 $finish;
+
+ end
+
+ always
+ #5 clk = !clk;
+
+endmodule
\ No newline at end of file
diff --git a/compiler/tests/testutils.py b/compiler/tests/testutils.py
old mode 100755
new mode 100644
index 799c223e..95675c38
--- a/compiler/tests/testutils.py
+++ b/compiler/tests/testutils.py
@@ -1,14 +1,22 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import unittest,warnings
+import pdb,traceback
import sys,os,glob,copy
import shutil
-sys.path.append(os.path.join(sys.path[0],".."))
+sys.path.append(os.getenv("OPENRAM_HOME"))
from globals import OPTS
import debug
class openram_test(unittest.TestCase):
""" Base unit test that we have some shared classes in. """
-
+
def local_drc_check(self, w):
self.reset()
@@ -23,11 +31,11 @@ class openram_test(unittest.TestCase):
if OPTS.purge_temp:
self.cleanup()
-
+
def local_check(self, a, final_verification=False):
self.reset()
-
+
tempspice = "{0}{1}.sp".format(OPTS.openram_temp,a.name)
tempgds = "{0}{1}.gds".format(OPTS.openram_temp,a.name)
@@ -44,7 +52,7 @@ class openram_test(unittest.TestCase):
#shutil.make_archive(zip_file, 'zip', OPTS.openram_temp)
self.fail("DRC failed: {}".format(a.name))
-
+
result=verify.run_lvs(a.name, tempgds, tempspice, final_verification=final_verification)
if result != 0:
#zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid())
@@ -52,9 +60,22 @@ class openram_test(unittest.TestCase):
#shutil.make_archive(zip_file, 'zip', OPTS.openram_temp)
self.fail("LVS mismatch: {}".format(a.name))
+ # For debug...
+ #import pdb; pdb.set_trace()
if OPTS.purge_temp:
self.cleanup()
-
+
+ def run_pex(self, a, output=None):
+ if output == None:
+ output = OPTS.openram_temp + a.name + ".pex.netlist"
+ tempspice = "{0}{1}.sp".format(OPTS.openram_temp,a.name)
+ tempgds = "{0}{1}.gds".format(OPTS.openram_temp,a.name)
+
+ import verify
+ result=verify.run_pex(a.name, tempgds, tempspice, output=output, final_verification=False)
+ if result != 0:
+ self.fail("PEX ERROR: {}".format(a.name))
+ return output
def find_feasible_test_period(self, delay_obj, sram, load, slew):
"""Creates a delay simulation to determine a feasible period for the functional tests to run.
@@ -62,24 +83,21 @@ class openram_test(unittest.TestCase):
"""
debug.info(1, "Finding feasible period for current test.")
delay_obj.set_load_slew(load, slew)
- delay_obj.set_probe(probe_address="1"*sram.addr_size, probe_data=(sram.word_size-1))
test_port = delay_obj.read_ports[0] #Only test one port, assumes other ports have similar period.
- delay_obj.create_signal_names()
- delay_obj.create_measurement_names()
- delay_obj.create_measurement_objects()
- delay_obj.find_feasible_period_one_port(test_port)
- return delay_obj.period
-
+ delay_obj.analysis_init(probe_address="1"*sram.addr_size, probe_data=(sram.word_size-1))
+ delay_obj.find_feasible_period_one_port(test_port)
+ return delay_obj.period
+
def cleanup(self):
""" Reset the duplicate checker and cleanup files. """
files = glob.glob(OPTS.openram_temp + '*')
for f in files:
# Only remove the files
if os.path.isfile(f):
- os.remove(f)
+ os.remove(f)
def reset(self):
- """
+ """
Reset everything after each test.
"""
# Reset the static duplicate name checker for unit tests.
@@ -108,7 +126,7 @@ class openram_test(unittest.TestCase):
data_string=pprint.pformat(data)
debug.error("Results exceeded {:.1f}% tolerance compared to golden results:\n".format(error_tolerance*100)+data_string)
return data_matches
-
+
def isclose(self,key,value,actual_value,error_tolerance=1e-2):
@@ -124,7 +142,7 @@ class openram_test(unittest.TestCase):
return False
def relative_diff(self, value1, value2):
- """ Compute the relative difference of two values and normalize to the largest.
+ """ Compute the relative difference of two values and normalize to the largest.
If largest value is 0, just return the difference."""
# Edge case to avoid divide by zero
@@ -140,7 +158,7 @@ class openram_test(unittest.TestCase):
# Edge case where greater is a zero
if norm_value == 0:
min_value = abs(min(value1, value2))
-
+
return abs(value1 - value2) / norm_value
@@ -154,15 +172,15 @@ class openram_test(unittest.TestCase):
"""Compare two files.
Arguments:
-
+
filename1 -- First file name
-
+
filename2 -- Second file name
Return value:
-
+
True if the files are the same, False otherwise.
-
+
"""
import re
import debug
@@ -195,7 +213,7 @@ class openram_test(unittest.TestCase):
debug.info(3,"line1_floats: "+str(line1_floats))
debug.info(3,"line2_floats: "+str(line2_floats))
-
+
# 2. Remove the floats from the string
for f in line1_floats:
line1=line1.replace(f,"",1)
@@ -207,10 +225,10 @@ class openram_test(unittest.TestCase):
# 3. Convert to floats rather than strings
line1_floats = [float(x) for x in line1_floats]
line2_floats = [float(x) for x in line1_floats]
-
+
# 4. Check if remaining string matches
if line1 != line2:
- #Uncomment if you want to see all the individual chars of the two lines
+ #Uncomment if you want to see all the individual chars of the two lines
#print(str([i for i in line1]))
#print(str([i for i in line2]))
if mismatches==0:
@@ -273,12 +291,13 @@ class openram_test(unittest.TestCase):
debug.info(2,"MATCH {0} {1}".format(filename1,filename2))
return True
+
def header(filename, technology):
# Skip the header for gitlab regression
import getpass
if getpass.getuser() == "gitlab-runner":
return
-
+
tst = "Running Test for:"
print("\n")
print(" ______________________________________________________________________________ ")
@@ -289,3 +308,21 @@ def header(filename, technology):
from globals import OPTS
print("|=========" + OPTS.openram_temp.center(60) + "=========|")
print("|==============================================================================|")
+
+def debugTestRunner(post_mortem=None):
+ """unittest runner doing post mortem debugging on failing tests"""
+ if post_mortem is None and not OPTS.purge_temp:
+ post_mortem = pdb.post_mortem
+ class DebugTestResult(unittest.TextTestResult):
+ def addError(self, test, err):
+ # called before tearDown()
+ traceback.print_exception(*err)
+ if post_mortem:
+ post_mortem(err[2])
+ super(DebugTestResult, self).addError(test, err)
+ def addFailure(self, test, err):
+ traceback.print_exception(*err)
+ if post_mortem:
+ post_mortem(err[2])
+ super(DebugTestResult, self).addFailure(test, err)
+ return unittest.TextTestRunner(resultclass=DebugTestResult)
diff --git a/compiler/verify/__init__.py b/compiler/verify/__init__.py
index 1f0ffaab..042fecff 100644
--- a/compiler/verify/__init__.py
+++ b/compiler/verify/__init__.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
"""
This is a module that will import the correct DRC/LVS/PEX
module based on what tools are found. It is a layer of indirection
@@ -26,9 +33,6 @@ else:
OPTS.lvs_exe = get_tool("LVS", ["calibre","assura","netgen"], OPTS.lvs_name)
OPTS.pex_exe = get_tool("PEX", ["calibre","magic"], OPTS.pex_name)
-if OPTS.check_lvsdrc and OPTS.tech_name == "freepdk45":
- debug.check(OPTS.drc_exe[0]!="magic","Magic does not support FreePDK45 for DRC.")
-
if OPTS.drc_exe == None:
from .none import run_drc,print_drc_stats
elif "calibre"==OPTS.drc_exe[0]:
diff --git a/compiler/verify/assura.py b/compiler/verify/assura.py
index af034730..d1d6146f 100644
--- a/compiler/verify/assura.py
+++ b/compiler/verify/assura.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
"""
This is a DRC/LVS interface for Assura. It implements completely two
functions: run_drc and run_lvs, that perform these functions in batch
diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py
index 5f8d2c73..8abca448 100644
--- a/compiler/verify/calibre.py
+++ b/compiler/verify/calibre.py
@@ -1,82 +1,37 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
"""
This is a DRC/LVS interface for calibre. It implements completely
-independently two functions: run_drc and run_lvs, that perform these
+independently three functions: run_drc, run_lvs, run_pex, that perform these
functions in batch mode and will return true/false if the result
passes. All of the setup (the rules, temp dirs, etc.) should be
contained in this file. Replacing with another DRC/LVS tool involves
rewriting this code to work properly. Porting to a new technology in
Calibre means pointing the code to the proper DRC and LVS rule files.
-A calibre DRC runset file contains, at the minimum, the following information:
-
-*drcRulesFile: /mada/software/techfiles/FreePDK45/ncsu_basekit/techfile/calibre/calibreDRC.rul
-*drcRunDir: .
-*drcLayoutPaths: ./cell_6t.gds
-*drcLayoutPrimary: cell_6t
-*drcLayoutSystem: GDSII
-*drcResultsformat: ASCII
-*drcResultsFile: cell_6t.drc.results
-*drcSummaryFile: cell_6t.drc.summary
-*cmnFDILayerMapFile: ./layer.map
-*cmnFDIUseLayerMap: 1
-
-This can be executed in "batch" mode with the following command:
-
-calibre -gui -drc example_drc_runset -batch
-
-To open the results, you can do this:
-
-calibredrv cell_6t.gds
-Select Verification->Start RVE.
-Select the cell_6t.drc.results file.
-Click on the errors and they will highlight in the design layout viewer.
-
-For LVS:
-
-*lvsRulesFile: /mada/software/techfiles/FreePDK45/ncsu_basekit/techfile/calibre/calibreLVS.rul
-*lvsRunDir: .
-*lvsLayoutPaths: ./cell_6t.gds
-*lvsLayoutPrimary: cell_6t
-*lvsSourcePath: ./cell_6t.sp
-*lvsSourcePrimary: cell_6t
-*lvsSourceSystem: SPICE
-*lvsSpiceFile: extracted.sp
-*lvsPowerNames: vdd
-*lvsGroundNames: vss
-*lvsIgnorePorts: 1
-*lvsERCDatabase: cell_6t.erc.results
-*lvsERCSummaryFile: cell_6t.erc.summary
-*lvsReportFile: cell_6t.lvs.report
-*lvsMaskDBFile: cell_6t.maskdb
-*cmnFDILayerMapFile: ./layer.map
-*cmnFDIUseLayerMap: 1
-
-To run and see results:
-
-calibre -gui -lvs example_lvs_runset -batch
-more cell_6t.lvs.report
"""
import os
+import shutil
import re
import time
import debug
from globals import OPTS
-import subprocess
+from run_script import *
# Keep track of statistics
num_drc_runs = 0
num_lvs_runs = 0
num_pex_runs = 0
-def run_drc(cell_name, gds_name, extract=False, final_verification=False):
- """Run DRC check on a given top-level name which is
- implemented in gds_name."""
-
- global num_drc_runs
- num_drc_runs += 1
-
+def write_calibre_drc_script(cell_name, extract, final_verification):
+ """ Write a Calibre runset file and script to run DRC """
# the runset file contains all the options to run calibre
from tech import drc
drc_rules = drc["drc_rules"]
@@ -84,12 +39,12 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False):
drc_runset = {
'drcRulesFile': drc_rules,
'drcRunDir': OPTS.openram_temp,
- 'drcLayoutPaths': gds_name,
+ 'drcLayoutPaths': cell_name + ".gds",
'drcLayoutPrimary': cell_name,
'drcLayoutSystem': 'GDSII',
'drcResultsformat': 'ASCII',
- 'drcResultsFile': OPTS.openram_temp + cell_name + ".drc.results",
- 'drcSummaryFile': OPTS.openram_temp + cell_name + ".drc.summary",
+ 'drcResultsFile': cell_name + ".drc.results",
+ 'drcSummaryFile': cell_name + ".drc.summary",
'cmnFDILayerMapFile': drc["layer_map"],
'cmnFDIUseLayerMap': 1
}
@@ -100,26 +55,151 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False):
f.write("*{0}: {1}\n".format(k, drc_runset[k]))
f.close()
- # run drc
- cwd = os.getcwd()
- os.chdir(OPTS.openram_temp)
- errfile = "{0}{1}.drc.err".format(OPTS.openram_temp, cell_name)
- outfile = "{0}{1}.drc.out".format(OPTS.openram_temp, cell_name)
+ # Create an auxiliary script to run calibre with the runset
+ run_file = OPTS.openram_temp + "run_drc.sh"
+ f = open(run_file, "w")
+ f.write("#!/bin/sh\n")
+ cmd = "{0} -gui -drc {1}drc_runset -batch".format(OPTS.drc_exe[1],
+ OPTS.openram_temp)
+ f.write(cmd)
+ f.write("\n")
+ f.close()
+ os.system("chmod u+x {}".format(run_file))
+ return drc_runset
- cmd = "{0} -gui -drc {1}drc_runset -batch 2> {2} 1> {3}".format(OPTS.drc_exe[1],
- OPTS.openram_temp,
- errfile,
- outfile)
- debug.info(2, cmd)
- os.system(cmd)
- os.chdir(cwd)
+def write_calibre_lvs_script(cell_name, final_verification):
+ """ Write a Calibre runset file and script to run LVS """
+
+ from tech import drc
+ lvs_rules = drc["lvs_rules"]
+ lvs_runset = {
+ 'lvsRulesFile': lvs_rules,
+ 'lvsRunDir': OPTS.openram_temp,
+ 'lvsLayoutPaths': cell_name + ".gds",
+ 'lvsLayoutPrimary': cell_name,
+ 'lvsSourcePath': cell_name + ".sp",
+ 'lvsSourcePrimary': cell_name,
+ 'lvsSourceSystem': 'SPICE',
+ 'lvsSpiceFile': "extracted.sp",
+ 'lvsPowerNames': 'vdd',
+ 'lvsGroundNames': 'gnd',
+ 'lvsIncludeSVRFCmds': 1,
+ 'lvsIgnorePorts': 1,
+ 'lvsERCDatabase': cell_name + ".erc.results",
+ 'lvsERCSummaryFile': cell_name + ".erc.summary",
+ 'lvsReportFile': cell_name + ".lvs.report",
+ 'lvsMaskDBFile': cell_name + ".maskdb",
+ 'cmnFDILayerMapFile': drc["layer_map"],
+ 'cmnFDIUseLayerMap': 1,
+ 'cmnTranscriptFile': './lvs.log',
+ 'cmnTranscriptEchoToFile': 1,
+ 'lvsRecognizeGates': 'NONE',
+ }
+ # FIXME: Remove when vdd/gnd connected
+ #'cmnVConnectNamesState' : 'ALL', #connects all nets with the same namee
+ # FIXME: Remove when vdd/gnd connected
+ #'lvsAbortOnSupplyError' : 0
+
+ if not final_verification:
+ lvs_runset['cmnVConnectReport']=1
+ lvs_runset['cmnVConnectNamesState']='SOME'
+ lvs_runset['cmnVConnectNames']='vdd gnd'
+ else:
+ lvs_runset['lvsAbortOnSupplyError']=1
+
+
+
+ # write the runset file
+ f = open(OPTS.openram_temp + "lvs_runset", "w")
+ for k in sorted(iter(lvs_runset.keys())):
+ f.write("*{0}: {1}\n".format(k, lvs_runset[k]))
+ f.close()
+
+ # Create an auxiliary script to run calibre with the runset
+ run_file = OPTS.openram_temp + "run_lvs.sh"
+ f = open(run_file, "w")
+ f.write("#!/bin/sh\n")
+ PDK_DIR=os.environ.get("PDK_DIR")
+ f.write("export PDK_DIR={}\n".format(PDK_DIR))
+ cmd = "{0} -gui -lvs {1}lvs_runset -batch".format(OPTS.lvs_exe[1],
+ OPTS.openram_temp)
+ f.write(cmd)
+ f.write("\n")
+ f.close()
+ os.system("chmod u+x {}".format(run_file))
+
+ return lvs_runset
+
+def write_calibre_pex_script(cell_name, extract, output, final_verification):
+
+ if output == None:
+ output = name + ".pex.netlist"
+
+ # check if lvs report has been done
+ # if not run drc and lvs
+ if not os.path.isfile(cell_name + ".lvs.report"):
+ gds_name = OPTS.openram_temp +"/"+ cell_name + ".gds"
+ sp_name = OPTS.openram_temp +"/"+ cell_name + ".sp"
+ run_drc(cell_name, gds_name)
+ run_lvs(cell_name, gds_name, sp_name)
+
+ from tech import drc
+ pex_rules = drc["xrc_rules"]
+ pex_runset = {
+ 'pexRulesFile': pex_rules,
+ 'pexRunDir': OPTS.openram_temp,
+ 'pexLayoutPaths': cell_name + ".gds",
+ 'pexLayoutPrimary': cell_name,
+ #'pexSourcePath' : OPTS.openram_temp+"extracted.sp",
+ 'pexSourcePath': cell_name + ".sp",
+ 'pexSourcePrimary': cell_name,
+ 'pexReportFile': cell_name + ".lvs.report",
+ 'pexPexNetlistFile': cell_name + ".pex.netlist",
+ 'pexPexReportFile': cell_name + ".pex.report",
+ 'pexMaskDBFile': cell_name + ".maskdb",
+ 'cmnFDIDEFLayoutPath': cell_name + ".def",
+ }
+
+ # write the runset file
+ f = open(OPTS.openram_temp + "pex_runset", "w")
+ for k in sorted(iter(pex_runset.keys())):
+ f.write("*{0}: {1}\n".format(k, pex_runset[k]))
+ f.close()
+
+ # Create an auxiliary script to run calibre with the runset
+ run_file = OPTS.openram_temp + "run_pex.sh"
+ f = open(run_file, "w")
+ f.write("#!/bin/sh\n")
+ cmd = "{0} -gui -pex {1}pex_runset -batch".format(OPTS.pex_exe[1],
+ OPTS.openram_temp)
+ f.write(cmd)
+ f.write("\n")
+ f.close()
+ os.system("chmod u+x {}".format(run_file))
+
+ return pex_runset
+
+def run_drc(cell_name, gds_name, extract=False, final_verification=False):
+ """Run DRC check on a given top-level name which is
+ implemented in gds_name."""
+
+ global num_drc_runs
+ num_drc_runs += 1
+
+ # Copy file to local dir if it isn't already
+ if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'):
+ shutil.copy(gds_name, OPTS.openram_temp)
+
+ drc_runset = write_calibre_drc_script(cell_name, extract, final_verification)
+
+ (outfile, errfile, resultsfile) = run_script(cell_name, "drc")
# check the result for these lines in the summary:
# TOTAL Original Layer Geometries: 106 (157)
# TOTAL DRC RuleChecks Executed: 156
# TOTAL DRC Results Generated: 0 (0)
try:
- f = open(drc_runset['drcSummaryFile'], "r")
+ f = open(OPTS.openram_temp + drc_runset['drcSummaryFile'], "r")
except:
debug.error("Unable to retrieve DRC results file. Is calibre set up?",1)
results = f.readlines()
@@ -132,12 +212,12 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False):
# always display this summary
if errors > 0:
- debug.error("{0}\tGeometries: {1}\tChecks: {2}\tErrors: {3}".format(cell_name,
+ debug.error("{0}\tGeometries: {1}\tChecks: {2}\tErrors: {3}".format(cell_name,
geometries,
rulechecks,
errors))
else:
- debug.info(1, "{0}\tGeometries: {1}\tChecks: {2}\tErrors: {3}".format(cell_name,
+ debug.info(1, "{0}\tGeometries: {1}\tChecks: {2}\tErrors: {3}".format(cell_name,
geometries,
rulechecks,
errors))
@@ -148,71 +228,22 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
"""Run LVS check on a given top-level name which is
implemented in gds_name and sp_name. Final verification will
ensure that there are no remaining virtual conections. """
-
+
global num_lvs_runs
num_lvs_runs += 1
-
- from tech import drc
- lvs_rules = drc["lvs_rules"]
- lvs_runset = {
- 'lvsRulesFile': lvs_rules,
- 'lvsRunDir': OPTS.openram_temp,
- 'lvsLayoutPaths': gds_name,
- 'lvsLayoutPrimary': cell_name,
- 'lvsSourcePath': sp_name,
- 'lvsSourcePrimary': cell_name,
- 'lvsSourceSystem': 'SPICE',
- 'lvsSpiceFile': OPTS.openram_temp + "extracted.sp",
- 'lvsPowerNames': 'vdd',
- 'lvsGroundNames': 'gnd',
- 'lvsIncludeSVRFCmds': 1,
- 'lvsIgnorePorts': 1,
- 'lvsERCDatabase': OPTS.openram_temp + cell_name + ".erc.results",
- 'lvsERCSummaryFile': OPTS.openram_temp + cell_name + ".erc.summary",
- 'lvsReportFile': OPTS.openram_temp + cell_name + ".lvs.report",
- 'lvsMaskDBFile': OPTS.openram_temp + cell_name + ".maskdb",
- 'cmnFDILayerMapFile': drc["layer_map"],
- 'cmnFDIUseLayerMap': 1,
- 'cmnTranscriptFile': './lvs.log',
- 'cmnTranscriptEchoToFile': 1,
- 'lvsRecognizeGates': 'NONE',
- }
- # FIXME: Remove when vdd/gnd connected
- #'cmnVConnectNamesState' : 'ALL', #connects all nets with the same namee
- # FIXME: Remove when vdd/gnd connected
- #'lvsAbortOnSupplyError' : 0
- if not final_verification:
- lvs_runset['cmnVConnectReport']=1
- lvs_runset['cmnVConnectNamesState']='SOME'
- lvs_runset['cmnVConnectNames']='vdd gnd'
- else:
- lvs_runset['lvsAbortOnSupplyError']=1
-
+ lvs_runset = write_calibre_lvs_script(cell_name, final_verification)
+ # Copy file to local dir if it isn't already
+ if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'):
+ shutil.copy(gds_name, OPTS.openram_temp)
+ if os.path.dirname(sp_name)!=OPTS.openram_temp.rstrip('/'):
+ shutil.copy(sp_name, OPTS.openram_temp)
- # write the runset file
- f = open(OPTS.openram_temp + "lvs_runset", "w")
- for k in sorted(iter(lvs_runset.keys())):
- f.write("*{0}: {1}\n".format(k, lvs_runset[k]))
- f.close()
-
- # run LVS
- cwd = os.getcwd()
- os.chdir(OPTS.openram_temp)
- errfile = "{0}{1}.lvs.err".format(OPTS.openram_temp, cell_name)
- outfile = "{0}{1}.lvs.out".format(OPTS.openram_temp, cell_name)
-
- cmd = "{0} -gui -lvs {1}lvs_runset -batch 2> {2} 1> {3}".format(OPTS.lvs_exe[1],
- OPTS.openram_temp,
- errfile,
- outfile)
- debug.info(2, cmd)
- os.system(cmd)
- os.chdir(cwd)
+ (outfile, errfile, resultsfile) = run_script(cell_name, "lvs")
# check the result for these lines in the summary:
- f = open(lvs_runset['lvsReportFile'], "r")
+ f = open(OPTS.openram_temp + lvs_runset['lvsReportFile'], "r")
results = f.readlines()
f.close()
@@ -235,7 +266,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
summary_errors = len(notcompared) + len(incorrect) + len(errors)
# also check the extraction summary file
- f = open(lvs_runset['lvsReportFile'] + ".ext", "r")
+ f = open(OPTS.openram_temp + lvs_runset['lvsReportFile'] + ".ext", "r")
results = f.readlines()
f.close()
@@ -252,7 +283,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
# MRG - 9/26/17 - Change this to exclude warnings because of
# multiple labels on different pins in column mux.
ext_errors = len(exterrors)
- ext_warnings = len(extwarnings)
+ ext_warnings = len(extwarnings)
# also check the output file
f = open(outfile, "r")
@@ -269,16 +300,16 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
total_errors = summary_errors + out_errors + ext_errors
if total_errors > 0:
- debug.error("{0}\tSummary: {1}\tOutput: {2}\tExtraction: {3}".format(cell_name,
+ debug.error("{0}\tSummary: {1}\tOutput: {2}\tExtraction: {3}".format(cell_name,
summary_errors,
out_errors,
ext_errors))
else:
- debug.info(1, "{0}\tSummary: {1}\tOutput: {2}\tExtraction: {3}".format(cell_name,
+ debug.info(1, "{0}\tSummary: {1}\tOutput: {2}\tExtraction: {3}".format(cell_name,
summary_errors,
out_errors,
ext_errors))
-
+
return total_errors
@@ -288,52 +319,11 @@ def run_pex(cell_name, gds_name, sp_name, output=None, final_verification=False)
global num_pex_runs
num_pex_runs += 1
-
- from tech import drc
- if output == None:
- output = name + ".pex.netlist"
- # check if lvs report has been done
- # if not run drc and lvs
- if not os.path.isfile(cell_name + ".lvs.report"):
- run_drc(cell_name, gds_name)
- run_lvs(cell_name, gds_name, sp_name)
+ write_calibre_pex_script(cell_name,True,output,final_verification)
- pex_rules = drc["xrc_rules"]
- pex_runset = {
- 'pexRulesFile': pex_rules,
- 'pexRunDir': OPTS.openram_temp,
- 'pexLayoutPaths': gds_name,
- 'pexLayoutPrimary': cell_name,
- #'pexSourcePath' : OPTS.openram_temp+"extracted.sp",
- 'pexSourcePath': sp_name,
- 'pexSourcePrimary': cell_name,
- 'pexReportFile': cell_name + ".lvs.report",
- 'pexPexNetlistFile': output,
- 'pexPexReportFile': cell_name + ".pex.report",
- 'pexMaskDBFile': cell_name + ".maskdb",
- 'cmnFDIDEFLayoutPath': cell_name + ".def",
- }
+ (outfile, errfile, resultsfile) = run_script(cell_name, "pex")
- # write the runset file
- f = open(OPTS.openram_temp + "pex_runset", "w")
- for k in sorted(iter(pex_runset.keys())):
- f.write("*{0}: {1}\n".format(k, pex_runset[k]))
- f.close()
-
- # run pex
- cwd = os.getcwd()
- os.chdir(OPTS.openram_temp)
- errfile = "{0}{1}.pex.err".format(OPTS.openram_temp, cell_name)
- outfile = "{0}{1}.pex.out".format(OPTS.openram_temp, cell_name)
-
- cmd = "{0} -gui -pex {1}pex_runset -batch 2> {2} 1> {3}".format(OPTS.pex_exe[1],
- OPTS.openram_temp,
- errfile,
- outfile)
- debug.info(2, cmd)
- os.system(cmd)
- os.chdir(cwd)
# also check the output file
f = open(outfile, "r")
diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py
index 7db9a5c2..63aeaabe 100644
--- a/compiler/verify/magic.py
+++ b/compiler/verify/magic.py
@@ -1,9 +1,16 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
"""
-This is a DRC/LVS/PEX interface file for magic + netgen.
+This is a DRC/LVS/PEX interface file for magic + netgen.
-We include the tech file for SCN3ME_SUBM in the tech directory,
-that is included in OpenRAM during DRC.
-You can use this interactively by appending the magic system path in
+We include the tech file for SCN4M_SUBM in the tech directory,
+that is included in OpenRAM during DRC.
+You can use this interactively by appending the magic system path in
your .magicrc file
path sys /Users/mrg/openram/technology/scn3me_subm/tech
@@ -19,14 +26,15 @@ import time
import shutil
import debug
from globals import OPTS
-import subprocess
+from run_script import *
# Keep track of statistics
num_drc_runs = 0
num_lvs_runs = 0
num_pex_runs = 0
-def write_magic_script(cell_name, gds_name, extract=False, final_verification=False):
+
+def write_magic_script(cell_name, extract=False, final_verification=False):
""" Write a magic script to perform DRC and optionally extraction. """
global OPTS
@@ -37,7 +45,7 @@ def write_magic_script(cell_name, gds_name, extract=False, final_verification=Fa
f.write("{} -dnull -noconsole << EOF\n".format(OPTS.drc_exe[1]))
f.write("gds polygon subcell true\n")
f.write("gds warning default\n")
- f.write("gds read {}\n".format(gds_name))
+ f.write("gds read {}.gds\n".format(cell_name))
f.write("load {}\n".format(cell_name))
# Flatten the cell to get rid of DRCs spanning multiple layers
# (e.g. with routes)
@@ -53,6 +61,7 @@ def write_magic_script(cell_name, gds_name, extract=False, final_verification=Fa
f.write("drc catchup\n")
f.write("drc count total\n")
f.write("drc count\n")
+ f.write("port makeall\n")
if not extract:
pre = "#"
else:
@@ -60,7 +69,7 @@ def write_magic_script(cell_name, gds_name, extract=False, final_verification=Fa
if final_verification:
f.write(pre+"extract unique all\n".format(cell_name))
f.write(pre+"extract\n".format(cell_name))
- #f.write(pre+"ext2spice hierarchy on\n")
+ #f.write(pre+"ext2spice hierarchy on\n")
#f.write(pre+"ext2spice scale off\n")
# lvs exists in 8.2.79, but be backword compatible for now
#f.write(pre+"ext2spice lvs\n")
@@ -73,26 +82,28 @@ def write_magic_script(cell_name, gds_name, extract=False, final_verification=Fa
f.write(pre+"ext2spice blackbox on\n")
f.write(pre+"ext2spice subcircuit top auto\n")
f.write(pre+"ext2spice global off\n")
-
+
# Can choose hspice, ngspice, or spice3,
# but they all seem compatible enough.
#f.write(pre+"ext2spice format ngspice\n")
f.write(pre+"ext2spice {}\n".format(cell_name))
f.write("quit -noprompt\n")
f.write("EOF\n")
-
+
f.close()
os.system("chmod u+x {}".format(run_file))
-def write_netgen_script(cell_name, sp_name):
+
+def write_netgen_script(cell_name):
""" Write a netgen script to perform LVS. """
global OPTS
- setup_file = OPTS.openram_tech + "mag_lib/setup.tcl"
- if os.path.exists(setup_file):
+ setup_file = "setup.tcl"
+ full_setup_file = OPTS.openram_tech + "mag_lib/" + setup_file
+ if os.path.exists(full_setup_file):
# Copy setup.tcl file into temp dir
- shutil.copy(setup_file, OPTS.openram_temp)
+ shutil.copy(full_setup_file, OPTS.openram_temp)
else:
setup_file = 'nosetup'
@@ -101,26 +112,24 @@ def write_netgen_script(cell_name, sp_name):
f.write("#!/bin/sh\n")
f.write("{} -noconsole << EOF\n".format(OPTS.lvs_exe[1]))
f.write("readnet spice {0}.spice\n".format(cell_name))
- f.write("readnet spice {0}\n".format(sp_name))
- # Allow some flexibility in W size because magic will snap to a lambda grid
- # This can also cause disconnects unfortunately!
- # f.write("property {{{0}{1}.spice nfet}} tolerance {{w 0.1}}\n".format(OPTS.openram_temp,
- # cell_name))
- # f.write("property {{{0}{1}.spice pfet}} tolerance {{w 0.1}}\n".format(OPTS.openram_temp,
- # cell_name))
- f.write("lvs {0}.spice {{{1} {0}}} {2} {0}.lvs.report\n".format(cell_name, sp_name, setup_file))
+ f.write("readnet spice {0}.sp\n".format(cell_name))
+ f.write("lvs {{{0}.spice {0}}} {{{0}.sp {0}}} {1} {0}.lvs.report\n".format(cell_name, setup_file))
f.write("quit\n")
f.write("EOF\n")
f.close()
os.system("chmod u+x {}".format(run_file))
-
+
def run_drc(cell_name, gds_name, extract=True, final_verification=False):
"""Run DRC check on a cell which is implemented in gds_name."""
global num_drc_runs
num_drc_runs += 1
+ # Copy file to local dir if it isn't already
+ if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'):
+ shutil.copy(gds_name, OPTS.openram_temp)
+
# Copy .magicrc file into temp dir
magic_file = OPTS.openram_tech + "mag_lib/.magicrc"
if os.path.exists(magic_file):
@@ -128,20 +137,9 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False):
else:
debug.warning("Could not locate .magicrc file: {}".format(magic_file))
- write_magic_script(cell_name, gds_name, extract, final_verification)
-
- # run drc
- cwd = os.getcwd()
- os.chdir(OPTS.openram_temp)
- errfile = "{0}{1}.drc.err".format(OPTS.openram_temp, cell_name)
- outfile = "{0}{1}.drc.summary".format(OPTS.openram_temp, cell_name)
+ write_magic_script(cell_name, extract, final_verification)
- cmd = "{0}run_drc.sh 2> {1} 1> {2}".format(OPTS.openram_temp,
- errfile,
- outfile)
- debug.info(2, cmd)
- os.system(cmd)
- os.chdir(cwd)
+ (outfile, errfile, resultsfile) = run_script(cell_name, "drc")
# Check the result for these lines in the summary:
# Total DRC errors found: 0
@@ -153,7 +151,7 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False):
f = open(outfile, "r")
except FileNotFoundError:
debug.error("Unable to load DRC results file from {}. Is magic set up?".format(outfile),1)
-
+
results = f.readlines()
f.close()
errors=1
@@ -164,7 +162,7 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False):
break
else:
debug.error("Unable to find the total error line in Magic output.",1)
-
+
# always display this summary
if errors > 0:
@@ -185,31 +183,25 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
global num_lvs_runs
num_lvs_runs += 1
-
- write_netgen_script(cell_name, sp_name)
-
- # run LVS
- cwd = os.getcwd()
- os.chdir(OPTS.openram_temp)
- errfile = "{0}{1}.lvs.err".format(OPTS.openram_temp, cell_name)
- outfile = "{0}{1}.lvs.out".format(OPTS.openram_temp, cell_name)
- resultsfile = "{0}{1}.lvs.report".format(OPTS.openram_temp, cell_name)
- cmd = "{0}run_lvs.sh lvs 2> {1} 1> {2}".format(OPTS.openram_temp,
- errfile,
- outfile)
- debug.info(2, cmd)
- os.system(cmd)
- os.chdir(cwd)
+ # Copy file to local dir if it isn't already
+ if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'):
+ shutil.copy(gds_name, OPTS.openram_temp)
+ if os.path.dirname(sp_name)!=OPTS.openram_temp.rstrip('/'):
+ shutil.copy(sp_name, OPTS.openram_temp)
+
+ write_netgen_script(cell_name)
+
+ (outfile, errfile, resultsfile) = run_script(cell_name, "lvs")
total_errors = 0
-
+
# check the result for these lines in the summary:
try:
f = open(resultsfile, "r")
except FileNotFoundError:
debug.error("Unable to load LVS results from {}".format(resultsfile),1)
-
+
results = f.readlines()
f.close()
# Look for the results after the final "Subcircuit summary:"
@@ -225,14 +217,14 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
test = re.compile("Property errors were found.")
propertyerrors = list(filter(test.search, results))
total_errors += len(propertyerrors)
-
+
# Require pins to match?
# Cell pin lists for pnand2_1.spice and pnand2_1 altered to match.
# test = re.compile(".*altered to match.")
# pinerrors = list(filter(test.search, results))
# if len(pinerrors)>0:
# debug.warning("Pins altered to match in {}.".format(cell_name))
-
+
#if len(propertyerrors)>0:
# debug.warning("Property errors found, but not checking them.")
@@ -240,7 +232,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
test = re.compile("Netlists do not match.")
incorrect = list(filter(test.search, final_results))
total_errors += len(incorrect)
-
+
# Netlists match uniquely.
test = re.compile("match uniquely.")
correct = list(filter(test.search, final_results))
@@ -252,7 +244,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
# Just print out the whole file, it is short.
for e in results:
debug.info(1,e.strip("\n"))
- debug.error("{0}\tLVS mismatch (results in {1})".format(cell_name,resultsfile))
+ debug.error("{0}\tLVS mismatch (results in {1})".format(cell_name,resultsfile))
else:
debug.info(1, "{0}\tLVS matches".format(cell_name))
@@ -265,9 +257,9 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
global num_pex_runs
num_pex_runs += 1
-
- debug.warning("PEX using magic not implemented.")
- return 1
+ #debug.warning("PEX using magic not implemented.")
+ #return 1
+ os.chdir(OPTS.openram_temp)
from tech import drc
if output == None:
@@ -279,25 +271,67 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
run_drc(name, gds_name)
run_lvs(name, gds_name, sp_name)
- """
- 2. magic can perform extraction with the following:
- #!/bin/sh
- rm -f $1.ext
- rm -f $1.spice
- magic -dnull -noconsole << EOF
- tech load SCN3ME_SUBM.30
- #scalegrid 1 2
- gds rescale no
- gds polygon subcell true
- gds warning default
- gds read $1
- extract
- ext2spice scale off
- ext2spice
- quit -noprompt
- EOF
- """
-
+ # pex_fix did run the pex using a script while dev orignial method
+ # use batch mode.
+ # the dev old code using batch mode does not run and is split into functions
+ #pex_runset = write_batch_pex_rule(gds_name,name,sp_name,output)
+ pex_runset = write_script_pex_rule(gds_name,name,output)
+
+ errfile = "{0}{1}.pex.err".format(OPTS.openram_temp, name)
+ outfile = "{0}{1}.pex.out".format(OPTS.openram_temp, name)
+
+ # bash mode command from dev branch
+ #batch_cmd = "{0} -gui -pex {1}pex_runset -batch 2> {2} 1> {3}".format(OPTS.pex_exe,
+ # OPTS.openram_temp,
+ # errfile,
+ # outfile)
+ script_cmd = "{0} 2> {1} 1> {2}".format(pex_runset,
+ errfile,
+ outfile)
+ cmd = script_cmd
+ debug.info(2, cmd)
+ os.system(cmd)
+
+ # rename technology models
+ pex_nelist = open(output, 'r')
+ s = pex_nelist.read()
+ pex_nelist.close()
+ s = s.replace('pfet','p')
+ s = s.replace('nfet','n')
+ f = open(output, 'w')
+ f.write(s)
+ f.close()
+
+ # also check the output file
+ f = open(outfile, "r")
+ results = f.readlines()
+ f.close()
+ out_errors = find_error(results)
+ debug.check(os.path.isfile(output),"Couldn't find PEX extracted output.")
+
+ correct_port(name,output,sp_name)
+ return out_errors
+
+def write_batch_pex_rule(gds_name,name,sp_name,output):
+ """
+ The dev branch old batch mode runset
+ 2. magic can perform extraction with the following:
+ #!/bin/sh
+ rm -f $1.ext
+ rm -f $1.spice
+ magic -dnull -noconsole << EOF
+ tech load SCN3ME_SUBM.30
+ #scalegrid 1 2
+ gds rescale no
+ gds polygon subcell true
+ gds warning default
+ gds read $1
+ extract
+ ext2spice scale off
+ ext2spice
+ quit -noprompt
+ EOF
+ """
pex_rules = drc["xrc_rules"]
pex_runset = {
'pexRulesFile': pex_rules,
@@ -315,43 +349,89 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
}
# write the runset file
- f = open(OPTS.openram_temp + "pex_runset", "w")
- for k in sorted(pex_runset.iterkeys()):
+ file = OPTS.openram_temp + "pex_runset"
+ f = open(file, "w")
+ for k in sorted(pex_runset.keys()):
f.write("*{0}: {1}\n".format(k, pex_runset[k]))
f.close()
+ return file
- # run pex
- cwd = os.getcwd()
- os.chdir(OPTS.openram_temp)
- errfile = "{0}{1}.pex.err".format(OPTS.openram_temp, name)
- outfile = "{0}{1}.pex.out".format(OPTS.openram_temp, name)
+def write_script_pex_rule(gds_name,cell_name,output):
+ global OPTS
+ run_file = OPTS.openram_temp + "run_pex.sh"
+ f = open(run_file, "w")
+ f.write("#!/bin/sh\n")
+ f.write("{} -dnull -noconsole << eof\n".format(OPTS.drc_exe[1]))
+ f.write("gds polygon subcell true\n")
+ f.write("gds warning default\n")
+ f.write("gds read {}\n".format(gds_name))
+ f.write("load {}\n".format(cell_name))
+ f.write("select top cell\n")
+ f.write("expand\n")
+ f.write("port makeall\n")
+ extract = True
+ if not extract:
+ pre = "#"
+ else:
+ pre = ""
+ f.write(pre+"extract\n".format(cell_name))
+ #f.write(pre+"ext2spice hierarchy on\n")
+ #f.write(pre+"ext2spice format ngspice\n")
+ #f.write(pre+"ext2spice renumber off\n")
+ #f.write(pre+"ext2spice scale off\n")
+ #f.write(pre+"ext2spice blackbox on\n")
+ f.write(pre+"ext2spice subcircuit top on\n")
+ #f.write(pre+"ext2spice global off\n")
+ f.write(pre+"ext2spice {}\n".format(cell_name))
+ f.write("quit -noprompt\n")
+ f.write("eof\n")
+ f.write("mv {0}.spice {1}\n".format(cell_name,output))
- cmd = "{0} -gui -pex {1}pex_runset -batch 2> {2} 1> {3}".format(OPTS.pex_exe,
- OPTS.openram_temp,
- errfile,
- outfile)
- debug.info(2, cmd)
- os.system(cmd)
- os.chdir(cwd)
-
- # also check the output file
- f = open(outfile, "r")
- results = f.readlines()
f.close()
+ os.system("chmod u+x {}".format(run_file))
+ return run_file
+def find_error(results):
# Errors begin with "ERROR:"
test = re.compile("ERROR:")
stdouterrors = list(filter(test.search, results))
for e in stdouterrors:
debug.error(e.strip("\n"))
-
out_errors = len(stdouterrors)
-
- assert(os.path.isfile(output))
- #correct_port(name, output, sp_name)
-
return out_errors
+def correct_port(name, output_file_name, ref_file_name):
+ pex_file = open(output_file_name, "r")
+ contents = pex_file.read()
+ # locate the start of circuit definition line
+ match = re.search(".subckt " + str(name) + ".*", contents)
+ match_index_start = match.start()
+ pex_file.seek(match_index_start)
+ rest_text = pex_file.read()
+ # locate the end of circuit definition line
+ match = re.search(r'\n', rest_text)
+ match_index_end = match.start()
+ # store the unchanged part of pex file in memory
+ pex_file.seek(0)
+ part1 = pex_file.read(match_index_start)
+ pex_file.seek(match_index_start + match_index_end)
+ part2 = pex_file.read()
+ pex_file.close()
+
+ # obtain the correct definition line from the original spice file
+ sp_file = open(ref_file_name, "r")
+ contents = sp_file.read()
+ circuit_title = re.search(".SUBCKT " + str(name) + ".*\n", contents)
+ circuit_title = circuit_title.group()
+ sp_file.close()
+
+ # write the new pex file with info in the memory
+ output_file = open(output_file_name, "w")
+ output_file.write(part1)
+ output_file.write(circuit_title)
+ output_file.write(part2)
+ output_file.close()
+
def print_drc_stats():
debug.info(1,"DRC runs: {0}".format(num_drc_runs))
def print_lvs_stats():
diff --git a/compiler/verify/none.py b/compiler/verify/none.py
index c69ed93b..9d7ac938 100644
--- a/compiler/verify/none.py
+++ b/compiler/verify/none.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
"""
This is a DRC/LVS/PEX interface file the case with no DRC/LVS tools.
diff --git a/compiler/verify/run_script.py b/compiler/verify/run_script.py
new file mode 100644
index 00000000..3bc8d2d8
--- /dev/null
+++ b/compiler/verify/run_script.py
@@ -0,0 +1,34 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
+"""
+Some baseline functions to run scripts.
+"""
+
+import os
+import debug
+from globals import OPTS
+
+def run_script(cell_name, script="lvs"):
+ """ Run script and create output files. """
+
+ cwd = os.getcwd()
+ os.chdir(OPTS.openram_temp)
+ errfile = "{0}{1}.{2}.err".format(OPTS.openram_temp, cell_name, script)
+ outfile = "{0}{1}.{2}.out".format(OPTS.openram_temp, cell_name, script)
+ resultsfile = "{0}{1}.{2}.report".format(OPTS.openram_temp, cell_name, script)
+
+ cmd = "{0}run_{1}.sh 2> {2} 1> {3}".format(OPTS.openram_temp,
+ script,
+ errfile,
+ outfile)
+ debug.info(2, cmd)
+ os.system(cmd)
+ os.chdir(cwd)
+
+ return (outfile,errfile,resultsfile)
+
diff --git a/compiler/view_profile.py b/compiler/view_profile.py
index aadcd459..cad8e9ae 100755
--- a/compiler/view_profile.py
+++ b/compiler/view_profile.py
@@ -1,4 +1,11 @@
#!/usr/bin/env python3
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import pstats
p = pstats.Stats("profile.dat")
p.strip_dirs()
diff --git a/technology/setup_scripts/setup_openram_freepdk45.py b/technology/freepdk45/__init__.py
similarity index 76%
rename from technology/setup_scripts/setup_openram_freepdk45.py
rename to technology/freepdk45/__init__.py
index 3ba0aa16..363df6f4 100644
--- a/technology/setup_scripts/setup_openram_freepdk45.py
+++ b/technology/freepdk45/__init__.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
#!/usr/bin/python
"""
This type of setup script should be placed in the setup_scripts directory in
@@ -8,7 +15,6 @@ import sys
import os
TECHNOLOGY = "freepdk45"
-LOCAL = "{0}/..".format(os.path.dirname(__file__))
##########################
# FreePDK45 paths
@@ -33,8 +39,3 @@ os.environ["DRCLVS_HOME"] = DRCLVS_HOME
# except:
# Always use the one in the PDK dir for FreePDK45
os.environ["SPICE_MODEL_DIR"] = PDK_DIR+"/ncsu_basekit/models/hspice/tran_models"
-
-##########################
-#Paths required for OPENRAM to function
-
-sys.path.append("{0}/{1}/tech".format(LOCAL,TECHNOLOGY))
diff --git a/technology/freepdk45/gds_lib/dummy_cell_1rw_1r.gds b/technology/freepdk45/gds_lib/dummy_cell_1rw_1r.gds
new file mode 100644
index 00000000..2ac1a287
Binary files /dev/null and b/technology/freepdk45/gds_lib/dummy_cell_1rw_1r.gds differ
diff --git a/technology/freepdk45/gds_lib/dummy_cell_1w_1r.gds b/technology/freepdk45/gds_lib/dummy_cell_1w_1r.gds
new file mode 100644
index 00000000..fa89439e
Binary files /dev/null and b/technology/freepdk45/gds_lib/dummy_cell_1w_1r.gds differ
diff --git a/technology/freepdk45/gds_lib/dummy_cell_6t.gds b/technology/freepdk45/gds_lib/dummy_cell_6t.gds
new file mode 100644
index 00000000..c6575122
Binary files /dev/null and b/technology/freepdk45/gds_lib/dummy_cell_6t.gds differ
diff --git a/technology/freepdk45/gds_lib/write_driver.gds b/technology/freepdk45/gds_lib/write_driver.gds
index 742e39d4..86015e7a 100644
Binary files a/technology/freepdk45/gds_lib/write_driver.gds and b/technology/freepdk45/gds_lib/write_driver.gds differ
diff --git a/technology/freepdk45/lib/.cadence/cadence.signature.xml b/technology/freepdk45/lib/.cadence/cadence.signature.xml
deleted file mode 100755
index 64bab7f4..00000000
--- a/technology/freepdk45/lib/.cadence/cadence.signature.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
- Do not remove or change this .cadence directory signature file.
diff --git a/technology/freepdk45/lib/.cadence/dfII/viva/viva.ini b/technology/freepdk45/lib/.cadence/dfII/viva/viva.ini
deleted file mode 100755
index dfde08be..00000000
--- a/technology/freepdk45/lib/.cadence/dfII/viva/viva.ini
+++ /dev/null
@@ -1,43 +0,0 @@
-[browser]
-orientation=horizontal
-pathlist=/mada/users/cpeters/Working/simulations/latch.run1/si.raw, /mada/users/cpeters/Working/simulations/out_latch.run1/si.raw, /mada/users/cpeters/Working/simulations/ms_ff.run1/si.raw
-pos=@Point(1118 92)
-size=@Size(214 928)
-splitter=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\xc0\x1\0\0\0\x4\x1\0\0\0\x1)
-
-[fullCalculator]
-_bufferState=@Invalid()
-_funcPanelName=undefined
-_funcPanelSplitter=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x2\0\0\0\xb3\0\0\x1\xb4\0\0\0\0\x4\x1\0\0\0\x2)
-_funcPanelType=FuncListType
-_keyPadSplitter=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x2\0\0\x2\xf4\0\0\0\x64\x1\0\0\0\x4\x1\0\0\0\x1)
-_resultsDir=
-_signalSelectionHistory=@Invalid()
-_splitter=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x2\0\0\0\xb3\0\0\0\0\x1\0\0\0\x4\x1\0\0\0\x2)
-_testName=
-clipSelectionMode=true
-defaultCategory=Special Functions
-displayContext=true
-mathToolBar=false
-plotStyle=Append
-pos=@Point(582 186)
-rpnMode=true
-schematicAnalyses="tran,ac,dc,sweptDc,info,noise,rf"
-schematicToolBar=true
-showKeyPad=true
-showStack=false
-signalSelection=Off
-size=@Size(866 834)
-trigToolBar=false
-userButton1=user 1, undefined
-userButton10=user 1, undefined
-userButton11=user 1, undefined
-userButton12=user 1, undefined
-userButton2=user 2, undefined
-userButton3=user 3, undefined
-userButton4=user 4, undefined
-userButton5=user 5, undefined
-userButton6=user 6, undefined
-userButton7=user 7, undefined
-userButton8=user 8, undefined
-userButton9=user 9, undefined
diff --git a/technology/freepdk45/lib/.cdsinit b/technology/freepdk45/lib/.cdsinit
deleted file mode 100755
index 14e60079..00000000
--- a/technology/freepdk45/lib/.cdsinit
+++ /dev/null
@@ -1,47 +0,0 @@
-
-envSetVal( "graphic" "drfPath" 'string
- strcat( getShellEnvVar("PDK_DIR") "/ncsu_basekit/cdssetup/display.drf"))
-
-
-loadi( strcat( getShellEnvVar("PDK_DIR") "/ncsu_basekit/cdssetup/common_bindkeys.il"))
-if( getShellEnvVar("MGC_HOME") then
- loadi( strcat( getShellEnvVar("MGC_HOME") "/shared/pkgs/icv/tools/queryskl/calibre.OA.skl"))
-) ;if
-procedure( prependNCSUCDKInstallPath( dir)
- strcat( getShellEnvVar("PDK_DIR") "/ncsu_basekit/" dir))
-(envLoadVals
-?envFile ( prependNCSUCDKInstallPath "cdssetup/cdsenv")
-?tool "layout")
-
-printf( strcat(
-"---------------------------------------------------------------------------\n"
-"Welcome to the FreePDK 45nm Free, Open-Source Process Design Kit\n"
-"\n"
-"This initiative is brought to you by the Semiconductor Research\n"
-"Corporation (SRC), the National Science Foundation (NSF), Silicon\n"
-"Integration Initiative (Si2), Mentor Graphics, and Synopsys.\n"
-"\n"
-"This version of the kit was created by Rhett Davis, Paul Franzon,\n"
-"Michael Bucher, and Sunil Basavarajaiah of North Carolina State University,\n"
-"and James Stine and Ivan Castellanos of Oklahoma State University.\n"
-"\n"
-"Contributions and modifications to this kit are welcomed and encouraged.\n"
-"\n"
-"Copyright 2008 North Carolina State University (ncsu_basekit subtree)\n"
-" and Oklahoma State University (osu_soc subtree)\n"
-"\n"
-"Licensed under the Apache License, Version 2.0 (the \"License\");\n"
-"you may not use this file except in compliance with the License.\n"
-"You may obtain a copy of the License at\n"
-"\n"
-" http://www.apache.org/licenses/LICENSE-2.0\n"
-"\n"
-"Unless required by applicable law or agreed to in writing, software\n"
-"distributed under the License is distributed on an \"AS IS\" BASIS,\n"
-"WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
-"See the License for the specific language governing permissions and\n"
-"limitations under the License.\n"
-"---------------------------------------------------------------------------\n"
-"\n"
-"Done loading FreePDK customizations.\n"
-))
diff --git a/technology/freepdk45/lib/.runset.calibre.drc b/technology/freepdk45/lib/.runset.calibre.drc
deleted file mode 100755
index 35186ce6..00000000
--- a/technology/freepdk45/lib/.runset.calibre.drc
+++ /dev/null
@@ -1,2 +0,0 @@
-*drcRulesFile: $PDK_DIR/ncsu_basekit/techfile/calibre/calibreDRC.rul
-
diff --git a/technology/freepdk45/lib/.runset.calibre.lfd b/technology/freepdk45/lib/.runset.calibre.lfd
deleted file mode 100755
index f770b0a1..00000000
--- a/technology/freepdk45/lib/.runset.calibre.lfd
+++ /dev/null
@@ -1,2 +0,0 @@
-*drcRulesFile: $PDK_DIR/ncsu_basekit/techfile/calibre/calibreLFD.rul
-
diff --git a/technology/freepdk45/lib/.runset.calibre.lvs b/technology/freepdk45/lib/.runset.calibre.lvs
deleted file mode 100755
index aa47aacb..00000000
--- a/technology/freepdk45/lib/.runset.calibre.lvs
+++ /dev/null
@@ -1,3 +0,0 @@
-*lvsRulesFile: $PDK_DIR/ncsu_basekit/techfile/calibre/calibreLVS.rul
-
-
diff --git a/technology/freepdk45/lib/.runset.calibre.pex b/technology/freepdk45/lib/.runset.calibre.pex
deleted file mode 100755
index a1f8b6d9..00000000
--- a/technology/freepdk45/lib/.runset.calibre.pex
+++ /dev/null
@@ -1,3 +0,0 @@
-*pexRulesFile: $PDK_DIR/ncsu_basekit/techfile/calibre/calibrexRC.rul
-
-
diff --git a/technology/freepdk45/lib/cds.lib b/technology/freepdk45/lib/cds.lib
deleted file mode 100644
index e3c63316..00000000
--- a/technology/freepdk45/lib/cds.lib
+++ /dev/null
@@ -1,8 +0,0 @@
-DEFINE analogLib $CDSHOME/tools/dfII/etc/cdslib/artist/analogLib
-DEFINE US_8ths $CDSHOME/tools/dfII/etc/cdslib/sheets/US_8ths
-DEFINE basic $CDSHOME/tools/dfII/etc/cdslib/basic
-DEFINE cdsDefTechLib $CDSHOME/tools/dfII/etc/cdsDefTechLib
-DEFINE NCSU_TechLib_FreePDK45 $PDK_DIR/ncsu_basekit/lib/NCSU_TechLib_FreePDK45
-DEFINE NCSU_Devices_FreePDK45 $PDK_DIR/ncsu_basekit/lib/NCSU_Devices_FreePDK45
-DEFINE sram $OPENRAM_HOME/lib/sram
-DEFINE sub_sram $OPENRAM_HOME/lib/sub_sram
diff --git a/technology/freepdk45/lib/lib.defs b/technology/freepdk45/lib/lib.defs
deleted file mode 100644
index c2a6982c..00000000
--- a/technology/freepdk45/lib/lib.defs
+++ /dev/null
@@ -1,16 +0,0 @@
-DEFINE analogLib $CDSHOME/tools/dfII/etc/cdslib/artist/analogLib
-ASSIGN analogLib libMode shared
-DEFINE US_8ths $CDSHOME/tools/dfII/etc/cdslib/sheets/US_8ths
-ASSIGN US_8ths libMode shared
-DEFINE basic $CDSHOME/tools/dfII/etc/cdslib/basic
-ASSIGN basic libMode shared
-DEFINE cdsDefTechLib $CDSHOME/tools/dfII/etc/cdsDefTechLib
-ASSIGN cdsDefTechLib libMode shared
-DEFINE NCSU_TechLib_FreePDK45 $PDK_DIR/ncsu_basekit/lib/NCSU_TechLib_FreePDK45
-ASSIGN NCSU_TechLib_FreePDK45 libMode shared
-DEFINE NCSU_Devices_FreePDK45 $PDK_DIR/ncsu_basekit/lib/NCSU_Devices_FreePDK45
-ASSIGN NCSU_Devices_FreePDK45 libMode shared
-DEFINE sram $OPENRAM_HOME/lib/sram
-ASSIGN sram libMode shared
-DEFINE sub_sram $OPENRAM_HOME/lib/sub_sram
-ASSIGN sub_sram libMode shared
diff --git a/technology/freepdk45/lib/sram/.oalib b/technology/freepdk45/lib/sram/.oalib
deleted file mode 100755
index 21ffef89..00000000
--- a/technology/freepdk45/lib/sram/.oalib
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
diff --git a/technology/freepdk45/lib/sram/addr_ff/layout/layout.oa b/technology/freepdk45/lib/sram/addr_ff/layout/layout.oa
deleted file mode 100755
index 60a18e10..00000000
Binary files a/technology/freepdk45/lib/sram/addr_ff/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/addr_ff/layout/master.tag b/technology/freepdk45/lib/sram/addr_ff/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/addr_ff/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/addr_ff/schematic/data.dm b/technology/freepdk45/lib/sram/addr_ff/schematic/data.dm
deleted file mode 100755
index 11925091..00000000
Binary files a/technology/freepdk45/lib/sram/addr_ff/schematic/data.dm and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/addr_ff/schematic/master.tag b/technology/freepdk45/lib/sram/addr_ff/schematic/master.tag
deleted file mode 100755
index 26be1bef..00000000
--- a/technology/freepdk45/lib/sram/addr_ff/schematic/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-sch.oa
diff --git a/technology/freepdk45/lib/sram/addr_ff/schematic/sch.oa b/technology/freepdk45/lib/sram/addr_ff/schematic/sch.oa
deleted file mode 100755
index eabefc20..00000000
Binary files a/technology/freepdk45/lib/sram/addr_ff/schematic/sch.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/addr_latch/layout/layout.oa b/technology/freepdk45/lib/sram/addr_latch/layout/layout.oa
deleted file mode 100755
index 3525ac02..00000000
Binary files a/technology/freepdk45/lib/sram/addr_latch/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/addr_latch/layout/master.tag b/technology/freepdk45/lib/sram/addr_latch/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/addr_latch/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/addr_latch/schematic/data.dm b/technology/freepdk45/lib/sram/addr_latch/schematic/data.dm
deleted file mode 100755
index 6a4c9f97..00000000
Binary files a/technology/freepdk45/lib/sram/addr_latch/schematic/data.dm and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/addr_latch/schematic/master.tag b/technology/freepdk45/lib/sram/addr_latch/schematic/master.tag
deleted file mode 100755
index 26be1bef..00000000
--- a/technology/freepdk45/lib/sram/addr_latch/schematic/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-sch.oa
diff --git a/technology/freepdk45/lib/sram/addr_latch/schematic/sch.oa b/technology/freepdk45/lib/sram/addr_latch/schematic/sch.oa
deleted file mode 100755
index 74b3999f..00000000
Binary files a/technology/freepdk45/lib/sram/addr_latch/schematic/sch.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/array/layout/layout.oa b/technology/freepdk45/lib/sram/array/layout/layout.oa
deleted file mode 100755
index 8af1983b..00000000
Binary files a/technology/freepdk45/lib/sram/array/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/array/layout/master.tag b/technology/freepdk45/lib/sram/array/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/array/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/cdsinfo.tag b/technology/freepdk45/lib/sram/cdsinfo.tag
deleted file mode 100644
index a8dcdcb4..00000000
--- a/technology/freepdk45/lib/sram/cdsinfo.tag
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# This is a cdsinfo.tag file.
-#
-# See the "Cadence Application Infrastructure Reference Manual" for
-# details on the format of this file, its semantics, and its use.
-#
-# The `#' character denotes a comment. Removing the leading `#'
-# character from any of the entries below will activate them.
-#
-# CDSLIBRARY entry - add this entry if the directory containing
-# this cdsinfo.tag file is the root of a Cadence library.
-# CDSLIBRARY
-#
-# CDSLIBCHECK - set this entry to require that libraries have
-# a cdsinfo.tag file with a CDSLIBRARY entry. Legal values are
-# ON and OFF. By default (OFF), directories named in a cds.lib file
-# do not have to have a cdsinfo.tag file with a CDSLIBRARY entry.
-# CDSLIBCHECK ON
-#
-# DMTYPE - set this entry to define the DM system for Cadence's
-# Generic DM facility. Values will be shifted to lower case.
-# DMTYPE none
-# DMTYPE crcs
-# DMTYPE tdm
-# DMTYPE sync
-#
-# NAMESPACE - set this entry to define the library namespace according
-# to the type of machine on which the data is stored. Legal values are
-# `LibraryNT' and
-# `LibraryUnix'.
-# NAMESPACE LibraryUnix
-#
-# Other entries may be added for use by specific applications as
-# name-value pairs. Application documentation will describe the
-# use and behaviour of these entries when appropriate.
-#
-# Current Settings:
-#
-CDSLIBRARY
-NAMESPACE LibraryUnix
diff --git a/technology/freepdk45/lib/sram/cell_10t/layout/layout.oa b/technology/freepdk45/lib/sram/cell_10t/layout/layout.oa
deleted file mode 100755
index d19dccf7..00000000
Binary files a/technology/freepdk45/lib/sram/cell_10t/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/cell_10t/layout/layout.oa- b/technology/freepdk45/lib/sram/cell_10t/layout/layout.oa-
deleted file mode 100755
index 7f81fccb..00000000
Binary files a/technology/freepdk45/lib/sram/cell_10t/layout/layout.oa- and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/cell_10t/layout/master.tag b/technology/freepdk45/lib/sram/cell_10t/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/cell_10t/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/cell_10t/schematic/data.dm b/technology/freepdk45/lib/sram/cell_10t/schematic/data.dm
deleted file mode 100755
index ff96d2ab..00000000
Binary files a/technology/freepdk45/lib/sram/cell_10t/schematic/data.dm and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/cell_10t/schematic/master.tag b/technology/freepdk45/lib/sram/cell_10t/schematic/master.tag
deleted file mode 100755
index 26be1bef..00000000
--- a/technology/freepdk45/lib/sram/cell_10t/schematic/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-sch.oa
diff --git a/technology/freepdk45/lib/sram/cell_10t/schematic/sch.oa b/technology/freepdk45/lib/sram/cell_10t/schematic/sch.oa
deleted file mode 100755
index 8f2d4cd0..00000000
Binary files a/technology/freepdk45/lib/sram/cell_10t/schematic/sch.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/cell_6t/layout/layout.oa b/technology/freepdk45/lib/sram/cell_6t/layout/layout.oa
deleted file mode 100755
index 2c763698..00000000
Binary files a/technology/freepdk45/lib/sram/cell_6t/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/cell_6t/layout/layout.oa- b/technology/freepdk45/lib/sram/cell_6t/layout/layout.oa-
deleted file mode 100755
index 43f013e8..00000000
Binary files a/technology/freepdk45/lib/sram/cell_6t/layout/layout.oa- and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/cell_6t/layout/master.tag b/technology/freepdk45/lib/sram/cell_6t/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/cell_6t/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/cell_6t/schematic/data.dm b/technology/freepdk45/lib/sram/cell_6t/schematic/data.dm
deleted file mode 100755
index c2d60e51..00000000
Binary files a/technology/freepdk45/lib/sram/cell_6t/schematic/data.dm and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/cell_6t/schematic/master.tag b/technology/freepdk45/lib/sram/cell_6t/schematic/master.tag
deleted file mode 100755
index 26be1bef..00000000
--- a/technology/freepdk45/lib/sram/cell_6t/schematic/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-sch.oa
diff --git a/technology/freepdk45/lib/sram/cell_6t/schematic/sch.oa b/technology/freepdk45/lib/sram/cell_6t/schematic/sch.oa
deleted file mode 100755
index 51940d44..00000000
Binary files a/technology/freepdk45/lib/sram/cell_6t/schematic/sch.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/clock_nor/layout/layout.oa b/technology/freepdk45/lib/sram/clock_nor/layout/layout.oa
deleted file mode 100755
index 7bf4d583..00000000
Binary files a/technology/freepdk45/lib/sram/clock_nor/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/clock_nor/layout/master.tag b/technology/freepdk45/lib/sram/clock_nor/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/clock_nor/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/data.dm b/technology/freepdk45/lib/sram/data.dm
deleted file mode 100644
index 329ccd3c..00000000
Binary files a/technology/freepdk45/lib/sram/data.dm and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/delay_line/layout/layout.oa b/technology/freepdk45/lib/sram/delay_line/layout/layout.oa
deleted file mode 100755
index 2a84a075..00000000
Binary files a/technology/freepdk45/lib/sram/delay_line/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/delay_line/layout/master.tag b/technology/freepdk45/lib/sram/delay_line/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/delay_line/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/dinv/layout/layout.oa b/technology/freepdk45/lib/sram/dinv/layout/layout.oa
deleted file mode 100755
index a7735463..00000000
Binary files a/technology/freepdk45/lib/sram/dinv/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/dinv/layout/master.tag b/technology/freepdk45/lib/sram/dinv/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/dinv/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/dinv_mx/layout/layout.oa b/technology/freepdk45/lib/sram/dinv_mx/layout/layout.oa
deleted file mode 100755
index ca7c13d2..00000000
Binary files a/technology/freepdk45/lib/sram/dinv_mx/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/dinv_mx/layout/master.tag b/technology/freepdk45/lib/sram/dinv_mx/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/dinv_mx/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/inv/layout/layout.oa b/technology/freepdk45/lib/sram/inv/layout/layout.oa
deleted file mode 100755
index e98db560..00000000
Binary files a/technology/freepdk45/lib/sram/inv/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/inv/layout/master.tag b/technology/freepdk45/lib/sram/inv/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/inv/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/inv_clk/layout/layout.oa b/technology/freepdk45/lib/sram/inv_clk/layout/layout.oa
deleted file mode 100755
index 20790f89..00000000
Binary files a/technology/freepdk45/lib/sram/inv_clk/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/inv_clk/layout/master.tag b/technology/freepdk45/lib/sram/inv_clk/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/inv_clk/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/inv_col/layout/layout.oa b/technology/freepdk45/lib/sram/inv_col/layout/layout.oa
deleted file mode 100755
index 3335bece..00000000
Binary files a/technology/freepdk45/lib/sram/inv_col/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/inv_col/layout/master.tag b/technology/freepdk45/lib/sram/inv_col/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/inv_col/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/inv_dec/layout/layout.oa b/technology/freepdk45/lib/sram/inv_dec/layout/layout.oa
deleted file mode 100755
index 3ec1f587..00000000
Binary files a/technology/freepdk45/lib/sram/inv_dec/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/inv_dec/layout/master.tag b/technology/freepdk45/lib/sram/inv_dec/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/inv_dec/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/inv_nor/layout/layout.oa b/technology/freepdk45/lib/sram/inv_nor/layout/layout.oa
deleted file mode 100755
index 6c23bc4e..00000000
Binary files a/technology/freepdk45/lib/sram/inv_nor/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/inv_nor/layout/master.tag b/technology/freepdk45/lib/sram/inv_nor/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/inv_nor/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/mux_a/layout/layout.oa b/technology/freepdk45/lib/sram/mux_a/layout/layout.oa
deleted file mode 100755
index 16e1369b..00000000
Binary files a/technology/freepdk45/lib/sram/mux_a/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/mux_a/layout/master.tag b/technology/freepdk45/lib/sram/mux_a/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/mux_a/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/mux_abar/layout/layout.oa b/technology/freepdk45/lib/sram/mux_abar/layout/layout.oa
deleted file mode 100755
index 126897ec..00000000
Binary files a/technology/freepdk45/lib/sram/mux_abar/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/mux_abar/layout/master.tag b/technology/freepdk45/lib/sram/mux_abar/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/mux_abar/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/nor_1/layout/layout.oa b/technology/freepdk45/lib/sram/nor_1/layout/layout.oa
deleted file mode 100755
index b0d79792..00000000
Binary files a/technology/freepdk45/lib/sram/nor_1/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/nor_1/layout/master.tag b/technology/freepdk45/lib/sram/nor_1/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/nor_1/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/nor_1_mx/layout/layout.oa b/technology/freepdk45/lib/sram/nor_1_mx/layout/layout.oa
deleted file mode 100755
index 82764ea0..00000000
Binary files a/technology/freepdk45/lib/sram/nor_1_mx/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/nor_1_mx/layout/master.tag b/technology/freepdk45/lib/sram/nor_1_mx/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/nor_1_mx/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/ntap/layout/layout.oa b/technology/freepdk45/lib/sram/ntap/layout/layout.oa
deleted file mode 100755
index aa2cdc19..00000000
Binary files a/technology/freepdk45/lib/sram/ntap/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/ntap/layout/master.tag b/technology/freepdk45/lib/sram/ntap/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/ntap/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/out_inv_16/layout/layout.oa b/technology/freepdk45/lib/sram/out_inv_16/layout/layout.oa
deleted file mode 100755
index 00d0b24e..00000000
Binary files a/technology/freepdk45/lib/sram/out_inv_16/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/out_inv_16/layout/layout.oa- b/technology/freepdk45/lib/sram/out_inv_16/layout/layout.oa-
deleted file mode 100755
index 211c52e7..00000000
Binary files a/technology/freepdk45/lib/sram/out_inv_16/layout/layout.oa- and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/out_inv_16/layout/master.tag b/technology/freepdk45/lib/sram/out_inv_16/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/out_inv_16/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/out_inv_2/layout/layout.oa b/technology/freepdk45/lib/sram/out_inv_2/layout/layout.oa
deleted file mode 100755
index c1480a3c..00000000
Binary files a/technology/freepdk45/lib/sram/out_inv_2/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/out_inv_2/layout/layout.oa- b/technology/freepdk45/lib/sram/out_inv_2/layout/layout.oa-
deleted file mode 100755
index 94f550c6..00000000
Binary files a/technology/freepdk45/lib/sram/out_inv_2/layout/layout.oa- and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/out_inv_2/layout/master.tag b/technology/freepdk45/lib/sram/out_inv_2/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/out_inv_2/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/out_inv_2/schematic/data.dm b/technology/freepdk45/lib/sram/out_inv_2/schematic/data.dm
deleted file mode 100755
index 7cfdc2da..00000000
Binary files a/technology/freepdk45/lib/sram/out_inv_2/schematic/data.dm and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/out_inv_2/schematic/master.tag b/technology/freepdk45/lib/sram/out_inv_2/schematic/master.tag
deleted file mode 100755
index 26be1bef..00000000
--- a/technology/freepdk45/lib/sram/out_inv_2/schematic/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-sch.oa
diff --git a/technology/freepdk45/lib/sram/out_inv_2/schematic/sch.oa b/technology/freepdk45/lib/sram/out_inv_2/schematic/sch.oa
deleted file mode 100755
index 1f45ca4a..00000000
Binary files a/technology/freepdk45/lib/sram/out_inv_2/schematic/sch.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/out_inv_4/layout/layout.oa b/technology/freepdk45/lib/sram/out_inv_4/layout/layout.oa
deleted file mode 100755
index e0690088..00000000
Binary files a/technology/freepdk45/lib/sram/out_inv_4/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/out_inv_4/layout/layout.oa- b/technology/freepdk45/lib/sram/out_inv_4/layout/layout.oa-
deleted file mode 100755
index e0690088..00000000
Binary files a/technology/freepdk45/lib/sram/out_inv_4/layout/layout.oa- and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/out_inv_4/layout/master.tag b/technology/freepdk45/lib/sram/out_inv_4/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/out_inv_4/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/output_latch/layout/layout.oa b/technology/freepdk45/lib/sram/output_latch/layout/layout.oa
deleted file mode 100755
index ff29df6d..00000000
Binary files a/technology/freepdk45/lib/sram/output_latch/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/output_latch/layout/layout.oa- b/technology/freepdk45/lib/sram/output_latch/layout/layout.oa-
deleted file mode 100755
index 6b39e820..00000000
Binary files a/technology/freepdk45/lib/sram/output_latch/layout/layout.oa- and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/output_latch/layout/master.tag b/technology/freepdk45/lib/sram/output_latch/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/output_latch/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/precharge/layout/layout.oa b/technology/freepdk45/lib/sram/precharge/layout/layout.oa
deleted file mode 100755
index 8e1768fc..00000000
Binary files a/technology/freepdk45/lib/sram/precharge/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/precharge/layout/master.tag b/technology/freepdk45/lib/sram/precharge/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/precharge/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/ptap/layout/layout.oa b/technology/freepdk45/lib/sram/ptap/layout/layout.oa
deleted file mode 100755
index f55a28cd..00000000
Binary files a/technology/freepdk45/lib/sram/ptap/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/ptap/layout/master.tag b/technology/freepdk45/lib/sram/ptap/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/ptap/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/sense_amp/layout.oa.backup b/technology/freepdk45/lib/sram/sense_amp/layout.oa.backup
deleted file mode 100755
index 99f09b81..00000000
Binary files a/technology/freepdk45/lib/sram/sense_amp/layout.oa.backup and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/sense_amp/layout/layout.oa b/technology/freepdk45/lib/sram/sense_amp/layout/layout.oa
deleted file mode 100755
index 33c3ce0e..00000000
Binary files a/technology/freepdk45/lib/sram/sense_amp/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/sense_amp/layout/layout.oa- b/technology/freepdk45/lib/sram/sense_amp/layout/layout.oa-
deleted file mode 100755
index b69654d6..00000000
Binary files a/technology/freepdk45/lib/sram/sense_amp/layout/layout.oa- and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/sense_amp/layout/master.tag b/technology/freepdk45/lib/sram/sense_amp/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/sense_amp/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/tgate/layout/layout.oa b/technology/freepdk45/lib/sram/tgate/layout/layout.oa
deleted file mode 100755
index df7fd9be..00000000
Binary files a/technology/freepdk45/lib/sram/tgate/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/tgate/layout/layout.oa- b/technology/freepdk45/lib/sram/tgate/layout/layout.oa-
deleted file mode 100755
index df7fd9be..00000000
Binary files a/technology/freepdk45/lib/sram/tgate/layout/layout.oa- and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/tgate/layout/master.tag b/technology/freepdk45/lib/sram/tgate/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/tgate/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/sram/write_driver/layout/layout.oa b/technology/freepdk45/lib/sram/write_driver/layout/layout.oa
deleted file mode 100755
index 79c3ed15..00000000
Binary files a/technology/freepdk45/lib/sram/write_driver/layout/layout.oa and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/write_driver/layout/layout.oa- b/technology/freepdk45/lib/sram/write_driver/layout/layout.oa-
deleted file mode 100755
index e5f3cdf7..00000000
Binary files a/technology/freepdk45/lib/sram/write_driver/layout/layout.oa- and /dev/null differ
diff --git a/technology/freepdk45/lib/sram/write_driver/layout/master.tag b/technology/freepdk45/lib/sram/write_driver/layout/master.tag
deleted file mode 100755
index 431d8f04..00000000
--- a/technology/freepdk45/lib/sram/write_driver/layout/master.tag
+++ /dev/null
@@ -1,2 +0,0 @@
--- Master.tag File, Rev:1.0
-layout.oa
diff --git a/technology/freepdk45/lib/stream_all_gds.sh b/technology/freepdk45/lib/stream_all_gds.sh
deleted file mode 100644
index 8a2c1048..00000000
--- a/technology/freepdk45/lib/stream_all_gds.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-
-for i in addr_ff clock_nor dinv inv_clk inv_nor nor_1 out_inv_16 output_latch sense_amp addr_latch cell_10t dinv_mx inv_col mux_a nor_1_mx out_inv_2 precharge tgate cell_6t inv inv_dec mux_abar out_inv_4 write_driver
-do
- echo $i
- strmout -layerMap ../sram_lib/layers.map -library sram -topCell $i -view layout -strmFile ../sram_lib/$i.gds
-done
-
-
diff --git a/technology/freepdk45/sp_lib/dummy_cell_1rw_1r.sp b/technology/freepdk45/sp_lib/dummy_cell_1rw_1r.sp
new file mode 100644
index 00000000..c3c082ee
--- /dev/null
+++ b/technology/freepdk45/sp_lib/dummy_cell_1rw_1r.sp
@@ -0,0 +1,14 @@
+
+.SUBCKT dummy_cell_1rw_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
+MM9 RA_to_R_right wl1 br1_noconn gnd NMOS_VTG W=180.0n L=50n m=1
+MM8 RA_to_R_right Q gnd gnd NMOS_VTG W=180.0n L=50n m=1
+MM7 RA_to_R_left Q_bar gnd gnd NMOS_VTG W=180.0n L=50n m=1
+MM6 RA_to_R_left wl1 bl1_noconn gnd NMOS_VTG W=180.0n L=50n m=1
+MM5 Q wl0 bl0_noconn gnd NMOS_VTG W=135.00n L=50n m=1
+MM4 Q_bar wl0 br0_noconn gnd NMOS_VTG W=135.00n L=50n m=1
+MM1 Q Q_bar gnd gnd NMOS_VTG W=205.0n L=50n m=1
+MM0 Q_bar Q gnd gnd NMOS_VTG W=205.0n L=50n m=1
+MM3 Q Q_bar vdd vdd PMOS_VTG W=90n L=50n m=1
+MM2 Q_bar Q vdd vdd PMOS_VTG W=90n L=50n m=1
+.ENDS
+
diff --git a/technology/freepdk45/sp_lib/dummy_cell_1w_1r.sp b/technology/freepdk45/sp_lib/dummy_cell_1w_1r.sp
new file mode 100644
index 00000000..72d7553f
--- /dev/null
+++ b/technology/freepdk45/sp_lib/dummy_cell_1w_1r.sp
@@ -0,0 +1,14 @@
+
+.SUBCKT dummy_cell_1w_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
+MM9 RA_to_R_right wl1 br1_noconn gnd NMOS_VTG W=180.0n L=50n m=1
+MM8 RA_to_R_right Q gnd gnd NMOS_VTG W=180.0n L=50n m=1
+MM7 RA_to_R_left Q_bar gnd gnd NMOS_VTG W=180.0n L=50n m=1
+MM6 RA_to_R_left wl1 bl1_noconn gnd NMOS_VTG W=180.0n L=50n m=1
+MM5 Q wl0 bl0_noconn gnd NMOS_VTG W=135.00n L=50n m=1
+MM4 Q_bar wl0 br0_noconn gnd NMOS_VTG W=135.00n L=50n m=1
+MM1 Q Q_bar gnd gnd NMOS_VTG W=205.0n L=50n m=1
+MM0 Q_bar Q gnd gnd NMOS_VTG W=205.0n L=50n m=1
+MM3 Q Q_bar vdd vdd PMOS_VTG W=90n L=50n m=1
+MM2 Q_bar Q vdd vdd PMOS_VTG W=90n L=50n m=1
+.ENDS
+
diff --git a/technology/freepdk45/sp_lib/dummy_cell_6t.sp b/technology/freepdk45/sp_lib/dummy_cell_6t.sp
new file mode 100644
index 00000000..ab862ec5
--- /dev/null
+++ b/technology/freepdk45/sp_lib/dummy_cell_6t.sp
@@ -0,0 +1,15 @@
+
+.SUBCKT dummy_cell_6t bl br wl vdd gnd
+* Inverter 1
+MM0 Qbar Q gnd gnd NMOS_VTG W=205.00n L=50n
+MM4 Qbar Q vdd vdd PMOS_VTG W=90n L=50n
+
+* Inverer 2
+MM1 Q Qbar gnd gnd NMOS_VTG W=205.00n L=50n
+MM5 Q Qbar vdd vdd PMOS_VTG W=90n L=50n
+
+* Access transistors
+MM3 bl_noconn wl Q gnd NMOS_VTG W=135.00n L=50n
+MM2 br_noconn wl Qbar gnd NMOS_VTG W=135.00n L=50n
+.ENDS cell_6t
+
diff --git a/technology/freepdk45/tech/__init__.py b/technology/freepdk45/tech/__init__.py
index 6b2d03b3..662a09b6 100644
--- a/technology/freepdk45/tech/__init__.py
+++ b/technology/freepdk45/tech/__init__.py
@@ -1,6 +1,13 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
"""
Import tech specific modules.
"""
-from tech import *
+from .tech import *
diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py
index 760d2a5a..caa3c748 100644
--- a/technology/freepdk45/tech/tech.py
+++ b/technology/freepdk45/tech/tech.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import os
from design_rules import *
@@ -7,7 +14,16 @@ File containing the process technology parameters for FreePDK 45nm.
#GDS file info
GDS = {}
-# gds units
+# gds units
+# From http://www.cnf.cornell.edu/cnf_spie9.html: "The first
+#is the size of a database unit in user units. The second is the size
+#of a database unit in meters. For example, if your library was
+#created with the default units (user unit = 1 m and 1000 database
+#units per user unit), then the first number would be 0.001 and the
+#second number would be 10-9. Typically, the first number is less than
+#1, since you use more than 1 database unit per user unit. To
+#calculate the size of a user unit in meters, divide the second number
+#by the first."
GDS["unit"] = (0.0005,1e-9)
# default label zoom
GDS["zoom"] = 0.05
@@ -287,37 +303,16 @@ spice["fall_time"] = 0.005 # fall time in [Nano-seconds]
spice["temperatures"] = [0, 25, 100] # Temperature corners (celcius)
spice["nom_temperature"] = 25 # Nominal temperature (celcius)
-
-#sram signal names
-#FIXME: We don't use these everywhere...
-spice["vdd_name"] = "vdd"
-spice["gnd_name"] = "gnd"
-spice["control_signals"] = ["CSB", "WEB"]
-spice["data_name"] = "DATA"
-spice["addr_name"] = "ADDR"
-spice["minwidth_tx"] = drc["minwidth_tx"]
-spice["channel"] = drc["minlength_channel"]
-spice["clk"] = "clk"
-
# analytical delay parameters
-spice["vdd_nominal"] = 1.0 # Typical Threshold voltage in Volts
-spice["temp_nominal"] = 25.0 # Typical Threshold voltage in Volts
-spice["v_threshold_typical"] = 0.4 # Typical Threshold voltage in Volts
+spice["nom_threshold"] = 0.4 # Typical Threshold voltage in Volts
spice["wire_unit_r"] = 0.075 # Unit wire resistance in ohms/square
spice["wire_unit_c"] = 0.64 # Unit wire capacitance ff/um^2
-spice["min_tx_r"] = 9250.0 # Minimum transistor on resistance in ohms
spice["min_tx_drain_c"] = 0.7 # Minimum transistor drain capacitance in ff
spice["min_tx_gate_c"] = 0.2 # Minimum transistor gate capacitance in ff
-spice["msflop_setup"] = 9 # DFF setup time in ps
-spice["msflop_hold"] = 1 # DFF hold time in ps
-spice["msflop_delay"] = 20.5 # DFF Clk-to-q delay in ps
-spice["msflop_slew"] = 13.1 # DFF output slew in ps w/ no load
-spice["msflop_in_cap"] = 0.2091 # Input capacitance of ms_flop (Din) [Femto-farad]
spice["dff_setup"] = 9 # DFF setup time in ps
spice["dff_hold"] = 1 # DFF hold time in ps
-spice["dff_delay"] = 20.5 # DFF Clk-to-q delay in ps
-spice["dff_slew"] = 13.1 # DFF output slew in ps w/ no load
-spice["dff_in_cap"] = 0.2091 # Input capacitance of ms_flop (Din) [Femto-farad]
+spice["dff_in_cap"] = 0.2091 # Input capacitance (D) [Femto-farad]
+spice["dff_out_cap"] = 2 # Output capacitance (Q) [Femto-farad]
# analytical power parameters, many values are temporary
spice["bitcell_leakage"] = 1 # Leakage power of a single bitcell in nW
@@ -325,26 +320,21 @@ spice["inv_leakage"] = 1 # Leakage power of inverter in nW
spice["nand2_leakage"] = 1 # Leakage power of 2-input nand in nW
spice["nand3_leakage"] = 1 # Leakage power of 3-input nand in nW
spice["nor2_leakage"] = 1 # Leakage power of 2-input nor in nW
-spice["msflop_leakage"] = 1 # Leakage power of flop in nW
-spice["flop_para_cap"] = 2 # Parasitic Output capacitance in fF
+spice["dff_leakage"] = 1 # Leakage power of flop in nW
-spice["default_event_rate"] = 100 # Default event activity of every gate. MHz
-spice["flop_transition_prob"] = .5 # Transition probability of inverter.
-spice["inv_transition_prob"] = .5 # Transition probability of inverter.
-spice["nand2_transition_prob"] = .1875 # Transition probability of 2-input nand.
-spice["nand3_transition_prob"] = .1094 # Transition probability of 3-input nand.
-spice["nor2_transition_prob"] = .1875 # Transition probability of 2-input nor.
+spice["default_event_frequency"] = 100 # Default event activity of every gate. MHz
#Parameters related to sense amp enable timing and delay chain/RBL sizing
-parameter["static_delay_stages"] = 4
-parameter["static_fanout_per_stage"] = 3
-parameter["static_fanout_list"] = parameter["static_delay_stages"]*[parameter["static_fanout_per_stage"]]
+parameter["le_tau"] = 2.25 #In pico-seconds.
+parameter["cap_relative_per_ff"] = 7.5 #Units of Relative Capacitance/ Femto-Farad
parameter["dff_clk_cin"] = 30.6 #relative capacitance
parameter["6tcell_wl_cin"] = 3 #relative capacitance
parameter["min_inv_para_delay"] = 2.4 #Tau delay units
-parameter["sa_en_pmos_size"] = .72 #micro-meters
-parameter["sa_en_nmos_size"] = .27 #micro-meters
-parameter["rbl_height_percentage"] = .5 #Height of RBL compared to bitcell array
+parameter["sa_en_pmos_size"] = 0.72 #micro-meters
+parameter["sa_en_nmos_size"] = 0.27 #micro-meters
+parameter["sa_inv_pmos_size"] = 0.54 #micro-meters
+parameter["sa_inv_nmos_size"] = 0.27 #micro-meters
+parameter["bitcell_drain_cap"] = 0.1 #In Femto-Farad, approximation of drain capacitance
###################################################
##END Spice Simulation Parameters
diff --git a/technology/freepdk45/tf/FreePDK45.lyp b/technology/freepdk45/tf/FreePDK45.lyp
new file mode 100644
index 00000000..29e8e32f
--- /dev/null
+++ b/technology/freepdk45/tf/FreePDK45.lyp
@@ -0,0 +1,1749 @@
+
+
+
+ #ff8000
+ #ff8000
+ 0
+ 0
+ C36
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ pwell.drawing - 2/0
+ 2/0@1
+
+
+ #00cc66
+ #00cc66
+ 0
+ 0
+ C36
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ nwell.drawing - 3/0
+ 3/0@1
+
+
+ #0000ff
+ #0000ff
+ 0
+ 0
+ C41
+ C1
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ vtg.drawing - 6/0
+ 6/0@1
+
+
+ #0000ff
+ #0000ff
+ 0
+ 0
+ C42
+ C1
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ vth.drawing - 7/0
+ 7/0@1
+
+
+ #00cc66
+ #00cc66
+ 0
+ 0
+ C34
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ active.drawing - 1/0
+ 1/0@1
+
+
+ #00cc66
+ #00cc66
+ 0
+ 0
+ C20
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ nimplant.drawing - 4/0
+ 4/0@1
+
+
+ #ff8000
+ #ff8000
+ 0
+ 0
+ C20
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ pimplant.drawing - 5/0
+ 5/0@1
+
+
+ #ff0000
+ #ff0000
+ 0
+ 0
+ C37
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ poly.drawing - 9/0
+ 9/0@1
+
+
+ #ffff00
+ #ffff00
+ 0
+ 0
+ C43
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ thkox.drawing - 8/0
+ 8/0@1
+
+
+ #00cc66
+ #00cc66
+ 0
+ 0
+ C1
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ contact.drawing - 10/0
+ 10/0@1
+
+
+ #0000ff
+ #0000ff
+ 0
+ 0
+ C12
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ metal1.drawing - 11/0
+ 11/0@1
+
+
+ #333399
+ #ff00ff
+ 0
+ 0
+ C39
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ via1.drawing - 12/0
+ 12/0@1
+
+
+ #ff00ff
+ #ff00ff
+ 0
+ 0
+ C2
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ metal2.drawing - 13/0
+ 13/0@1
+
+
+ #39bfff
+ #39bfff
+ 0
+ 0
+ C39
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ via2.drawing - 14/0
+ 14/0@1
+
+
+ #00ffff
+ #00ffff
+ 0
+ 0
+ C11
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ metal3.drawing - 15/0
+ 15/0@1
+
+
+ #ffe6bf
+ #ffe6bf
+ 0
+ 0
+ C39
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ via3.drawing - 16/0
+ 16/0@1
+
+
+ #ffffcc
+ #ffffcc
+ 0
+ 0
+ C25
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ metal4.drawing - 17/0
+ 17/0@1
+
+
+ #0000ff
+ #0000ff
+ 0
+ 0
+ C39
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ via4.drawing - 18/0
+ 18/0@1
+
+
+ #39bfff
+ #39bfff
+ 0
+ 0
+ C29
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ metal5.drawing - 19/0
+ 19/0@1
+
+
+ #ffff00
+ #ffff00
+ 0
+ 0
+ C39
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ via5.drawing - 20/0
+ 20/0@1
+
+
+ #d9cc00
+ #d9cc00
+ 0
+ 0
+ C8
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ metal6.drawing - 21/0
+ 21/0@1
+
+
+ #ff00ff
+ #ff00ff
+ 0
+ 0
+ C39
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ via6.drawing - 22/0
+ 22/0@1
+
+
+ #00ff00
+ #00ff00
+ 0
+ 0
+ C11
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ metal7.drawing - 23/0
+ 23/0@1
+
+
+ #39bfff
+ #39bfff
+ 0
+ 0
+ C39
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ via7.drawing - 24/0
+ 24/0@1
+
+
+ #ffffff
+ #ffffff
+ 0
+ 0
+ C4
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ metal8.drawing - 25/0
+ 25/0@1
+
+
+ #ffffcc
+ #ffffcc
+ 0
+ 0
+ C39
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ via8.drawing - 26/0
+ 26/0@1
+
+
+ #ffe6bf
+ #ffe6bf
+ 0
+ 0
+ C6
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ metal9.drawing - 27/0
+ 27/0@1
+
+
+ #0000ff
+ #0000ff
+ 0
+ 0
+ C39
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ via9.drawing - 28/0
+ 28/0@1
+
+
+ #ff8000
+ #ff8000
+ 0
+ 0
+ C29
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ metal10.drawing - 29/0
+ 29/0@1
+
+
+ #9900e6
+ #9900e6
+ 0
+ 0
+ C0
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ comment.drawing - 239/0
+ 239/0@1
+
+
+
+
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+
+ 1
+ blank
+
+
+
+ ****************
+ ****************
+ ****************
+ ****************
+ ****************
+ ****************
+ ****************
+ ****************
+ ****************
+ ****************
+ ****************
+ ****************
+ ****************
+ ****************
+ ****************
+ ****************
+
+ 2
+ solid
+
+
+
+ .*...*...*...*..
+ ................
+ ...*...*...*...*
+ ................
+ .*...*...*...*..
+ ................
+ ...*...*...*...*
+ ................
+ .*...*...*...*..
+ ................
+ ...*...*...*...*
+ ................
+ .*...*...*...*..
+ ................
+ ...*...*...*...*
+ ................
+
+ 3
+ dots
+
+
+
+ ................
+ ................
+ ................
+ ****************
+ ................
+ ................
+ ................
+ ****************
+ ................
+ ................
+ ................
+ ****************
+ ................
+ ................
+ ................
+ ****************
+
+ 4
+ hLine
+
+
+
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ****************
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ****************
+
+ 5
+ hLine2
+
+
+
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+
+ 6
+ vLine
+
+
+
+ *......*.......*
+ *......*.......*
+ *......*.......*
+ *......*.......*
+ *......*.......*
+ *......*.......*
+ *......*.......*
+ *......*.......*
+ *......*.......*
+ *......*.......*
+ *......*.......*
+ *......*.......*
+ *......*.......*
+ *......*.......*
+ *......*.......*
+ *......*.......*
+
+ 7
+ vLine2
+
+
+
+ *...*...*...*...
+ .*.*.*.*.*.*.*.*
+ ..*...*...*...*.
+ .*.*.*.*.*.*.*.*
+ *...*...*...*...
+ .*.*.*.*.*.*.*.*
+ ..*...*...*...*.
+ .*.*.*.*.*.*.*.*
+ *...*...*...*...
+ .*.*.*.*.*.*.*.*
+ ..*...*...*...*.
+ .*.*.*.*.*.*.*.*
+ *...*...*...*...
+ .*.*.*.*.*.*.*.*
+ ..*...*...*...*.
+ .*.*.*.*.*.*.*.*
+
+ 8
+ cross
+
+
+
+ *...*...*...*...
+ .*.......*......
+ ................
+ ................
+ *....*..*....*..
+ ....*.......*...
+ ................
+ ................
+ *...*...*...*...
+ .*.......*......
+ ................
+ ................
+ *....*..*....*..
+ ....*.......*...
+ ................
+ ................
+
+ 9
+ miniHatch
+
+
+
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ****************
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ****************
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ****************
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ****************
+
+ 10
+ grid
+
+
+
+ ...*...*...*...*
+ ..*...*...*...*.
+ .*...*...*...*..
+ *...*...*...*...
+ ...*...*...*...*
+ ..*...*...*...*.
+ .*...*...*...*..
+ *...*...*...*...
+ ...*...*...*...*
+ ..*...*...*...*.
+ .*...*...*...*..
+ *...*...*...*...
+ ...*...*...*...*
+ ..*...*...*...*.
+ .*...*...*...*..
+ *...*...*...*...
+
+ 11
+ slash
+
+
+
+ ...*.......*....
+ ..*.......*.....
+ .*.......*......
+ *.......*.......
+ .......*.......*
+ ......*.......*.
+ .....*.......*..
+ ....*.......*...
+ ...*.......*....
+ ..*.......*.....
+ .*.......*......
+ *.......*.......
+ .......*.......*
+ ......*.......*.
+ .....*.......*..
+ ....*.......*...
+
+ 12
+ halfslash
+
+
+
+ *...*...*...*...
+ .*...*...*...*..
+ ..*...*...*...*.
+ ...*...*...*...*
+ *...*...*...*...
+ .*...*...*...*..
+ ..*...*...*...*.
+ ...*...*...*...*
+ *...*...*...*...
+ .*...*...*...*..
+ ..*...*...*...*.
+ ...*...*...*...*
+ *...*...*...*...
+ .*...*...*...*..
+ ..*...*...*...*.
+ ...*...*...*...*
+
+ 13
+ backSlash
+
+
+
+ **......**......
+ ..*.......*.....
+ ...**......**...
+ .....*.......*..
+ ......**......**
+ *.......*.......
+ .**......**.....
+ ...*.......*....
+ ....**......**..
+ ......*.......*.
+ *......**......*
+ .*.......*......
+ ..**......**....
+ ....*.......*...
+ .....**......**.
+ .......*.......*
+
+ 14
+ hZigZag
+
+
+
+ *....*....*.....
+ *.....*....*....
+ .*....*.....*...
+ ..*....*....*...
+ ..*.....*....*..
+ ...*....*.....*.
+ ....*....*....*.
+ ....*.....*....*
+ *....*....*.....
+ *.....*....*....
+ .*....*.....*...
+ ..*....*....*...
+ ..*.....*....*..
+ ...*....*.....*.
+ ....*....*....*.
+ ....*.....*....*
+
+ 15
+ vZigZag
+
+
+
+ .....*....*....*
+ ....*....*.....*
+ ...*.....*....*.
+ ...*....*....*..
+ ..*....*.....*..
+ .*.....*....*...
+ .*....*....*....
+ *....*.....*....
+ .....*....*....*
+ ....*....*.....*
+ ...*.....*....*.
+ ...*....*....*..
+ ..*....*.....*..
+ .*.....*....*...
+ .*....*....*....
+ *....*.....*....
+
+ 16
+ rvZigZag
+
+
+
+ ................
+ ................
+ ...*****...*****
+ ...*...*...*...*
+ ...*...*...*...*
+ ****...*****...*
+ ................
+ ................
+ ................
+ ................
+ ...*****...*****
+ ...*...*...*...*
+ ...*...*...*...*
+ ****...*****...*
+ ................
+ ................
+
+ 17
+ hCurb
+
+
+
+ .....*.......*..
+ .....*.......*..
+ .....*.......*..
+ ..****....****..
+ ..*.......*.....
+ ..*.......*.....
+ ..*.......*.....
+ ..****....****..
+ .....*.......*..
+ .....*.......*..
+ .....*.......*..
+ ..****....****..
+ ..*.......*.....
+ ..*.......*.....
+ ..*.......*.....
+ ..****....****..
+
+ 18
+ vCurb
+
+
+
+ ****************
+ ..*.......*.....
+ ..*.......*.....
+ ..*.......*.....
+ ****************
+ ......*.......*.
+ ......*.......*.
+ ......*.......*.
+ ****************
+ ..*.......*.....
+ ..*.......*.....
+ ..*.......*.....
+ ****************
+ ......*.......*.
+ ......*.......*.
+ ......*.......*.
+
+ 19
+ brick
+
+
+
+ ................
+ ..*.......*.....
+ ..*.......*.....
+ ..*.......*.....
+ *****...*****...
+ ..*.......*.....
+ ..*.......*.....
+ ..*.......*.....
+ ................
+ .....*.......*..
+ .....*.......*..
+ .....*.......*..
+ ...*****...*****
+ .....*.......*..
+ .....*.......*..
+ .....*.......*..
+
+ 20
+ dagger
+
+
+
+ ................
+ ....*...........
+ ...*.*..........
+ ..*...*.........
+ .*.....*........
+ *********.......
+ ................
+ ................
+ ................
+ ...........*....
+ ..........*.*...
+ .........*...*..
+ ........*.....*.
+ .......*********
+ ................
+ ................
+
+ 21
+ triangle
+
+
+
+ *...*...*...*...
+ .*.*.*.*.*.*.*.*
+ ..*...*...*...*.
+ .*.*.*.*.*.*.*.*
+ *...*...*...*...
+ .*.*.*.*.*.*.*.*
+ ..*...*...*...*.
+ .*.*.*.*.*.*.*.*
+ *...*...*...*...
+ .*.*.*.*.*.*.*.*
+ ..*...*...*...*.
+ .*.*.*.*.*.*.*.*
+ *...*...*...*...
+ .*.*.*.*.*.*.*.*
+ ..*...*...*...*.
+ .*.*.*.*.*.*.*.*
+
+ 22
+ x
+
+
+
+ *...............
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+
+ 23
+ dot1
+
+
+
+ ................
+ ................
+ ................
+ ...***..........
+ ...***..........
+ ...***..........
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+
+ 24
+ dot2
+
+
+
+ ................
+ ................
+ ..*.....*.....*.
+ ................
+ ................
+ .....*.....*....
+ ................
+ ................
+ ..*.....*.....*.
+ ................
+ ................
+ .....*.....*....
+ ................
+ ................
+ ..*.....*.....*.
+ ................
+
+ 25
+ dot3
+
+
+
+ ................
+ ................
+ .*...*.....*....
+ ................
+ ................
+ ........*.....*.
+ ................
+ ................
+ .*...*.....*....
+ ................
+ ................
+ ........*.....*.
+ ................
+ ................
+ .*...*.....*....
+ ................
+
+ 26
+ dot4
+
+
+
+ ********........
+ ********........
+ ********........
+ ********........
+ ********........
+ ********........
+ ********........
+ ********........
+ ........********
+ ........********
+ ........********
+ ........********
+ ........********
+ ........********
+ ........********
+ ........********
+
+ 27
+ checker
+
+
+
+ ..*...*...*.....
+ ................
+ *...*...*...*...
+ ................
+ ..*...*...*...*.
+ ................
+ *...*...*...*...
+ ................
+ ..*...*...*...*.
+ ................
+ *...*...*...*...
+ ................
+ ..*...*...*...*.
+ ................
+ ....*...*...*...
+ ...............*
+
+ 28
+ viap
+
+
+
+ *...............
+ **..............
+ .**.............
+ ..**............
+ ...**...........
+ ....**..........
+ .....**.........
+ ......**........
+ .......**.......
+ ........**......
+ .........**.....
+ ..........**....
+ ...........**...
+ ............**..
+ .............**.
+ ..............**
+
+ 29
+ metal1S
+
+
+
+ *..............*
+ ................
+ ................
+ ................
+ ...........*....
+ .....*..........
+ ................
+ ................
+ ................
+ ..*.............
+ ................
+ ..........*.....
+ ................
+ ................
+ .....*..........
+ *..............*
+
+ 30
+ metal2S
+
+
+
+ *.....***.....**
+ *.......*.......
+ ***.....***.....
+ ..*.......*.....
+ ..***.....***...
+ ....*.......*...
+ ....***.....***.
+ ......*.......*.
+ *.....***.....**
+ *.......*.......
+ ***.....***.....
+ ..*.......*.....
+ ..***.....***...
+ ....*.......*...
+ ....***.....***.
+ ......*.......*.
+
+ 31
+ gnd2S
+
+
+
+ ...**......**...
+ ....*.......*...
+ .....**......**.
+ ......*.......*.
+ *......**......*
+ *.......*.......
+ .**......**.....
+ ..*.......*.....
+ ...**......**...
+ ....*.......*...
+ .....**......**.
+ ......*.......*.
+ *......**......*
+ *.......*.......
+ .**......**.....
+ ..*.......*.....
+
+ 32
+ vcc2S
+
+
+
+ *..**...*..**...
+ .*..*....*..*...
+ ..*..**...*..**.
+ ...*..*....*..*.
+ *...*..**...*..*
+ *....*..*....*..
+ .**...*..**...*.
+ ..*....*..*....*
+ *..**...*..**...
+ .*..*....*..*...
+ ..*..**...*..**.
+ ...*..*....*..*.
+ *...*..**...*..*
+ *....*..*....*..
+ .**...*..**...*.
+ ..*....*..*....*
+
+ 33
+ vcc1S
+
+
+
+ ................
+ ................
+ ................
+ ..***.....**....
+ ..*..*...*..*...
+ ..*..*......*...
+ ..***......*....
+ ..*.......*.....
+ ..*......*......
+ ..*......****...
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+
+ 34
+ poly2p
+
+
+
+ **......**......
+ **......**......
+ ................
+ ................
+ ....**......**..
+ ....**......**..
+ ................
+ ................
+ **......**......
+ **......**......
+ ................
+ ................
+ ....**......**..
+ ....**......**..
+ ................
+ ................
+
+ 35
+ contp
+
+
+
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ...............*................
+ ...............*................
+ .............*****..............
+ ...............*................
+ ...............*................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+
+ 36
+ pplusp
+
+
+
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ..........*...........*.........
+ ..........*.....*.....*.........
+ ...........*...*.*...*..........
+ ...........*...*.*...*..........
+ ............*.*...*.*...........
+ ............*.*...*.*...........
+ .............*.....*............
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+
+ 37
+ wellp
+
+
+
+ .*.*.*.*.*.*.*.*
+ *.*.*.*.*.*.*.*.
+ .*.*.*.*.*.*.*.*
+ *.*.*.*.*.*.*.*.
+ .*.*.*.*.*.*.*.*
+ *.*.*.*.*.*.*.*.
+ .*.*.*.*.*.*.*.*
+ *.*.*.*.*.*.*.*.
+ .*.*.*.*.*.*.*.*
+ *.*.*.*.*.*.*.*.
+ .*.*.*.*.*.*.*.*
+ *.*.*.*.*.*.*.*.
+ .*.*.*.*.*.*.*.*
+ *.*.*.*.*.*.*.*.
+ .*.*.*.*.*.*.*.*
+ *.*.*.*.*.*.*.*.
+
+ 38
+ checker1
+
+
+
+ **..**..**..**..
+ **..**..**..**..
+ ..**..**..**..**
+ ..**..**..**..**
+ **..**..**..**..
+ **..**..**..**..
+ ..**..**..**..**
+ ..**..**..**..**
+ **..**..**..**..
+ **..**..**..**..
+ ..**..**..**..**
+ ..**..**..**..**
+ **..**..**..**..
+ **..**..**..**..
+ ..**..**..**..**
+ ..**..**..**..**
+
+ 39
+ checker2
+
+
+
+ **.***.***.***.*
+ *.*.*.*.*.*.*.*.
+ .***.***.***.***
+ *.*.*.*.*.*.*.*.
+ **.***.***.***.*
+ *.*.*.*.*.*.*.*.
+ .***.***.***.***
+ *.*.*.*.*.*.*.*.
+ **.***.***.***.*
+ *.*.*.*.*.*.*.*.
+ .***.***.***.***
+ *.*.*.*.*.*.*.*.
+ **.***.***.***.*
+ *.*.*.*.*.*.*.*.
+ .***.***.***.***
+ *.*.*.*.*.*.*.*.
+
+ 40
+ invCross
+
+
+
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ........***....***...***........
+ .........**....***...**.........
+ .........**....***...**.........
+ .........**....*.*...**.........
+ .........***..**.**..**.........
+ ..........**..**.**.**..........
+ ..........**..**.**.**..........
+ ..........**..**.**.**..........
+ ..........**..*...*.**..........
+ ...........***....***...........
+ ...........***....***...........
+ ...........***....***...........
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+
+ 41
+ wellBp
+
+
+
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ...........**********...........
+ ...........*.........*..........
+ ...........*....................
+ ...........*....................
+ ...........*....................
+ ...........*....................
+ ...........*....*****...........
+ ...........*........*...........
+ ...........*........*...........
+ ...........*........*...........
+ ...........**********...........
+
+ 42
+ wellvtg
+
+
+
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ...........*....................
+ ...........*.......*............
+ ...........*.......*............
+ ...........*.......*............
+ ...........*.......*............
+ ...........*********............
+ ...........*.......*............
+ ...........*.......*............
+ ...........*.......*............
+ ...........*.......*............
+ ...........*.......*............
+
+ 43
+ wellvth
+
+
+
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ...........*********............
+ ...........*...*...*............
+ ...............*................
+ ...............*................
+ ...............*................
+ ...............*................
+ ...............*................
+ ...............*................
+ ...............*................
+ ...............*................
+ ...............*................
+
+ 44
+ thickox
+
+
+
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ..............****..............
+ ............********............
+ ............**...***............
+ ...........**.....***...........
+ ...........**...................
+ ...........**...................
+ ...........**...................
+ ...........**...................
+ ...........**.....***...........
+ ............**...***............
+ ............*******.............
+ ..............****..............
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+ ................................
+
+ 45
+ cwellBp
+
+
+
+ ................
+ ................
+ .......**.......
+ .......**.......
+ .......**.......
+ .......**.......
+ ...**********...
+ ................
+ ................
+ .....******.....
+ ....*..**..*....
+ ...*...**...*...
+ .......**.......
+ .......**.......
+ ................
+ ................
+
+ 46
+ capID
+
+
+
+ ................
+ ................
+ ................
+ ................
+ ...*............
+ ...*............
+ ..*.*...........
+ ..*.*...........
+ ***.*..***......
+ .....*.*........
+ .....*.*........
+ ......*.........
+ ......*.........
+ ................
+ ................
+ ................
+
+ 47
+ resID
+
+
+
+ ................
+ ................
+ ................
+ ................
+ ......*....*....
+ ......**...*....
+ ......*.*..*....
+ ......*..*.*....
+ ...****...****..
+ ......*..*.*....
+ ......*.*..*....
+ ......**...*....
+ ......*....*....
+ ................
+ ................
+ ................
+
+ 48
+ diodeID
+
+
+
+ ****************
+ ****************
+ **.*.*.***.*.*.*
+ ****************
+ **.*.*.***.*.*.*
+ ****************
+ **.*.*.***.*.*.*
+ ****************
+ ****************
+ ****************
+ **.*.*.***.*.*.*
+ ****************
+ **.*.*.***.*.*.*
+ ****************
+ **.*.*.***.*.*.*
+ ****************
+
+ 49
+ sgrid
+
+
+ ***
+ 1
+ solid
+
+
+ ****..
+ 2
+ dashed
+
+
+ *..
+ 3
+ dots
+
+
+ ***..*..
+ 4
+ dashDot
+
+
+ **..
+ 5
+ shortDash
+
+
+ ****..**..
+ 6
+ doubleDash
+
+
+ *...
+ 7
+ hidden
+
+
+ ***
+ 8
+ thickLine
+
+
+ ***
+ 9
+ mLine
+
+
diff --git a/technology/freepdk45/tf/README.txt b/technology/freepdk45/tf/README.txt
index 5393b0b3..662dbb7c 100644
--- a/technology/freepdk45/tf/README.txt
+++ b/technology/freepdk45/tf/README.txt
@@ -44,4 +44,14 @@ Contributions and modifications to this kit are welcomed and encouraged.
ncsu_basekit/ Base kit for custom design
osu_soc/ Standard-cell kit for synthesis, place, & route
+FreePDK45.lyp is converted automatically from the .tf using:
+https://github.com/klayoutmatthias/tf_import
+Command line:
+klayout -z -rd tf_file=FreePDK45.tf -rd lyp_file=FreePDK45.lyp
+You can then view layouts with:
+klayout file.gds -l mosis.lyp
+glade_freepdk45.py is a script for Glade:
+https://peardrop.co.uk/
+to load the .tf using:
+glade -script ~/openram/technology/freepdk45/tf/glade_freepdk45.py -gds file.gds
diff --git a/technology/freepdk45/tf/SVRF_EULA_06Feb09.txt b/technology/freepdk45/tf/SVRF_EULA_06Feb09.txt
new file mode 100644
index 00000000..637a7627
--- /dev/null
+++ b/technology/freepdk45/tf/SVRF_EULA_06Feb09.txt
@@ -0,0 +1,84 @@
+ SVRF(TM) TECHNOLOGY LICENSE AGREEMENT
+ February 6, 2009
+
+This license is a legal "Agreement" concerning the use of SVRF
+Technology between you, the end user, either individually or as an
+authorized representative of the school or company acquiring the
+license ("You"), and Mentor Graphics Corporation and Mentor Graphics
+(Ireland) Limited acting directly or through their subsidiaries or
+authorized distributors (collectively "Mentor Graphics"). "SVRF
+Technology" shall mean Mentor Graphics' syntax for expressing process
+rules and controlling physical verification, principally the syntax
+expressed in Mentor Graphics. SVRF User Manual. USE OF SVRF TECHNOLOGY
+INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE OF THE TERMS AND
+CONDITIONS SET FORTH IN THIS AGREEMENT. If you do not agree to these
+terms and conditions, promptly certify destruction of the SVRF
+Technology and all accompanying items within five days after receipt
+of SVRF Technology.
+
+1. GRANT OF LICENSE. This file includes SVRF Technology under license
+ by Mentor Graphics Corporation. Mentor Graphics grants to You a
+ nontransferable, nonexclusive license to use SVRF Technology solely
+ for use with Mentor Graphics' Calibre(R) tools and either: (a) in an
+ educational classroom or laboratory environment; or (b) for your
+ internal business purpose as allowed by an existing license
+ agreement between You and Mentor Graphics.
+
+2. RESTRICTIONS ON USE. All SVRF Technology constitutes or contains
+ trade secrets and confidential information of Mentor Graphics or
+ its licensors. You shall not make SVRF Technology available in any
+ form to any person other those persons whose performance requires
+ such access and who are under obligations of confidentiality. You
+ shall take appropriate action to protect the confidentiality of
+ SVRF Technology and ensure that persons permitted access to SVRF
+ Technology do not disclose it or use it except as permitted by this
+ Agreement. The provisions of this Section 2 shall survive the
+ termination or expiration of this Agreement.
+
+3. NO WARRANTY. Mentor Graphics expressly disclaims any warranty for
+ SVRF Technology. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW,
+ SVRF TECHNOLOGY AND ANY RELATED DOCUMENTATION ARE PROVIDED "AS IS"
+ AND WITH ALL FAULTS AND WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, THE
+ IMPLIED WARRANTIES OR CONDITIONS OF MERCHANTABILITY, FITNESS FOR A
+ PARTICULAR PURPOSE, OR NONINFRINGEMENT. THE ENTIRE RISK ARISING OUT
+ OF USE OR PERFORMANCE OF SVRF TECHNOLOGY REMAINS WITH YOU.
+
+4. LIMITATION OF LIABILITY. EXCEPT WHERE THIS EXCLUSION OR RESTRICTION
+ OF LIABILITY WOULD BE VOID OR INEFFECTIVE UNDER APPLICABLE LAW, IN
+ NO EVENT WILL MENTOR GRAPHICS OR ITS LICENSORS BE LIABLE FOR
+ INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES (INCLUDING
+ LOST PROFITS OR SAVINGS) WHETHER BASED ON CONTRACT, TORT OR ANY
+ OTHER LEGAL THEORY, EVEN IF MENTOR GRAPHICS OR ITS LICENSORS HAVE
+ BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+5. TERM. This Agreement remains effective until termination. This
+ Agreement will immediately terminate upon notice if you exceed the
+ scope of license granted or otherwise fail to comply with the
+ provisions of Sections 1 or 2. For any other material breach under
+ this Agreement, Mentor Graphics may terminate this Agreement upon
+ 30 days written notice if you are in material breach and fail to
+ cure such breach within the 30-day notice period. Upon any
+ termination, you agree to cease all use of SVRF Technology and
+ certify destruction of SVRF Technology, including all copies, to
+ Mentor Graphics. reasonable satisfaction.
+
+6. GOVERNING LAW. This License shall be governed by and construed
+ under the laws of the State of Oregon, USA, if You are located in
+ North or South America, and the laws of Ireland if You are located
+ outside of North or South America.
+
+7. SEVERABILITY. If any provision of this Agreement is held by a court
+ of competent jurisdiction to be void, invalid, unenforceable or
+ illegal, such provision shall be severed from this Agreement and
+ the remaining provisions will remain in full force and effect.
+
+8. MISCELLANEOUS. This Agreement contains the parties' entire
+ understanding relating to its subject matter and supersedes all
+ prior or contemporaneous agreements, except valid license
+ agreements related to the subject matter of this Agreement (which
+ are physically signed by you and an authorized agent of Mentor
+ Graphics). This Agreement may only be modified in writing by
+ authorized representatives of the parties. Waiver of terms or
+ excuse of breach must be in writing and shall not constitute
+ subsequent consent, waiver or excuse.
diff --git a/technology/freepdk45/tf/display.drf b/technology/freepdk45/tf/display.drf
index 7923ae62..2b6304ec 100644
--- a/technology/freepdk45/tf/display.drf
+++ b/technology/freepdk45/tf/display.drf
@@ -1097,7 +1097,7 @@ drDefinePacket(
( display metal1Pin X solid blue blue )
( display metal1Lbl blank solid blue blue )
( display metal1Bnd blank solid blue blue )
- ( display contact X solid black lime )
+ ( display contact solid solid green green )
( display contactNe blank solid brown brown )
( display contactPin X solid black black )
( display contactLbl blank solid black black )
@@ -1223,6 +1223,7 @@ drDefinePacket(
( display prBoundary blank solid purple purple )
( display prBoundaryBnd blank solid cyan cyan )
( display prBoundaryLbl blank solid purple purple )
+ ( display comment blank solid purple purple )
( display align blank solid tan tan )
( display hardFence blank solid red red )
( display softFence blank solid yellow yellow )
diff --git a/technology/setup_scripts/setup_openram_scn3me_subm.py b/technology/scn3me_subm/__init__.py
similarity index 77%
rename from technology/setup_scripts/setup_openram_scn3me_subm.py
rename to technology/scn3me_subm/__init__.py
index 1508b2a8..87b26056 100644
--- a/technology/setup_scripts/setup_openram_scn3me_subm.py
+++ b/technology/scn3me_subm/__init__.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+#Copyright (c) 2016-2019 Regents of the University of California and The Board
+#of Regents for the Oklahoma Agricultural and Mechanical College
+#(acting for and on behalf of Oklahoma State University)
+#All rights reserved.
+#
#!/usr/bin/python
"""
This type of setup script should be placed in the setup_scripts directory in the trunk
@@ -34,8 +41,3 @@ os.environ["DRCLVS_HOME"] = DRCLVS_HOME
OPENRAM_TECH=os.path.abspath(os.environ.get("OPENRAM_TECH"))
os.environ["SPICE_MODEL_DIR"] = "{0}/{1}/models".format(OPENRAM_TECH, TECHNOLOGY)
-##########################
-# Paths required for OPENRAM to function
-
-LOCAL = "{0}/..".format(os.path.dirname(__file__))
-sys.path.append("{0}/{1}/tech".format(LOCAL,TECHNOLOGY))
diff --git a/technology/scn3me_subm/gds_lib/cell_1rw_1r.gds b/technology/scn3me_subm/gds_lib/cell_1rw_1r.gds
new file mode 100644
index 00000000..f9a19873
Binary files /dev/null and b/technology/scn3me_subm/gds_lib/cell_1rw_1r.gds differ
diff --git a/technology/scn3me_subm/gds_lib/cell_1w_1r.gds b/technology/scn3me_subm/gds_lib/cell_1w_1r.gds
new file mode 100644
index 00000000..41cff8af
Binary files /dev/null and b/technology/scn3me_subm/gds_lib/cell_1w_1r.gds differ
diff --git a/technology/scn3me_subm/gds_lib/cell_6t.gds b/technology/scn3me_subm/gds_lib/cell_6t.gds
index 20e5367e..673962cc 100644
Binary files a/technology/scn3me_subm/gds_lib/cell_6t.gds and b/technology/scn3me_subm/gds_lib/cell_6t.gds differ
diff --git a/technology/scn3me_subm/gds_lib/dff.gds b/technology/scn3me_subm/gds_lib/dff.gds
index 07c37298..6d089c49 100644
Binary files a/technology/scn3me_subm/gds_lib/dff.gds and b/technology/scn3me_subm/gds_lib/dff.gds differ
diff --git a/technology/scn3me_subm/gds_lib/replica_cell_1rw_1r.gds b/technology/scn3me_subm/gds_lib/replica_cell_1rw_1r.gds
new file mode 100644
index 00000000..90002b77
Binary files /dev/null and b/technology/scn3me_subm/gds_lib/replica_cell_1rw_1r.gds differ
diff --git a/technology/scn3me_subm/gds_lib/replica_cell_1w_1r.gds b/technology/scn3me_subm/gds_lib/replica_cell_1w_1r.gds
new file mode 100644
index 00000000..2adb9582
Binary files /dev/null and b/technology/scn3me_subm/gds_lib/replica_cell_1w_1r.gds differ
diff --git a/technology/scn3me_subm/gds_lib/replica_cell_6t.gds b/technology/scn3me_subm/gds_lib/replica_cell_6t.gds
index 12d97796..b26d63d4 100644
Binary files a/technology/scn3me_subm/gds_lib/replica_cell_6t.gds and b/technology/scn3me_subm/gds_lib/replica_cell_6t.gds differ
diff --git a/technology/scn3me_subm/gds_lib/sense_amp.gds b/technology/scn3me_subm/gds_lib/sense_amp.gds
index 0fc7eb56..11081bd3 100644
Binary files a/technology/scn3me_subm/gds_lib/sense_amp.gds and b/technology/scn3me_subm/gds_lib/sense_amp.gds differ
diff --git a/technology/scn3me_subm/gds_lib/tri_gate.gds b/technology/scn3me_subm/gds_lib/tri_gate.gds
index a3f25a39..c48fe3a1 100644
Binary files a/technology/scn3me_subm/gds_lib/tri_gate.gds and b/technology/scn3me_subm/gds_lib/tri_gate.gds differ
diff --git a/technology/scn3me_subm/gds_lib/write_driver.gds b/technology/scn3me_subm/gds_lib/write_driver.gds
index fdd3ad88..0bef7b79 100644
Binary files a/technology/scn3me_subm/gds_lib/write_driver.gds and b/technology/scn3me_subm/gds_lib/write_driver.gds differ
diff --git a/technology/scn3me_subm/mag_lib/cell_1rw_1r.mag b/technology/scn3me_subm/mag_lib/cell_1rw_1r.mag
new file mode 100644
index 00000000..6a6fbc86
--- /dev/null
+++ b/technology/scn3me_subm/mag_lib/cell_1rw_1r.mag
@@ -0,0 +1,156 @@
+magic
+tech scmos
+timestamp 1558933786
+<< nwell >>
+rect 0 48 54 77
+<< pwell >>
+rect 0 0 54 48
+<< ntransistor >>
+rect 14 34 16 38
+rect 22 30 24 38
+rect 30 30 32 38
+rect 38 34 40 38
+rect 14 17 16 23
+rect 22 17 24 23
+rect 30 17 32 23
+rect 38 17 40 23
+<< ptransistor >>
+rect 22 56 24 59
+rect 30 56 32 59
+<< ndiffusion >>
+rect 13 34 14 38
+rect 16 34 17 38
+rect 21 34 22 38
+rect 17 30 22 34
+rect 24 36 30 38
+rect 24 32 25 36
+rect 29 32 30 36
+rect 24 30 30 32
+rect 32 34 33 38
+rect 37 34 38 38
+rect 40 34 41 38
+rect 32 30 37 34
+rect 9 21 14 23
+rect 13 17 14 21
+rect 16 17 22 23
+rect 24 22 30 23
+rect 24 18 25 22
+rect 29 18 30 22
+rect 24 17 30 18
+rect 32 17 38 23
+rect 40 21 45 23
+rect 40 17 41 21
+<< pdiffusion >>
+rect 21 56 22 59
+rect 24 56 25 59
+rect 29 56 30 59
+rect 32 56 33 59
+<< ndcontact >>
+rect 9 34 13 38
+rect 17 34 21 38
+rect 25 32 29 36
+rect 33 34 37 38
+rect 41 34 45 38
+rect 9 17 13 21
+rect 25 18 29 22
+rect 41 17 45 21
+<< pdcontact >>
+rect 17 56 21 60
+rect 25 56 29 60
+rect 33 56 37 60
+<< psubstratepcontact >>
+rect 25 9 29 13
+<< nsubstratencontact >>
+rect 37 70 41 74
+<< polysilicon >>
+rect 22 59 24 62
+rect 30 59 32 62
+rect 22 45 24 56
+rect 30 53 32 56
+rect 13 41 16 43
+rect 14 38 16 41
+rect 22 38 24 41
+rect 30 38 32 49
+rect 38 41 41 43
+rect 38 38 40 41
+rect 14 32 16 34
+rect 38 32 40 34
+rect 14 23 16 24
+rect 22 23 24 30
+rect 30 23 32 30
+rect 38 23 40 24
+rect 14 15 16 17
+rect 22 15 24 17
+rect 30 15 32 17
+rect 38 15 40 17
+<< polycontact >>
+rect 28 49 32 53
+rect 9 41 13 45
+rect 22 41 26 45
+rect 41 41 45 45
+rect 12 24 16 28
+rect 38 24 42 28
+<< metal1 >>
+rect 0 70 25 74
+rect 29 70 37 74
+rect 41 70 54 74
+rect 0 63 54 67
+rect 9 45 13 63
+rect 16 56 17 60
+rect 37 56 38 60
+rect 16 53 20 56
+rect 16 49 28 53
+rect 16 38 19 49
+rect 35 45 38 56
+rect 26 41 38 45
+rect 41 45 45 63
+rect 35 38 38 41
+rect 6 34 9 38
+rect 16 34 17 38
+rect 25 36 29 38
+rect 37 34 38 38
+rect 45 34 48 38
+rect 25 22 29 32
+rect 25 13 29 18
+rect 0 9 25 13
+rect 29 9 54 13
+rect 0 2 16 6
+rect 20 2 34 6
+rect 38 2 54 6
+<< m2contact >>
+rect 25 70 29 74
+rect 25 56 29 60
+rect 2 34 6 38
+rect 48 34 52 38
+rect 16 24 20 28
+rect 34 24 38 28
+rect 9 17 13 21
+rect 41 17 45 21
+rect 16 2 20 6
+rect 34 2 38 6
+<< metal2 >>
+rect 2 38 6 74
+rect 2 0 6 34
+rect 9 21 13 74
+rect 25 60 29 70
+rect 9 0 13 17
+rect 16 6 20 24
+rect 34 6 38 24
+rect 41 21 45 74
+rect 41 0 45 17
+rect 48 38 52 74
+rect 48 0 52 34
+<< comment >>
+rect 0 0 54 72
+<< labels >>
+rlabel metal1 27 4 27 4 4 wl1
+rlabel psubstratepcontact 27 11 27 11 4 gnd
+rlabel metal2 4 7 4 7 4 bl0
+rlabel metal2 50 7 50 7 4 br0
+rlabel metal1 19 65 19 65 4 wl0
+rlabel metal2 11 7 11 7 4 bl1
+rlabel metal2 43 7 43 7 4 br1
+rlabel metal1 18 72 18 72 1 vdd
+<< properties >>
+string path 0.000 0.000 243.000 0.000 243.000 324.000 0.000 324.000 0.000 0.000
+<< end >>
diff --git a/technology/scn3me_subm/mag_lib/cell_1w_1r.mag b/technology/scn3me_subm/mag_lib/cell_1w_1r.mag
new file mode 100644
index 00000000..6a6fbc86
--- /dev/null
+++ b/technology/scn3me_subm/mag_lib/cell_1w_1r.mag
@@ -0,0 +1,156 @@
+magic
+tech scmos
+timestamp 1558933786
+<< nwell >>
+rect 0 48 54 77
+<< pwell >>
+rect 0 0 54 48
+<< ntransistor >>
+rect 14 34 16 38
+rect 22 30 24 38
+rect 30 30 32 38
+rect 38 34 40 38
+rect 14 17 16 23
+rect 22 17 24 23
+rect 30 17 32 23
+rect 38 17 40 23
+<< ptransistor >>
+rect 22 56 24 59
+rect 30 56 32 59
+<< ndiffusion >>
+rect 13 34 14 38
+rect 16 34 17 38
+rect 21 34 22 38
+rect 17 30 22 34
+rect 24 36 30 38
+rect 24 32 25 36
+rect 29 32 30 36
+rect 24 30 30 32
+rect 32 34 33 38
+rect 37 34 38 38
+rect 40 34 41 38
+rect 32 30 37 34
+rect 9 21 14 23
+rect 13 17 14 21
+rect 16 17 22 23
+rect 24 22 30 23
+rect 24 18 25 22
+rect 29 18 30 22
+rect 24 17 30 18
+rect 32 17 38 23
+rect 40 21 45 23
+rect 40 17 41 21
+<< pdiffusion >>
+rect 21 56 22 59
+rect 24 56 25 59
+rect 29 56 30 59
+rect 32 56 33 59
+<< ndcontact >>
+rect 9 34 13 38
+rect 17 34 21 38
+rect 25 32 29 36
+rect 33 34 37 38
+rect 41 34 45 38
+rect 9 17 13 21
+rect 25 18 29 22
+rect 41 17 45 21
+<< pdcontact >>
+rect 17 56 21 60
+rect 25 56 29 60
+rect 33 56 37 60
+<< psubstratepcontact >>
+rect 25 9 29 13
+<< nsubstratencontact >>
+rect 37 70 41 74
+<< polysilicon >>
+rect 22 59 24 62
+rect 30 59 32 62
+rect 22 45 24 56
+rect 30 53 32 56
+rect 13 41 16 43
+rect 14 38 16 41
+rect 22 38 24 41
+rect 30 38 32 49
+rect 38 41 41 43
+rect 38 38 40 41
+rect 14 32 16 34
+rect 38 32 40 34
+rect 14 23 16 24
+rect 22 23 24 30
+rect 30 23 32 30
+rect 38 23 40 24
+rect 14 15 16 17
+rect 22 15 24 17
+rect 30 15 32 17
+rect 38 15 40 17
+<< polycontact >>
+rect 28 49 32 53
+rect 9 41 13 45
+rect 22 41 26 45
+rect 41 41 45 45
+rect 12 24 16 28
+rect 38 24 42 28
+<< metal1 >>
+rect 0 70 25 74
+rect 29 70 37 74
+rect 41 70 54 74
+rect 0 63 54 67
+rect 9 45 13 63
+rect 16 56 17 60
+rect 37 56 38 60
+rect 16 53 20 56
+rect 16 49 28 53
+rect 16 38 19 49
+rect 35 45 38 56
+rect 26 41 38 45
+rect 41 45 45 63
+rect 35 38 38 41
+rect 6 34 9 38
+rect 16 34 17 38
+rect 25 36 29 38
+rect 37 34 38 38
+rect 45 34 48 38
+rect 25 22 29 32
+rect 25 13 29 18
+rect 0 9 25 13
+rect 29 9 54 13
+rect 0 2 16 6
+rect 20 2 34 6
+rect 38 2 54 6
+<< m2contact >>
+rect 25 70 29 74
+rect 25 56 29 60
+rect 2 34 6 38
+rect 48 34 52 38
+rect 16 24 20 28
+rect 34 24 38 28
+rect 9 17 13 21
+rect 41 17 45 21
+rect 16 2 20 6
+rect 34 2 38 6
+<< metal2 >>
+rect 2 38 6 74
+rect 2 0 6 34
+rect 9 21 13 74
+rect 25 60 29 70
+rect 9 0 13 17
+rect 16 6 20 24
+rect 34 6 38 24
+rect 41 21 45 74
+rect 41 0 45 17
+rect 48 38 52 74
+rect 48 0 52 34
+<< comment >>
+rect 0 0 54 72
+<< labels >>
+rlabel metal1 27 4 27 4 4 wl1
+rlabel psubstratepcontact 27 11 27 11 4 gnd
+rlabel metal2 4 7 4 7 4 bl0
+rlabel metal2 50 7 50 7 4 br0
+rlabel metal1 19 65 19 65 4 wl0
+rlabel metal2 11 7 11 7 4 bl1
+rlabel metal2 43 7 43 7 4 br1
+rlabel metal1 18 72 18 72 1 vdd
+<< properties >>
+string path 0.000 0.000 243.000 0.000 243.000 324.000 0.000 324.000 0.000 0.000
+<< end >>
diff --git a/technology/scn3me_subm/mag_lib/convertall.sh b/technology/scn3me_subm/mag_lib/convertall.sh
index f5e2482c..43de584f 100755
--- a/technology/scn3me_subm/mag_lib/convertall.sh
+++ b/technology/scn3me_subm/mag_lib/convertall.sh
@@ -11,4 +11,12 @@ load tri_gate
gds write tri_gate.gds
load write_driver
gds write write_driver.gds
+load replica_cell_1w_1r
+gds write replica_cell_1w_1r
+load replica_cell_1rw_1r
+gds write replica_cell_1rw_1r
+load cell_1rw_1r
+gds write cell_1rw_1r
+load cell_1w_1r
+gds write cell_1w_1r
EOF
diff --git a/technology/scn3me_subm/mag_lib/replica_cell_1rw_1r.mag b/technology/scn3me_subm/mag_lib/replica_cell_1rw_1r.mag
new file mode 100644
index 00000000..a7387b7e
--- /dev/null
+++ b/technology/scn3me_subm/mag_lib/replica_cell_1rw_1r.mag
@@ -0,0 +1,157 @@
+magic
+tech scmos
+timestamp 1558933826
+<< nwell >>
+rect 0 48 54 77
+<< pwell >>
+rect 0 0 54 48
+<< ntransistor >>
+rect 14 34 16 38
+rect 22 30 24 38
+rect 30 30 32 38
+rect 38 34 40 38
+rect 14 17 16 23
+rect 22 17 24 23
+rect 30 17 32 23
+rect 38 17 40 23
+<< ptransistor >>
+rect 22 56 24 59
+rect 30 56 32 59
+<< ndiffusion >>
+rect 13 34 14 38
+rect 16 34 17 38
+rect 21 34 22 38
+rect 17 30 22 34
+rect 24 36 30 38
+rect 24 32 25 36
+rect 29 32 30 36
+rect 24 30 30 32
+rect 32 34 33 38
+rect 37 34 38 38
+rect 40 34 41 38
+rect 32 30 37 34
+rect 9 21 14 23
+rect 13 17 14 21
+rect 16 17 22 23
+rect 24 22 30 23
+rect 24 18 25 22
+rect 29 18 30 22
+rect 24 17 30 18
+rect 32 17 38 23
+rect 40 21 45 23
+rect 40 17 41 21
+<< pdiffusion >>
+rect 21 56 22 59
+rect 24 56 25 59
+rect 29 56 30 59
+rect 32 56 33 59
+<< ndcontact >>
+rect 9 34 13 38
+rect 17 34 21 38
+rect 25 32 29 36
+rect 33 34 37 38
+rect 41 34 45 38
+rect 9 17 13 21
+rect 25 18 29 22
+rect 41 17 45 21
+<< pdcontact >>
+rect 17 56 21 60
+rect 25 56 29 60
+rect 33 56 37 60
+<< psubstratepcontact >>
+rect 25 9 29 13
+<< nsubstratencontact >>
+rect 37 70 41 74
+<< polysilicon >>
+rect 22 59 24 62
+rect 30 59 32 62
+rect 22 45 24 56
+rect 30 53 32 56
+rect 13 41 16 43
+rect 14 38 16 41
+rect 22 38 24 41
+rect 30 38 32 49
+rect 38 41 41 43
+rect 38 38 40 41
+rect 14 32 16 34
+rect 38 32 40 34
+rect 14 23 16 24
+rect 22 23 24 30
+rect 30 23 32 30
+rect 38 23 40 24
+rect 14 15 16 17
+rect 22 15 24 17
+rect 30 15 32 17
+rect 38 15 40 17
+<< polycontact >>
+rect 28 49 32 53
+rect 9 41 13 45
+rect 22 41 26 45
+rect 41 41 45 45
+rect 12 24 16 28
+rect 38 24 42 28
+<< metal1 >>
+rect 0 70 25 74
+rect 29 70 37 74
+rect 41 70 54 74
+rect 0 63 54 67
+rect 9 45 13 63
+rect 16 56 17 60
+rect 29 56 33 60
+rect 37 56 38 60
+rect 16 53 20 56
+rect 16 49 28 53
+rect 16 38 19 49
+rect 35 45 38 56
+rect 26 41 38 45
+rect 41 45 45 63
+rect 35 38 38 41
+rect 6 34 9 38
+rect 16 34 17 38
+rect 25 36 29 38
+rect 37 34 38 38
+rect 45 34 48 38
+rect 25 22 29 32
+rect 25 13 29 18
+rect 0 9 25 13
+rect 29 9 54 13
+rect 0 2 16 6
+rect 20 2 34 6
+rect 38 2 54 6
+<< m2contact >>
+rect 25 70 29 74
+rect 25 56 29 60
+rect 2 34 6 38
+rect 48 34 52 38
+rect 16 24 20 28
+rect 34 24 38 28
+rect 9 17 13 21
+rect 41 17 45 21
+rect 16 2 20 6
+rect 34 2 38 6
+<< metal2 >>
+rect 2 38 6 74
+rect 2 0 6 34
+rect 9 21 13 74
+rect 25 60 29 70
+rect 9 0 13 17
+rect 16 6 20 24
+rect 34 6 38 24
+rect 41 21 45 74
+rect 41 0 45 17
+rect 48 38 52 74
+rect 48 0 52 34
+<< comment >>
+rect 0 0 54 72
+<< labels >>
+rlabel metal1 27 4 27 4 4 wl1
+rlabel psubstratepcontact 27 11 27 11 4 gnd
+rlabel metal2 4 7 4 7 4 bl0
+rlabel metal2 50 7 50 7 4 br0
+rlabel metal1 19 65 19 65 4 wl0
+rlabel metal2 11 7 11 7 4 bl1
+rlabel metal2 43 7 43 7 4 br1
+rlabel metal1 18 72 18 72 1 vdd
+<< properties >>
+string path 0.000 0.000 243.000 0.000 243.000 324.000 0.000 324.000 0.000 0.000
+<< end >>
diff --git a/technology/scn3me_subm/mag_lib/replica_cell_1w_1r.mag b/technology/scn3me_subm/mag_lib/replica_cell_1w_1r.mag
new file mode 100644
index 00000000..a7387b7e
--- /dev/null
+++ b/technology/scn3me_subm/mag_lib/replica_cell_1w_1r.mag
@@ -0,0 +1,157 @@
+magic
+tech scmos
+timestamp 1558933826
+<< nwell >>
+rect 0 48 54 77
+<< pwell >>
+rect 0 0 54 48
+<< ntransistor >>
+rect 14 34 16 38
+rect 22 30 24 38
+rect 30 30 32 38
+rect 38 34 40 38
+rect 14 17 16 23
+rect 22 17 24 23
+rect 30 17 32 23
+rect 38 17 40 23
+<< ptransistor >>
+rect 22 56 24 59
+rect 30 56 32 59
+<< ndiffusion >>
+rect 13 34 14 38
+rect 16 34 17 38
+rect 21 34 22 38
+rect 17 30 22 34
+rect 24 36 30 38
+rect 24 32 25 36
+rect 29 32 30 36
+rect 24 30 30 32
+rect 32 34 33 38
+rect 37 34 38 38
+rect 40 34 41 38
+rect 32 30 37 34
+rect 9 21 14 23
+rect 13 17 14 21
+rect 16 17 22 23
+rect 24 22 30 23
+rect 24 18 25 22
+rect 29 18 30 22
+rect 24 17 30 18
+rect 32 17 38 23
+rect 40 21 45 23
+rect 40 17 41 21
+<< pdiffusion >>
+rect 21 56 22 59
+rect 24 56 25 59
+rect 29 56 30 59
+rect 32 56 33 59
+<< ndcontact >>
+rect 9 34 13 38
+rect 17 34 21 38
+rect 25 32 29 36
+rect 33 34 37 38
+rect 41 34 45 38
+rect 9 17 13 21
+rect 25 18 29 22
+rect 41 17 45 21
+<< pdcontact >>
+rect 17 56 21 60
+rect 25 56 29 60
+rect 33 56 37 60
+<< psubstratepcontact >>
+rect 25 9 29 13
+<< nsubstratencontact >>
+rect 37 70 41 74
+<< polysilicon >>
+rect 22 59 24 62
+rect 30 59 32 62
+rect 22 45 24 56
+rect 30 53 32 56
+rect 13 41 16 43
+rect 14 38 16 41
+rect 22 38 24 41
+rect 30 38 32 49
+rect 38 41 41 43
+rect 38 38 40 41
+rect 14 32 16 34
+rect 38 32 40 34
+rect 14 23 16 24
+rect 22 23 24 30
+rect 30 23 32 30
+rect 38 23 40 24
+rect 14 15 16 17
+rect 22 15 24 17
+rect 30 15 32 17
+rect 38 15 40 17
+<< polycontact >>
+rect 28 49 32 53
+rect 9 41 13 45
+rect 22 41 26 45
+rect 41 41 45 45
+rect 12 24 16 28
+rect 38 24 42 28
+<< metal1 >>
+rect 0 70 25 74
+rect 29 70 37 74
+rect 41 70 54 74
+rect 0 63 54 67
+rect 9 45 13 63
+rect 16 56 17 60
+rect 29 56 33 60
+rect 37 56 38 60
+rect 16 53 20 56
+rect 16 49 28 53
+rect 16 38 19 49
+rect 35 45 38 56
+rect 26 41 38 45
+rect 41 45 45 63
+rect 35 38 38 41
+rect 6 34 9 38
+rect 16 34 17 38
+rect 25 36 29 38
+rect 37 34 38 38
+rect 45 34 48 38
+rect 25 22 29 32
+rect 25 13 29 18
+rect 0 9 25 13
+rect 29 9 54 13
+rect 0 2 16 6
+rect 20 2 34 6
+rect 38 2 54 6
+<< m2contact >>
+rect 25 70 29 74
+rect 25 56 29 60
+rect 2 34 6 38
+rect 48 34 52 38
+rect 16 24 20 28
+rect 34 24 38 28
+rect 9 17 13 21
+rect 41 17 45 21
+rect 16 2 20 6
+rect 34 2 38 6
+<< metal2 >>
+rect 2 38 6 74
+rect 2 0 6 34
+rect 9 21 13 74
+rect 25 60 29 70
+rect 9 0 13 17
+rect 16 6 20 24
+rect 34 6 38 24
+rect 41 21 45 74
+rect 41 0 45 17
+rect 48 38 52 74
+rect 48 0 52 34
+<< comment >>
+rect 0 0 54 72
+<< labels >>
+rlabel metal1 27 4 27 4 4 wl1
+rlabel psubstratepcontact 27 11 27 11 4 gnd
+rlabel metal2 4 7 4 7 4 bl0
+rlabel metal2 50 7 50 7 4 br0
+rlabel metal1 19 65 19 65 4 wl0
+rlabel metal2 11 7 11 7 4 bl1
+rlabel metal2 43 7 43 7 4 br1
+rlabel metal1 18 72 18 72 1 vdd
+<< properties >>
+string path 0.000 0.000 243.000 0.000 243.000 324.000 0.000 324.000 0.000 0.000
+<< end >>
diff --git a/technology/scn3me_subm/mag_lib/setup.tcl b/technology/scn3me_subm/mag_lib/setup.tcl
index af55a416..01639fe2 100644
--- a/technology/scn3me_subm/mag_lib/setup.tcl
+++ b/technology/scn3me_subm/mag_lib/setup.tcl
@@ -4,10 +4,12 @@ equate class {-circuit1 nfet} {-circuit2 n}
equate class {-circuit1 pfet} {-circuit2 p}
# This circuit has symmetries and needs to be flattened to resolve them
# or the banks won't pass
-flatten class {-circuit1 precharge_array_1}
-flatten class {-circuit1 precharge_array_2}
-flatten class {-circuit1 precharge_array_3}
-flatten class {-circuit1 precharge_array_4}
+flatten class {-circuit1 bitcell_array_0}
+flatten class {-circuit1 bitcell_array_1}
+#flatten class {-circuit1 precharge_array_0}
+#flatten class {-circuit1 precharge_array_1}
+#flatten class {-circuit1 precharge_array_2}
+#flatten class {-circuit1 precharge_array_3}
property {-circuit1 nfet} remove as ad ps pd
property {-circuit1 pfet} remove as ad ps pd
property {-circuit2 n} remove as ad ps pd
diff --git a/technology/scn3me_subm/sp_lib/cell_1rw_1r.sp b/technology/scn3me_subm/sp_lib/cell_1rw_1r.sp
new file mode 100644
index 00000000..f58867a7
--- /dev/null
+++ b/technology/scn3me_subm/sp_lib/cell_1rw_1r.sp
@@ -0,0 +1,14 @@
+
+.SUBCKT cell_1rw_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
+MM9 RA_to_R_right wl1 br1 gnd n w=1.8u l=0.6u
+MM8 RA_to_R_right Q gnd gnd n w=1.8u l=0.6u
+MM7 RA_to_R_left Q_bar gnd gnd n w=1.8u l=0.6u
+MM6 RA_to_R_left wl1 bl1 gnd n w=1.8u l=0.6u
+MM5 Q wl0 bl0 gnd n w=1.2u l=0.6u
+MM4 Q_bar wl0 br0 gnd n w=1.2u l=0.6u
+MM1 Q Q_bar gnd gnd n w=2.4u l=0.6u
+MM0 Q_bar Q gnd gnd n w=2.4u l=0.6u
+MM3 Q Q_bar vdd vdd p w=0.9u l=0.6u
+MM2 Q_bar Q vdd vdd p w=0.9u l=0.6u
+.ENDS
+
diff --git a/technology/scn3me_subm/sp_lib/cell_1w_1r.sp b/technology/scn3me_subm/sp_lib/cell_1w_1r.sp
new file mode 100644
index 00000000..fe981d6d
--- /dev/null
+++ b/technology/scn3me_subm/sp_lib/cell_1w_1r.sp
@@ -0,0 +1,14 @@
+
+.SUBCKT cell_1w_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
+MM9 RA_to_R_right wl1 br1 gnd n w=1.8u l=0.6u
+MM8 RA_to_R_right Q gnd gnd n w=1.8u l=0.6u
+MM7 RA_to_R_left Q_bar gnd gnd n w=1.8u l=0.6u
+MM6 RA_to_R_left wl1 bl1 gnd n w=1.8u l=0.6u
+MM5 Q wl0 bl0 gnd n w=1.2u l=0.6u
+MM4 Q_bar wl0 br0 gnd n w=1.2u l=0.6u
+MM1 Q Q_bar gnd gnd n w=2.4u l=0.6u
+MM0 Q_bar Q gnd gnd n w=2.4u l=0.6u
+MM3 Q Q_bar vdd vdd p w=0.9u l=0.6u
+MM2 Q_bar Q vdd vdd p w=0.9u l=0.6u
+.ENDS
+
diff --git a/technology/scn3me_subm/sp_lib/incorrect/cell_1rw_1r.sp b/technology/scn3me_subm/sp_lib/incorrect/cell_1rw_1r.sp
new file mode 100644
index 00000000..1c4c1bc3
--- /dev/null
+++ b/technology/scn3me_subm/sp_lib/incorrect/cell_1rw_1r.sp
@@ -0,0 +1,14 @@
+
+.SUBCKT cell_1rw_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
+MM9 RA_to_R_right wl1 br1 gnd n w=1.8u l=0.6u
+MM8 RA_to_R_right Q gnd gnd n w=1.8u l=0.6u
+MM7 RA_to_R_left Q_bar gnd gnd n w=1.8u l=0.6u
+MM6 RA_to_R_left wl1 bl1 gnd n w=1.8u l=0.6u
+MM5 Q wl0 bl0 gnd n w=1.2u l=0.6u
+MM4 Q_bar wl0 br0 gnd n w=1.2u l=0.6u
+MM1 Q Q_bar gnd gnd n w=2.4u l=0.6u
+MM0 Q_bar Q gnd gnd n w=2.4u l=0.6u
+MM3 Q Q_bar vdd vdd p w=1.2u l=0.6u
+MM2 Q_bar Q vdd vdd p w=1.2u l=0.6u
+.ENDS
+
diff --git a/technology/scn3me_subm/sp_lib/incorrect/cell_1w_1r.sp b/technology/scn3me_subm/sp_lib/incorrect/cell_1w_1r.sp
new file mode 100644
index 00000000..aed7466b
--- /dev/null
+++ b/technology/scn3me_subm/sp_lib/incorrect/cell_1w_1r.sp
@@ -0,0 +1,14 @@
+
+.SUBCKT cell_1w_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
+MM9 RA_to_R_right wl1 br1 gnd n w=1.8u l=0.6u
+MM8 RA_to_R_right Q gnd gnd n w=1.8u l=0.6u
+MM7 RA_to_R_left Q_bar gnd gnd n w=1.8u l=0.6u
+MM6 RA_to_R_left wl1 bl1 gnd n w=1.8u l=0.6u
+MM5 Q wl0 bl0 gnd n w=1.2u l=0.6u
+MM4 Q_bar wl0 br0 gnd n w=1.2u l=0.6u
+MM1 Q Q_bar gnd gnd n w=2.4u l=0.6u
+MM0 Q_bar Q gnd gnd n w=2.4u l=0.6u
+MM3 Q Q_bar vdd vdd p w=1.2u l=0.6u
+MM2 Q_bar Q vdd vdd p w=1.2u l=0.6u
+.ENDS
+
diff --git a/technology/scn3me_subm/sp_lib/incorrect/replica_cell_1rw_1r.sp b/technology/scn3me_subm/sp_lib/incorrect/replica_cell_1rw_1r.sp
new file mode 100644
index 00000000..e90dd033
--- /dev/null
+++ b/technology/scn3me_subm/sp_lib/incorrect/replica_cell_1rw_1r.sp
@@ -0,0 +1,14 @@
+
+.SUBCKT replica_cell_1rw_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
+MM9 RA_to_R_right wl1 br1 gnd n w=1.8u l=0.6u
+MM8 RA_to_R_right Q gnd gnd n w=1.8u l=0.6u
+MM7 RA_to_R_left vdd gnd gnd n w=1.8u l=0.6u
+MM6 RA_to_R_left wl1 bl1 gnd n w=1.8u l=0.6u
+MM5 Q wl0 bl0 gnd n w=1.2u l=0.6u
+MM4 vdd wl0 br0 gnd n w=1.2u l=0.6u
+MM1 Q vdd gnd gnd n w=2.4u l=0.6u
+MM0 vdd Q gnd gnd n w=2.4u l=0.6u
+MM3 Q vdd vdd vdd p w=1.2u l=0.6u
+MM2 vdd Q vdd vdd p w=1.2u l=0.6u
+.ENDS
+
diff --git a/technology/scn3me_subm/sp_lib/incorrect/replica_cell_1w_1r.sp b/technology/scn3me_subm/sp_lib/incorrect/replica_cell_1w_1r.sp
new file mode 100644
index 00000000..bd2e5eb5
--- /dev/null
+++ b/technology/scn3me_subm/sp_lib/incorrect/replica_cell_1w_1r.sp
@@ -0,0 +1,14 @@
+
+.SUBCKT replica_cell_1w_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
+MM9 RA_to_R_right wl1 br1 gnd n w=1.8u l=0.6u
+MM8 RA_to_R_right Q gnd gnd n w=1.8u l=0.6u
+MM7 RA_to_R_left vdd gnd gnd n w=1.8u l=0.6u
+MM6 RA_to_R_left wl1 bl1 gnd n w=1.8u l=0.6u
+MM5 Q wl0 bl0 gnd n w=1.2u l=0.6u
+MM4 vdd wl0 br0 gnd n w=0.8u l=0.6u
+MM1 Q vdd gnd gnd n w=2.4u l=0.6u
+MM0 vdd Q gnd gnd n w=2.4u l=0.6u
+MM3 Q vdd vdd vdd p w=0.6u l=0.6u
+MM2 vdd Q vdd vdd p w=0.6u l=0.6u
+.ENDS
+
diff --git a/technology/scn3me_subm/sp_lib/replica_cell_1rw_1r.sp b/technology/scn3me_subm/sp_lib/replica_cell_1rw_1r.sp
new file mode 100644
index 00000000..a8654c83
--- /dev/null
+++ b/technology/scn3me_subm/sp_lib/replica_cell_1rw_1r.sp
@@ -0,0 +1,14 @@
+
+.SUBCKT replica_cell_1rw_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
+MM9 RA_to_R_right wl1 br1 gnd n w=1.8u l=0.6u
+MM8 RA_to_R_right Q gnd gnd n w=1.8u l=0.6u
+MM7 RA_to_R_left vdd gnd gnd n w=1.8u l=0.6u
+MM6 RA_to_R_left wl1 bl1 gnd n w=1.8u l=0.6u
+MM5 Q wl0 bl0 gnd n w=1.2u l=0.6u
+MM4 vdd wl0 br0 gnd n w=1.2u l=0.6u
+MM1 Q vdd gnd gnd n w=2.4u l=0.6u
+MM0 vdd Q gnd gnd n w=2.4u l=0.6u
+MM3 Q vdd vdd vdd p w=0.9u l=0.6u
+MM2 vdd Q vdd vdd p w=0.9u l=0.6u
+.ENDS
+
diff --git a/technology/scn3me_subm/sp_lib/replica_cell_1w_1r.sp b/technology/scn3me_subm/sp_lib/replica_cell_1w_1r.sp
new file mode 100644
index 00000000..5b9c9b18
--- /dev/null
+++ b/technology/scn3me_subm/sp_lib/replica_cell_1w_1r.sp
@@ -0,0 +1,14 @@
+
+.SUBCKT replica_cell_1w_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
+MM9 RA_to_R_right wl1 br1 gnd n w=1.8u l=0.6u
+MM8 RA_to_R_right Q gnd gnd n w=1.8u l=0.6u
+MM7 RA_to_R_left vdd gnd gnd n w=1.8u l=0.6u
+MM6 RA_to_R_left wl1 bl1 gnd n w=1.8u l=0.6u
+MM5 Q wl0 bl0 gnd n w=1.2u l=0.6u
+MM4 vdd wl0 br0 gnd n w=1.2u l=0.6u
+MM1 Q vdd gnd gnd n w=2.4u l=0.6u
+MM0 vdd Q gnd gnd n w=2.4u l=0.6u
+MM3 Q vdd vdd vdd p w=0.9u l=0.6u
+MM2 vdd Q vdd vdd p w=0.9u l=0.6u
+.ENDS
+
diff --git a/technology/scn3me_subm/tech/SCN3ME_SUBM.30.tech b/technology/scn3me_subm/tech/SCN3ME_SUBM.30.tech
index be511001..bc447205 100644
--- a/technology/scn3me_subm/tech/SCN3ME_SUBM.30.tech
+++ b/technology/scn3me_subm/tech/SCN3ME_SUBM.30.tech
@@ -1,10 +1,10 @@
tech
- format 32
+ format 29
scmos
end
version
- version 2002a
+ version 2001a
description "SCMOS: Submit as technology.lambda: SCN3ME_SUBM.30 [to process: AMIc5]"
end
@@ -34,8 +34,7 @@ types
select nselect,ns
select pselect,ps
cap electrode,poly2,el,p2
- cap electrodecontact,poly2contact,poly2c,p2c,elc
- cap p2m12contact,p2m12c
+ metal1 electrodecontact,poly2contact,poly2c,p2c,elc
cap electrodecap,ecap,poly2cap,p2cap,pcap
contact genericpoly2contact,gc2
active ntransistor,nfet
@@ -104,12 +103,7 @@ contact
psc psd metal1
m2c metal1 metal2
m3c metal2 metal3
- stackable pc m2c pm12contact,pm12c
- stackable pdc m2c pdm12contact,pdm12c
- stackable psc m2c psm12contact,psm12c,pom12c,pwm12c
- stackable ndc m2c ndm12contact,ndm12c
- stackable nsc m2c nsm12contact,nsm12c,nom12c,nwm12c
- stackable m2c m3c m123contact,m123c
+ stackable
end
styles
@@ -147,7 +141,6 @@ styles
fapm 1 20 21 34
gv1 55
m2contact 20 21 55
- p2m12contact 14 20 21 32 55
metal2 21
rm2 21 48
prm2 48
@@ -218,10 +211,6 @@ compose
paint nsc pwell psc
paint poly2 poly ecap
erase ecap poly poly2
- paint p2c poly2 p2c
- paint p2c ecap p2c
- paint p2m12c poly2 p2m12c
- paint p2m12c ecap p2m12c
paint pad m3 pad
compose phr poly2 hr
paint hr poly2 phr
@@ -246,18 +235,15 @@ end
connect
nwell,nsc/a,nsd nwell,nsc/a,nsd
pwell,psc/a,psd pwell,psc/a,psd
- m1,fm1,fapm,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1 m1,fm1,fapm,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1
+ m1,fm1,fapm,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 m1,fm1,fapm,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1
m2,fm2,fapm,m2c/m2,m3c/m2,m3c/m2 m2,fm2,fapm,m2c/m2,m3c/m2,m3c/m2
m3,fm3,fapm,m3c/m3 m3,fm3,fapm,m3c/m3
ndiff,ndc/a,pdiff,pdc/a ndiff,ndc/a,pdiff,pdc/a
poly,fp,nfet,pfet,fet,fapm,pc/a poly,fp,nfet,pfet,fet,fapm,pc/a
+ poly2,ecap,p2c poly2,ecap,p2c
gc2 poly2,ecap,metal1
- p2c poly2,ecap,m1,fm1,fapm,m2c/m1
- p2m12c poly2,ecap,m1,fm1,fapm,m2c/m1,m2,fm2,fapm,m2c/m2,m3c/m2
- poly2,ecap,p2c,p2m12c poly2,ecap,p2c,p2m12c
- gc2 poly2,ecap,m1,fm1,fapm,m2c/m1
gc poly,fp,ndiff,pdiff,nsd,psd,m1,fm1,fapm,m2c/m1
- gv1 m1,fm1,fapm,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2,fm2,fapm,m3c/m2
+ gv1 m1,fm1,fapm,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2,fm2,fapm,m3c/m2
gv2 m2,fm2,fapm,m2c/m2,m3c/m2,m3,fm3,fapm
pad m1,fm1,m2,fm2,m3,fm3
rm1 prm1
@@ -275,12 +261,8 @@ cifoutput
style lambda=0.30(p)
scalefactor 30 15
+ options calma-permissive-labels
- # This is a custom section to add bounding boxes in OpenRAM
- layer BB bb
- labels bb
- calma 63 0
-
layer CWN nwell,rnw
bloat-or pdiff,rpd,pdc/a,pfet * 180
bloat-or nsd,nsc/a * 90
@@ -377,7 +359,7 @@ style lambda=0.30(p)
squares 0 60 90
calma 55 0
- layer CCE p2c,p2m12c
+ layer CCE p2c
squares 30 60 90
calma 55 0
@@ -389,7 +371,7 @@ style lambda=0.30(p)
squares 0 60 90
calma 25 0
- layer CV1 m2c/m1,p2m12c
+ layer CV1 m2c/m1
squares 30 60 90
calma 50 0
@@ -431,12 +413,12 @@ style lambda=0.30(p)
layer CM1 pad
calma 49 0
- layer CM1 m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1,p2c,p2m12c
- labels m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1,p2c,p2m12c
+ layer CM1 m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1
+ labels m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1
calma 49 0
- layer CM2 m2,rm2,m2c/m2,m3c/m2,m3c/m2,p2m12c
- labels m2,rm2,m2c/m2,m3c/m2,m3c/m2,p2m12c
+ layer CM2 m2,rm2,m2c/m2,m3c/m2,m3c/m2
+ labels m2,rm2,m2c/m2,m3c/m2,m3c/m2
calma 51 0
layer CMFP m1p
@@ -527,8 +509,8 @@ style lambda=0.30(p)
labels hr,phr
calma 34 0
- layer CEL poly2,ecap,phr,p2c,p2m12c
- labels poly2,ecap,phr,p2c,p2m12c
+ layer CEL poly2,ecap,phr,p2c
+ labels poly2,ecap,phr,p2c
calma 56 0
#CRE/CRM
@@ -559,8 +541,8 @@ style lambda=0.30(p)
#CRE/CRM layer CRM rm1,prm1,rm2,prm2,rm3,prm3
#CRE/CRM calma 70 0
- layer CX comment
- labels comment
+ layer CX comment,bb
+ labels comment,bb
calma 63 0
layer XP pad,xp
@@ -606,9 +588,9 @@ style fapm-boxes
scalefactor 30 15
- templayer CRIT fapm,fn,diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a,pfet,pfet,fet,poly,rp,nfet,pfet,fet,pc/a,poly2,ecap,phr,p2c,p2m12c
- or fm1,m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1,p2c,p2m12c
- or fm2,m2,rm2,m2c/m2,m3c/m2,m3c/m2,p2m12c
+ templayer CRIT fapm,fn,diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a,pfet,pfet,fet,poly,rp,nfet,pfet,fet,pc/a,poly2,ecap,phr,p2c
+ or fm1,m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1
+ or fm2,m2,rm2,m2c/m2,m3c/m2,m3c/m2
or fm3,m3,rm3,m3c/m3
or glass,pad
grow 510
@@ -631,9 +613,9 @@ style fapm-stripes
# and then *replacing* the left side (1-lambda wide) stripe of each 'fa' box
# to be a 1-lambda wide layer 'fb' box -- else you won't get strips!
- templayer CRIT fapm,fn,diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a,pfet,pfet,fet,poly,rp,nfet,pfet,fet,pc/a,poly2,ecap,phr,p2c,p2m12c
- or fm1,m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1,p2c,p2m12c
- or fm2,m2,rm2,m2c/m2,m3c/m2,m3c/m2,p2m12c
+ templayer CRIT fapm,fn,diff,ndiff,rnd,nfet,nsd,pdiff,rpd,pfet,psd,ndc/a,nsc/a,pdc/a,psc/a,pfet,pfet,fet,poly,rp,nfet,pfet,fet,pc/a,poly2,ecap,phr,p2c
+ or fm1,m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1
+ or fm2,m2,rm2,m2c/m2,m3c/m2,m3c/m2
or fm3,m3,rm3,m3c/m3
or glass,pad
grow 510
@@ -754,7 +736,7 @@ style lambda=0.30(cp)
squares 0 60 90
calma 25 0
- layer CCC p2c,p2m12c
+ layer CCC p2c
squares 30 60 90
calma 25 0
@@ -766,7 +748,7 @@ style lambda=0.30(cp)
squares 0 60 90
calma 25 0
- layer CV1 m2c/m1,p2m12c
+ layer CV1 m2c/m1
squares 30 60 90
calma 50 0
@@ -808,12 +790,12 @@ style lambda=0.30(cp)
layer CM1 pad
calma 49 0
- layer CM1 m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1,p2c,p2m12c
- labels m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1,p2c,p2m12c
+ layer CM1 m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1
+ labels m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1
calma 49 0
- layer CM2 m2,rm2,m2c/m2,m3c/m2,m3c/m2,p2m12c
- labels m2,rm2,m2c/m2,m3c/m2,m3c/m2,p2m12c
+ layer CM2 m2,rm2,m2c/m2,m3c/m2,m3c/m2
+ labels m2,rm2,m2c/m2,m3c/m2,m3c/m2
calma 51 0
layer CMFP m1p
@@ -904,8 +886,8 @@ style lambda=0.30(cp)
labels hr,phr
calma 34 0
- layer CEL poly2,ecap,phr,p2c,p2m12c
- labels poly2,ecap,phr,p2c,p2m12c
+ layer CEL poly2,ecap,phr,p2c
+ labels poly2,ecap,phr,p2c
calma 56 0
#CRE/CRM
@@ -936,8 +918,8 @@ style lambda=0.30(cp)
#CRE/CRM layer CRM rm1,prm1,rm2,prm2,rm3,prm3
#CRE/CRM calma 70 0
- layer CX comment
- labels comment
+ layer CX comment,bb
+ labels comment,bb
calma 63 0
layer XP pad,xp
@@ -1034,7 +1016,7 @@ style lambda=0.30(c)
squares 0 60 90
calma 25 0
- layer CCC p2c,p2m12c
+ layer CCC p2c
squares 30 60 90
calma 25 0
@@ -1046,7 +1028,7 @@ style lambda=0.30(c)
squares 0 60 90
calma 25 0
- layer CV1 m2c/m1,p2m12c
+ layer CV1 m2c/m1
squares 30 60 90
calma 50 0
@@ -1088,12 +1070,12 @@ style lambda=0.30(c)
layer CM1 pad
calma 49 0
- layer CM1 m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1,p2c,p2m12c
- labels m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1,p2c,p2m12c
+ layer CM1 m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1
+ labels m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1
calma 49 0
- layer CM2 m2,rm2,m2c/m2,m3c/m2,m3c/m2,p2m12c
- labels m2,rm2,m2c/m2,m3c/m2,m3c/m2,p2m12c
+ layer CM2 m2,rm2,m2c/m2,m3c/m2,m3c/m2
+ labels m2,rm2,m2c/m2,m3c/m2,m3c/m2
calma 51 0
layer CMFP m1p
@@ -1184,8 +1166,8 @@ style lambda=0.30(c)
labels hr,phr
calma 34 0
- layer CEL poly2,ecap,phr,p2c,p2m12c
- labels poly2,ecap,phr,p2c,p2m12c
+ layer CEL poly2,ecap,phr,p2c
+ labels poly2,ecap,phr,p2c
calma 56 0
#CRE/CRM
@@ -1216,8 +1198,8 @@ style lambda=0.30(c)
#CRE/CRM layer CRM rm1,prm1,rm2,prm2,rm3,prm3
#CRE/CRM calma 70 0
- layer CX comment
- labels comment
+ layer CX comment,bb
+ labels comment,bb
calma 63 0
layer XP pad,xp
@@ -1314,7 +1296,7 @@ style lambda=0.30()
squares 0 60 90
calma 55 0
- layer CCE p2c,p2m12c
+ layer CCE p2c
squares 30 60 90
calma 55 0
@@ -1326,7 +1308,7 @@ style lambda=0.30()
squares 0 60 90
calma 25 0
- layer CV1 m2c/m1,p2m12c
+ layer CV1 m2c/m1
squares 30 60 90
calma 50 0
@@ -1368,12 +1350,12 @@ style lambda=0.30()
layer CM1 pad
calma 49 0
- layer CM1 m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1,p2c,p2m12c
- labels m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1,p2c,p2m12c
+ layer CM1 m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1
+ labels m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1
calma 49 0
- layer CM2 m2,rm2,m2c/m2,m3c/m2,m3c/m2,p2m12c
- labels m2,rm2,m2c/m2,m3c/m2,m3c/m2,p2m12c
+ layer CM2 m2,rm2,m2c/m2,m3c/m2,m3c/m2
+ labels m2,rm2,m2c/m2,m3c/m2,m3c/m2
calma 51 0
layer CMFP m1p
@@ -1464,8 +1446,8 @@ style lambda=0.30()
labels hr,phr
calma 34 0
- layer CEL poly2,ecap,phr,p2c,p2m12c
- labels poly2,ecap,phr,p2c,p2m12c
+ layer CEL poly2,ecap,phr,p2c
+ labels poly2,ecap,phr,p2c
calma 56 0
#CRE/CRM
@@ -1496,8 +1478,8 @@ style lambda=0.30()
#CRE/CRM layer CRM rm1,prm1,rm2,prm2,rm3,prm3
#CRE/CRM calma 70 0
- layer CX comment
- labels comment
+ layer CX comment,bb
+ labels comment,bb
calma 63 0
layer XP pad,xp
@@ -1514,7 +1496,7 @@ style lambda=0.30(p)
# This is a custom section to add bounding boxes in OpenRAM
layer bb BB
labels BB
- calma 63 0
+ calma BB 63 0
layer nwell CWN
and-not CWNR
@@ -1721,7 +1703,6 @@ layer nwell CWN
layer ndc CAA
and CSN
and CCA
- and-not CV1
and-not CWNR
and-not CTA
@@ -1735,7 +1716,6 @@ layer nwell CWN
layer ndc CAA
and CSN
and CCC
- and-not CV1
and-not CWNR
and-not CTA
@@ -1749,7 +1729,6 @@ layer nwell CWN
layer nsc CAA
and CSN
and CCA
- and-not CV1
and-not CWNR
and-not CTA
@@ -1763,7 +1742,6 @@ layer nwell CWN
layer nsc CAA
and CSN
and CCC
- and-not CV1
and-not CWNR
and-not CTA
@@ -1777,7 +1755,6 @@ layer nwell CWN
layer pdc CAA
and CSP
and CCA
- and-not CV1
and-not CTA
and-not CPS
@@ -1791,7 +1768,6 @@ layer nwell CWN
layer pdc CAA
and CSP
and CCC
- and-not CV1
and-not CTA
and-not CPS
@@ -1805,7 +1781,6 @@ layer nwell CWN
layer psc CAA
and CSP
and CCA
- and-not CV1
and-not CTA
and-not CPS
@@ -1819,128 +1794,6 @@ layer nwell CWN
layer psc CAA
and CSP
and CCC
- and-not CV1
- and-not CWNR
- and-not CTA
-
- and-not CPS
- and-not CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer ndc CAA
- and CSN
- and CCA
- and CV1
- and CV2
- and-not CWNR
- and-not CTA
-
- and-not CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCA 48 *
-
- layer ndc CAA
- and CSN
- and CCC
- and CV1
- and CV2
- and-not CWNR
- and-not CTA
-
- and-not CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer nsc CAA
- and CSN
- and CCA
- and CV1
- and CV2
- and-not CWNR
- and-not CTA
-
- and CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCA 48 *
-
- layer nsc CAA
- and CSN
- and CCC
- and CV1
- and CV2
- and-not CWNR
- and-not CTA
-
- and CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer pdc CAA
- and CSP
- and CCA
- and CV1
- and CV2
- and-not CTA
-
- and-not CPS
- and CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCA 48 *
-
- layer pdc CAA
- and CSP
- and CCC
- and CV1
- and CV2
- and-not CTA
-
- and-not CPS
- and CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer psc CAA
- and CSP
- and CCA
- and CV1
- and CV2
- and-not CTA
-
- and-not CPS
- and-not CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCA 48 *
-
- layer psc CAA
- and CSP
- and CCC
- and CV1
- and CV2
and-not CWNR
and-not CTA
@@ -1971,7 +1824,6 @@ layer nwell CWN
calma CRG 67 *
layer pc CCP
- and-not CV1
and CPG
and-not CPC
and-not CEL
@@ -1983,7 +1835,6 @@ layer nwell CWN
calma CCP 47 *
layer pc CCC
- and-not CV1
and CPG
and-not CPC
and-not CEL
@@ -1994,82 +1845,6 @@ layer nwell CWN
shrink 15
calma CCC 25 *
- layer pc CCP
- and CV1
- and CV2
- and CPG
- and-not CPC
- and-not CEL
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCP 47 *
-
- layer pc CCC
- and CV1
- and CV2
- and CPG
- and-not CPC
- and-not CEL
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer p2c CCE
- and-not CV1
- and CPG
- and CEL
- and-not CPC
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCE 55 *
-
- layer p2c CCC
- and-not CV1
- and CPG
- and CEL
- and-not CPC
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer p2c CCE
- and CV1
- and CV2
- and CPG
- and CEL
- and-not CPC
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCE 55 *
-
- layer p2c CCC
- and CV1
- and CV2
- and CPG
- and CEL
- and-not CPC
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCC 25 *
-
layer gc CCP
and-not CPG
and-not CPC
@@ -2134,11 +1909,6 @@ layer nwell CWN
calma CV2 61 *
layer m2c CV1
- and-not CV2
- and-not CCC
- and-not CCE
- and-not CCP
- and-not CCA
and-not XP
grow 30
and CM2
@@ -2147,32 +1917,6 @@ layer nwell CWN
shrink 15
calma CV1 50 *
-
-
- layer p2m12c CV1
- and-not CV2
- and CCE
- grow 30
- and CM2
- and CM1
- and CPG
- and CEL
- grow 15
- shrink 15
- calma CV1 50 *
-
- layer p2m12c CV1
- and-not CV2
- and CCC
- grow 30
- and CM2
- and CM1
- and CPG
- and CEL
- grow 15
- shrink 15
- calma CV1 50 *
-
layer m1 CM1
and-not CRM
and-not CRF
@@ -2219,14 +1963,6 @@ layer nwell CWN
labels CMSP
calma CMSP 82 *
-
-
-
-
-
-
-
-
layer fp 100
calma 100 100 *
@@ -2249,8 +1985,6 @@ layer nwell CWN
calma 110 110 *
layer m3c CV2
-
- and-not CV1
and-not XP
grow 30
and CM3
@@ -2259,7 +1993,6 @@ layer nwell CWN
shrink 15
calma CV2 61 *
-
layer m3 CM3
and-not CRM
and-not CRT
@@ -2329,6 +2062,20 @@ layer nwell CWN
and-not CRE
calma CRG2 68 *
+ layer elc CCE
+ grow 30
+ and CM1
+ and CEL
+ labels CM1
+ calma CCE 55 *
+
+ layer elc CCC
+ grow 30
+ and CM1
+ and CEL
+ labels CM1
+ calma CCC 25 *
+
layer comment CX
labels CX
calma CX 63 *
@@ -2348,6 +2095,11 @@ layer nwell CWN
style lambda=0.30(s)
scalefactor 30
+ # This is a custom section to add bounding boxes in OpenRAM
+ layer bb BB
+ labels BB
+ calma BB 63 0
+
layer nwell CWN
and-not CWNR
and-not CTA
@@ -2554,7 +2306,6 @@ style lambda=0.30(s)
layer ndc CAA
and CSN
and CCA
- and-not CV1
and-not CWNR
and-not CTA
@@ -2568,7 +2319,6 @@ style lambda=0.30(s)
layer ndc CAA
and CSN
and CCC
- and-not CV1
and-not CWNR
and-not CTA
@@ -2582,7 +2332,6 @@ style lambda=0.30(s)
layer nsc CAA
and CSN
and CCA
- and-not CV1
and-not CWNR
and-not CTA
@@ -2596,7 +2345,6 @@ style lambda=0.30(s)
layer nsc CAA
and CSN
and CCC
- and-not CV1
and-not CWNR
and-not CTA
@@ -2610,7 +2358,6 @@ style lambda=0.30(s)
layer pdc CAA
and CSP
and CCA
- and-not CV1
and-not CTA
and-not CPS
@@ -2624,7 +2371,6 @@ style lambda=0.30(s)
layer pdc CAA
and CSP
and CCC
- and-not CV1
and-not CTA
and-not CPS
@@ -2638,7 +2384,6 @@ style lambda=0.30(s)
layer psc CAA
and CSP
and CCA
- and-not CV1
and-not CTA
and-not CPS
@@ -2652,128 +2397,6 @@ style lambda=0.30(s)
layer psc CAA
and CSP
and CCC
- and-not CV1
- and-not CWNR
- and-not CTA
-
- and-not CPS
- and-not CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer ndc CAA
- and CSN
- and CCA
- and CV1
- and CV2
- and-not CWNR
- and-not CTA
-
- and-not CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCA 48 *
-
- layer ndc CAA
- and CSN
- and CCC
- and CV1
- and CV2
- and-not CWNR
- and-not CTA
-
- and-not CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer nsc CAA
- and CSN
- and CCA
- and CV1
- and CV2
- and-not CWNR
- and-not CTA
-
- and CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCA 48 *
-
- layer nsc CAA
- and CSN
- and CCC
- and CV1
- and CV2
- and-not CWNR
- and-not CTA
-
- and CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer pdc CAA
- and CSP
- and CCA
- and CV1
- and CV2
- and-not CTA
-
- and-not CPS
- and CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCA 48 *
-
- layer pdc CAA
- and CSP
- and CCC
- and CV1
- and CV2
- and-not CTA
-
- and-not CPS
- and CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer psc CAA
- and CSP
- and CCA
- and CV1
- and CV2
- and-not CTA
-
- and-not CPS
- and-not CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCA 48 *
-
- layer psc CAA
- and CSP
- and CCC
- and CV1
- and CV2
and-not CWNR
and-not CTA
@@ -2804,7 +2427,6 @@ style lambda=0.30(s)
calma CRG 67 *
layer pc CCP
- and-not CV1
and CPG
and-not CPC
and-not CEL
@@ -2816,7 +2438,6 @@ style lambda=0.30(s)
calma CCP 47 *
layer pc CCC
- and-not CV1
and CPG
and-not CPC
and-not CEL
@@ -2827,82 +2448,6 @@ style lambda=0.30(s)
shrink 15
calma CCC 25 *
- layer pc CCP
- and CV1
- and CV2
- and CPG
- and-not CPC
- and-not CEL
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCP 47 *
-
- layer pc CCC
- and CV1
- and CV2
- and CPG
- and-not CPC
- and-not CEL
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer p2c CCE
- and-not CV1
- and CPG
- and CEL
- and-not CPC
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCE 55 *
-
- layer p2c CCC
- and-not CV1
- and CPG
- and CEL
- and-not CPC
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer p2c CCE
- and CV1
- and CV2
- and CPG
- and CEL
- and-not CPC
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCE 55 *
-
- layer p2c CCC
- and CV1
- and CV2
- and CPG
- and CEL
- and-not CPC
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCC 25 *
-
layer gc CCP
and-not CPG
and-not CPC
@@ -2967,11 +2512,6 @@ style lambda=0.30(s)
calma CV2 61 *
layer m2c CV1
- and-not CV2
- and-not CCC
- and-not CCE
- and-not CCP
- and-not CCA
and-not XP
grow 30
and CM2
@@ -2980,32 +2520,6 @@ style lambda=0.30(s)
shrink 15
calma CV1 50 *
-
-
- layer p2m12c CV1
- and-not CV2
- and CCE
- grow 30
- and CM2
- and CM1
- and CPG
- and CEL
- grow 15
- shrink 15
- calma CV1 50 *
-
- layer p2m12c CV1
- and-not CV2
- and CCC
- grow 30
- and CM2
- and CM1
- and CPG
- and CEL
- grow 15
- shrink 15
- calma CV1 50 *
-
layer m1 CM1
and-not CRM
and-not CRF
@@ -3052,14 +2566,6 @@ style lambda=0.30(s)
labels CMSP
calma CMSP 82 *
-
-
-
-
-
-
-
-
layer fp 100
calma 100 100 *
@@ -3082,8 +2588,6 @@ style lambda=0.30(s)
calma 110 110 *
layer m3c CV2
-
- and-not CV1
and-not XP
grow 30
and CM3
@@ -3092,7 +2596,6 @@ style lambda=0.30(s)
shrink 15
calma CV2 61 *
-
layer m3 CM3
and-not CRM
and-not CRT
@@ -3162,6 +2665,20 @@ style lambda=0.30(s)
and-not CRE
calma CRG2 68 *
+ layer elc CCE
+ grow 30
+ and CM1
+ and CEL
+ labels CM1
+ calma CCE 55 *
+
+ layer elc CCC
+ grow 30
+ and CM1
+ and CEL
+ labels CM1
+ calma CCC 25 *
+
layer comment CX
labels CX
calma CX 63 *
@@ -3181,6 +2698,11 @@ style lambda=0.30(s)
style lambda=0.30(ps)
scalefactor 30
+ # This is a custom section to add bounding boxes in OpenRAM
+ layer bb BB
+ labels BB
+ calma BB 63 0
+
layer nwell CWN
and-not CWNR
and-not CTA
@@ -3388,7 +2910,6 @@ style lambda=0.30(ps)
layer ndc CAA
and CSN
and CCA
- and-not CV1
and-not CWNR
and-not CTA
@@ -3402,7 +2923,6 @@ style lambda=0.30(ps)
layer ndc CAA
and CSN
and CCC
- and-not CV1
and-not CWNR
and-not CTA
@@ -3416,7 +2936,6 @@ style lambda=0.30(ps)
layer nsc CAA
and CSN
and CCA
- and-not CV1
and-not CWNR
and-not CTA
@@ -3430,7 +2949,6 @@ style lambda=0.30(ps)
layer nsc CAA
and CSN
and CCC
- and-not CV1
and-not CWNR
and-not CTA
@@ -3444,7 +2962,6 @@ style lambda=0.30(ps)
layer pdc CAA
and CSP
and CCA
- and-not CV1
and-not CTA
and-not CPS
@@ -3458,7 +2975,6 @@ style lambda=0.30(ps)
layer pdc CAA
and CSP
and CCC
- and-not CV1
and-not CTA
and-not CPS
@@ -3472,7 +2988,6 @@ style lambda=0.30(ps)
layer psc CAA
and CSP
and CCA
- and-not CV1
and-not CTA
and-not CPS
@@ -3486,128 +3001,6 @@ style lambda=0.30(ps)
layer psc CAA
and CSP
and CCC
- and-not CV1
- and-not CWNR
- and-not CTA
-
- and-not CPS
- and-not CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer ndc CAA
- and CSN
- and CCA
- and CV1
- and CV2
- and-not CWNR
- and-not CTA
-
- and-not CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCA 48 *
-
- layer ndc CAA
- and CSN
- and CCC
- and CV1
- and CV2
- and-not CWNR
- and-not CTA
-
- and-not CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer nsc CAA
- and CSN
- and CCA
- and CV1
- and CV2
- and-not CWNR
- and-not CTA
-
- and CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCA 48 *
-
- layer nsc CAA
- and CSN
- and CCC
- and CV1
- and CV2
- and-not CWNR
- and-not CTA
-
- and CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer pdc CAA
- and CSP
- and CCA
- and CV1
- and CV2
- and-not CTA
-
- and-not CPS
- and CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCA 48 *
-
- layer pdc CAA
- and CSP
- and CCC
- and CV1
- and CV2
- and-not CTA
-
- and-not CPS
- and CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer psc CAA
- and CSP
- and CCA
- and CV1
- and CV2
- and-not CTA
-
- and-not CPS
- and-not CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCA 48 *
-
- layer psc CAA
- and CSP
- and CCC
- and CV1
- and CV2
and-not CWNR
and-not CTA
@@ -3638,7 +3031,6 @@ style lambda=0.30(ps)
calma CRG 67 *
layer pc CCP
- and-not CV1
and CPG
and-not CPC
and-not CEL
@@ -3650,7 +3042,6 @@ style lambda=0.30(ps)
calma CCP 47 *
layer pc CCC
- and-not CV1
and CPG
and-not CPC
and-not CEL
@@ -3661,82 +3052,6 @@ style lambda=0.30(ps)
shrink 15
calma CCC 25 *
- layer pc CCP
- and CV1
- and CV2
- and CPG
- and-not CPC
- and-not CEL
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCP 47 *
-
- layer pc CCC
- and CV1
- and CV2
- and CPG
- and-not CPC
- and-not CEL
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer p2c CCE
- and-not CV1
- and CPG
- and CEL
- and-not CPC
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCE 55 *
-
- layer p2c CCC
- and-not CV1
- and CPG
- and CEL
- and-not CPC
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer p2c CCE
- and CV1
- and CV2
- and CPG
- and CEL
- and-not CPC
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCE 55 *
-
- layer p2c CCC
- and CV1
- and CV2
- and CPG
- and CEL
- and-not CPC
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCC 25 *
-
layer gc CCP
and-not CPG
and-not CPC
@@ -3801,11 +3116,6 @@ style lambda=0.30(ps)
calma CV2 61 *
layer m2c CV1
- and-not CV2
- and-not CCC
- and-not CCE
- and-not CCP
- and-not CCA
and-not XP
grow 30
and CM2
@@ -3814,32 +3124,6 @@ style lambda=0.30(ps)
shrink 15
calma CV1 50 *
-
-
- layer p2m12c CV1
- and-not CV2
- and CCE
- grow 30
- and CM2
- and CM1
- and CPG
- and CEL
- grow 15
- shrink 15
- calma CV1 50 *
-
- layer p2m12c CV1
- and-not CV2
- and CCC
- grow 30
- and CM2
- and CM1
- and CPG
- and CEL
- grow 15
- shrink 15
- calma CV1 50 *
-
layer m1 CM1
and-not CRM
and-not CRF
@@ -3886,14 +3170,6 @@ style lambda=0.30(ps)
labels CMSP
calma CMSP 82 *
-
-
-
-
-
-
-
-
layer fp 100
calma 100 100 *
@@ -3916,8 +3192,6 @@ style lambda=0.30(ps)
calma 110 110 *
layer m3c CV2
-
- and-not CV1
and-not XP
grow 30
and CM3
@@ -3926,7 +3200,6 @@ style lambda=0.30(ps)
shrink 15
calma CV2 61 *
-
layer m3 CM3
and-not CRM
and-not CRT
@@ -3996,6 +3269,20 @@ style lambda=0.30(ps)
and-not CRE
calma CRG2 68 *
+ layer elc CCE
+ grow 30
+ and CM1
+ and CEL
+ labels CM1
+ calma CCE 55 *
+
+ layer elc CCC
+ grow 30
+ and CM1
+ and CEL
+ labels CM1
+ calma CCC 25 *
+
layer comment CX
labels CX
calma CX 63 *
@@ -4015,6 +3302,11 @@ style lambda=0.30(ps)
style lambda=0.30()
scalefactor 30
+ # This is a custom section to add bounding boxes in OpenRAM
+ layer bb BB
+ labels BB
+ calma BB 63 0
+
layer nwell CWN
and-not CWNR
and-not CTA
@@ -4219,7 +3511,6 @@ style lambda=0.30()
layer ndc CAA
and CSN
and CCA
- and-not CV1
and-not CWNR
and-not CTA
@@ -4233,7 +3524,6 @@ style lambda=0.30()
layer ndc CAA
and CSN
and CCC
- and-not CV1
and-not CWNR
and-not CTA
@@ -4247,7 +3537,6 @@ style lambda=0.30()
layer nsc CAA
and CSN
and CCA
- and-not CV1
and-not CWNR
and-not CTA
@@ -4261,7 +3550,6 @@ style lambda=0.30()
layer nsc CAA
and CSN
and CCC
- and-not CV1
and-not CWNR
and-not CTA
@@ -4275,7 +3563,6 @@ style lambda=0.30()
layer pdc CAA
and CSP
and CCA
- and-not CV1
and-not CTA
and-not CPS
@@ -4289,7 +3576,6 @@ style lambda=0.30()
layer pdc CAA
and CSP
and CCC
- and-not CV1
and-not CTA
and-not CPS
@@ -4303,7 +3589,6 @@ style lambda=0.30()
layer psc CAA
and CSP
and CCA
- and-not CV1
and-not CTA
and-not CPS
@@ -4317,128 +3602,6 @@ style lambda=0.30()
layer psc CAA
and CSP
and CCC
- and-not CV1
- and-not CWNR
- and-not CTA
-
- and-not CPS
- and-not CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer ndc CAA
- and CSN
- and CCA
- and CV1
- and CV2
- and-not CWNR
- and-not CTA
-
- and-not CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCA 48 *
-
- layer ndc CAA
- and CSN
- and CCC
- and CV1
- and CV2
- and-not CWNR
- and-not CTA
-
- and-not CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer nsc CAA
- and CSN
- and CCA
- and CV1
- and CV2
- and-not CWNR
- and-not CTA
-
- and CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCA 48 *
-
- layer nsc CAA
- and CSN
- and CCC
- and CV1
- and CV2
- and-not CWNR
- and-not CTA
-
- and CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer pdc CAA
- and CSP
- and CCA
- and CV1
- and CV2
- and-not CTA
-
- and-not CPS
- and CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCA 48 *
-
- layer pdc CAA
- and CSP
- and CCC
- and CV1
- and CV2
- and-not CTA
-
- and-not CPS
- and CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer psc CAA
- and CSP
- and CCA
- and CV1
- and CV2
- and-not CTA
-
- and-not CPS
- and-not CWN
- and CM1
- grow 30
- grow 15
- shrink 15
- calma CCA 48 *
-
- layer psc CAA
- and CSP
- and CCC
- and CV1
- and CV2
and-not CWNR
and-not CTA
@@ -4469,7 +3632,6 @@ style lambda=0.30()
calma CRG 67 *
layer pc CCP
- and-not CV1
and CPG
and-not CPC
and-not CEL
@@ -4481,7 +3643,6 @@ style lambda=0.30()
calma CCP 47 *
layer pc CCC
- and-not CV1
and CPG
and-not CPC
and-not CEL
@@ -4492,82 +3653,6 @@ style lambda=0.30()
shrink 15
calma CCC 25 *
- layer pc CCP
- and CV1
- and CV2
- and CPG
- and-not CPC
- and-not CEL
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCP 47 *
-
- layer pc CCC
- and CV1
- and CV2
- and CPG
- and-not CPC
- and-not CEL
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer p2c CCE
- and-not CV1
- and CPG
- and CEL
- and-not CPC
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCE 55 *
-
- layer p2c CCC
- and-not CV1
- and CPG
- and CEL
- and-not CPC
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCC 25 *
-
- layer p2c CCE
- and CV1
- and CV2
- and CPG
- and CEL
- and-not CPC
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCE 55 *
-
- layer p2c CCC
- and CV1
- and CV2
- and CPG
- and CEL
- and-not CPC
- and-not CAA
- grow 30
- and CM1
- grow 15
- shrink 15
- calma CCC 25 *
-
layer gc CCP
and-not CPG
and-not CPC
@@ -4632,11 +3717,6 @@ style lambda=0.30()
calma CV2 61 *
layer m2c CV1
- and-not CV2
- and-not CCC
- and-not CCE
- and-not CCP
- and-not CCA
and-not XP
grow 30
and CM2
@@ -4645,32 +3725,6 @@ style lambda=0.30()
shrink 15
calma CV1 50 *
-
-
- layer p2m12c CV1
- and-not CV2
- and CCE
- grow 30
- and CM2
- and CM1
- and CPG
- and CEL
- grow 15
- shrink 15
- calma CV1 50 *
-
- layer p2m12c CV1
- and-not CV2
- and CCC
- grow 30
- and CM2
- and CM1
- and CPG
- and CEL
- grow 15
- shrink 15
- calma CV1 50 *
-
layer m1 CM1
and-not CRM
and-not CRF
@@ -4717,14 +3771,6 @@ style lambda=0.30()
labels CMSP
calma CMSP 82 *
-
-
-
-
-
-
-
-
layer fp 100
calma 100 100 *
@@ -4747,8 +3793,6 @@ style lambda=0.30()
calma 110 110 *
layer m3c CV2
-
- and-not CV1
and-not XP
grow 30
and CM3
@@ -4757,7 +3801,6 @@ style lambda=0.30()
shrink 15
calma CV2 61 *
-
layer m3 CM3
and-not CRM
and-not CRT
@@ -4827,6 +3870,20 @@ style lambda=0.30()
and-not CRE
calma CRG2 68 *
+ layer elc CCE
+ grow 30
+ and CM1
+ and CEL
+ labels CM1
+ calma CCE 55 *
+
+ layer elc CCC
+ grow 30
+ and CM1
+ and CEL
+ labels CM1
+ calma CCC 25 *
+
layer comment CX
labels CX
calma CX 63 *
@@ -4846,6 +3903,11 @@ style lambda=0.30()
style lambda=0.30(c)
scalefactor 30
+ # This is a custom section to add bounding boxes in OpenRAM
+ layer bb BB
+ labels BB
+ calma BB 63 0
+
layer nwell CWN
and-not CWNR
and-not CTA
@@ -5301,6 +4363,11 @@ style lambda=0.30(c)
style lambda=0.30(cs)
scalefactor 30
+ # This is a custom section to add bounding boxes in OpenRAM
+ layer bb BB
+ labels BB
+ calma BB 63 0
+
layer nwell CWN
and-not CWNR
and-not CTA
@@ -5758,6 +4825,11 @@ style lambda=0.30(cs)
style lambda=0.30(cps)
scalefactor 30
+ # This is a custom section to add bounding boxes in OpenRAM
+ layer bb BB
+ labels BB
+ calma BB 63 0
+
layer nwell CWN
and-not CWNR
and-not CTA
@@ -6216,6 +5288,11 @@ style lambda=0.30(cps)
style lambda=0.30(cp)
scalefactor 30
+ # This is a custom section to add bounding boxes in OpenRAM
+ layer bb BB
+ labels BB
+ calma BB 63 0
+
layer nwell CWN
and-not CWNR
and-not CTA
@@ -6740,27 +5817,22 @@ drc
width pc/m1 4 \
"Poly contact width < 4 (Mosis #5.1)"
-
width gc 2 \
"GC contact width < 2 (Mosis #6.1)"
width ndc/m1 4 \
"Diffusion contact width < 4 (Mosis #6.1)"
-
width nsc/m1 4 \
"Diffusion contact width < 4 (Mosis #6.1)"
-
width pdc/m1 4 \
"Diffusion contact width < 4 (Mosis #6.1)"
-
width psc/m1 4 \
"Diffusion contact width < 4 (Mosis #6.1)"
-
- width m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1 3 \
+ width m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 3 \
"Metal1 width < 3 (Mosis #7.1)"
width gv1 2 \
@@ -6769,22 +5841,13 @@ drc
width m2c/m1 4 \
"Metal2 contact width < 4 (Mosis #8.1)"
-
-
-
-
-
-
- width p2m12c 4 \
- "Metal2 contact width < 4 (Mosis #8.1)"
-
- width p2m12c 4 \
- "stacked p2m12c width < 4 (Mosis #8.1)"
-
width m2,fm2,rm2,m2c/m2,m3c/m2 3 \
"Metal2 width < 3 (Mosis #9.1)"
- width poly2,ecap,phr,p2c,p2m12c,p2c,p2m12c 5 \
+ width ecap 8 \
+ "Ecap width < 8 (Mosis #11.1)"
+
+ width poly2,ecap,phr 5 \
"Poly2 width < 5 (Mosis #11.1)"
width gc2 2 \
@@ -6793,16 +5856,12 @@ drc
width p2c 4 \
"Poly2 contact width < 4 (Mosis #13.1)"
- width p2m12c 4 \
- "Poly2 contact width < 4 (Mosis #13.1)"
-
width gv2 2 \
"GV2 via width < 2 (Mosis #14.1)"
width m3c/m2 4 \
"Metal3 contact width < 4 (Mosis #14.1)"
-
width m3,fm3,rm3,m3c/m3,pad 5 \
"Metal3 width < 5 (Mosis #15.1)"
@@ -6890,7 +5949,7 @@ drc
edge4way nfet,pfet,fet space/active,ndiff,rnd,ndc/a,pdiff,rpd,pdc/a 3 ndiff,rnd,ndc/a,pdiff,rpd,pdc/a,nfet,pfet,fet 0 0 \
"N-Diffusion,P-Diffusion overhang of Transistor < 3 (Mosis #3.4)" active
- edge4way poly,fp,rp,pc/a ~(poly,fp,rp,pc/a,nfet,pfet,fet,prp)/active 1 space space 1 \
+ edge4way poly,fp,rp,pc/a ~(poly,fp,rp,pc/a,nfet,pfet,fet,prp)/active 1 space/a space/a 1 \
"Poly spacing to Diffusion < 1 (Mosis #3.5)"
edge4way nfet ~(nfet)/active 3 ~(pselect)/select ~(nfet)/active 3 \
@@ -6977,12 +6036,9 @@ drc
spacing gc gc 3 touching_ok \
"Generic contact spacing < 3 (Mosis #5.3)"
- edge4way ~(gc)/contact gc 1 ~(ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1)/metal1 0 0 \
+ edge4way ~(gc)/contact gc 1 ~(ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c)/metal1 0 0 \
"GC contact cannot touch Metal1 contacts (Mosis #0)" metal1
- edge4way ~(gc2)/contact gc2 1 ~(ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1)/metal1 0 0 \
- "Generic contact2 cannot touch Metal1 contacts (Mosis #0)" metal1
-
spacing gv1 m2c/m2 2 touching_illegal \
"GV1 via spacing to Metal2 contacts < 2 (Mosis #14.2)"
@@ -7001,12 +6057,6 @@ drc
spacing psc/m1 ndc/m1 1 touching_illegal \
"psc spacing to ndc < 1 (Mosis #6.3)"
-
-
-
-
-
-
spacing nfet,pfet ndc/a,pdc/a,psc/a,nsc/a 1 touching_illegal \
"N-Transistor,P-Transistor spacing to Diffusion contact < 1 (Mosis #6.4)"
@@ -7020,35 +6070,44 @@ drc
"Diffusion spacing to Diffusion contact < 4 (Mosis #6.5.b)"
spacing pc/a ndc/a,pdc/a,psc/a,nsc/a 2 touching_illegal \
- "pc/a,pm12c/a spacing to ndc/a,pdc/a,psc/a,nsc/a < 2 (Mosis #6.7)"
+ "pc/a spacing to ndc/a,pdc/a,psc/a,nsc/a < 2 (Mosis #6.7)"
- spacing m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1 m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1 3 touching_ok \
+ spacing m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 3 touching_ok \
"Metal1 spacing < 3 (Mosis #7.2)"
- spacing m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1 fm1,fapm 3 touching_illegal \
+ spacing m1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 fm1,fapm 3 touching_illegal \
"Metal1 spacing to fill layer (fm1) < 3 (Mosis #7.2)"
spacing fm1 fm1 4 touching_ok \
"Metal1 fill layer (fm1) spacing < 4 (Mosis #0)"
- edge4way gc space 1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1 space 1 \
+ edge4way gc space 1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 space 1 \
"Metal1 must overlap GC contact by 1 (Mosis #7.3,7.4)" metal1
- edge4way ~(m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1)/metal1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1 1 ~(gc)/contact 0 0 \
+ edge4way ~(m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1)/metal1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 1 ~(gc)/contact 0 0 \
"Metal1(edge) cannot touch GC contact (Mosis #7.3+7.4)" contact
spacing gv1 gv1 3 touching_ok \
"GV1 via spacing < 3 (Mosis #8.2)"
- edge4way gv1 ~(gv1)/via1 1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1 ~(gv1)/via1 1 \
+ edge4way gv1 ~(gv1)/via1 1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 ~(gv1)/via1 1 \
"Metal1 overlap of GV1 via < 1 (Mosis #8.3)" metal1
- edge4way gv1 space 1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1 space 1 \
+ edge4way gv1 space 1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 space 1 \
"Metal1 must overlap GV1 via by 1 (Mosis #8.3)" metal1
- edge4way ~(m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1)/metal1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1 1 ~(gv1)/via1 0 0 \
+ edge4way ~(m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1)/metal1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 1 ~(gv1)/via1 0 0 \
"Metal1(edge) cannot touch GV1 via (Mosis #8.3)" via1
+ spacing gc gv1 2 touching_illegal \
+ "GC contact spacing to GV1 via < 2 (Mosis #8.4)"
+
+ spacing gc m2c/m2 2 touching_illegal \
+ " spacing to Metal2 contacts < 2 (Mosis #14.2)"
+
+ spacing gc m2c/m2 2 touching_illegal \
+ "GC contact spacing to Metal2 contacts < 2 (Mosis #8.4)"
+
spacing m2,rm2,m2c/m2,m3c/m2 m2,rm2,m2c/m2,m3c/m2 3 touching_ok \
"Metal2 spacing < 3 (Mosis #9.2)"
@@ -7079,7 +6138,7 @@ drc
edge4way ~(ecap)/cap ecap 1 poly,fp,rp,pc/a 0 0 \
"Ecap must touch Poly (Mosis #11.3x)" active
- edge4way poly2,phr,p2c,p2m12c space 5 ~(poly,fp,rp,pc/a)/active space 5 \
+ edge4way poly2,phr space 5 ~(poly,fp,rp,pc/a)/active space 5 \
"Poly2 spacing to Poly < 5 (Mosis #11.3c)" active
spacing ecap pc/a 2 touching_illegal \
@@ -7088,13 +6147,13 @@ drc
spacing ecap gc 3 touching_illegal \
"Ecap spacing to Generic contact < 3 (Mosis #11.5)"
- spacing poly2,ecap,phr,p2c,p2m12c poly2,ecap,phr,p2c,p2m12c 3 touching_ok \
+ spacing poly2,ecap,phr poly2,ecap,phr 3 touching_ok \
"Poly2 spacing < 3 (Mosis #11.2)"
- spacing poly2,ecap,phr,p2c,p2m12c pc/a,ndc/a,pdc/a,psc/a,nsc/a 2 touching_illegal \
+ spacing poly2,ecap,phr pc/a,ndc/a,pdc/a,psc/a,nsc/a 2 touching_illegal \
"Poly2 spacing to Poly contact,Diffusion contact < 2 (Mosis #11.5)"
- spacing poly2,ecap,phr,p2c,p2m12c gc,gc 3 touching_illegal \
+ spacing poly2,ecap,phr gc,gc 3 touching_illegal \
"Poly2 spacing to GC contact < 3 (Mosis #11.5)"
spacing gc2 gc2 3 touching_ok \
@@ -7103,17 +6162,17 @@ drc
edge4way ~(ecap)/cap ecap 3 ~(gc2)/contact ecap 3 \
"Ecap overlap of Generic contact2 < 3 (Mosis #13.3)" contact
- edge4way ~(ecap)/cap ecap 2 ~(p2c,p2m12c)/cap ecap 2 \
- "Ecap overlap of Poly2 contact < 2 (Mosis #13.3)" cap
+ edge4way ~(ecap)/cap ecap 2 ~(p2c)/metal1 ecap 2 \
+ "Ecap overlap of Poly2 contact < 2 (Mosis #13.3)" metal1
- edge4way gc2 space 1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1 space 1 \
+ edge4way gc2 space 1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 space 1 \
"Metal1 must overlap Generic contact2 by 1 (Mosis #13.4)" metal1
- edge4way ~(m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1)/metal1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1 1 ~(gc2)/contact 0 0 \
+ edge4way ~(m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1)/metal1 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 1 ~(gc2)/contact 0 0 \
"Metal1(edge) cannot touch Generic contact2 (Mosis #13.4)" contact
- edge4way ~(poly2,ecap,phr,p2c,p2m12c)/cap poly2,ecap,phr,p2c,p2m12c 1 ~(p2c,p2m12c)/cap poly2,ecap,phr,p2c,p2m12c 1 \
- "Poly2 overlap of Poly2 contact < 1 (Mosis #13.4)" cap
+ edge4way ~(poly2,ecap,phr)/cap poly2,ecap,phr 1 ~(p2c)/metal1 poly2,ecap,phr 1 \
+ "Poly2 overlap of Poly2 contact < 1 (Mosis #13.4)" metal1
spacing gv2 gv2 3 touching_ok \
"GV2 via spacing < 3 (Mosis #14.2)"
@@ -7127,6 +6186,12 @@ drc
edge4way ~(m2,fm2,rm2,m2c/m2,m3c/m2)/metal2 m2,fm2,rm2,m2c/m2,m3c/m2 1 ~(gv2)/via2 0 0 \
"Metal2(edge) cannot touch GV2 via (Mosis #14.3)" via2
+ spacing gv1 gv2 2 touching_illegal \
+ "GV1 via spacing to GV2 via < 2 (Mosis #14.4)"
+
+ spacing gv1 m3c/m2 1 touching_illegal \
+ "GV1 via spacing to Metal3 contact < 1 (Mosis #14.4)"
+
spacing m3,rm3,m3c/m3,pad m3,rm3,m3c/m3,pad 3 touching_ok \
"Metal3 spacing < 3 (Mosis #15.2)"
@@ -7148,7 +6213,7 @@ drc
spacing hr,phr hr,phr 4 touching_ok \
"High-Resist spacing < 4 (Mosis #27.2)"
- spacing hr,phr,phr p2c,p2m12c 2 touching_illegal \
+ spacing hr,phr,phr p2c 2 touching_illegal \
"High-Resist spacing to Poly2 contact < 2 (Mosis #27.3)"
spacing hr,phr,phr gc 2 touching_illegal \
@@ -7157,10 +6222,10 @@ drc
edge4way hr,phr space 2 ~(ndiff,rnd,ndc/a,pdiff,rpd,pdc/a)/active 0 2 \
"High-Resist space to Diffusion < 2 (Mosis #27.4)" active
- spacing hr,phr,phr poly2,ecap,phr,p2c,p2m12c 2 touching_ok \
+ spacing hr,phr,phr poly2,ecap,phr 2 touching_ok \
"High-Resist spacing to other Poly2 < 2 (Mosis #27.5)"
- edge4way hr,phr space 2 ~(poly2,ecap,phr,p2c,p2m12c)/contact hr,phr 2 \
+ edge4way hr,phr space 2 ~(poly2,ecap,phr)/contact hr,phr 2 \
"High-Resist space to Poly2 < 2 (Mosis #27.5x)" contact
spacing nwell phr 4 touching_illegal \
@@ -7271,7 +6336,7 @@ drc
edge4way gc2 ~(gc2)/contact 1 ~(gc2)/contact (~(gc2),gc2)/contact 1 \
"Contact not rectangular (Magic rule)"
- edge4way p2c,p2m12c ~(p2c,p2m12c)/cap 1 ~(p2c,p2m12c)/cap (~(p2c,p2m12c),p2c,p2m12c)/cap 1 \
+ edge4way p2c ~(p2c)/metal1 1 ~(p2c)/metal1 (~(p2c),p2c)/metal1 1 \
"Contact not rectangular (Magic rule)"
edge4way gc ~(gc)/contact 1 ~(gc)/contact (~(gc),gc)/contact 1 \
@@ -7291,12 +6356,12 @@ drc
exact_overlap gc,ndc/a,pdc/a,psc/a,nsc/a,gc,pc/a,gc
- exact_overlap gc2,p2c,p2m12c
+ exact_overlap gc2,p2c
edge4way pad ~(pad)/m3 1 ~(pad)/m3 (~(pad),pad)/m3 1 \
"Contact not rectangular (Magic rule)"
- exact_overlap ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1
+ exact_overlap ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c
exact_overlap m2c/m2
@@ -7356,17 +6421,17 @@ lef
ignore PC
ignore CA
-routing m1 M1 m1 met1
-routing m2 M2 m2 met2
-routing m3 M3 m3 met3
+routing m1 metal1 M1 m1 met1
+routing m2 metal2 M2 m2 met2
+routing m3 metal3 M3 m3 met3
-contact m2c via via1 V1 v1
+contact m2c via1 via V1 v1
contact m3c via2 V2 v2
end
extract
- style AMI0.5um(amic5)from:T24H
+ style AMI0.5um(amic5)from:T11Z
cscale 1
lambda 30
step 100
@@ -7387,162 +6452,164 @@ extract
planeorder via2 13
planeorder fill 14
- resist (ndiff,rnd,ndc,nsd,nsc)/active 82200
- resist (pdiff,rpd,pdc,psd,psc)/active 105200
- resist (nwell)/well 808000
- resist (rnw)/active 808000
- resist (pwell)/well 1
- resist (poly,fp,rp,pc,pc,nfet,pfet,fet)/active 22000
- resist (poly2,ecap,p2c,p2m12c,p2c,p2m12c)/cap 40300
- resist (phr)/cap 40300
- resist (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c,m2c)/metal1 90
- resist (m2,fm2,rm2,m2c,m3c,m3c)/metal2 90
- resist (m3,fm3,rm3,m3c,pad)/metal3 50
+ substrate *psd,space/w,pwell well
- contact ndc 4 62700
- contact pdc 4 160000
- contact pc 4 15600
- contact p2c 4 26100
- contact m2c 4 910
- contact m3c 4 830
+ resist (ndiff,rnd,ndc,nsd,nsc)/active 82400
+ resist (pdiff,rpd,pdc,psd,psc)/active 102700
+ resist (nwell)/well 816000
+ resist (rnw)/active 816000 0.5
+ resist (pwell)/well 1
+ resist (poly,fp,rp,pc,pc,nfet,pfet,fet)/active 22300
+ resist (poly2,ecap,p2c)/cap 41300
+ resist (phr)/cap 41300 0.5
+ resist (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c,m2c)/metal1 90
+ resist (m2,fm2,rm2,m2c,m3c,m3c)/metal2 90
+ resist (m3,fm3,rm3,m3c,pad)/metal3 60
+
+ contact ndc 4 58700
+ contact pdc 4 141000
+ contact pc 4 15800
+ contact p2c 4 26800
+ contact m2c 4 760
+ contact m3c 4 730
#poly2
- overlap (poly,fp,rp,pc,pc)/active (poly2,ecap,phr,p2c,p2m12c,p2c,p2m12c)/cap 84.960
+ overlap (poly,fp,rp,pc,pc)/active (poly2,ecap,phr,p2c)/cap 82.260
#nwell,cwell,pwell
- areacap (nwell)/well 3.600
+ areacap (nwell)/well 3.510
#rnw
- areacap (rnw)/active 3.600
+ areacap (rnw)/active 3.510
#ndiff
-# MODEL HANDLES THIS: areacap (ndiff,ndc)/active 38.430
-# MODEL HANDLES THIS: overlap (ndiff,ndc)/active ~space/w 38.430
-# MODEL HANDLES THIS: perimc (ndiff,ndc)/active ~(ndiff,ndc,nfet,pfet,fet)/active 94.800
-# MODEL HANDLES THIS: sideoverlap (ndiff,ndc)/active ~(ndiff,ndc,nfet,pfet,fet)/active ~space/w 94.800
+# MODEL HANDLES THIS: areacap (ndiff,ndc)/active 38.070
+# MODEL HANDLES THIS: overlap (ndiff,ndc)/active ~space/w 38.070
+# MODEL HANDLES THIS: perimc (ndiff,ndc)/active ~(ndiff,ndc,nfet,pfet,fet)/active 95.700
+# MODEL HANDLES THIS: sideoverlap (ndiff,ndc)/active ~(ndiff,ndc,nfet,pfet,fet)/active ~space/w 95.700
- areacap (rnd)/active 38.430
- overlap (rnd)/active ~space/w 38.430
- perimc (rnd)/active ~(rnd)/active 94.800
- sideoverlap (rnd)/active ~(rnd)/active ~space/w 94.800
+ areacap (rnd)/active 38.070
+ overlap (rnd)/active ~space/w 38.070
+ perimc (rnd)/active ~(rnd)/active 95.700
+ sideoverlap (rnd)/active ~(rnd)/active ~space/w 95.700
#pdiff
-# MODEL HANDLES THIS: areacap (pdiff,pdc)/active 65.880
-# MODEL HANDLES THIS: overlap (pdiff,pdc)/active ~space/w 65.880
-# MODEL HANDLES THIS: perimc (pdiff,pdc)/active ~(pdiff,pdc,nfet,pfet,fet)/active 75.300
-# MODEL HANDLES THIS: sideoverlap (pdiff,pdc)/active ~(pdiff,pdc,nfet,pfet,fet)/active ~space/w 75.300
+# MODEL HANDLES THIS: areacap (pdiff,pdc)/active 65.610
+# MODEL HANDLES THIS: overlap (pdiff,pdc)/active ~space/w 65.610
+# MODEL HANDLES THIS: perimc (pdiff,pdc)/active ~(pdiff,pdc,nfet,pfet,fet)/active 73.800
+# MODEL HANDLES THIS: sideoverlap (pdiff,pdc)/active ~(pdiff,pdc,nfet,pfet,fet)/active ~space/w 73.800
- areacap (rpd)/active 65.880
- overlap (rpd)/active ~space/w 65.880
- perimc (rpd)/active ~(rpd)/active 75.300
- sideoverlap (rpd)/active ~(rpd)/active ~space/w 75.300
+ areacap (rpd)/active 65.610
+ overlap (rpd)/active ~space/w 65.610
+ perimc (rpd)/active ~(rpd)/active 73.800
+ sideoverlap (rpd)/active ~(rpd)/active ~space/w 73.800
#rnw
#poly
-# MODEL HANDLES THIS: overlap (nfet)/active (ndiff,rnd,ndc)/active 221.670
-# MODEL HANDLES THIS: sideoverlap (nfet)/active ~(nfet)/active (ndiff,rnd,ndc)/active 58.500
-# MODEL HANDLES THIS: overlap (pfet)/active (pdiff,rpd,pdc)/active 213.480
-# MODEL HANDLES THIS: sideoverlap (pfet)/active ~(pfet)/active (pdiff,rpd,pdc)/active 82.800
+# MODEL HANDLES THIS: overlap (nfet)/active (ndiff,rnd,ndc)/active 225.450
+# MODEL HANDLES THIS: sideoverlap (nfet)/active ~(nfet)/active (ndiff,rnd,ndc)/active 65.700
+# MODEL HANDLES THIS: overlap (pfet)/active (pdiff,rpd,pdc)/active 219.060
+# MODEL HANDLES THIS: sideoverlap (pfet)/active ~(pfet)/active (pdiff,rpd,pdc)/active 69
- areacap (poly,fp,rp,pc)/active 7.740
- overlap (poly,fp,rp,pc)/active ~space/w 7.740
+ areacap (poly,fp,rp,pc)/active 7.920
+ overlap (poly,fp,rp,pc)/active ~space/w 7.920
#poly2
#rnw
#metal1
- areacap (m1,fm1,rm1,ndc,pdc,pc,m2c)/metal1 2.700
+ areacap (m1,fm1,rm1,ndc,pdc,pc,p2c,m2c)/metal1 2.790
#metal1-sub blocked by ~space/a,~space/c
- overlap (m1,fm1,rm1,ndc,pdc,pc,m2c)/metal1 ~space/w 2.700 ~space/a,~space/c
- perimc (m1,fm1,rm1,ndc,pdc,pc,m2c)/metal1 ~(m1,fm1,rm1,ndc,pdc,pc,m2c)/metal1 20.700
- sideoverlap (m1,fm1,rm1,ndc,pdc,pc,m2c)/metal1 ~(m1,fm1,rm1,ndc,pdc,pc,m2c)/metal1 ~space/w 20.700 ~space/a,~space/c
+ overlap (m1,fm1,rm1,ndc,pdc,pc,p2c,m2c)/metal1 ~space/w 2.790 ~space/a,~space/c
+ perimc (m1,fm1,rm1,ndc,pdc,pc,p2c,m2c)/metal1 ~(m1,fm1,rm1,ndc,pdc,pc,p2c,m2c)/metal1 22.200
+ sideoverlap (m1,fm1,rm1,ndc,pdc,pc,p2c,m2c)/metal1 ~(m1,fm1,rm1,ndc,pdc,pc,p2c,m2c)/metal1 ~space/w 22.200 ~space/a,~space/c
#rnw
- overlap (m1,fm1,rm1,ndc,pdc,pc,m2c)/metal1 rnw/active 2.700 ~space/c
- sideoverlap (m1,fm1,rm1,ndc,pdc,pc,m2c)/metal1 ~(m1,fm1,rm1,ndc,pdc,pc,m2c)/metal1 rnw/active 20.700 ~space/c
+ overlap (m1,fm1,rm1,ndc,pdc,pc,p2c,m2c)/metal1 rnw/active 2.790 ~space/c
+ sideoverlap (m1,fm1,rm1,ndc,pdc,pc,p2c,m2c)/metal1 ~(m1,fm1,rm1,ndc,pdc,pc,p2c,m2c)/metal1 rnw/active 22.200 ~space/c
#metal1-diff blocked by ~space/c
- overlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 (ndiff,rnd,ndc)/active 3.150 ~space/c
- sideoverlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 (ndiff,rnd,ndc)/active 20.700 ~space/c
- overlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 (pdiff,rpd,pdc)/active 3.150 ~space/c
- sideoverlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 (pdiff,rpd,pdc)/active 20.700 ~space/c
+ overlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 (ndiff,rnd,ndc)/active 3.150 ~space/c
+ sideoverlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 (ndiff,rnd,ndc)/active 22.200 ~space/c
+ overlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 (pdiff,rpd,pdc)/active 3.150 ~space/c
+ sideoverlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 (pdiff,rpd,pdc)/active 22.200 ~space/c
#metal1-poly blocked by ~space/c
- overlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 (poly,fp,rp,pc,nfet,pfet,fet)/active 4.590 ~space/c
- sideoverlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 (poly,fp,rp,pc,nfet,pfet,fet)/active 15.900 ~space/c
- sideoverlap (poly,fp,rp,pc,nfet,pfet,fet)/active ~(poly,fp,rp,pc,nfet,pfet,fet)/active (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 15.900 ~space/c
+ overlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 (poly,fp,rp,pc,nfet,pfet,fet)/active 4.680 ~space/c
+ sideoverlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 (poly,fp,rp,pc,nfet,pfet,fet)/active 18 ~space/c
+ sideoverlap (poly,fp,rp,pc,nfet,pfet,fet)/active ~(poly,fp,rp,pc,nfet,pfet,fet)/active (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 18 ~space/c
#metal1-poly2 not blocked
- overlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 (poly2,ecap,phr,p2c,p2m12c)/cap 3.960
+ overlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 (poly2,ecap,phr)/cap 4.320
#metal2
- areacap (m2,fm2,rm2,m3c)/metal2 1.350
+ areacap (m2,fm2,rm2,m3c)/metal2 1.440
#metal2-sub blocked by
- overlap (m2,fm2,rm2,m3c)/metal2 ~space/w 1.350 ~space/a,~space/m1,~space/c
- perimc (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 15.900
- sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 ~space/w 15.900 ~space/a,~space/m1,~space/c
- overlap (m2,fm2,rm2,m3c)/metal2 rnw/active 1.350 ~space/m1,~space/c
- sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 rnw/active 15.900 ~space/m1,~space/c
+ overlap (m2,fm2,rm2,m3c)/metal2 ~space/w 1.440 ~space/a,~space/m1,~space/c
+ perimc (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 17.400
+ sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 ~space/w 17.400 ~space/a,~space/m1,~space/c
+ overlap (m2,fm2,rm2,m3c)/metal2 rnw/active 1.440 ~space/m1,~space/c
+ sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 rnw/active 17.400 ~space/m1,~space/c
#metal2-*diff blocked by ~space/m1,~space/c
- overlap (m2,fm2,rm2,m3c)/metal2 (ndiff,rnd,ndc)/active 1.350 ~space/m1,~space/c
- sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 (ndiff,rnd,ndc)/active 15.900 ~space/m1,~space/c
- overlap (m2,fm2,rm2,m2c,m3c)/metal2 (pdiff,rpd,pdc)/active 1.350 ~space/m1,~space/c
- sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 (pdiff,rpd,pdc)/active 15.900 ~space/m1,~space/c
+ overlap (m2,fm2,rm2,m3c)/metal2 (ndiff,rnd,ndc)/active 1.440 ~space/m1,~space/c
+ sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 (ndiff,rnd,ndc)/active 17.400 ~space/m1,~space/c
+ overlap (m2,fm2,rm2,m2c,m3c)/metal2 (pdiff,rpd,pdc)/active 1.440 ~space/m1,~space/c
+ sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 (pdiff,rpd,pdc)/active 17.400 ~space/m1,~space/c
#metal2-poly blocked by ~space/m1,~space/c
overlap (m2,fm2,rm2,m3c)/metal2 (poly,fp,rp,pc,nfet,pfet,fet)/active 1.350 ~space/m1,~space/c
- sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 (poly,fp,rp,pc,nfet,pfet,fet)/active 10.800 ~space/m1,~space/c
- sideoverlap (poly,fp,rp,pc,nfet,pfet,fet)/active ~(poly,fp,rp,pc,nfet,pfet,fet)/active (m2,fm2,rm2,m2c,m3c)/metal2 10.800 ~space/m1,~space/c
+ sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 (poly,fp,rp,pc,nfet,pfet,fet)/active 11.400 ~space/m1,~space/c
+ sideoverlap (poly,fp,rp,pc,nfet,pfet,fet)/active ~(poly,fp,rp,pc,nfet,pfet,fet)/active (m2,fm2,rm2,m2c,m3c)/metal2 11.400 ~space/m1,~space/c
#metal2-poly2 blocked by ~space/m1
#M2->M1
- overlap (m2,fm2,rm2,m3c)/metal2 (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 2.520
- sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 14.700
- sideoverlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 (m2,fm2,rm2,m2c,m3c)/metal2 14.700
+ overlap (m2,fm2,rm2,m3c)/metal2 (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 2.700
+ sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 15
+ sideoverlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 (m2,fm2,rm2,m2c,m3c)/metal2 15
#metal3
areacap (m3,fm3,rm3,pad)/metal3 0.900
#metal3-sub blocked by ~space/a,~space/m1,~space/m2,~space/c
overlap (m3,fm3,rm3,pad)/metal3 ~space/w 0.900 ~space/a,~space/m1,~space/m2,~space/c
- perimc (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 10.500
- sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 ~space/w 10.500 ~space/a,~space/m1,~space/m2,~space/c
+ perimc (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 11.400
+ sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 ~space/w 11.400 ~space/a,~space/m1,~space/m2,~space/c
#rnw
overlap (m3,fm3,rm3,pad)/metal3 rnw/active 0.900 ~space/m1,~space/m2,~space/c
- sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 rnw/active 10.500 ~space/m1,~space/m2,~space/c
+ sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 rnw/active 11.400 ~space/m1,~space/m2,~space/c
#metal3-*diff blocked by ~space/m1,~space/m2,~space/c
overlap (m3,fm3,rm3,pad)/metal3 (ndiff,rnd,ndc)/active 0.990 ~space/m1,~space/m2,~space/c
- sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 (ndiff,rnd,ndc)/active 10.500 ~space/m1,~space/m2,~space/c
+ sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 (ndiff,rnd,ndc)/active 11.400 ~space/m1,~space/m2,~space/c
overlap (m3,fm3,rm3,pad)/metal3 (pdiff,rpd,pdc)/active 0.990 ~space/m1,~space/m2,~space/c
- sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 (pdiff,rpd,pdc)/active 10.500 ~space/m1,~space/m2,~space/c
+ sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 (pdiff,rpd,pdc)/active 11.400 ~space/m1,~space/m2,~space/c
#metal3-poly blocked by ~space/m1,~space/m2,~space/c
overlap (m3,fm3,rm3,pad)/metal3 (poly,fp,rp,pc,nfet,pfet,fet)/active 0.810 ~space/m1,~space/m2,~space/c
- sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 (poly,fp,rp,pc,nfet,pfet,fet)/active 8.100 ~space/m1,~space/m2,~space/c
- sideoverlap (poly,fp,rp,pc,nfet,pfet,fet)/active ~(poly,fp,rp,pc,nfet,pfet,fet)/active (m3,fm3,rm3,m3c,pad)/metal3 8.100 ~space/m1,~space/m2,~space/c
+ sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 (poly,fp,rp,pc,nfet,pfet,fet)/active 8.400 ~space/m1,~space/m2,~space/c
+ sideoverlap (poly,fp,rp,pc,nfet,pfet,fet)/active ~(poly,fp,rp,pc,nfet,pfet,fet)/active (m3,fm3,rm3,m3c,pad)/metal3 8.400 ~space/m1,~space/m2,~space/c
#metal3-poly2 blocked by ~space/m1,~space/m2
#M3->M1
- overlap (m3,fm3,rm3,pad)/metal3 (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 1.080 ~space/m2
+ overlap (m3,fm3,rm3,pad)/metal3 (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 1.080 ~space/m2
#metal3-metal1 blocked by ~space/m2
- sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 9.900 ~space/m2
- sideoverlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,pdc,psc,pc,m2c)/metal1 (m3,fm3,rm3,m3c,pad)/metal3 9.900 ~space/m2
+ sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 9.600 ~space/m2
+ sideoverlap (m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 ~(m1,fm1,rm1,ndc,nsc,pdc,psc,pc,p2c,m2c)/metal1 (m3,fm3,rm3,m3c,pad)/metal3 9.600 ~space/m2
#M3->M2
- overlap (m3,fm3,rm3,pad)/metal3 (m2,fm2,rm2,m2c,m3c)/metal2 3.060
- sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 (m2,fm2,rm2,m2c,m3c)/metal2 16.800
- sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 (m3,fm3,rm3,m3c,pad)/metal3 16.800
+ overlap (m3,fm3,rm3,pad)/metal3 (m2,fm2,rm2,m2c,m3c)/metal2 2.880
+ sideoverlap (m3,fm3,rm3,m3c,pad)/metal3 ~(m3,fm3,rm3,m3c,pad)/metal3 (m2,fm2,rm2,m2c,m3c)/metal2 15.600
+ sideoverlap (m2,fm2,rm2,m2c,m3c)/metal2 ~(m2,fm2,rm2,m2c,m3c)/metal2 (m3,fm3,rm3,m3c,pad)/metal3 15.600
#metal4
@@ -7554,44 +6621,28 @@ extract
#metali
-#fets
+#devices
-# fet pfet pdiff,pdc 2 pfet Vdd! nwell 83 213
-# fet pfet pdiff,pdc 1 pfet Vdd! nwell 83 213
+ device mosfet pfet pfet pdiff,pdc nwell ERROR 69 219
+ device mosfet nfet nfet ndiff,ndc pwell,space/w ERROR 66 225
- device mosfet pfet pfet pdiff,pdc nwell $VDD 83 213
+ fetresis pfet linear 21001
+ fetresis pfet saturation 21001
+ fetresis nfet linear 6020
+ fetresis nfet saturation 6020
-# fet nfet ndiff,ndc 2 nfet Gnd! pwell 59 222
-# fet nfet ndiff,ndc 1 nfet Gnd! pwell 59 222
+ device resistor nwellResistor rnwell *nsd
+ device resistor polyResistor rpoly *poly
+ device resistor poly2Resistor rpoly2 *poly2
+ device resistor ndiffResistor rndiff *ndiff
+ device resistor pdiffResistor rpdiff *pdiff
- device mosfet nfet nfet ndiff,ndc pwell $GND 59 222
+ device resistor metal1Resistor rmetal1 *metal1
+ device resistor metal2Resistor rmetal2 *metal2
+ device resistor metal3Resistor rmetal3 *metal3
- fetresis pfet linear 20996
- fetresis pfet saturation 20996
- fetresis nfet linear 6144
- fetresis nfet saturation 6144
+ device resistor presResistor phr *poly2
-# fet rnwell nsd,nsc 2 nwellResistor Gnd! nwell,pwell 0 0
-# fet rpoly poly,pc 2 polyResistor Gnd! nwell,pwell 0 0
-# fet rpoly2 poly2,p2c 2 poly2Resistor Gnd! nwell,pwell 0 0
-# fet rndiff ndiff,ndc 2 ndiffResistor Gnd! nwell,pwell 0 0
-# fet rpdiff pdiff,pdc 2 pdiffResistor Gnd! nwell,pwell 0 0
-
- device resistor None rnwell nsd,nsc
- device resistor None rpoly poly,pc
- device resistor None rpoly2 poly2,p2c
- device resistor None rndiff ndiff,ndc
- device resistor None rpdiff pdiff,pdc
-
-# fet rmetal1 metal1 2 metal1Resistor Gnd! nwell,pwell 0 0
-# fet rmetal2 metal2 2 metal2Resistor Gnd! nwell,pwell 0 0
-# fet rmetal3 metal3 2 metal3Resistor Gnd! nwell,pwell 0 0
-# fet phr poly2,p2c 2 phrResistor Gnd! nwell,pwell 0 0
-
- device resistor None rmetal1 *metal1
- device resistor None rmetal2 *metal2
- device resistor None rmetal3 *metal3
- device resistor None phr poly2,p2c
end
@@ -7606,7 +6657,7 @@ end
router
layer2 metal2 3 m2,fm2,rm2,m2c/m2,m3c/m2,m3c/m2 4 poly,fp,rp,ndiff,rnd,nsd,pdiff,rpd,psd,m1,fm1,rm1 1
- layer1 metal1 3 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1 3
+ layer1 metal1 3 m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 3
contacts m2contact 4
gridspacing 8
@@ -7706,12 +6757,12 @@ style colorversatec
4949 A0A0 5252 2828 \
9494 0A0A 2525 8282 \
4949 A0A0 5252 2828
- poly2,ecap,phr,p2c,p2m12c yellow \
+ poly2,ecap,phr yellow \
FFFF FFFF FFFF FFFF \
FFFF FFFF FFFF FFFF \
FFFF FFFF FFFF FFFF \
FFFF FFFF FFFF FFFF
- m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1 cyan \
+ m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 cyan \
AAAA 0000 AAAA 0000 \
AAAA 0000 AAAA 0000 \
AAAA 0000 AAAA 0000 \
@@ -7834,7 +6885,7 @@ style versatec
8080 4000 2020 1010 \
0808 0004 0202 0101 \
8080 0040 2020 1010
- m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,m2c/m1 \
+ m1,fm1,rm1,ndc/m1,nsc/m1,pdc/m1,psc/m1,pc/m1,p2c,m2c/m1 \
8080 0000 0000 0000 \
0808 0000 0000 0000 \
8080 0000 0000 0000 \
diff --git a/technology/scn3me_subm/tech/__init__.py b/technology/scn3me_subm/tech/__init__.py
index 6b2d03b3..2573d2c2 100755
--- a/technology/scn3me_subm/tech/__init__.py
+++ b/technology/scn3me_subm/tech/__init__.py
@@ -2,5 +2,5 @@
Import tech specific modules.
"""
-from tech import *
+from .tech import *
diff --git a/technology/scn3me_subm/tech/tech.py b/technology/scn3me_subm/tech/tech.py
index e088eff9..074009f2 100755
--- a/technology/scn3me_subm/tech/tech.py
+++ b/technology/scn3me_subm/tech/tech.py
@@ -8,6 +8,16 @@ File containing the process technology parameters for SCMOS 3me, subm, 180nm.
#GDS file info
GDS={}
# gds units
+# gds units
+# From http://www.cnf.cornell.edu/cnf_spie9.html: "The first
+#is the size of a database unit in user units. The second is the size
+#of a database unit in meters. For example, if your library was
+#created with the default units (user unit = 1 m and 1000 database
+#units per user unit), then the first number would be 0.001 and the
+#second number would be 10-9. Typically, the first number is less than
+#1, since you use more than 1 database unit per user unit. To
+#calculate the size of a user unit in meters, divide the second number
+#by the first."
GDS["unit"]=(0.001,1e-6)
# default label zoom
GDS["zoom"] = 0.5
@@ -209,17 +219,20 @@ spice["nmos"]="n"
spice["pmos"]="p"
# This is a map of corners to model files
SPICE_MODEL_DIR=os.environ.get("SPICE_MODEL_DIR")
-# FIXME: Uncomment when we have the new spice models
-#spice["fet_models"] = { "TT" : [SPICE_MODEL_DIR+"/nom/pmos.sp",SPICE_MODEL_DIR+"/nom/nmos.sp"] }
spice["fet_models"] = { "TT" : [SPICE_MODEL_DIR+"/nom/pmos.sp",SPICE_MODEL_DIR+"/nom/nmos.sp"],
"FF" : [SPICE_MODEL_DIR+"/ff/pmos.sp",SPICE_MODEL_DIR+"/ff/nmos.sp"],
"FS" : [SPICE_MODEL_DIR+"/ff/pmos.sp",SPICE_MODEL_DIR+"/ss/nmos.sp"],
"SF" : [SPICE_MODEL_DIR+"/ss/pmos.sp",SPICE_MODEL_DIR+"/ff/nmos.sp"],
- "SS" : [SPICE_MODEL_DIR+"/ss/pmos.sp",SPICE_MODEL_DIR+"/ss/nmos.sp"] }
+ "SS" : [SPICE_MODEL_DIR+"/ss/pmos.sp",SPICE_MODEL_DIR+"/ss/nmos.sp"],
+ "ST" : [SPICE_MODEL_DIR+"/ss/pmos.sp",SPICE_MODEL_DIR+"/nom/nmos.sp"],
+ "TS" : [SPICE_MODEL_DIR+"/nom/pmos.sp",SPICE_MODEL_DIR+"/ss/nmos.sp"],
+ "FT" : [SPICE_MODEL_DIR+"/ff/pmos.sp",SPICE_MODEL_DIR+"/nom/nmos.sp"],
+ "TF" : [SPICE_MODEL_DIR+"/nom/pmos.sp",SPICE_MODEL_DIR+"/ff/nmos.sp"],
+ }
#spice stimulus related variables
-spice["feasible_period"] = 5 # estimated feasible period in ns
+spice["feasible_period"] = 10 # estimated feasible period in ns
spice["supply_voltages"] = [4.5, 5.0, 5.5] # Supply voltage corners in [Volts]
spice["nom_supply_voltage"] = 5.0 # Nominal supply voltage in [Volts]
spice["rise_time"] = 0.05 # rise time in [Nano-seconds]
@@ -227,37 +240,17 @@ spice["fall_time"] = 0.05 # fall time in [Nano-seconds]
spice["temperatures"] = [0, 25, 100] # Temperature corners (celcius)
spice["nom_temperature"] = 25 # Nominal temperature (celcius)
-#sram signal names
-#FIXME: We don't use these everywhere...
-spice["vdd_name"] = "vdd"
-spice["gnd_name"] = "gnd"
-spice["control_signals"] = ["CSB", "WEB"]
-spice["data_name"] = "DATA"
-spice["addr_name"] = "ADDR"
-spice["minwidth_tx"] = drc["minwidth_tx"]
-spice["channel"] = drc["minlength_channel"]
-spice["clk"] = "clk"
-
# analytical delay parameters
+spice["nom_threshold"] = 1.3 # Typical Threshold voltage in Volts
# FIXME: These need to be updated for SCMOS, they are copied from FreePDK45.
-spice["vdd_nominal"] = 5.0 # Typical Threshold voltage in Volts
-spice["temp_nominal"] = 25.0 # Typical Threshold voltage in Volts
-spice["v_threshold_typical"] = 1.3 # Typical Threshold voltage in Volts
spice["wire_unit_r"] = 0.075 # Unit wire resistance in ohms/square
spice["wire_unit_c"] = 0.64 # Unit wire capacitance ff/um^2
-spice["min_tx_r"] = 9250.0 # Minimum transistor on resistance in ohms
spice["min_tx_drain_c"] = 0.7 # Minimum transistor drain capacitance in ff
spice["min_tx_gate_c"] = 0.1 # Minimum transistor gate capacitance in ff
-spice["msflop_setup"] = 9 # DFF setup time in ps
-spice["msflop_hold"] = 1 # DFF hold time in ps
-spice["msflop_delay"] = 20.5 # DFF Clk-to-q delay in ps
-spice["msflop_slew"] = 13.1 # DFF output slew in ps w/ no load
-spice["msflop_in_cap"] = 9.8242 # Input capacitance of ms_flop (Din) [Femto-farad]
spice["dff_setup"] = 9 # DFF setup time in ps
spice["dff_hold"] = 1 # DFF hold time in ps
-spice["dff_delay"] = 20.5 # DFF Clk-to-q delay in ps
-spice["dff_slew"] = 13.1 # DFF output slew in ps w/ no load
-spice["dff_in_cap"] = 9.8242 # Input capacitance of ms_flop (Din) [Femto-farad]
+spice["dff_in_cap"] = 9.8242 # Input capacitance (D) [Femto-farad]
+spice["dff_out_cap"] = 2 # Output capacitance (Q) [Femto-farad]
# analytical power parameters, many values are temporary
spice["bitcell_leakage"] = 1 # Leakage power of a single bitcell in nW
@@ -265,15 +258,22 @@ spice["inv_leakage"] = 1 # Leakage power of inverter in nW
spice["nand2_leakage"] = 1 # Leakage power of 2-input nand in nW
spice["nand3_leakage"] = 1 # Leakage power of 3-input nand in nW
spice["nor2_leakage"] = 1 # Leakage power of 2-input nor in nW
-spice["msflop_leakage"] = 1 # Leakage power of flop in nW
-spice["flop_para_cap"] = 2 # Parasitic Output capacitance in fF
+spice["dff_leakage"] = 1 # Leakage power of flop in nW
+
+spice["default_event_frequency"] = 100 # Default event activity of every gate. MHz
+
+#Logical Effort relative values for the Handmade cells
+parameter["le_tau"] = 23 #In pico-seconds.
+parameter["min_inv_para_delay"] = 0.73 #In relative delay units
+parameter["cap_relative_per_ff"] = 0.91 #Units of Relative Capacitance/ Femto-Farad
+parameter["dff_clk_cin"] = 27.5 #In relative capacitance units
+parameter["6tcell_wl_cin"] = 2 #In relative capacitance units
+parameter["sa_en_pmos_size"] = 24*_lambda_
+parameter["sa_en_nmos_size"] = 9*_lambda_
+parameter["sa_inv_pmos_size"] = 18*_lambda_
+parameter["sa_inv_nmos_size"] = 9*_lambda_
+parameter["bitcell_drain_cap"] = 0.2 #In Femto-Farad, approximation of drain capacitance
-spice["default_event_rate"] = 100 # Default event activity of every gate. MHz
-spice["flop_transition_prob"] = .5 # Transition probability of inverter.
-spice["inv_transition_prob"] = .5 # Transition probability of inverter.
-spice["nand2_transition_prob"] = .1875 # Transition probability of 2-input nand.
-spice["nand3_transition_prob"] = .1094 # Transition probability of 3-input nand.
-spice["nor2_transition_prob"] = .1875 # Transition probability of 2-input nor.
###################################################
##END Spice Simulation Parameters
###################################################
diff --git a/technology/setup_scripts/setup_openram_scn4m_subm.py b/technology/scn4m_subm/__init__.py
similarity index 76%
rename from technology/setup_scripts/setup_openram_scn4m_subm.py
rename to technology/scn4m_subm/__init__.py
index 19a4960c..c7a863f0 100644
--- a/technology/setup_scripts/setup_openram_scn4m_subm.py
+++ b/technology/scn4m_subm/__init__.py
@@ -1,3 +1,10 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
#!/usr/bin/python
"""
This type of setup script should be placed in the setup_scripts directory in the trunk
@@ -34,8 +41,3 @@ os.environ["DRCLVS_HOME"] = DRCLVS_HOME
OPENRAM_TECH=os.path.abspath(os.environ.get("OPENRAM_TECH"))
os.environ["SPICE_MODEL_DIR"] = "{0}/{1}/models".format(OPENRAM_TECH, TECHNOLOGY)
-##########################
-# Paths required for OPENRAM to function
-
-LOCAL = "{0}/..".format(os.path.dirname(__file__))
-sys.path.append("{0}/{1}/tech".format(LOCAL,TECHNOLOGY))
diff --git a/technology/scn4m_subm/gds_lib/cell_6t.gds b/technology/scn4m_subm/gds_lib/cell_6t.gds
index df644048..14d6ab7e 100644
Binary files a/technology/scn4m_subm/gds_lib/cell_6t.gds and b/technology/scn4m_subm/gds_lib/cell_6t.gds differ
diff --git a/technology/scn4m_subm/gds_lib/dummy_cell_1rw_1r.gds b/technology/scn4m_subm/gds_lib/dummy_cell_1rw_1r.gds
new file mode 100644
index 00000000..42727119
Binary files /dev/null and b/technology/scn4m_subm/gds_lib/dummy_cell_1rw_1r.gds differ
diff --git a/technology/scn4m_subm/gds_lib/dummy_cell_1w_1r.gds b/technology/scn4m_subm/gds_lib/dummy_cell_1w_1r.gds
new file mode 100644
index 00000000..34d692e8
Binary files /dev/null and b/technology/scn4m_subm/gds_lib/dummy_cell_1w_1r.gds differ
diff --git a/technology/scn4m_subm/gds_lib/dummy_cell_6t.gds b/technology/scn4m_subm/gds_lib/dummy_cell_6t.gds
new file mode 100644
index 00000000..4a950a68
Binary files /dev/null and b/technology/scn4m_subm/gds_lib/dummy_cell_6t.gds differ
diff --git a/technology/scn4m_subm/gds_lib/replica_cell_6t.gds b/technology/scn4m_subm/gds_lib/replica_cell_6t.gds
index f16f7b13..191f1206 100644
Binary files a/technology/scn4m_subm/gds_lib/replica_cell_6t.gds and b/technology/scn4m_subm/gds_lib/replica_cell_6t.gds differ
diff --git a/technology/scn4m_subm/gds_lib/write_driver.gds b/technology/scn4m_subm/gds_lib/write_driver.gds
index 44dabaf1..8223c795 100644
Binary files a/technology/scn4m_subm/gds_lib/write_driver.gds and b/technology/scn4m_subm/gds_lib/write_driver.gds differ
diff --git a/technology/scn4m_subm/mag_lib/cell_1w_1r.mag b/technology/scn4m_subm/mag_lib/cell_1w_1r.mag
new file mode 100644
index 00000000..9aec1c5d
--- /dev/null
+++ b/technology/scn4m_subm/mag_lib/cell_1w_1r.mag
@@ -0,0 +1,142 @@
+magic
+tech scmos
+timestamp 1542220294
+<< nwell >>
+rect 0 46 54 75
+<< pwell >>
+rect 0 0 54 46
+<< ntransistor >>
+rect 14 33 16 37
+rect 22 29 24 37
+rect 30 29 32 37
+rect 38 33 40 37
+rect 14 17 16 23
+rect 22 17 24 23
+rect 30 17 32 23
+rect 38 17 40 23
+<< ptransistor >>
+rect 22 54 24 57
+rect 30 54 32 57
+<< ndiffusion >>
+rect 13 33 14 37
+rect 16 33 17 37
+rect 21 33 22 37
+rect 17 29 22 33
+rect 24 29 25 37
+rect 29 29 30 37
+rect 32 33 33 37
+rect 37 33 38 37
+rect 40 33 41 37
+rect 32 29 37 33
+rect 9 21 14 23
+rect 13 17 14 21
+rect 16 17 22 23
+rect 24 17 25 23
+rect 29 17 30 23
+rect 32 17 38 23
+rect 40 21 45 23
+rect 40 17 41 21
+<< pdiffusion >>
+rect 21 54 22 57
+rect 24 54 25 57
+rect 29 54 30 57
+rect 32 54 33 57
+<< ndcontact >>
+rect 9 33 13 37
+rect 17 33 21 37
+rect 25 29 29 37
+rect 33 33 37 37
+rect 41 33 45 37
+rect 25 17 29 23
+<< pdcontact >>
+rect 17 54 21 58
+rect 33 54 37 58
+<< psubstratepcontact >>
+rect 25 9 29 13
+<< polysilicon >>
+rect 22 57 24 60
+rect 30 57 32 60
+rect 22 44 24 54
+rect 30 51 32 54
+rect 31 47 32 51
+rect 14 37 16 44
+rect 22 40 23 44
+rect 22 37 24 40
+rect 30 37 32 47
+rect 38 37 40 44
+rect 14 31 16 33
+rect 38 31 40 33
+rect 14 23 16 24
+rect 22 23 24 29
+rect 30 23 32 29
+rect 38 23 40 24
+rect 14 15 16 17
+rect 22 15 24 17
+rect 30 15 32 17
+rect 38 15 40 17
+<< polycontact >>
+rect 27 47 31 51
+rect 10 40 14 44
+rect 23 40 27 44
+rect 40 40 44 44
+rect 12 24 16 28
+rect 38 24 42 28
+<< metal1 >>
+rect 0 68 25 72
+rect 29 68 54 72
+rect 0 61 54 65
+rect 10 44 14 61
+rect 17 51 20 54
+rect 17 47 27 51
+rect 17 37 20 47
+rect 34 44 37 54
+rect 27 40 37 44
+rect 40 44 44 61
+rect 34 37 37 40
+rect 6 33 9 37
+rect 45 33 48 37
+rect 25 23 29 29
+rect 25 13 29 17
+rect 0 9 25 13
+rect 29 9 54 13
+rect 0 2 16 6
+rect 20 2 34 6
+rect 38 2 54 6
+<< m2contact >>
+rect 2 33 6 37
+rect 48 33 52 37
+rect 16 24 20 28
+rect 34 24 38 28
+rect 16 2 20 6
+rect 34 2 38 6
+<< pdm12contact >>
+rect 25 54 29 58
+<< ndm12contact >>
+rect 9 17 13 21
+rect 41 17 45 21
+<< nsm12contact >>
+rect 25 68 29 72
+<< metal2 >>
+rect 2 37 6 72
+rect 2 0 6 33
+rect 9 21 13 72
+rect 25 58 29 68
+rect 9 0 13 17
+rect 16 6 20 24
+rect 34 6 38 24
+rect 41 21 45 72
+rect 41 0 45 17
+rect 48 37 52 72
+rect 48 0 52 33
+<< comment >>
+rect 0 0 54 70
+<< labels >>
+rlabel metal1 19 63 19 63 1 wl0
+rlabel metal1 19 70 19 70 5 vdd
+rlabel metal1 27 4 27 4 1 wl1
+rlabel psubstratepcontact 27 11 27 11 1 gnd
+rlabel metal2 4 7 4 7 2 bl0
+rlabel metal2 11 7 11 7 1 bl1
+rlabel metal2 43 7 43 7 1 br1
+rlabel metal2 50 7 50 7 8 br0
+<< end >>
diff --git a/technology/scn4m_subm/mag_lib/cell_6t.mag b/technology/scn4m_subm/mag_lib/cell_6t.mag
index f2e9906a..bb9d943d 100644
--- a/technology/scn4m_subm/mag_lib/cell_6t.mag
+++ b/technology/scn4m_subm/mag_lib/cell_6t.mag
@@ -1,117 +1,118 @@
magic
tech scmos
-timestamp 1536091415
+timestamp 1560809302
<< nwell >>
-rect -8 29 42 51
+rect -8 35 42 57
<< pwell >>
-rect -8 -8 42 29
+rect -8 -2 42 35
<< ntransistor >>
-rect 7 10 9 18
-rect 29 10 31 18
-rect 10 3 14 5
-rect 24 3 28 5
+rect 7 16 9 24
+rect 29 16 31 24
+rect 10 9 14 11
+rect 24 9 28 11
<< ptransistor >>
-rect 7 37 11 40
-rect 27 37 31 40
+rect 7 43 11 46
+rect 27 43 31 46
<< ndiffusion >>
+rect -2 22 7 24
+rect 2 18 7 22
rect -2 16 7 18
-rect 2 12 7 16
-rect -2 10 7 12
-rect 9 14 10 18
-rect 9 10 14 14
-rect 28 14 29 18
-rect 24 10 29 14
+rect 9 20 10 24
+rect 9 16 14 20
+rect 28 20 29 24
+rect 24 16 29 20
+rect 31 22 36 24
+rect 31 18 32 22
rect 31 16 36 18
-rect 31 12 32 16
-rect 31 10 36 12
-rect 10 5 14 10
-rect 24 5 28 10
-rect 10 2 14 3
-rect 24 2 28 3
+rect 10 11 14 16
+rect 24 11 28 16
+rect 10 8 14 9
+rect 24 8 28 9
<< pdiffusion >>
-rect 2 37 7 40
-rect 11 37 12 40
-rect 26 37 27 40
-rect 31 37 32 40
+rect 2 43 7 46
+rect 11 43 12 46
+rect 26 43 27 46
+rect 31 43 32 46
<< ndcontact >>
-rect -2 12 2 16
-rect 10 14 14 18
-rect 24 14 28 18
-rect 32 12 36 16
-rect 10 -2 14 2
-rect 24 -2 28 2
+rect -2 18 2 22
+rect 10 20 14 24
+rect 24 20 28 24
+rect 32 18 36 22
+rect 10 4 14 8
+rect 24 4 28 8
<< pdcontact >>
-rect -2 36 2 40
-rect 12 36 16 40
-rect 22 36 26 40
-rect 32 36 36 40
+rect -2 42 2 46
+rect 12 42 16 46
+rect 22 42 26 46
+rect 32 42 36 46
<< psubstratepcontact >>
-rect -2 22 2 26
-rect 32 22 36 26
+rect -2 28 2 32
+rect 32 28 36 32
<< nsubstratencontact >>
-rect 32 44 36 48
+rect 32 50 36 54
<< polysilicon >>
-rect 7 40 11 42
-rect 27 40 31 42
-rect 7 35 11 37
-rect 7 21 9 35
-rect 27 34 31 37
-rect 15 33 31 34
-rect 19 32 31 33
-rect 7 20 21 21
-rect 7 19 24 20
-rect 7 18 9 19
-rect 29 18 31 32
-rect 7 8 9 10
-rect 17 5 21 6
-rect 29 8 31 10
-rect -2 3 10 5
-rect 14 3 24 5
-rect 28 3 36 5
+rect 7 46 11 48
+rect 27 46 31 48
+rect 7 41 11 43
+rect 7 27 9 41
+rect 27 40 31 43
+rect 15 39 31 40
+rect 19 38 31 39
+rect 7 26 21 27
+rect 7 25 24 26
+rect 7 24 9 25
+rect 29 24 31 38
+rect 7 14 9 16
+rect 17 11 21 12
+rect 29 14 31 16
+rect -2 9 10 11
+rect 14 9 24 11
+rect 28 9 36 11
<< polycontact >>
-rect 15 29 19 33
-rect 21 20 25 24
-rect 17 6 21 10
+rect 15 35 19 39
+rect 21 26 25 30
+rect 17 12 21 16
<< metal1 >>
-rect -2 44 15 48
-rect 19 44 32 48
-rect -2 40 2 44
-rect 32 40 36 44
-rect 11 36 12 40
-rect 26 36 27 40
-rect -2 26 2 29
-rect -2 16 2 22
-rect 11 18 15 36
-rect 23 24 27 36
-rect 25 20 27 24
-rect 14 14 15 18
-rect 23 18 27 20
-rect 32 26 36 29
-rect 23 14 24 18
-rect 32 16 36 22
-rect -2 6 17 9
-rect 21 6 36 9
-rect -2 5 36 6
+rect -2 50 15 54
+rect 19 50 32 54
+rect -2 46 2 50
+rect 32 46 36 50
+rect 11 42 12 46
+rect 26 42 27 46
+rect -2 32 2 35
+rect -2 22 2 28
+rect 11 24 15 42
+rect 23 30 27 42
+rect 25 26 27 30
+rect 14 20 15 24
+rect 23 24 27 26
+rect 32 32 36 35
+rect 23 20 24 24
+rect 32 22 36 28
+rect -2 12 17 15
+rect 21 12 36 15
+rect -2 11 36 12
<< m2contact >>
-rect 15 44 19 48
-rect -2 29 2 33
-rect 32 29 36 33
-rect 6 -2 10 2
-rect 20 -2 24 2
+rect 15 50 19 54
+rect -2 35 2 39
+rect 32 35 36 39
+rect 6 4 10 8
+rect 20 4 24 8
<< metal2 >>
-rect -2 33 2 48
-rect -2 -2 2 29
-rect 6 2 10 48
-rect 24 -2 28 48
-rect 32 33 36 48
-rect 32 -2 36 29
+rect -2 39 2 54
+rect -2 0 2 35
+rect 6 8 10 54
+rect 6 0 10 4
+rect 24 0 28 54
+rect 32 39 36 54
+rect 32 0 36 35
<< bb >>
-rect 0 0 34 46
+rect 0 0 34 52
<< labels >>
-rlabel metal2 0 0 0 0 1 gnd
-rlabel metal2 34 0 34 0 1 gnd
-rlabel m2contact 17 46 17 46 5 vdd
-rlabel metal2 8 43 8 43 1 bl
-rlabel metal2 26 43 26 43 1 br
-rlabel metal1 4 7 4 7 1 wl
+rlabel metal2 0 6 0 6 1 gnd
+rlabel metal2 34 6 34 6 1 gnd
+rlabel m2contact 17 52 17 52 5 vdd
+rlabel metal2 8 49 8 49 1 bl
+rlabel metal2 26 49 26 49 1 br
+rlabel metal1 4 13 4 13 1 wl
<< end >>
diff --git a/technology/scn4m_subm/mag_lib/dummy_cell_1rw_1r.mag b/technology/scn4m_subm/mag_lib/dummy_cell_1rw_1r.mag
new file mode 100644
index 00000000..60e24aca
--- /dev/null
+++ b/technology/scn4m_subm/mag_lib/dummy_cell_1rw_1r.mag
@@ -0,0 +1,136 @@
+magic
+tech scmos
+timestamp 1562188987
+<< nwell >>
+rect 0 46 54 75
+<< pwell >>
+rect 0 0 54 46
+<< ntransistor >>
+rect 14 33 16 37
+rect 22 29 24 37
+rect 30 29 32 37
+rect 38 33 40 37
+rect 14 17 16 23
+rect 22 17 24 23
+rect 30 17 32 23
+rect 38 17 40 23
+<< ptransistor >>
+rect 22 54 24 57
+rect 30 54 32 57
+<< ndiffusion >>
+rect 13 33 14 37
+rect 16 33 17 37
+rect 21 33 22 37
+rect 17 29 22 33
+rect 24 29 25 37
+rect 29 29 30 37
+rect 32 33 33 37
+rect 37 33 38 37
+rect 40 33 41 37
+rect 32 29 37 33
+rect 9 21 14 23
+rect 13 17 14 21
+rect 16 17 22 23
+rect 24 17 25 23
+rect 29 17 30 23
+rect 32 17 38 23
+rect 40 21 45 23
+rect 40 17 41 21
+<< pdiffusion >>
+rect 21 54 22 57
+rect 24 54 25 57
+rect 29 54 30 57
+rect 32 54 33 57
+<< ndcontact >>
+rect 9 33 13 37
+rect 17 33 21 37
+rect 25 29 29 37
+rect 33 33 37 37
+rect 41 33 45 37
+rect 9 17 13 21
+rect 25 17 29 23
+rect 41 17 45 21
+<< pdcontact >>
+rect 17 54 21 58
+rect 25 54 29 58
+rect 33 54 37 58
+<< psubstratepcontact >>
+rect 25 9 29 13
+<< nsubstratencontact >>
+rect 25 68 29 72
+<< polysilicon >>
+rect 22 57 24 60
+rect 30 57 32 60
+rect 22 44 24 54
+rect 30 51 32 54
+rect 31 47 32 51
+rect 14 37 16 44
+rect 22 40 23 44
+rect 22 37 24 40
+rect 30 37 32 47
+rect 38 37 40 44
+rect 14 31 16 33
+rect 38 31 40 33
+rect 14 23 16 24
+rect 22 23 24 29
+rect 30 23 32 29
+rect 38 23 40 24
+rect 14 15 16 17
+rect 22 15 24 17
+rect 30 15 32 17
+rect 38 15 40 17
+<< polycontact >>
+rect 27 47 31 51
+rect 10 40 14 44
+rect 23 40 27 44
+rect 40 40 44 44
+rect 12 24 16 28
+rect 38 24 42 28
+<< metal1 >>
+rect 0 68 25 72
+rect 29 68 54 72
+rect 0 61 54 65
+rect 10 44 14 61
+rect 17 51 20 54
+rect 17 47 27 51
+rect 17 37 20 47
+rect 34 44 37 54
+rect 27 40 37 44
+rect 40 44 44 61
+rect 34 37 37 40
+rect 2 33 9 37
+rect 45 33 52 37
+rect 25 23 29 29
+rect 25 13 29 17
+rect 0 9 25 13
+rect 29 9 54 13
+rect 0 2 16 6
+rect 20 2 34 6
+rect 38 2 54 6
+<< m2contact >>
+rect 25 68 29 72
+rect 25 54 29 58
+rect 16 24 20 28
+rect 34 24 38 28
+rect 16 2 20 6
+rect 34 2 38 6
+<< metal2 >>
+rect 2 0 6 72
+rect 9 0 13 72
+rect 25 58 29 68
+rect 16 6 20 24
+rect 34 6 38 24
+rect 41 0 45 72
+rect 48 0 52 72
+<< comment >>
+rect 0 0 54 70
+<< labels >>
+rlabel metal1 19 63 19 63 1 wl0
+rlabel metal1 19 70 19 70 5 vdd
+rlabel metal1 27 4 27 4 1 wl1
+rlabel psubstratepcontact 27 11 27 11 1 gnd
+rlabel metal2 4 7 4 7 2 bl0
+rlabel metal2 11 7 11 7 1 bl1
+rlabel metal2 43 7 43 7 1 br1
+rlabel metal2 50 7 50 7 8 br0
+<< end >>
diff --git a/technology/scn4m_subm/mag_lib/dummy_cell_1w_1r.mag b/technology/scn4m_subm/mag_lib/dummy_cell_1w_1r.mag
new file mode 100644
index 00000000..03e49f03
--- /dev/null
+++ b/technology/scn4m_subm/mag_lib/dummy_cell_1w_1r.mag
@@ -0,0 +1,136 @@
+magic
+tech scmos
+timestamp 1562189027
+<< nwell >>
+rect 0 46 54 75
+<< pwell >>
+rect 0 0 54 46
+<< ntransistor >>
+rect 14 33 16 37
+rect 22 29 24 37
+rect 30 29 32 37
+rect 38 33 40 37
+rect 14 17 16 23
+rect 22 17 24 23
+rect 30 17 32 23
+rect 38 17 40 23
+<< ptransistor >>
+rect 22 54 24 57
+rect 30 54 32 57
+<< ndiffusion >>
+rect 13 33 14 37
+rect 16 33 17 37
+rect 21 33 22 37
+rect 17 29 22 33
+rect 24 29 25 37
+rect 29 29 30 37
+rect 32 33 33 37
+rect 37 33 38 37
+rect 40 33 41 37
+rect 32 29 37 33
+rect 9 21 14 23
+rect 13 17 14 21
+rect 16 17 22 23
+rect 24 17 25 23
+rect 29 17 30 23
+rect 32 17 38 23
+rect 40 21 45 23
+rect 40 17 41 21
+<< pdiffusion >>
+rect 21 54 22 57
+rect 24 54 25 57
+rect 29 54 30 57
+rect 32 54 33 57
+<< ndcontact >>
+rect 9 33 13 37
+rect 17 33 21 37
+rect 25 29 29 37
+rect 33 33 37 37
+rect 41 33 45 37
+rect 9 17 13 21
+rect 25 17 29 23
+rect 41 17 45 21
+<< pdcontact >>
+rect 17 54 21 58
+rect 25 54 29 58
+rect 33 54 37 58
+<< psubstratepcontact >>
+rect 25 9 29 13
+<< nsubstratencontact >>
+rect 25 68 29 72
+<< polysilicon >>
+rect 22 57 24 60
+rect 30 57 32 60
+rect 22 44 24 54
+rect 30 51 32 54
+rect 31 47 32 51
+rect 14 37 16 44
+rect 22 40 23 44
+rect 22 37 24 40
+rect 30 37 32 47
+rect 38 37 40 44
+rect 14 31 16 33
+rect 38 31 40 33
+rect 14 23 16 24
+rect 22 23 24 29
+rect 30 23 32 29
+rect 38 23 40 24
+rect 14 15 16 17
+rect 22 15 24 17
+rect 30 15 32 17
+rect 38 15 40 17
+<< polycontact >>
+rect 27 47 31 51
+rect 10 40 14 44
+rect 23 40 27 44
+rect 40 40 44 44
+rect 12 24 16 28
+rect 38 24 42 28
+<< metal1 >>
+rect 0 68 25 72
+rect 29 68 54 72
+rect 0 61 54 65
+rect 10 44 14 61
+rect 17 51 20 54
+rect 17 47 27 51
+rect 17 37 20 47
+rect 34 44 37 54
+rect 27 40 37 44
+rect 40 44 44 61
+rect 34 37 37 40
+rect 2 33 9 37
+rect 45 33 52 37
+rect 25 23 29 29
+rect 25 13 29 17
+rect 0 9 25 13
+rect 29 9 54 13
+rect 0 2 16 6
+rect 20 2 34 6
+rect 38 2 54 6
+<< m2contact >>
+rect 25 68 29 72
+rect 25 54 29 58
+rect 16 24 20 28
+rect 34 24 38 28
+rect 16 2 20 6
+rect 34 2 38 6
+<< metal2 >>
+rect 2 0 6 72
+rect 9 0 13 72
+rect 25 58 29 68
+rect 16 6 20 24
+rect 34 6 38 24
+rect 41 0 45 72
+rect 48 0 52 72
+<< comment >>
+rect 0 0 54 70
+<< labels >>
+rlabel metal1 19 63 19 63 1 wl0
+rlabel metal1 19 70 19 70 5 vdd
+rlabel metal1 27 4 27 4 1 wl1
+rlabel psubstratepcontact 27 11 27 11 1 gnd
+rlabel metal2 4 7 4 7 2 bl0
+rlabel metal2 11 7 11 7 1 bl1
+rlabel metal2 43 7 43 7 1 br1
+rlabel metal2 50 7 50 7 8 br0
+<< end >>
diff --git a/technology/scn4m_subm/mag_lib/dummy_cell_6t.mag b/technology/scn4m_subm/mag_lib/dummy_cell_6t.mag
new file mode 100644
index 00000000..74562f15
--- /dev/null
+++ b/technology/scn4m_subm/mag_lib/dummy_cell_6t.mag
@@ -0,0 +1,115 @@
+magic
+tech scmos
+timestamp 1560809362
+<< nwell >>
+rect -8 35 42 57
+<< pwell >>
+rect -8 -2 42 35
+<< ntransistor >>
+rect 7 16 9 24
+rect 29 16 31 24
+rect 10 9 14 11
+rect 24 9 28 11
+<< ptransistor >>
+rect 7 43 11 46
+rect 27 43 31 46
+<< ndiffusion >>
+rect -2 22 7 24
+rect 2 18 7 22
+rect -2 16 7 18
+rect 9 20 10 24
+rect 9 16 14 20
+rect 28 20 29 24
+rect 24 16 29 20
+rect 31 22 36 24
+rect 31 18 32 22
+rect 31 16 36 18
+rect 10 11 14 16
+rect 24 11 28 16
+rect 10 8 14 9
+rect 24 8 28 9
+<< pdiffusion >>
+rect 2 43 7 46
+rect 11 43 12 46
+rect 26 43 27 46
+rect 31 43 32 46
+<< ndcontact >>
+rect -2 18 2 22
+rect 10 20 14 24
+rect 24 20 28 24
+rect 32 18 36 22
+rect 10 4 14 8
+rect 24 4 28 8
+<< pdcontact >>
+rect -2 42 2 46
+rect 12 42 16 46
+rect 22 42 26 46
+rect 32 42 36 46
+<< psubstratepcontact >>
+rect -2 28 2 32
+rect 32 28 36 32
+<< nsubstratencontact >>
+rect 32 50 36 54
+<< polysilicon >>
+rect 7 46 11 48
+rect 27 46 31 48
+rect 7 41 11 43
+rect 7 27 9 41
+rect 27 40 31 43
+rect 15 39 31 40
+rect 19 38 31 39
+rect 7 26 21 27
+rect 7 25 24 26
+rect 7 24 9 25
+rect 29 24 31 38
+rect 7 14 9 16
+rect 17 11 21 12
+rect 29 14 31 16
+rect -2 9 10 11
+rect 14 9 24 11
+rect 28 9 36 11
+<< polycontact >>
+rect 15 35 19 39
+rect 21 26 25 30
+rect 17 12 21 16
+<< metal1 >>
+rect -2 50 15 54
+rect 19 50 32 54
+rect -2 46 2 50
+rect 32 46 36 50
+rect 11 42 12 46
+rect 26 42 27 46
+rect -2 32 2 35
+rect -2 22 2 28
+rect 11 24 15 42
+rect 23 30 27 42
+rect 25 26 27 30
+rect 14 20 15 24
+rect 23 24 27 26
+rect 32 32 36 35
+rect 23 20 24 24
+rect 32 22 36 28
+rect -2 12 17 15
+rect 21 12 36 15
+rect -2 11 36 12
+<< m2contact >>
+rect 15 50 19 54
+rect -2 35 2 39
+rect 32 35 36 39
+<< metal2 >>
+rect -2 39 2 54
+rect -2 0 2 35
+rect 6 0 10 54
+rect 24 0 28 54
+rect 32 39 36 54
+rect 32 0 36 35
+<< bb >>
+rect 0 0 34 52
+<< labels >>
+rlabel metal2 0 6 0 6 1 gnd
+rlabel metal2 34 6 34 6 1 gnd
+rlabel m2contact 17 52 17 52 5 vdd
+rlabel metal2 8 49 8 49 1 bl
+rlabel metal2 26 49 26 49 1 br
+rlabel metal1 4 13 4 13 1 wl
+<< end >>
diff --git a/technology/scn4m_subm/mag_lib/replica_cell_1w_1r.mag b/technology/scn4m_subm/mag_lib/replica_cell_1w_1r.mag
new file mode 100644
index 00000000..f215ff04
--- /dev/null
+++ b/technology/scn4m_subm/mag_lib/replica_cell_1w_1r.mag
@@ -0,0 +1,145 @@
+magic
+tech scmos
+timestamp 1542221056
+<< nwell >>
+rect 0 46 54 75
+<< pwell >>
+rect 0 0 54 46
+<< ntransistor >>
+rect 14 33 16 37
+rect 22 29 24 37
+rect 30 29 32 37
+rect 38 33 40 37
+rect 14 17 16 23
+rect 22 17 24 23
+rect 30 17 32 23
+rect 38 17 40 23
+<< ptransistor >>
+rect 22 54 24 57
+rect 30 54 32 57
+<< ndiffusion >>
+rect 13 33 14 37
+rect 16 33 17 37
+rect 21 33 22 37
+rect 17 29 22 33
+rect 24 29 25 37
+rect 29 29 30 37
+rect 32 33 33 37
+rect 37 33 38 37
+rect 40 33 41 37
+rect 32 29 37 33
+rect 9 21 14 23
+rect 13 17 14 21
+rect 16 17 22 23
+rect 24 17 25 23
+rect 29 17 30 23
+rect 32 17 38 23
+rect 40 21 45 23
+rect 40 17 41 21
+<< pdiffusion >>
+rect 21 54 22 57
+rect 24 54 25 57
+rect 29 54 30 57
+rect 32 54 33 57
+<< ndcontact >>
+rect 9 33 13 37
+rect 17 33 21 37
+rect 25 29 29 37
+rect 33 33 37 37
+rect 41 33 45 37
+rect 9 17 13 21
+rect 25 17 29 23
+rect 41 17 45 21
+<< pdcontact >>
+rect 17 54 21 58
+rect 25 54 29 58
+rect 33 54 37 58
+<< psubstratepcontact >>
+rect 25 9 29 13
+<< nsubstratencontact >>
+rect 25 68 29 72
+<< polysilicon >>
+rect 22 57 24 60
+rect 30 57 32 60
+rect 22 44 24 54
+rect 30 51 32 54
+rect 31 47 32 51
+rect 14 37 16 44
+rect 22 40 23 44
+rect 22 37 24 40
+rect 30 37 32 47
+rect 38 37 40 44
+rect 14 31 16 33
+rect 38 31 40 33
+rect 14 23 16 24
+rect 22 23 24 29
+rect 30 23 32 29
+rect 38 23 40 24
+rect 14 15 16 17
+rect 22 15 24 17
+rect 30 15 32 17
+rect 38 15 40 17
+<< polycontact >>
+rect 27 47 31 51
+rect 10 40 14 44
+rect 23 40 27 44
+rect 40 40 44 44
+rect 12 24 16 28
+rect 38 24 42 28
+<< metal1 >>
+rect 0 68 25 72
+rect 29 68 54 72
+rect 0 61 54 65
+rect 10 44 14 61
+rect 29 54 33 58
+rect 17 51 20 54
+rect 17 47 27 51
+rect 17 37 20 47
+rect 34 44 37 54
+rect 27 40 37 44
+rect 40 44 44 61
+rect 34 37 37 40
+rect 6 33 9 37
+rect 45 33 48 37
+rect 25 23 29 29
+rect 25 13 29 17
+rect 0 9 25 13
+rect 29 9 54 13
+rect 0 2 16 6
+rect 20 2 34 6
+rect 38 2 54 6
+<< m2contact >>
+rect 25 68 29 72
+rect 25 54 29 58
+rect 2 33 6 37
+rect 48 33 52 37
+rect 16 24 20 28
+rect 34 24 38 28
+rect 9 17 13 21
+rect 41 17 45 21
+rect 16 2 20 6
+rect 34 2 38 6
+<< metal2 >>
+rect 2 37 6 72
+rect 2 0 6 33
+rect 9 21 13 72
+rect 25 58 29 68
+rect 9 0 13 17
+rect 16 6 20 24
+rect 34 6 38 24
+rect 41 21 45 72
+rect 41 0 45 17
+rect 48 37 52 72
+rect 48 0 52 33
+<< comment >>
+rect 0 0 54 70
+<< labels >>
+rlabel metal1 19 63 19 63 1 wl0
+rlabel metal1 19 70 19 70 5 vdd
+rlabel metal1 27 4 27 4 1 wl1
+rlabel psubstratepcontact 27 11 27 11 1 gnd
+rlabel metal2 4 7 4 7 2 bl0
+rlabel metal2 11 7 11 7 1 bl1
+rlabel metal2 43 7 43 7 1 br1
+rlabel metal2 50 7 50 7 8 br0
+<< end >>
diff --git a/technology/scn4m_subm/mag_lib/replica_cell_6t.mag b/technology/scn4m_subm/mag_lib/replica_cell_6t.mag
index c28cb2c6..b5a5f7b8 100644
--- a/technology/scn4m_subm/mag_lib/replica_cell_6t.mag
+++ b/technology/scn4m_subm/mag_lib/replica_cell_6t.mag
@@ -1,118 +1,119 @@
magic
tech scmos
-timestamp 1541443051
+timestamp 1560809329
<< nwell >>
-rect -8 29 42 51
+rect -8 35 42 57
<< pwell >>
-rect -8 -8 42 29
+rect -8 -2 42 35
<< ntransistor >>
-rect 7 10 9 18
-rect 29 10 31 18
-rect 10 3 14 5
-rect 24 3 28 5
+rect 7 16 9 24
+rect 29 16 31 24
+rect 10 9 14 11
+rect 24 9 28 11
<< ptransistor >>
-rect 7 37 11 40
-rect 27 37 31 40
+rect 7 43 11 46
+rect 27 43 31 46
<< ndiffusion >>
+rect -2 22 7 24
+rect 2 18 7 22
rect -2 16 7 18
-rect 2 12 7 16
-rect -2 10 7 12
-rect 9 14 10 18
-rect 9 10 14 14
-rect 28 14 29 18
-rect 24 10 29 14
+rect 9 20 10 24
+rect 9 16 14 20
+rect 28 20 29 24
+rect 24 16 29 20
+rect 31 22 36 24
+rect 31 18 32 22
rect 31 16 36 18
-rect 31 12 32 16
-rect 31 10 36 12
-rect 10 5 14 10
-rect 24 5 28 10
-rect 10 2 14 3
-rect 24 2 28 3
+rect 10 11 14 16
+rect 24 11 28 16
+rect 10 8 14 9
+rect 24 8 28 9
<< pdiffusion >>
-rect 2 37 7 40
-rect 11 37 12 40
-rect 26 37 27 40
-rect 31 37 32 40
+rect 2 43 7 46
+rect 11 43 12 46
+rect 26 43 27 46
+rect 31 43 32 46
<< ndcontact >>
-rect -2 12 2 16
-rect 10 14 14 18
-rect 24 14 28 18
-rect 32 12 36 16
-rect 10 -2 14 2
-rect 24 -2 28 2
+rect -2 18 2 22
+rect 10 20 14 24
+rect 24 20 28 24
+rect 32 18 36 22
+rect 10 4 14 8
+rect 24 4 28 8
<< pdcontact >>
-rect -2 36 2 40
-rect 12 36 16 40
-rect 22 36 26 40
-rect 32 36 36 40
+rect -2 42 2 46
+rect 12 42 16 46
+rect 22 42 26 46
+rect 32 42 36 46
<< psubstratepcontact >>
-rect -2 22 2 26
-rect 32 22 36 26
+rect -2 28 2 32
+rect 32 28 36 32
<< nsubstratencontact >>
-rect 32 44 36 48
+rect 32 50 36 54
<< polysilicon >>
-rect 7 40 11 42
-rect 27 40 31 42
-rect 7 35 11 37
-rect 7 21 9 35
-rect 27 34 31 37
-rect 15 33 31 34
-rect 19 32 31 33
-rect 7 20 21 21
-rect 7 19 24 20
-rect 7 18 9 19
-rect 29 18 31 32
-rect 7 8 9 10
-rect 17 5 21 6
-rect 29 8 31 10
-rect -2 3 10 5
-rect 14 3 24 5
-rect 28 3 36 5
+rect 7 46 11 48
+rect 27 46 31 48
+rect 7 41 11 43
+rect 7 27 9 41
+rect 27 40 31 43
+rect 15 39 31 40
+rect 19 38 31 39
+rect 7 26 21 27
+rect 7 25 24 26
+rect 7 24 9 25
+rect 29 24 31 38
+rect 7 14 9 16
+rect 17 11 21 12
+rect 29 14 31 16
+rect -2 9 10 11
+rect 14 9 24 11
+rect 28 9 36 11
<< polycontact >>
-rect 15 29 19 33
-rect 21 20 25 24
-rect 17 6 21 10
+rect 15 35 19 39
+rect 21 26 25 30
+rect 17 12 21 16
<< metal1 >>
-rect -2 44 15 48
-rect 19 44 32 48
-rect -2 40 2 44
-rect 22 40 26 44
-rect 32 40 36 44
-rect 11 36 12 40
-rect 26 36 27 40
-rect -2 26 2 29
-rect -2 16 2 22
-rect 11 18 15 36
-rect 23 24 27 36
-rect 25 20 27 24
-rect 14 14 15 18
-rect 23 18 27 20
-rect 32 26 36 29
-rect 23 14 24 18
-rect 32 16 36 22
-rect -2 6 17 9
-rect 21 6 36 9
-rect -2 5 36 6
+rect -2 50 15 54
+rect 19 50 32 54
+rect -2 46 2 50
+rect 22 46 26 50
+rect 32 46 36 50
+rect 11 42 12 46
+rect 26 42 27 46
+rect -2 32 2 35
+rect -2 22 2 28
+rect 11 24 15 42
+rect 23 30 27 42
+rect 25 26 27 30
+rect 14 20 15 24
+rect 23 24 27 26
+rect 32 32 36 35
+rect 23 20 24 24
+rect 32 22 36 28
+rect -2 12 17 15
+rect 21 12 36 15
+rect -2 11 36 12
<< m2contact >>
-rect 15 44 19 48
-rect -2 29 2 33
-rect 32 29 36 33
-rect 6 -2 10 2
-rect 20 -2 24 2
+rect 15 50 19 54
+rect -2 35 2 39
+rect 32 35 36 39
+rect 6 4 10 8
+rect 20 4 24 8
<< metal2 >>
-rect -2 33 2 48
-rect -2 -2 2 29
-rect 6 2 10 48
-rect 24 -2 28 48
-rect 32 33 36 48
-rect 32 -2 36 29
+rect -2 39 2 54
+rect -2 0 2 35
+rect 6 8 10 54
+rect 6 0 10 4
+rect 24 0 28 54
+rect 32 39 36 54
+rect 32 0 36 35
<< bb >>
-rect 0 0 34 46
+rect 0 0 34 52
<< labels >>
-rlabel metal2 0 0 0 0 1 gnd
-rlabel metal2 34 0 34 0 1 gnd
-rlabel m2contact 17 46 17 46 5 vdd
-rlabel metal2 8 43 8 43 1 bl
-rlabel metal2 26 43 26 43 1 br
-rlabel metal1 4 7 4 7 1 wl
+rlabel metal2 0 6 0 6 1 gnd
+rlabel metal2 34 6 34 6 1 gnd
+rlabel m2contact 17 52 17 52 5 vdd
+rlabel metal2 8 49 8 49 1 bl
+rlabel metal2 26 49 26 49 1 br
+rlabel metal1 4 13 4 13 1 wl
<< end >>
diff --git a/technology/scn4m_subm/mag_lib/setup.tcl b/technology/scn4m_subm/mag_lib/setup.tcl
index 084428b5..95e7dbea 100644
--- a/technology/scn4m_subm/mag_lib/setup.tcl
+++ b/technology/scn4m_subm/mag_lib/setup.tcl
@@ -2,14 +2,13 @@
ignore class c
equate class {-circuit1 nfet} {-circuit2 n}
equate class {-circuit1 pfet} {-circuit2 p}
-# This circuit has symmetries and needs to be flattened to resolve them
-# or the banks won't pass
+# We must flatten these because the ports are disconnected
+flatten class {-circuit1 dummy_cell_6t}
+flatten class {-circuit1 dummy_cell_1rw_1r}
+flatten class {-circuit1 dummy_cell_1w_1r}
flatten class {-circuit1 bitcell_array_0}
-flatten class {-circuit1 bitcell_array_1}
-flatten class {-circuit1 precharge_array_0}
-flatten class {-circuit1 precharge_array_1}
-flatten class {-circuit1 precharge_array_2}
-flatten class {-circuit1 precharge_array_3}
+flatten class {-circuit1 pbitcell_0}
+flatten class {-circuit1 pbitcell_1}
property {-circuit1 nfet} remove as ad ps pd
property {-circuit1 pfet} remove as ad ps pd
property {-circuit2 n} remove as ad ps pd
diff --git a/technology/scn4m_subm/mag_lib/write_driver.mag b/technology/scn4m_subm/mag_lib/write_driver.mag
index ab2014aa..0aa48197 100644
--- a/technology/scn4m_subm/mag_lib/write_driver.mag
+++ b/technology/scn4m_subm/mag_lib/write_driver.mag
@@ -1,16 +1,15 @@
magic
tech scmos
-timestamp 1536089714
+timestamp 1565304081
<< nwell >>
rect -3 101 37 138
rect -3 0 37 51
<< pwell >>
-rect -3 138 37 202
+rect -3 138 37 203
rect -3 51 37 101
<< ntransistor >>
-rect 9 177 11 189
-rect 17 177 19 189
-rect 15 162 27 164
+rect 9 178 11 190
+rect 17 178 19 190
rect 9 144 11 148
rect 17 144 19 148
rect 10 82 12 89
@@ -27,14 +26,10 @@ rect 8 38 10 45
rect 16 38 18 45
rect 24 38 26 45
<< ndiffusion >>
-rect 8 177 9 189
-rect 11 177 12 189
-rect 16 177 17 189
-rect 19 177 20 189
-rect 15 164 27 165
-rect 15 161 27 162
-rect 12 157 15 160
-rect 12 156 16 157
+rect 8 178 9 190
+rect 11 178 12 190
+rect 16 178 17 190
+rect 19 178 20 190
rect 8 144 9 148
rect 11 144 12 148
rect 16 144 17 148
@@ -43,7 +38,7 @@ rect 9 82 10 89
rect 12 82 13 89
rect 17 82 18 89
rect 20 82 21 89
-rect 25 82 26 86
+rect 25 82 26 89
rect 7 57 8 64
rect 10 57 11 64
rect 15 57 16 64
@@ -68,11 +63,9 @@ rect 23 38 24 45
rect 26 38 27 45
rect 3 35 7 38
<< ndcontact >>
-rect 4 177 8 189
-rect 12 177 16 189
-rect 20 177 24 189
-rect 15 165 27 169
-rect 15 157 27 161
+rect 4 178 8 190
+rect 12 178 16 190
+rect 20 178 24 190
rect 4 144 8 148
rect 12 144 16 148
rect 20 144 24 148
@@ -95,22 +88,19 @@ rect 11 38 15 45
rect 19 38 23 45
rect 27 38 31 45
<< psubstratepcontact >>
-rect 12 152 16 156
-rect 26 82 30 86
+rect 26 82 30 89
<< nsubstratencontact >>
rect 12 118 16 122
rect 3 31 7 35
<< polysilicon >>
-rect 9 194 30 196
-rect 9 189 11 194
-rect 17 189 19 191
-rect 28 185 30 194
-rect 9 175 11 177
-rect 17 172 19 177
-rect 6 170 19 172
-rect 6 167 8 170
-rect 13 162 15 164
-rect 27 162 33 164
+rect 9 195 30 197
+rect 9 190 11 195
+rect 17 190 19 192
+rect 28 186 30 195
+rect 9 176 11 178
+rect 17 173 19 178
+rect 6 171 19 173
+rect 6 168 8 171
rect 9 148 11 150
rect 17 148 19 150
rect 9 132 11 144
@@ -133,12 +123,9 @@ rect 18 89 20 90
rect 10 81 12 82
rect 10 79 13 81
rect 2 71 3 75
-rect 11 71 13 79
+rect 11 67 13 79
rect 18 79 20 82
rect 18 77 23 79
-rect 31 71 33 162
-rect 11 69 33 71
-rect 11 67 13 69
rect 8 65 13 67
rect 8 64 10 65
rect 16 64 18 66
@@ -153,26 +140,23 @@ rect 8 28 10 38
rect 16 14 18 38
rect 24 36 26 38
<< polycontact >>
-rect 28 181 32 185
-rect 4 163 8 167
+rect 28 182 32 186
+rect 4 164 8 168
rect 23 96 27 100
rect 3 71 7 75
rect 23 75 27 79
rect 7 24 11 28
rect 15 10 19 14
<< metal1 >>
-rect 5 192 10 196
-rect 5 189 8 192
-rect 32 181 33 185
-rect 13 169 16 177
-rect 13 165 15 169
-rect 4 148 8 163
-rect 12 157 15 161
-rect 12 156 16 157
-rect 12 148 16 152
+rect 5 193 10 197
+rect 5 190 8 193
+rect 32 182 33 186
+rect 4 148 8 164
+rect 12 163 16 178
+rect 12 148 16 159
rect 4 132 8 144
rect 20 142 24 144
-rect 30 142 33 181
+rect 30 142 33 182
rect 20 138 33 142
rect 20 132 24 138
rect 12 122 16 125
@@ -193,32 +177,33 @@ rect 27 45 31 60
rect 3 35 7 38
rect 19 35 23 38
rect 7 31 19 35
-rect 0 24 7 28
-rect 11 24 36 28
+rect 3 24 7 28
+rect 11 24 31 28
<< m2contact >>
-rect 10 192 14 196
-rect 20 189 24 193
-rect 23 153 27 157
+rect 10 193 14 197
+rect 20 190 24 194
+rect 12 159 16 163
rect 16 118 20 122
-rect 26 86 30 90
+rect 26 89 30 90
+rect 26 86 30 89
rect 19 64 23 68
rect 19 31 23 35
rect 15 6 19 10
<< metal2 >>
-rect 10 196 14 202
-rect 20 193 24 202
-rect 20 177 24 189
+rect 10 197 14 203
+rect 20 194 24 203
+rect 20 178 24 190
rect 15 0 19 6
<< bb >>
-rect 0 0 34 202
+rect 0 0 34 203
<< labels >>
rlabel metal2 15 1 15 1 1 din
-rlabel metal1 2 25 2 25 3 en
-rlabel metal2 12 200 12 200 5 bl
-rlabel metal2 22 200 22 200 5 br
rlabel m2contact 21 66 21 66 1 gnd
rlabel m2contact 28 88 28 88 1 gnd
rlabel m2contact 21 33 21 33 1 vdd
rlabel m2contact 18 120 18 120 1 vdd
-rlabel m2contact 25 155 25 155 1 gnd
+rlabel metal2 12 201 12 201 5 bl
+rlabel metal2 22 201 22 201 5 br
+rlabel m2contact 14 161 14 161 1 gnd
+rlabel metal1 17 26 17 26 1 en
<< end >>
diff --git a/technology/scn4m_subm/sp_lib/dummy_cell_1rw_1r.sp b/technology/scn4m_subm/sp_lib/dummy_cell_1rw_1r.sp
new file mode 100644
index 00000000..9766a840
--- /dev/null
+++ b/technology/scn4m_subm/sp_lib/dummy_cell_1rw_1r.sp
@@ -0,0 +1,14 @@
+
+.SUBCKT dummy_cell_1rw_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
+MM9 RA_to_R_right wl1 br1_noconn gnd n w=1.2u l=0.4u
+MM8 RA_to_R_right Q gnd gnd n w=1.2u l=0.4u
+MM7 RA_to_R_left Q_bar gnd gnd n w=1.2u l=0.4u
+MM6 RA_to_R_left wl1 bl1_noconn gnd n w=1.2u l=0.4u
+MM5 Q wl0 bl0_noconn gnd n w=0.8u l=0.4u
+MM4 Q_bar wl0 br0_noconn gnd n w=0.8u l=0.4u
+MM1 Q Q_bar gnd gnd n w=1.6u l=0.4u
+MM0 Q_bar Q gnd gnd n w=1.6u l=0.4u
+MM3 Q Q_bar vdd vdd p w=0.6u l=0.4u
+MM2 Q_bar Q vdd vdd p w=0.6u l=0.4u
+.ENDS
+
diff --git a/technology/scn4m_subm/sp_lib/dummy_cell_1w_1r.sp b/technology/scn4m_subm/sp_lib/dummy_cell_1w_1r.sp
new file mode 100644
index 00000000..f5424998
--- /dev/null
+++ b/technology/scn4m_subm/sp_lib/dummy_cell_1w_1r.sp
@@ -0,0 +1,14 @@
+
+.SUBCKT dummy_cell_1w_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
+MM9 RA_to_R_right wl1 br1_noconn gnd n w=1.2u l=0.4u
+MM8 RA_to_R_right Q gnd gnd n w=1.2u l=0.4u
+MM7 RA_to_R_left Q_bar gnd gnd n w=1.2u l=0.4u
+MM6 RA_to_R_left wl1 bl1_noconn gnd n w=1.2u l=0.4u
+MM5 Q wl0 bl0_noconn gnd n w=0.8u l=0.4u
+MM4 Q_bar wl0 br0_noconn gnd n w=0.8u l=0.4u
+MM1 Q Q_bar gnd gnd n w=1.6u l=0.4u
+MM0 Q_bar Q gnd gnd n w=1.6u l=0.4u
+MM3 Q Q_bar vdd vdd p w=0.6u l=0.4u
+MM2 Q_bar Q vdd vdd p w=0.6u l=0.4u
+.ENDS
+
diff --git a/technology/scn4m_subm/sp_lib/dummy_cell_6t.sp b/technology/scn4m_subm/sp_lib/dummy_cell_6t.sp
new file mode 100644
index 00000000..3b0584df
--- /dev/null
+++ b/technology/scn4m_subm/sp_lib/dummy_cell_6t.sp
@@ -0,0 +1,17 @@
+
+*********************** "dummy_cell_6t" ******************************
+.SUBCKT dummy_cell_6t bl br wl vdd gnd
+
+* Inverter 1
+M1000 Q Qbar vdd vdd p w=0.6u l=0.8u
+M1002 Q Qbar gnd gnd n w=1.6u l=0.4u
+
+* Inverter 2
+M1001 vdd Q Qbar vdd p w=0.6u l=0.8u
+M1003 gnd Q Qbar gnd n w=1.6u l=0.4u
+
+* Access transistors
+M1004 Q wl bl_noconn gnd n w=0.8u l=0.4u
+M1005 Qbar wl br_noconn gnd n w=0.8u l=0.4u
+
+.ENDS
diff --git a/technology/scn4m_subm/sp_lib/write_driver.sp b/technology/scn4m_subm/sp_lib/write_driver.sp
index d1dbf9b2..e86da288 100644
--- a/technology/scn4m_subm/sp_lib/write_driver.sp
+++ b/technology/scn4m_subm/sp_lib/write_driver.sp
@@ -28,9 +28,8 @@ M_14 din_gated_bar din_gated gnd gnd n W=0.8u L=0.4u
************************************************
* pull down with en enable
-M_15 bl din_gated_bar net_5 gnd n W=2.4u L=0.4u
-M_16 br din_bar_gated_bar net_5 gnd n W=2.4u L=0.4u
-M_17 net_5 en gnd gnd n W=2.4u L=0.4u
+M_15 bl din_gated_bar gnd gnd n W=2.4u L=0.4u
+M_16 br din_bar_gated_bar gnd gnd n W=2.4u L=0.4u
diff --git a/technology/scn4m_subm/tech/SCN4M_SUBM.20.tech b/technology/scn4m_subm/tech/SCN4M_SUBM.20.tech
index f39aa84f..7207f681 100644
--- a/technology/scn4m_subm/tech/SCN4M_SUBM.20.tech
+++ b/technology/scn4m_subm/tech/SCN4M_SUBM.20.tech
@@ -636,8 +636,8 @@ style lambda=0.20(p)
#CRE/CRM layer CRM rm1,prm1,rm2,prm2,rm3,prm3,rm4,prm4
#CRE/CRM calma 70 0
- layer CX comment
- labels comment
+ layer CX comment,bb
+ labels comment,bb
calma 63 0
layer XP pad,xp
@@ -1075,8 +1075,8 @@ style lambda=0.20(cp)
#CRE/CRM layer CRM rm1,prm1,rm2,prm2,rm3,prm3,rm4,prm4
#CRE/CRM calma 70 0
- layer CX comment
- labels comment
+ layer CX comment,bb
+ labels comment,bb
calma 63 0
layer XP pad,xp
@@ -1412,8 +1412,8 @@ style lambda=0.20(c)
#CRE/CRM layer CRM rm1,prm1,rm2,prm2,rm3,prm3,rm4,prm4
#CRE/CRM calma 70 0
- layer CX comment
- labels comment
+ layer CX comment,bb
+ labels comment,bb
calma 63 0
layer XP pad,xp
@@ -1749,8 +1749,8 @@ style lambda=0.20()
#CRE/CRM layer CRM rm1,prm1,rm2,prm2,rm3,prm3,rm4,prm4
#CRE/CRM calma 70 0
- layer CX comment
- labels comment
+ layer CX comment,bb
+ labels comment,bb
calma 63 0
layer XP pad,xp
@@ -1764,6 +1764,11 @@ cifinput
style lambda=0.20(p)
scalefactor 20
+ # This is a custom section to add bounding boxes in OpenRAM
+ layer bb BB
+ labels BB
+ calma BB 63 0
+
layer nwell CWN
and-not CWNR
and-not CTA
@@ -2450,10 +2455,6 @@ style lambda=0.20(p)
and-not CBA
calma CAA 43 *
- layer comment CX
- labels CX
- calma CX 63 *
-
calma CTA 60 *
calma CRW 65 *
@@ -2470,6 +2471,11 @@ style lambda=0.20(p)
style lambda=0.20(s)
scalefactor 20
+ # This is a custom section to add bounding boxes in OpenRAM
+ layer bb BB
+ labels BB
+ calma BB 63 0
+
layer nwell CWN
and-not CWNR
and-not CTA
@@ -3158,10 +3164,6 @@ style lambda=0.20(s)
and-not CBA
calma CAA 43 *
- layer comment CX
- labels CX
- calma CX 63 *
-
calma CTA 60 *
calma CRW 65 *
@@ -3178,6 +3180,11 @@ style lambda=0.20(s)
style lambda=0.20(ps)
scalefactor 20
+ # This is a custom section to add bounding boxes in OpenRAM
+ layer bb BB
+ labels BB
+ calma BB 63 0
+
layer nwell CWN
and-not CWNR
and-not CTA
@@ -3810,10 +3817,6 @@ style lambda=0.20(ps)
and-not CBA
calma CAA 43 *
- layer comment CX
- labels CX
- calma CX 63 *
-
calma CTA 60 *
calma CRW 65 *
@@ -3830,6 +3833,11 @@ style lambda=0.20(ps)
style lambda=0.20()
scalefactor 20
+ # This is a custom section to add bounding boxes in OpenRAM
+ layer bb BB
+ labels BB
+ calma BB 63 0
+
layer nwell CWN
and-not CWNR
and-not CTA
@@ -4516,10 +4524,6 @@ style lambda=0.20()
and-not CBA
calma CAA 43 *
- layer comment CX
- labels CX
- calma CX 63 *
-
calma CTA 60 *
calma CRW 65 *
@@ -4536,6 +4540,11 @@ style lambda=0.20()
style lambda=0.20(c)
scalefactor 20
+ # This is a custom section to add bounding boxes in OpenRAM
+ layer bb BB
+ labels BB
+ calma BB 63 0
+
layer nwell CWN
and-not CWNR
and-not CTA
@@ -4989,10 +4998,6 @@ style lambda=0.20(c)
and-not CBA
calma CAA 43 *
- layer comment CX
- labels CX
- calma CX 63 *
-
calma CTA 60 *
calma CRW 65 *
@@ -5009,6 +5014,11 @@ style lambda=0.20(c)
style lambda=0.20(cs)
scalefactor 20
+ # This is a custom section to add bounding boxes in OpenRAM
+ layer bb BB
+ labels BB
+ calma BB 63 0
+
layer nwell CWN
and-not CWNR
and-not CTA
@@ -5464,10 +5474,6 @@ style lambda=0.20(cs)
and-not CBA
calma CAA 43 *
- layer comment CX
- labels CX
- calma CX 63 *
-
calma CTA 60 *
calma CRW 65 *
@@ -5484,6 +5490,11 @@ style lambda=0.20(cs)
style lambda=0.20(cps)
scalefactor 20
+ # This is a custom section to add bounding boxes in OpenRAM
+ layer bb BB
+ labels BB
+ calma BB 63 0
+
layer nwell CWN
and-not CWNR
and-not CTA
@@ -5940,10 +5951,6 @@ style lambda=0.20(cps)
and-not CBA
calma CAA 43 *
- layer comment CX
- labels CX
- calma CX 63 *
-
calma CTA 60 *
calma CRW 65 *
@@ -5960,6 +5967,11 @@ style lambda=0.20(cps)
style lambda=0.20(cp)
scalefactor 20
+ # This is a custom section to add bounding boxes in OpenRAM
+ layer bb BB
+ labels BB
+ calma BB 63 0
+
layer nwell CWN
and-not CWNR
and-not CTA
@@ -6414,10 +6426,6 @@ style lambda=0.20(cp)
and-not CBA
calma CAA 43 *
- layer comment CX
- labels CX
- calma CX 63 *
-
calma CTA 60 *
calma CRW 65 *
diff --git a/technology/scn4m_subm/tech/__init__.py b/technology/scn4m_subm/tech/__init__.py
old mode 100755
new mode 100644
index 6b2d03b3..662a09b6
--- a/technology/scn4m_subm/tech/__init__.py
+++ b/technology/scn4m_subm/tech/__init__.py
@@ -1,6 +1,13 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
"""
Import tech specific modules.
"""
-from tech import *
+from .tech import *
diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py
old mode 100755
new mode 100644
index 78222fd6..68066c09
--- a/technology/scn4m_subm/tech/tech.py
+++ b/technology/scn4m_subm/tech/tech.py
@@ -1,13 +1,29 @@
+# See LICENSE for licensing information.
+#
+# Copyright (c) 2016-2019 Regents of the University of California and The Board
+# of Regents for the Oklahoma Agricultural and Mechanical College
+# (acting for and on behalf of Oklahoma State University)
+# All rights reserved.
+#
import os
from design_rules import *
"""
-File containing the process technology parameters for SCMOS 3me, subm, 180nm.
+File containing the process technology parameters for SCMOS 4m, 0.35um
"""
#GDS file info
GDS={}
# gds units
+# From http://www.cnf.cornell.edu/cnf_spie9.html: "The first
+#is the size of a database unit in user units. The second is the size
+#of a database unit in meters. For example, if your library was
+#created with the default units (user unit = 1 m and 1000 database
+#units per user unit), then the first number would be 0.001 and the
+#second number would be 10-9. Typically, the first number is less than
+#1, since you use more than 1 database unit per user unit. To
+#calculate the size of a user unit in meters, divide the second number
+#by the first."
GDS["unit"]=(0.001,1e-6)
# default label zoom
GDS["zoom"] = 0.5
@@ -54,6 +70,7 @@ parameter={}
parameter["min_tx_size"] = 4*_lambda_
parameter["beta"] = 2
+# These 6T sizes are used in the parameterized bitcell.
parameter["6T_inv_nmos_size"] = 8*_lambda_
parameter["6T_inv_pmos_size"] = 3*_lambda_
parameter["6T_access_size"] = 4*_lambda_
@@ -70,8 +87,8 @@ drc["has_nwell"] = True
drc["grid"]=0.5*_lambda_
#DRC/LVS test set_up
-drc["drc_rules"]=drclvs_home+"/calibreDRC_scn3me_subm.rul"
-drc["lvs_rules"]=drclvs_home+"/calibreLVS_scn3me_subm.rul"
+drc["drc_rules"]=None #drclvs_home+"/calibreDRC_scn3me_subm.rul"
+drc["lvs_rules"]=None #drclvs_home+"/calibreLVS_scn3me_subm.rul"
drc["layer_map"]=os.environ.get("OPENRAM_TECH")+"/scn3me_subm/layers.map"
# minwidth_tx with contact (no dog bone transistors)
@@ -230,8 +247,6 @@ spice["nmos"]="n"
spice["pmos"]="p"
# This is a map of corners to model files
SPICE_MODEL_DIR=os.environ.get("SPICE_MODEL_DIR")
-# FIXME: Uncomment when we have the new spice models
-#spice["fet_models"] = { "TT" : [SPICE_MODEL_DIR+"/nom/pmos.sp",SPICE_MODEL_DIR+"/nom/nmos.sp"] }
spice["fet_models"] = { "TT" : [SPICE_MODEL_DIR+"/nom/pmos.sp",SPICE_MODEL_DIR+"/nom/nmos.sp"],
"FF" : [SPICE_MODEL_DIR+"/ff/pmos.sp",SPICE_MODEL_DIR+"/ff/nmos.sp"],
"FS" : [SPICE_MODEL_DIR+"/ff/pmos.sp",SPICE_MODEL_DIR+"/ss/nmos.sp"],
@@ -253,37 +268,17 @@ spice["fall_time"] = 0.05 # fall time in [Nano-seconds]
spice["temperatures"] = [0, 25, 100] # Temperature corners (celcius)
spice["nom_temperature"] = 25 # Nominal temperature (celcius)
-#sram signal names
-#FIXME: We don't use these everywhere...
-spice["vdd_name"] = "vdd"
-spice["gnd_name"] = "gnd"
-spice["control_signals"] = ["CSB", "WEB"]
-spice["data_name"] = "DATA"
-spice["addr_name"] = "ADDR"
-spice["minwidth_tx"] = drc["minwidth_tx"]
-spice["channel"] = drc["minlength_channel"]
-spice["clk"] = "clk"
-
# analytical delay parameters
+spice["nom_threshold"] = 1.3 # Nominal Threshold voltage in Volts
# FIXME: These need to be updated for SCMOS, they are copied from FreePDK45.
-spice["vdd_nominal"] = 5.0 # Typical Threshold voltage in Volts
-spice["temp_nominal"] = 25.0 # Typical Threshold voltage in Volts
-spice["v_threshold_typical"] = 1.3 # Typical Threshold voltage in Volts
spice["wire_unit_r"] = 0.075 # Unit wire resistance in ohms/square
spice["wire_unit_c"] = 0.64 # Unit wire capacitance ff/um^2
-spice["min_tx_r"] = 9250.0 # Minimum transistor on resistance in ohms
spice["min_tx_drain_c"] = 0.7 # Minimum transistor drain capacitance in ff
spice["min_tx_gate_c"] = 0.1 # Minimum transistor gate capacitance in ff
-spice["msflop_setup"] = 9 # DFF setup time in ps
-spice["msflop_hold"] = 1 # DFF hold time in ps
-spice["msflop_delay"] = 20.5 # DFF Clk-to-q delay in ps
-spice["msflop_slew"] = 13.1 # DFF output slew in ps w/ no load
-spice["msflop_in_cap"] = 9.8242 # Input capacitance of ms_flop (Din) [Femto-farad]
spice["dff_setup"] = 9 # DFF setup time in ps
spice["dff_hold"] = 1 # DFF hold time in ps
-spice["dff_delay"] = 20.5 # DFF Clk-to-q delay in ps
-spice["dff_slew"] = 13.1 # DFF output slew in ps w/ no load
-spice["dff_in_cap"] = 9.8242 # Input capacitance of ms_flop (Din) [Femto-farad]
+spice["dff_in_cap"] = 9.8242 # Input capacitance (D) [Femto-farad]
+spice["dff_out_cap"] = 2 # Output capacitance (Q) [Femto-farad]
# analytical power parameters, many values are temporary
spice["bitcell_leakage"] = 1 # Leakage power of a single bitcell in nW
@@ -291,26 +286,21 @@ spice["inv_leakage"] = 1 # Leakage power of inverter in nW
spice["nand2_leakage"] = 1 # Leakage power of 2-input nand in nW
spice["nand3_leakage"] = 1 # Leakage power of 3-input nand in nW
spice["nor2_leakage"] = 1 # Leakage power of 2-input nor in nW
-spice["msflop_leakage"] = 1 # Leakage power of flop in nW
-spice["flop_para_cap"] = 2 # Parasitic Output capacitance in fF
+spice["dff_leakage"] = 1 # Leakage power of flop in nW
-spice["default_event_rate"] = 100 # Default event activity of every gate. MHz
-spice["flop_transition_prob"] = .5 # Transition probability of inverter.
-spice["inv_transition_prob"] = .5 # Transition probability of inverter.
-spice["nand2_transition_prob"] = .1875 # Transition probability of 2-input nand.
-spice["nand3_transition_prob"] = .1094 # Transition probability of 3-input nand.
-spice["nor2_transition_prob"] = .1875 # Transition probability of 2-input nor.
+spice["default_event_frequency"] = 100 # Default event activity of every gate. MHz
#Logical Effort relative values for the Handmade cells
-parameter["static_delay_stages"] = 4
-parameter["static_fanout_per_stage"] = 3
-parameter["static_fanout_list"] = parameter["static_delay_stages"]*[parameter["static_fanout_per_stage"]]
-parameter["dff_clk_cin"] = 27.5
-parameter["6tcell_wl_cin"] = 2
-parameter["min_inv_para_delay"] = .5
+parameter["le_tau"] = 23 #In pico-seconds.
+parameter["min_inv_para_delay"] = .73 #In relative delay units
+parameter["cap_relative_per_ff"] = .91 #Units of Relative Capacitance/ Femto-Farad
+parameter["dff_clk_cin"] = 27.5 #In relative capacitance units
+parameter["6tcell_wl_cin"] = 2 #In relative capacitance units
parameter["sa_en_pmos_size"] = 24*_lambda_
parameter["sa_en_nmos_size"] = 9*_lambda_
-parameter["rbl_height_percentage"] = .5 #Height of RBL compared to bitcell array
+parameter["sa_inv_pmos_size"] = 18*_lambda_
+parameter["sa_inv_nmos_size"] = 9*_lambda_
+parameter["bitcell_drain_cap"] = 0.2 #In Femto-Farad, approximation of drain capacitance
###################################################
##END Spice Simulation Parameters
diff --git a/technology/scn4m_subm/tf/README b/technology/scn4m_subm/tf/README.txt
similarity index 63%
rename from technology/scn4m_subm/tf/README
rename to technology/scn4m_subm/tf/README.txt
index d2531fe1..a89a588e 100644
--- a/technology/scn4m_subm/tf/README
+++ b/technology/scn4m_subm/tf/README.txt
@@ -18,4 +18,16 @@ be found in the file cdb2oa/OA_Conversion.txt.
This kit is not yet fully supported. Please post problems and solutions at
http://www.chiptalk.org -> Forums -> NCSU CDK -> NCSU CDK 1.6.0.beta for Virtuoso 6.1
-Modified 2018 by MRG to contain SCN4ME Via3/Metal4 layers.
\ No newline at end of file
+Modified 2018 by MRG to contain SCN4ME Via3/Metal4 layers.
+
+mosis.lyp is converted automatically from the .tf using:
+https://github.com/klayoutmatthias/tf_import
+Command line:
+klayout -z -rd tf_file=FreePDK45.tf -rd lyp_file=FreePDK45.ly
+You can then view layouts with:
+klayout file.gds -l mosis.lyp
+
+glade_scn4m_subm.py is a script for Glade:
+https://peardrop.co.uk/
+to load the .tf using:
+glade -script ~/openram/technology/scn3me_subm/tf/glade_scn3me_subm.py -gds file.gds
diff --git a/technology/scn4m_subm/tf/mosis.lyp b/technology/scn4m_subm/tf/mosis.lyp
new file mode 100644
index 00000000..69480a0d
--- /dev/null
+++ b/technology/scn4m_subm/tf/mosis.lyp
@@ -0,0 +1,2557 @@
+
+
+
+ #000000
+ #000000
+ 0
+ 0
+ C17
+ C8
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ background.drawing - 0/0
+ 0/0@1
+
+
+ #8c8ca6
+ #8c8ca6
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ grid.drawing - 0/0
+ 0/0@1
+
+
+ #ccccd9
+ #ccccd9
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ grid.drawing1 - 0/0
+ 0/0@1
+
+
+ #8c8ca6
+ #8c8ca6
+ 0
+ 0
+ C30
+ C7
+ true
+ true
+ false
+ 3
+ false
+ false
+ 0
+ Nwell.drawing - 42/0
+ 42/0@1
+
+
+ #8c8ca6
+ #8c8ca6
+ 0
+ 0
+ C25
+ C8
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Pwell.drawing - 41/0
+ 41/0@1
+
+
+ #8c8ca6
+ #8c8ca6
+ 0
+ 0
+ C13
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ CapWell.drawing - 0/0
+ 0/0@1
+
+
+ #bf4026
+ #bf4026
+ 0
+ 0
+ C1
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Pselect.drawing - 44/0
+ 44/0@1
+
+
+ #00cc66
+ #00cc66
+ 0
+ 0
+ C29
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Nselect.drawing - 45/0
+ 45/0@1
+
+
+ #ffff00
+ #ffff00
+ 0
+ 0
+ C28
+ C8
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Active.drawing - 43/0
+ 43/0@1
+
+
+ #ffff00
+ #ffff00
+ 0
+ 0
+ I1
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ ActX.drawing - 48/0
+ 48/0@1
+
+
+ #ffe6bf
+ #ffe6bf
+ 0
+ 0
+ I1
+ C1
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ SiBlock.drawing - 0/0
+ 0/0@1
+
+
+ #737373
+ #802626
+ 0
+ 0
+ C15
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ HR.drawing - 0/0
+ 0/0@1
+
+
+ #ff3333
+ #ff3333
+ 0
+ 0
+ C0
+ C8
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Poly1.drawing - 46/0
+ 46/0@1
+
+
+ #ff3333
+ #ff3333
+ 0
+ 0
+ I1
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ P1Con.drawing - 47/0
+ 47/0@1
+
+
+ #ff8000
+ #ff8000
+ 0
+ 0
+ C1
+ C8
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Poly2.drawing - 0/0
+ 0/0@1
+
+
+ #ff8000
+ #ff8000
+ 0
+ 0
+ I1
+ C8
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ P2Con.drawing - 0/0
+ 0/0@1
+
+
+ #39bfff
+ #39bfff
+ 0
+ 0
+ C22
+ C8
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Metal1.drawing - 49/0
+ 49/0@1
+
+
+ #ff00ff
+ #ff00ff
+ 0
+ 0
+ I1
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Via.drawing - 50/0
+ 50/0@1
+
+
+ #ff00ff
+ #ff00ff
+ 0
+ 0
+ C21
+ C8
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Metal2.drawing - 51/0
+ 51/0@1
+
+
+ #333399
+ #333399
+ 0
+ 0
+ I1
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Via2.drawing - 61/0
+ 61/0@1
+
+
+ #5e00e6
+ #333399
+ 0
+ 0
+ C5
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Metal3.drawing - 62/0
+ 62/0@1
+
+
+ #ffe6bf
+ #ffe6bf
+ 0
+ 0
+ I1
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Via3.drawing - 30/0
+ 30/0@1
+
+
+ #ffe6bf
+ #ffe6bf
+ 0
+ 0
+ C5
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Metal4.drawing - 31/0
+ 31/0@1
+
+
+ #ff8000
+ #ff8000
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ annotate.drawing - 0/0
+ 0/0@1
+
+
+ #ffbff2
+ #ffbff2
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ annotate.drawing1 - 0/0
+ 0/0@1
+
+
+ #00ff00
+ #00ff00
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ annotate.drawing2 - 0/0
+ 0/0@1
+
+
+ #00ffff
+ #00ffff
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ annotate.drawing3 - 0/0
+ 0/0@1
+
+
+ #ffff00
+ #ffff00
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ annotate.drawing4 - 0/0
+ 0/0@1
+
+
+ #ffffff
+ #ffffff
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ annotate.drawing5 - 0/0
+ 0/0@1
+
+
+ #d9e6ff
+ #d9e6ff
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ annotate.drawing6 - 0/0
+ 0/0@1
+
+
+ #ff3333
+ #ff3333
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ annotate.drawing7 - 0/0
+ 0/0@1
+
+
+ #ffe6bf
+ #ffe6bf
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ annotate.drawing8 - 0/0
+ 0/0@1
+
+
+ #00cc66
+ #00cc66
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ annotate.drawing9 - 0/0
+ 0/0@1
+
+
+ #ff3333
+ #ff3333
+ 0
+ 0
+ C16
+ C8
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Poly1.pin - 0/0
+ 0/0@1
+
+
+ #334dff
+ #334dff
+ 0
+ 0
+ C16
+ C8
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Metal1.pin - 0/0
+ 0/0@1
+
+
+ #ff00ff
+ #ff00ff
+ 0
+ 0
+ C16
+ C8
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Metal2.pin - 0/0
+ 0/0@1
+
+
+ #ffffff
+ #ffffff
+ 0
+ 0
+ I1
+ C8
+ true
+ true
+ false
+ 1
+ false
+ true
+ 0
+ Glass.drawing - 52/0
+ 52/0@1
+
+
+ #d9cc00
+ #e0e0e0
+ 0
+ 0
+ I1
+ C8
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ XP.drawing - 60/0
+ 60/0@1
+
+
+ #9900e6
+ #9900e6
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ prBoundary.drawing - 0/0
+ 0/0@1
+
+
+ #00ffff
+ #00ffff
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ prBoundary.boundary - 0/0
+ 0/0@1
+
+
+ #ff3333
+ #e0e0e0
+ 0
+ 0
+ I1
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ instance.drawing - 246/0
+ 246/0@1
+
+
+ #d9cc00
+ #d9cc00
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ instance.label - 0/0
+ 0/0@1
+
+
+ #8c8ca6
+ #8c8ca6
+ 0
+ 0
+ C29
+ C7
+ false
+ true
+ false
+ 3
+ false
+ false
+ 0
+ Nwell.net - 0/0
+ 0/0@1
+
+
+ #ffe6bf
+ #ffe6bf
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ align.drawing - 0/0
+ 0/0@1
+
+
+ #8c8ca6
+ #8c8ca6
+ 0
+ 0
+ C29
+ C8
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Pwell.net - 0/0
+ 0/0@1
+
+
+ #8c8ca6
+ #8c8ca6
+ 0
+ 0
+ C12
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ CapWell.net - 0/0
+ 0/0@1
+
+
+ #ff3333
+ #ff3333
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ hardFence.drawing - 0/0
+ 0/0@1
+
+
+ #ffff00
+ #ffff00
+ 0
+ 0
+ C29
+ C8
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Active.net - 0/0
+ 0/0@1
+
+
+ #ffff00
+ #ffff00
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ softFence.drawing - 0/0
+ 0/0@1
+
+
+ #ffff00
+ #ffff00
+ 0
+ 0
+ C15
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ ActX.net - 0/0
+ 0/0@1
+
+
+ #e0e0e0
+ #e0e0e0
+ 0
+ 0
+ C16
+ C8
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ A2.drawing - 5/0
+ 5/0@1
+
+
+ #e0e0e0
+ #e0e0e0
+ 0
+ 0
+ C16
+ C8
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ A1.drawing - 2/0
+ 2/0@1
+
+
+ #e0e0e0
+ #e0e0e0
+ 0
+ 0
+ C16
+ C8
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ comment.drawing - 0/0
+ 0/0@1
+
+
+ #ffe6bf
+ #ffe6bf
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ border.drawing - 0/0
+ 0/0@1
+
+
+ #bf4026
+ #bf4026
+ 0
+ 0
+ C29
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Pselect.net - 0/0
+ 0/0@1
+
+
+ #00cc66
+ #00cc66
+ 0
+ 0
+ C29
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Nselect.net - 0/0
+ 0/0@1
+
+
+ #ffe6bf
+ #ffe6bf
+ 0
+ 0
+ C15
+ C1
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ SiBlock.net - 0/0
+ 0/0@1
+
+
+ #737373
+ #802626
+ 0
+ 0
+ C15
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ HR.net - 0/0
+ 0/0@1
+
+
+ #00ffff
+ #00ffff
+ 0
+ 0
+ I1
+ C8
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ wire.drawing - 0/0
+ 0/0@1
+
+
+ #ff3333
+ #ff3333
+ 0
+ 0
+ C29
+ C8
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Poly1.net - 0/0
+ 0/0@1
+
+
+ #ff3333
+ #ff3333
+ 0
+ 0
+ C15
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ P1Con.net - 0/0
+ 0/0@1
+
+
+ #334dff
+ #334dff
+ 0
+ 0
+ C29
+ C8
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Metal1.net - 0/0
+ 0/0@1
+
+
+ #ff00ff
+ #ff00ff
+ 0
+ 0
+ C29
+ C8
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Metal2.net - 0/0
+ 0/0@1
+
+
+ #00cc66
+ #00cc66
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ device.label - 0/0
+ 0/0@1
+
+
+ #ff00ff
+ #ff00ff
+ 0
+ 0
+ C15
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Via.net - 0/0
+ 0/0@1
+
+
+ #333399
+ #333399
+ 0
+ 0
+ C29
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Metal3.net - 0/0
+ 0/0@1
+
+
+ #333399
+ #333399
+ 0
+ 0
+ C4
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Via2.net - 0/0
+ 0/0@1
+
+
+ #ffe6bf
+ #ffe6bf
+ 0
+ 0
+ C29
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Metal4.net - 0/0
+ 0/0@1
+
+
+ #ff3333
+ #ff3333
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ pin.label - 0/0
+ 0/0@1
+
+
+ #ffffff
+ #ffffff
+ 0
+ 0
+ I1
+ C0
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ text.drawing - 63/0
+ 63/0@1
+
+
+ #ff3333
+ #ff3333
+ 0
+ 0
+ I1
+ C8
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ pin.drawing - 0/0
+ 0/0@1
+
+
+ #00cc66
+ #00cc66
+ 0
+ 0
+ I1
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ device.drawing - 0/0
+ 0/0@1
+
+
+ #8c8ca6
+ #8c8ca6
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ axis.drawing - 0/0
+ 0/0@1
+
+
+ #ccccd9
+ #ccccd9
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ edgeLayer.drawing - 0/0
+ 0/0@1
+
+
+ #ffff00
+ #ffff00
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ edgeLayer.pin - 0/0
+ 0/0@1
+
+
+ #ffff00
+ #ffff00
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ snap.drawing - 0/0
+ 0/0@1
+
+
+ #ffff00
+ #ffff00
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ stretch.drawing - 0/0
+ 0/0@1
+
+
+ #ccccd9
+ #ccccd9
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ y0.drawing - 0/0
+ 0/0@1
+
+
+ #bf4026
+ #bf4026
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ y1.drawing - 0/0
+ 0/0@1
+
+
+ #ff3333
+ #ff3333
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ y2.drawing - 0/0
+ 0/0@1
+
+
+ #ff8000
+ #ff8000
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ y3.drawing - 0/0
+ 0/0@1
+
+
+ #ffff00
+ #ffff00
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ y4.drawing - 0/0
+ 0/0@1
+
+
+ #00cc66
+ #00cc66
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ y5.drawing - 0/0
+ 0/0@1
+
+
+ #334dff
+ #334dff
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ y6.drawing - 0/0
+ 0/0@1
+
+
+ #9900e6
+ #9900e6
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ y7.drawing - 0/0
+ 0/0@1
+
+
+ #d9cc00
+ #d9cc00
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ y8.drawing - 0/0
+ 0/0@1
+
+
+ #d9e6ff
+ #d9e6ff
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ y9.drawing - 0/0
+ 0/0@1
+
+
+ #ffffff
+ #ffffff
+ 0
+ 0
+ I1
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ hilite.drawing - 0/0
+ 0/0@1
+
+
+ #ffe6bf
+ #ffe6bf
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ hilite.drawing2 - 0/0
+ 0/0@1
+
+
+ #ffe6bf
+ #ffe6bf
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ select.drawing - 0/0
+ 0/0@1
+
+
+ #334dff
+ #334dff
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ drive.drawing - 0/0
+ 0/0@1
+
+
+ #ff8000
+ #ff8000
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ hiz.drawing - 0/0
+ 0/0@1
+
+
+ #00ffff
+ #00ffff
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ resist.drawing - 0/0
+ 0/0@1
+
+
+ #9900e6
+ #9900e6
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ spike.drawing - 0/0
+ 0/0@1
+
+
+ #00ff00
+ #00ff00
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ supply.drawing - 0/0
+ 0/0@1
+
+
+ #ffff00
+ #ffff00
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ unknown.drawing - 0/0
+ 0/0@1
+
+
+ #268c6b
+ #268c6b
+ 0
+ 0
+ C16
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ unset.drawing - 0/0
+ 0/0@1
+
+
+ #ff3333
+ #ff3333
+ 0
+ 0
+ C16
+ C0
+ false
+ false
+ false
+ 1
+ false
+ false
+ 0
+ changedLayer.tool0 - 0/0
+ 0/0@1
+
+
+ #ffff00
+ #ffff00
+ 0
+ 0
+ C26
+ C8
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Pbase.drawing - 0/0
+ 0/0@1
+
+
+ #ffff00
+ #ffff00
+ 0
+ 0
+ C29
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Pbase.net - 0/0
+ 0/0@1
+
+
+ #00ffff
+ #00ffff
+ 0
+ 0
+ C29
+ C0
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Resistor.net - 0/0
+ 0/0@1
+
+
+ #00ffff
+ #00ffff
+ 0
+ 0
+ C28
+ C8
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Resistor.drawing - 0/0
+ 0/0@1
+
+
+ #ffe6bf
+ #ffe6bf
+ 0
+ 0
+ C29
+ C8
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Capacitor.net - 0/0
+ 0/0@1
+
+
+ #ffe6bf
+ #ffe6bf
+ 0
+ 0
+ C23
+ C8
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Capacitor.drawing - 0/0
+ 0/0@1
+
+
+ #ffffcc
+ #ffffcc
+ 0
+ 0
+ C29
+ C8
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Diode.net - 0/0
+ 0/0@1
+
+
+ #ffffcc
+ #ffffcc
+ 0
+ 0
+ C23
+ C8
+ true
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Diode.drawing - 0/0
+ 0/0@1
+
+
+ #ff8000
+ #ff8000
+ 0
+ 0
+ C29
+ C8
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ Poly2.net - 0/0
+ 0/0@1
+
+
+ #ff8000
+ #ff8000
+ 0
+ 0
+ C15
+ C8
+ false
+ true
+ false
+ 1
+ false
+ false
+ 0
+ P2Con.net - 0/0
+ 0/0@1
+
+
+
+
+ .*...*...*...*..
+ ................
+ ...*...*...*...*
+ ................
+ .*...*...*...*..
+ ................
+ ...*...*...*...*
+ ................
+ .*...*...*...*..
+ ................
+ ...*...*...*...*
+ ................
+ .*...*...*...*..
+ ................
+ ...*...*...*...*
+ ................
+
+ 1
+ dots
+
+
+
+ ...*...*...*...*
+ ................
+ .*...*...*...*..
+ ................
+ ...*...*...*...*
+ ................
+ .*...*...*...*..
+ ................
+ ...*...*...*...*
+ ................
+ .*...*...*...*..
+ ................
+ ...*...*...*...*
+ ................
+ .*...*...*...*..
+ ................
+
+ 2
+ dots1
+
+
+
+ ................
+ ................
+ ................
+ ****************
+ ................
+ ................
+ ................
+ ****************
+ ................
+ ................
+ ................
+ ****************
+ ................
+ ................
+ ................
+ ****************
+
+ 3
+ hLine
+
+
+
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+
+ 4
+ vLine
+
+
+
+ *...*...*...*...
+ .*.*.*.*.*.*.*.*
+ ..*...*...*...*.
+ .*.*.*.*.*.*.*.*
+ *...*...*...*...
+ .*.*.*.*.*.*.*.*
+ ..*...*...*...*.
+ .*.*.*.*.*.*.*.*
+ *...*...*...*...
+ .*.*.*.*.*.*.*.*
+ ..*...*...*...*.
+ .*.*.*.*.*.*.*.*
+ *...*...*...*...
+ .*.*.*.*.*.*.*.*
+ ..*...*...*...*.
+ .*.*.*.*.*.*.*.*
+
+ 5
+ cross
+
+
+
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ****************
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ****************
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ****************
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ****************
+
+ 6
+ grid
+
+
+
+ ...*...*...*...*
+ ..*...*...*...*.
+ .*...*...*...*..
+ *...*...*...*...
+ ...*...*...*...*
+ ..*...*...*...*.
+ .*...*...*...*..
+ *...*...*...*...
+ ...*...*...*...*
+ ..*...*...*...*.
+ .*...*...*...*..
+ *...*...*...*...
+ ...*...*...*...*
+ ..*...*...*...*.
+ .*...*...*...*..
+ *...*...*...*...
+
+ 7
+ slash
+
+
+
+ *...*...*...*...
+ .*...*...*...*..
+ ..*...*...*...*.
+ ...*...*...*...*
+ *...*...*...*...
+ .*...*...*...*..
+ ..*...*...*...*.
+ ...*...*...*...*
+ *...*...*...*...
+ .*...*...*...*..
+ ..*...*...*...*.
+ ...*...*...*...*
+ *...*...*...*...
+ .*...*...*...*..
+ ..*...*...*...*.
+ ...*...*...*...*
+
+ 8
+ backSlash
+
+
+
+ **......**......
+ ..*.......*.....
+ ...**......**...
+ .....*.......*..
+ ......**......**
+ *.......*.......
+ .**......**.....
+ ...*.......*....
+ ....**......**..
+ ......*.......*.
+ *......**......*
+ .*.......*......
+ ..**......**....
+ ....*.......*...
+ .....**......**.
+ .......*.......*
+
+ 9
+ hZigZag
+
+
+
+ *....*....*.....
+ *.....*....*....
+ .*....*.....*...
+ ..*....*....*...
+ ..*.....*....*..
+ ...*....*.....*.
+ ....*....*....*.
+ ....*.....*....*
+ *....*....*.....
+ *.....*....*....
+ .*....*.....*...
+ ..*....*....*...
+ ..*.....*....*..
+ ...*....*.....*.
+ ....*....*....*.
+ ....*.....*....*
+
+ 10
+ vZigZag
+
+
+
+ ................
+ ................
+ ...*****...*****
+ ...*...*...*...*
+ ...*...*...*...*
+ ****...*****...*
+ ................
+ ................
+ ................
+ ................
+ ...*****...*****
+ ...*...*...*...*
+ ...*...*...*...*
+ ****...*****...*
+ ................
+ ................
+
+ 11
+ hCurb
+
+
+
+ .....*.......*..
+ .....*.......*..
+ .....*.......*..
+ ..****....****..
+ ..*.......*.....
+ ..*.......*.....
+ ..*.......*.....
+ ..****....****..
+ .....*.......*..
+ .....*.......*..
+ .....*.......*..
+ ..****....****..
+ ..*.......*.....
+ ..*.......*.....
+ ..*.......*.....
+ ..****....****..
+
+ 12
+ vCurb
+
+
+
+ ****************
+ ..*.......*.....
+ ..*.......*.....
+ ..*.......*.....
+ ****************
+ ......*.......*.
+ ......*.......*.
+ ......*.......*.
+ ****************
+ ..*.......*.....
+ ..*.......*.....
+ ..*.......*.....
+ ****************
+ ......*.......*.
+ ......*.......*.
+ ......*.......*.
+
+ 13
+ brick
+
+
+
+ ................
+ ..*.......*.....
+ ..*.......*.....
+ ..*.......*.....
+ *****...*****...
+ ..*.......*.....
+ ..*.......*.....
+ ..*.......*.....
+ ................
+ .....*.......*..
+ .....*.......*..
+ .....*.......*..
+ ...*****...*****
+ .....*.......*..
+ .....*.......*..
+ .....*.......*..
+
+ 14
+ dagger
+
+
+
+ ................
+ ....*...........
+ ...*.*..........
+ ..*...*.........
+ .*.....*........
+ *********.......
+ ................
+ ................
+ ................
+ ...........*....
+ ..........*.*...
+ .........*...*..
+ ........*.....*.
+ .......*********
+ ................
+ ................
+
+ 15
+ triangle
+
+
+
+ *...*...*...*...
+ .*.*.*.*.*.*.*.*
+ ..*...*...*...*.
+ .*.*.*.*.*.*.*.*
+ *...*...*...*...
+ .*.*.*.*.*.*.*.*
+ ..*...*...*...*.
+ .*.*.*.*.*.*.*.*
+ *...*...*...*...
+ .*.*.*.*.*.*.*.*
+ ..*...*...*...*.
+ .*.*.*.*.*.*.*.*
+ *...*...*...*...
+ .*.*.*.*.*.*.*.*
+ ..*...*...*...*.
+ .*.*.*.*.*.*.*.*
+
+ 16
+ x
+
+
+
+ *
+
+ 17
+ stipple0
+
+
+
+ ****************
+ ................
+ ................
+ ................
+ ****************
+ ................
+ ................
+ ................
+ ****************
+ ................
+ ................
+ ................
+ ****************
+ ................
+ ................
+ ................
+
+ 18
+ stipple1
+
+
+
+ ****....****....
+ ****....****....
+ ****....****....
+ ****....****....
+ ....****....****
+ ....****....****
+ ....****....****
+ ....****....****
+ ****....****....
+ ****....****....
+ ****....****....
+ ****....****....
+ ....****....****
+ ....****....****
+ ....****....****
+ ....****....****
+
+ 19
+ stipple2
+
+
+
+ *...*...*...*...
+ *...*...*...*...
+ *...*...*...*...
+ *...*...*...*...
+ *...*...*...*...
+ *...*...*...*...
+ *...*...*...*...
+ *...*...*...*...
+ *...*...*...*...
+ *...*...*...*...
+ *...*...*...*...
+ *...*...*...*...
+ *...*...*...*...
+ *...*...*...*...
+ *...*...*...*...
+ *...*...*...*...
+
+ 20
+ stipple3
+
+
+
+ ................
+ *.*.*.*.*.*.*.*.
+ ................
+ *.*.*.*.*.*.*.*.
+ ................
+ *.*.*.*.*.*.*.*.
+ ................
+ *.*.*.*.*.*.*.*.
+ ................
+ *.*.*.*.*.*.*.*.
+ ................
+ *.*.*.*.*.*.*.*.
+ ................
+ *.*.*.*.*.*.*.*.
+ ................
+ *.*.*.*.*.*.*.*.
+
+ 21
+ stipple4
+
+
+
+ *...*...*...*...
+ .*...*...*...*..
+ ..*...*...*...*.
+ ...*...*...*...*
+ *...*...*...*...
+ .*...*...*...*..
+ ..*...*...*...*.
+ ...*...*...*...*
+ *...*...*...*...
+ .*...*...*...*..
+ ..*...*...*...*.
+ ...*...*...*...*
+ *...*...*...*...
+ .*...*...*...*..
+ ..*...*...*...*.
+ ...*...*...*...*
+
+ 22
+ stipple5
+
+
+
+ ...*...*...*...*
+ ..*...*...*...*.
+ .*...*...*...*..
+ *...*...*...*...
+ ...*...*...*...*
+ ..*...*...*...*.
+ .*...*...*...*..
+ *...*...*...*...
+ ...*...*...*...*
+ ..*...*...*...*.
+ .*...*...*...*..
+ *...*...*...*...
+ ...*...*...*...*
+ ..*...*...*...*.
+ .*...*...*...*..
+ *...*...*...*...
+
+ 23
+ stipple6
+
+
+
+ ..****....****..
+ .*....*..*....*.
+ *......**......*
+ *......**......*
+ *......**......*
+ *......**......*
+ .*....*..*....*.
+ ..****....****..
+ ..****....****..
+ .*....*..*....*.
+ *......**......*
+ *......**......*
+ *......**......*
+ *......**......*
+ .*....*..*....*.
+ ..****....****..
+
+ 24
+ stipple7
+
+
+
+ ...*...*...*...*
+ *...*...*...*...
+ ...*...*...*...*
+ *...*...*...*...
+ ...*...*...*...*
+ *...*...*...*...
+ ...*...*...*...*
+ *...*...*...*...
+ ...*...*...*...*
+ *...*...*...*...
+ ...*...*...*...*
+ *...*...*...*...
+ ...*...*...*...*
+ *...*...*...*...
+ ...*...*...*...*
+ *...*...*...*...
+
+ 25
+ stipple8
+
+
+
+ .*...*...*...*..
+ .*...*...*...*..
+ .*...*...*...*..
+ .*...*...*...*..
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ .*...*...*...*..
+ .*...*...*...*..
+ .*...*...*...*..
+ .*...*...*...*..
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+ ..*...*...*...*.
+
+ 26
+ stipple9
+
+
+
+ *.......*.......
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ *.......*.......
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+
+ 27
+ stipple10
+
+
+
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+ ...*...*...*...*
+
+ 28
+ stipple11
+
+
+
+ .*...*...*...*..
+ ................
+ ...*...*...*...*
+ ................
+ .*...*...*...*..
+ ................
+ ...*...*...*...*
+ ................
+ .*...*...*...*..
+ ................
+ ...*...*...*...*
+ ................
+ .*...*...*...*..
+ ................
+ ...*...*...*...*
+ ................
+
+ 29
+ dots2
+
+
+
+ *.....*.....*...
+ ................
+ ................
+ ...*.....*.....*
+ ................
+ ................
+ *.....*.....*...
+ ................
+ ................
+ ...*.....*.....*
+ ................
+ ................
+ *.....*.....*...
+ ................
+ ................
+ ...*.....*.....*
+
+ 30
+ dots4
+
+
+
+ ................
+ .*........*.....
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ................
+ ...*........*...
+ ................
+ ................
+ ................
+ ................
+
+ 31
+ dats5
+
+
+ *
+ 1
+ solid
+
+
+ ***..***
+ 2
+ dashed
+
+
+ *..
+ 3
+ dots
+
+
+ ***..*..
+ 4
+ dashDot
+
+
+ **..
+ 5
+ shortDash
+
+
+ ****..**..
+ 6
+ doubleDash
+
+
+ *...
+ 7
+ hidden
+
+
+ ***
+ 8
+ thickLine
+
+
+ *
+ 9
+ lineStyle0
+
+
+ ***.***.***.**.*
+ 10
+ lineStyle1
+
+
diff --git a/technology/scn4m_subm/tf/mosis.tf b/technology/scn4m_subm/tf/mosis.tf
index bae7f07a..a8bf4ca6 100644
--- a/technology/scn4m_subm/tf/mosis.tf
+++ b/technology/scn4m_subm/tf/mosis.tf
@@ -552,6 +552,8 @@ layerRules(
( ("P1Con" "drawing") 47 0 t )
( ("Metal1" "drawing") 49 0 t )
( ("Metal2" "drawing") 51 0 t )
+ ( ("Metal3" "drawing") 62 0 t )
+ ( ("Metal4" "drawing") 31 0 t )
( ("annotate" "drawing") 0 0 nil )
( ("annotate" "drawing1") 0 0 nil )
( ("annotate" "drawing2") 0 0 nil )
@@ -562,7 +564,6 @@ layerRules(
( ("annotate" "drawing7") 0 0 nil )
( ("annotate" "drawing8") 0 0 nil )
( ("annotate" "drawing9") 0 0 nil )
- ( ("Via" "drawing") 50 0 t )
( ("Glass" "drawing") 52 0 t )
( ("XP" "drawing") 60 0 t )
( ("Metal2" "pin") 0 0 nil )
@@ -590,8 +591,9 @@ layerRules(
( ("P1Con" "net") 0 0 nil )
( ("Metal1" "net") 0 0 nil )
( ("Metal2" "net") 0 0 nil )
+ ( ("Metal3" "net") 0 0 nil )
+ ( ("Metal4" "net") 0 0 nil )
( ("device" "label") 0 0 nil )
- ( ("Via" "net") 0 0 nil )
( ("pin" "label") 0 0 nil )
( ("text" "drawing") 63 0 t )
( ("pin" "drawing") 0 0 nil )
@@ -649,11 +651,12 @@ layerRules(
( Metal2 0 0 nil )
( Glass 0 0 nil )
( XP 0 0 nil )
- ( ("Via2" "drawing") 50 0 t )
+ ( ("Via" "drawing") 50 0 t )
+ ( ("Via" "net") 0 0 nil )
+ ( ("Via2" "drawing") 61 0 t )
( ("Via2" "net") 0 0 nil )
- ( ("Metal3" "drawing") 50 0 t )
- ( ("Metal3" "net") 0 0 nil )
- ( ("Metal3" "pin") 0 0 nil )
+ ( ("Via3" "drawing") 30 0 t )
+ ( ("Via3" "net") 0 0 nil )
( ("CapWell" "drawing") 0 0 nil )
( ("CapWell" "net") 0 0 nil )
( ("SiBlock" "drawing") 0 0 nil )
@@ -665,6 +668,7 @@ layerRules(
viaLayers(
;( layer1 viaLayer layer2 )
;( ------ -------- ------ )
+ ( Metal3 Via3 Metal4 )
( Metal2 Via2 Metal3 )
( Metal1 Via Metal2 )
( Active ActX Poly1 )
@@ -798,6 +802,10 @@ electricalRules(
( currentDensity "Metal1" 1.0 )
( currentDensity "Via" 1.0 )
( currentDensity "Metal2" 1.0 )
+ ( currentDensity "Via2" 1.0 )
+ ( currentDensity "Metal3" 1.0 )
+ ( currentDensity "Via3" 1.0 )
+ ( currentDensity "Metal4" 1.0 )
) ;characterizationRules
) ;electricalRules
@@ -824,10 +832,13 @@ leRules(
( Metal2 drawing )
( Via2 drawing )
( Metal3 drawing )
+ ( Via3 drawing )
+ ( Metal4 drawing )
( Poly1 pin )
( Metal1 pin )
( Metal2 pin )
( Metal3 pin )
+ ( Metal4 pin )
( Poly2 drawing )
( P2Con drawing )
( instance drawing )
@@ -853,7 +864,7 @@ leRules(
lxRules(
lxExtractLayers(
- (Metal1 Metal2 Metal3)
+ (Metal1 Metal2 Metal3 Metal4)
) ;lxExtractLayers
) ;lxRules
diff --git a/technology/setup_scripts/README b/technology/setup_scripts/README
deleted file mode 100644
index 628cec7e..00000000
--- a/technology/setup_scripts/README
+++ /dev/null
@@ -1,4 +0,0 @@
-THIS DIRECTORY SHOULD ONLY CONTAIN SETUP SCRIPTS FOR TECHNOLOGIES.
-
-These scripts will be called automatically by the import_tech functions in
-globals.py in the compiler directory.