mirror of https://github.com/VLSIDA/OpenRAM.git
Vdd/gnd via stacks now use perferred directions, added cell property to override
This commit is contained in:
parent
1617840ed3
commit
d7529ce526
|
|
@ -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)<pitch
|
||||
|
||||
|
|
@ -1049,7 +1049,7 @@ class layout():
|
|||
# too if we want to minimize the
|
||||
# number of tracks!
|
||||
# hcg = {}
|
||||
|
||||
|
||||
# Initialize the vertical conflict graph (vcg)
|
||||
# and make a list of all pins
|
||||
vcg = collections.OrderedDict()
|
||||
|
|
@ -1084,7 +1084,7 @@ class layout():
|
|||
vertical,
|
||||
self.horizontal_pitch):
|
||||
vcg[net_name2].append(net_name1)
|
||||
|
||||
|
||||
# list of routes to do
|
||||
while vcg:
|
||||
# from pprint import pformat
|
||||
|
|
@ -1105,7 +1105,7 @@ class layout():
|
|||
|
||||
# Remove the net from other constriants in the VCG
|
||||
vcg = remove_net_from_graph(net_name, vcg)
|
||||
|
||||
|
||||
# Add the trunk routes from the bottom up for
|
||||
# horizontal or the left to right for vertical
|
||||
if vertical:
|
||||
|
|
@ -1137,7 +1137,7 @@ class layout():
|
|||
""" Add boundary for debugging dimensions """
|
||||
if OPTS.netlist_only:
|
||||
return
|
||||
|
||||
|
||||
if "stdc" in techlayer.keys():
|
||||
boundary_layer = "stdc"
|
||||
else:
|
||||
|
|
@ -1152,7 +1152,7 @@ class layout():
|
|||
offset=ll,
|
||||
height=ur.y-ll.y,
|
||||
width=ur.x-ll.x)
|
||||
|
||||
|
||||
def add_enclosure(self, insts, layer="nwell"):
|
||||
""" Add a layer that surrounds the given instances. Useful
|
||||
for creating wells, for example. Doesn't check for minimum widths or
|
||||
|
|
@ -1193,19 +1193,25 @@ class layout():
|
|||
"supply router."
|
||||
.format(name,inst.name,self.pwr_grid_layer))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def add_power_pin(self, name, loc, size=[1, 1], vertical=False, start_layer="m1"):
|
||||
"""
|
||||
Add a single power pin from the lowest power_grid layer down to M1 at
|
||||
the given center location. The starting layer is specified to determine
|
||||
which vias are needed.
|
||||
"""
|
||||
|
||||
# Force vdd/gnd via stack to be vertically or horizontally oriented
|
||||
# Default: None, uses prefered metal directions
|
||||
if vertical:
|
||||
direction = ("V", "V")
|
||||
else:
|
||||
elif not vertical and vertical is not None:
|
||||
direction = ("H", "H")
|
||||
|
||||
else:
|
||||
direction = None
|
||||
|
||||
|
||||
via = self.add_via_stack_center(from_layer=start_layer,
|
||||
to_layer=self.pwr_grid_layer,
|
||||
size=size,
|
||||
|
|
@ -1222,7 +1228,7 @@ class layout():
|
|||
offset=loc,
|
||||
width=via.width,
|
||||
height=via.height)
|
||||
|
||||
|
||||
def add_power_ring(self, bbox):
|
||||
"""
|
||||
Create vdd and gnd power rings around an area of the bounding box
|
||||
|
|
@ -1287,7 +1293,7 @@ class layout():
|
|||
offset=offset,
|
||||
width=width,
|
||||
height=self.supply_rail_width)
|
||||
|
||||
|
||||
# TOP horizontal rails
|
||||
offset = vector(ll.x, ur.y) + vector(-2 * self.supply_rail_pitch,
|
||||
0)
|
||||
|
|
@ -1328,7 +1334,7 @@ class layout():
|
|||
else:
|
||||
self.supply_vias -= 1
|
||||
break
|
||||
|
||||
|
||||
via_points = [vector(self.left_gnd_x_center, self.bottom_gnd_y_center),
|
||||
vector(self.left_gnd_x_center, self.top_gnd_y_center),
|
||||
vector(self.right_gnd_x_center, self.bottom_gnd_y_center),
|
||||
|
|
@ -1337,7 +1343,7 @@ class layout():
|
|||
vector(self.left_vdd_x_center, self.top_vdd_y_center),
|
||||
vector(self.right_vdd_x_center, self.bottom_vdd_y_center),
|
||||
vector(self.right_vdd_x_center, self.top_vdd_y_center)]
|
||||
|
||||
|
||||
for pt in via_points:
|
||||
self.add_via_center(layers=self.m1_stack,
|
||||
offset=pt,
|
||||
|
|
@ -1390,4 +1396,3 @@ class layout():
|
|||
debug.info(0, "name={0} : mod={1} : offset={2}".format(inst.name,
|
||||
inst.mod.name,
|
||||
inst.offset))
|
||||
|
||||
|
|
|
|||
|
|
@ -101,13 +101,20 @@ class bitcell_base_array(design.design):
|
|||
width=self.width,
|
||||
height=wl_pin.height())
|
||||
|
||||
# For every second row and column, add a via for gnd and vdd
|
||||
# For non-square via stacks, vertical/horizontal direction refers to the stack orientation in 2d space
|
||||
# Default uses prefered directions for each layer; this cell property is only currently used by s8 tech (03/20)
|
||||
try:
|
||||
force_power_pins_vertical = cell_properties.bitcell_force_power_pins_vertical
|
||||
except AttributeError:
|
||||
force_power_pins_vertical = None
|
||||
|
||||
# Add vdd/gnd via stacks
|
||||
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)
|
||||
self.add_power_pin(name=pin_name, loc=pin.center(), vertical=force_power_pins_vertical, start_layer=pin.layer)
|
||||
|
||||
def _adjust_x_offset(self, xoffset, col, col_offset):
|
||||
tempx = xoffset
|
||||
|
|
|
|||
Loading…
Reference in New Issue