From 5409f0be7dd153a4117f639d55c1640930bffd07 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Tue, 25 Feb 2020 08:06:26 -0800 Subject: [PATCH 1/4] Update project link and student contributors --- README.md | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 64c8aa25..997303ab 100644 --- a/README.md +++ b/README.md @@ -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 From 0db0c5a3a914b03dfce7f011464d1c0d25a4f56c Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Tue, 25 Feb 2020 08:09:08 -0800 Subject: [PATCH 2/4] Update version to 1.1.4 --- compiler/globals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/globals.py b/compiler/globals.py index 70e4b54b..3277ab1d 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -19,7 +19,7 @@ import re import copy import importlib -VERSION = "1.1.3" +VERSION = "1.1.4" NAME = "OpenRAM v{}".format(VERSION) USAGE = "openram.py [options] \nUse -h for help.\n" From 1d8f2a4ad6dea40bab54a49ff68d12b3934782d8 Mon Sep 17 00:00:00 2001 From: Olof Kindgren Date: Thu, 27 Feb 2020 07:09:26 +0100 Subject: [PATCH 3/4] Update documentation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 997303ab..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 From d7529ce526d49eddab2ca802960d75c4c722f28d Mon Sep 17 00:00:00 2001 From: Joey Kunzler Date: Wed, 4 Mar 2020 17:05:19 -0800 Subject: [PATCH 4/4] Vdd/gnd via stacks now use perferred directions, added cell property to override --- compiler/base/hierarchy_layout.py | 123 +++++++++++++------------ compiler/modules/bitcell_base_array.py | 11 ++- 2 files changed, 73 insertions(+), 61 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 451d1356..3c2e8992 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 @@ -325,9 +325,9 @@ class layout(): debug.check(start.x == end.x or start.y == end.y, "Cannot have a non-manhatten layout pin.") - + 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) @@ -341,7 +341,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, @@ -358,13 +358,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 @@ -408,7 +408,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 @@ -447,7 +447,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). """ @@ -462,14 +462,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, @@ -494,7 +494,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, @@ -504,7 +504,7 @@ class layout(): well_type=well_type) height = via.height width = via.width - + corrected_offset = offset + vector(-0.5 * width, -0.5 * height) @@ -580,7 +580,7 @@ class layout(): last_via=via, size=size) - + def add_ptx(self, offset, mirror="R0", rotate=0, width=1, mults=1, tx_type="nmos"): """Adds a ptx module to the design.""" import ptx @@ -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)