diff --git a/README.md b/README.md
index 64c8aa25..82fe75ed 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ An open-source static random access memory (SRAM) compiler.
# What is OpenRAM?
-OpenRAM is an open-source Python framework to create the layout,
+OpenRAM is an award winning open-source Python framework to create the layout,
netlists, timing and power models, placement and routing models, and
other views necessary to use SRAMs in ASIC design. OpenRAM supports
integration in both commercial and open-source flows with both
@@ -195,7 +195,7 @@ specific technology (e.g., [FreePDK45]) should be a subdirectory
+ Report bugs by submitting [Github issues].
+ Develop new features (see [how to contribute](./CONTRIBUTING.md))
+ Submit code/fixes using a [Github pull request]
-+ Follow our [project][Github projects].
++ Follow our [project][Github project].
+ Read and cite our [ICCAD paper][OpenRAMpaper]
# Further Help
@@ -214,15 +214,7 @@ OpenRAM is licensed under the [BSD 3-clause License](./LICENSE).
- [Matthew Guthaus] from [VLSIDA] created the OpenRAM project and is the lead architect.
- [James Stine] from [VLSIARCH] co-founded the project.
-- Hunter Nichols maintains and updates the timing characterization.
-- Michael Grimes created and maintains the multiport netlist code.
-- Jennifer Sowash is creating the OpenRAM IP library.
-- Jesse Cirimelli-Low created the datasheet generation.
-- Samira Ataei created early multi-bank layouts and control logic.
-- Bin Wu created early parameterized cells.
-- Yusu Wang is porting parameterized cells to new technologies.
-- Brian Chen created early prototypes of the timing characterizer.
-- Jeff Butera created early prototypes of the bank layout.
+- Many students: Hunter Nichols, Michael Grimes, Jennifer Sowash, Yusu Wang, Joey Kunzler, Jesse Cirimelli-Low, Samira Ataei, Bin Wu, Brian Chen, Jeff Butera
If I forgot to add you, please let me know!
@@ -236,7 +228,7 @@ If I forgot to add you, please let me know!
[Github issues]: https://github.com/VLSIDA/OpenRAM/issues
[Github pull request]: https://github.com/VLSIDA/OpenRAM/pulls
-[Github projects]: https://github.com/VLSIDA/OpenRAM/projects
+[Github project]: https://github.com/VLSIDA/OpenRAM
[documentation]: https://docs.google.com/presentation/d/10InGB33N51I6oBHnqpU7_w9DXlx-qe9zdrlco2Yc5co/edit?usp=sharing
[dev-group]: mailto:openram-dev-group@ucsc.edu
diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py
index 35aa73b1..049d2307 100644
--- a/compiler/base/hierarchy_layout.py
+++ b/compiler/base/hierarchy_layout.py
@@ -37,7 +37,7 @@ class layout():
self.objs = [] # Holds all other objects (labels, geometries, etc)
self.pin_map = {} # Holds name->pin_layout map for all pins
self.visited = [] # List of modules we have already visited
- self.is_library_cell = False # Flag for library cells
+ self.is_library_cell = False # Flag for library cells
self.gds_read()
try:
from tech import power_grid
@@ -71,7 +71,7 @@ class layout():
(inv_num + 1) * height - \
(inv_num % 2) * drc["minwidth_m1"])
y_dir = -1
-
+
return (base_offset, y_dir)
def find_lowest_coords(self):
@@ -90,7 +90,7 @@ class layout():
lowesty2 = min(inst.by() for inst in self.insts)
else:
lowestx2 = lowesty2 = None
-
+
if lowestx1 == None and lowestx2 == None:
return None
elif lowestx1 == None:
@@ -146,7 +146,7 @@ class layout():
subcoord = inst.mod.find_highest_layer_coords(layer) + inst.offset
highestx = max(highestx, subcoord.x)
highesty = max(highesty, subcoord.y)
-
+
return vector(highestx, highesty)
def find_lowest_layer_coords(self, layer):
@@ -172,7 +172,7 @@ class layout():
lowesty = min(lowesty, subcoord.y)
return vector(lowestx, lowesty)
-
+
def translate_all(self, offset):
"""
Translates all objects, instances, and pins by the given (x,y) offset
@@ -189,7 +189,7 @@ class layout():
pin_list = self.pin_map[pin_name]
for pin in pin_list:
pin.rect = [pin.ll() - offset, pin.ur() - offset]
-
+
def add_inst(self, name, mod, offset=[0, 0], mirror="R0", rotate=0):
""" Adds an instance of a mod to this module """
self.insts.append(geometry.instance(name, mod, offset, mirror, rotate))
@@ -204,7 +204,7 @@ class layout():
if inst.name == name:
return inst
return None
-
+
def add_rect(self, layer, offset, width=None, height=None):
"""
Adds a rectangle on a given layer,offset with width and height
@@ -260,7 +260,7 @@ class layout():
start-offset,
minwidth_layer,
end.y-start.y)
-
+
def get_pin(self, text):
"""
Return the pin or list of pins
@@ -275,7 +275,7 @@ class layout():
except Exception:
self.gds_write("missing_pin.gds")
debug.error("No pin found with name {0} on {1}. Saved as missing_pin.gds.".format(text,self.name),-1)
-
+
def get_pins(self, text):
"""
Return a pin list (instead of a single pin)
@@ -290,17 +290,17 @@ class layout():
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
@@ -317,7 +317,7 @@ class layout():
"""
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
@@ -326,9 +326,9 @@ class layout():
file_name = "non_rectilinear.gds"
self.gds_write(file_name)
debug.error("Cannot have a non-manhatten layout pin: {}".format(file_name), -1)
-
+
minwidth_layer = drc["minwidth_{}".format(layer)]
-
+
# one of these will be zero
width = max(start.x, end.x) - min(start.x, end.x)
height = max(start.y, end.y) - min(start.y, end.y)
@@ -342,7 +342,7 @@ class layout():
# This makes sure it is long enough, but also it is not 0 width!
height = max(minwidth_layer, height)
width = max(minwidth_layer, width)
-
+
return self.add_layout_pin(text,
layer,
ll_offset,
@@ -359,13 +359,13 @@ class layout():
ll_offset = offset - vector(0.5 * width, 0.5 * height)
return self.add_layout_pin(text, layer, ll_offset, width, height)
-
+
def remove_layout_pin(self, text):
"""
Delete a labeled pin (or all pins of the same name)
"""
self.pin_map[text] = set()
-
+
def add_layout_pin(self, text, layer, offset, width=None, height=None):
"""
Create a labeled pin
@@ -409,7 +409,7 @@ class layout():
layer=layer,
offset=offset + vector(0.5 * width,
0.5 * height))
-
+
def add_label(self, text, layer, offset=[0, 0], zoom=-1):
"""Adds a text label on the given layer,offset, and zoom level"""
# negative layers indicate "unused" layers in a given technology
@@ -448,7 +448,7 @@ class layout():
layer_stack=layers,
path=coordinates,
layer_widths=layer_widths)
-
+
def add_wire(self, layers, coordinates):
"""Connects a routing path on given layer,coordinates,width.
The layers are the (horizontal, via, vertical). """
@@ -463,14 +463,14 @@ class layout():
""" Return the preferred routing directions """
from tech import preferred_directions
return preferred_directions[layer]
-
+
def add_via(self, layers, offset, size=[1,1], directions=None, implant_type=None, well_type=None):
""" Add a three layer via structure. """
if not directions:
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,
@@ -495,7 +495,7 @@ class layout():
if not directions:
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,
@@ -505,7 +505,7 @@ class layout():
well_type=well_type)
height = via.height
width = via.width
-
+
corrected_offset = offset + vector(-0.5 * width,
-0.5 * height)
@@ -602,11 +602,11 @@ class layout():
# This must be done for netlist only mode too
if os.path.isfile(self.gds_file):
self.is_library_cell = True
-
+
if OPTS.netlist_only:
self.gds = None
return
-
+
# open the gds file if it exists or else create a blank layout
if os.path.isfile(self.gds_file):
debug.info(3, "opening {}".format(self.gds_file))
@@ -662,7 +662,7 @@ class layout():
height=height,
center=False)
debug.info(2, "Adding {0} boundary {1}".format(self.name, boundary))
-
+
self.visited.append(self.name)
def gds_write(self, gds_name):
@@ -681,10 +681,10 @@ class layout():
# which may have been previously processed!
# MRG: 10/4/18 We need to clear if we make changes and write a second GDS!
self.clear_visited()
-
+
# recursively create all the remaining objects
self.gds_write_file(self.gds)
-
+
# populates the xyTree data structure for gds
# self.gds.prepareForWrite()
writer.writeToFile(gds_name)
@@ -706,7 +706,7 @@ class layout():
lpp = techlayer[layer]
else:
lpp = layer
-
+
blockages = []
for i in self.objs:
blockages += i.get_blockages(lpp)
@@ -724,7 +724,7 @@ class layout():
pin_names = copy.deepcopy(self.pins)
if self.name.startswith("pmos") or self.name.startswith("nmos"):
pin_names.remove("B")
-
+
blockages = []
for pin_name in pin_names:
pin_list = self.get_pins(pin_name)
@@ -784,7 +784,7 @@ class layout():
# half minwidth so we can return the center line offsets
half_minwidth = 0.5 * drc["minwidth_{}".format(layer)]
-
+
line_positions = {}
if vertical:
for i in range(len(names)):
@@ -829,7 +829,7 @@ class layout():
layer_stack=("m1", "via1", "m2")):
""" Vertical version of connect_bus. """
self.connect_bus(mapping, inst, bus_offsets, layer_stack, False)
-
+
def connect_bus(self, mapping, inst, bus_offsets, layer_stack, horizontal):
"""
Connect a mapping of pin -> name for a bus. This could be
@@ -842,7 +842,7 @@ class layout():
route_layer = vertical_layer
else:
route_layer = horizontal_layer
-
+
for (pin_name, bus_name) in mapping:
pin = inst.get_pin(pin_name)
pin_pos = pin.center()
@@ -854,7 +854,7 @@ class layout():
else:
# left/right then up/down
mid_pos = vector(bus_pos.x, pin_pos.y)
-
+
self.add_wire(layer_stack,
[bus_pos, mid_pos, pin_pos])
@@ -865,7 +865,7 @@ class layout():
offset=pin_pos)
# FIXME: output pins tend to not be rotate,
# but supply pins are. Make consistent?
-
+
# We only need a via if they happened to align perfectly
# so the add_wire didn't add a via
if (horizontal and bus_pos.y == pin_pos.y) or (not horizontal and bus_pos.x == pin_pos.x):
@@ -899,7 +899,7 @@ class layout():
self.m3_space)
else:
debug.error("Cannot find layer pitch.")
-
+
def add_horizontal_trunk_route(self,
pins,
trunk_offset,
@@ -915,7 +915,7 @@ class layout():
# if we are less than a pitch, just create a non-preferred layer jog
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(self.vertical_layer,
[vector(min_x - half_layer_width, trunk_offset.y),
@@ -955,7 +955,7 @@ class layout():
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),
@@ -978,7 +978,7 @@ class layout():
self.add_path(self.horizontal_layer, [pin.center(), mid])
self.add_via_center(layers=layer_stack,
offset=mid)
-
+
def create_channel_route(self, netlist,
offset,
layer_stack,
@@ -996,7 +996,7 @@ class layout():
Remove the pin from the graph and all conflicts
"""
g.pop(pin, None)
-
+
# Remove the pin from all conflicts
# FIXME: This is O(n^2), so maybe optimize it.
for other_pin,conflicts in g.items():
@@ -1010,21 +1010,21 @@ class layout():
Check all the pin pairs on two nets and return a pin
overlap if any pin overlaps.
"""
-
+
for pin1 in net1:
for pin2 in net2:
if vcg_pin_overlap(pin1, pin2, vertical, pitch):
return True
return False
-
+
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
# extra comparison *shouldn't* matter.
-
+
# Pin 1 must be in the "BOTTOM" set
x_overlap = pin1.by() < pin2.by() and abs(pin1.center().x-pin2.center().x)