mirror of https://github.com/VLSIDA/OpenRAM.git
Abstracted LEF added. Params for array wordline layers.
This commit is contained in:
parent
584349c911
commit
f45efe3db6
|
|
@ -125,8 +125,10 @@ class _wordline_driver:
|
||||||
|
|
||||||
class _bitcell_array:
|
class _bitcell_array:
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
wordline_layer):
|
wordline_layer,
|
||||||
|
wordline_pitch_factor=2):
|
||||||
self.wordline_layer = wordline_layer
|
self.wordline_layer = wordline_layer
|
||||||
|
self.wordline_pitch_factor = wordline_pitch_factor
|
||||||
|
|
||||||
|
|
||||||
class layer_properties():
|
class layer_properties():
|
||||||
|
|
@ -165,7 +167,7 @@ class layer_properties():
|
||||||
|
|
||||||
self._wordline_driver = _wordline_driver(vertical_supply=False)
|
self._wordline_driver = _wordline_driver(vertical_supply=False)
|
||||||
|
|
||||||
self._local_bitcell_array = _bitcell_array(wordline_layer="m3")
|
self._local_bitcell_array = _bitcell_array(wordline_layer="m2")
|
||||||
|
|
||||||
self._global_bitcell_array = _bitcell_array(wordline_layer="m3")
|
self._global_bitcell_array = _bitcell_array(wordline_layer="m3")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -674,7 +674,8 @@ class layout():
|
||||||
directions=None,
|
directions=None,
|
||||||
size=[1, 1],
|
size=[1, 1],
|
||||||
implant_type=None,
|
implant_type=None,
|
||||||
well_type=None):
|
well_type=None,
|
||||||
|
min_area=False):
|
||||||
"""
|
"""
|
||||||
Punch a stack of vias from a start layer to a target layer by the center.
|
Punch a stack of vias from a start layer to a target layer by the center.
|
||||||
"""
|
"""
|
||||||
|
|
@ -708,7 +709,7 @@ class layout():
|
||||||
implant_type=implant_type,
|
implant_type=implant_type,
|
||||||
well_type=well_type)
|
well_type=well_type)
|
||||||
|
|
||||||
if cur_layer != from_layer:
|
if cur_layer != from_layer or min_area:
|
||||||
self.add_min_area_rect_center(cur_layer,
|
self.add_min_area_rect_center(cur_layer,
|
||||||
offset,
|
offset,
|
||||||
via.mod.first_layer_width,
|
via.mod.first_layer_width,
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ from tech import layer_names
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
from vector import vector
|
||||||
|
from pin_layout import pin_layout
|
||||||
|
|
||||||
|
|
||||||
class lef:
|
class lef:
|
||||||
|
|
@ -68,13 +70,63 @@ class lef:
|
||||||
def lef_write(self, lef_name):
|
def lef_write(self, lef_name):
|
||||||
""" Write the entire lef of the object to the file. """
|
""" Write the entire lef of the object to the file. """
|
||||||
|
|
||||||
if OPTS.drc_exe and OPTS.drc_exe[0] == "magic":
|
if OPTS.detailed_lef:
|
||||||
self.magic_lef_write(lef_name)
|
debug.info(3, "Writing detailed LEF to {0}".format(lef_name))
|
||||||
return
|
self.detailed_lef_write(lef_name)
|
||||||
|
else:
|
||||||
|
debug.info(3, "Writing abstract LEF to {0}".format(lef_name))
|
||||||
|
# Can possibly use magic lef write to create the LEF
|
||||||
|
# if OPTS.drc_exe and OPTS.drc_exe[0] == "magic":
|
||||||
|
# self.magic_lef_write(lef_name)
|
||||||
|
# return
|
||||||
|
self.abstract_lef_write(lef_name)
|
||||||
|
|
||||||
debug.info(3, "Writing detailed LEF to {0}".format(lef_name))
|
def abstract_lef_write(self, lef_name):
|
||||||
|
# To maintain the indent level easily
|
||||||
|
self.indent = ""
|
||||||
|
|
||||||
self.indent = "" # To maintain the indent level easily
|
self.lef = open(lef_name, "w")
|
||||||
|
self.lef_write_header()
|
||||||
|
|
||||||
|
# Start with blockages on all layers the size of the block
|
||||||
|
# minus the pin escape margin (hard coded to 4 x m3 pitch)
|
||||||
|
# These are a pin_layout to use their geometric functions
|
||||||
|
perimeter_margin = self.m3_pitch
|
||||||
|
self.blockages = {}
|
||||||
|
for layer_name in self.lef_layers:
|
||||||
|
self.blockages[layer_name]=[]
|
||||||
|
for layer_name in self.lef_layers:
|
||||||
|
ll = vector(perimeter_margin, perimeter_margin)
|
||||||
|
ur = vector(self.width - perimeter_margin, self.height - perimeter_margin)
|
||||||
|
self.blockages[layer_name].append(pin_layout("",
|
||||||
|
[ll, ur],
|
||||||
|
layer_name))
|
||||||
|
|
||||||
|
# For each pin, remove the blockage and add the pin
|
||||||
|
for pin_name in self.pins:
|
||||||
|
pin = self.get_pin(pin_name)
|
||||||
|
inflated_pin = pin.inflated_pin(multiple=1)
|
||||||
|
for blockage in self.blockages[pin.layer]:
|
||||||
|
if blockage.overlaps(inflated_pin):
|
||||||
|
intersection_shape = blockage.intersection(inflated_pin)
|
||||||
|
# If it is zero area, don't add the pin
|
||||||
|
if intersection_shape[0][0]==intersection_shape[1][0] or intersection_shape[0][1]==intersection_shape[1][1]:
|
||||||
|
continue
|
||||||
|
# Remove the old blockage and add the new ones
|
||||||
|
self.blockages[pin.layer].remove(blockage)
|
||||||
|
intersection_pin = pin_layout("", intersection_shape, inflated_pin.layer)
|
||||||
|
new_blockages = blockage.cut(intersection_pin)
|
||||||
|
self.blockages[pin.layer].extend(new_blockages)
|
||||||
|
|
||||||
|
self.lef_write_pin(pin_name)
|
||||||
|
|
||||||
|
self.lef_write_obstructions(abstracted=True)
|
||||||
|
self.lef_write_footer()
|
||||||
|
self.lef.close()
|
||||||
|
|
||||||
|
def detailed_lef_write(self, lef_name):
|
||||||
|
# To maintain the indent level easily
|
||||||
|
self.indent = ""
|
||||||
|
|
||||||
self.lef = open(lef_name, "w")
|
self.lef = open(lef_name, "w")
|
||||||
self.lef_write_header()
|
self.lef_write_header()
|
||||||
|
|
@ -136,24 +188,29 @@ class lef:
|
||||||
self.indent = self.indent[:-3]
|
self.indent = self.indent[:-3]
|
||||||
self.lef.write("{0}END {1}\n".format(self.indent, name))
|
self.lef.write("{0}END {1}\n".format(self.indent, name))
|
||||||
|
|
||||||
def lef_write_obstructions(self):
|
def lef_write_obstructions(self, abstracted=False):
|
||||||
""" Write all the obstructions on each layer """
|
""" Write all the obstructions on each layer """
|
||||||
self.lef.write("{0}OBS\n".format(self.indent))
|
self.lef.write("{0}OBS\n".format(self.indent))
|
||||||
for layer in self.lef_layers:
|
for layer in self.lef_layers:
|
||||||
self.lef.write("{0}LAYER {1} ;\n".format(self.indent, layer_names[layer]))
|
self.lef.write("{0}LAYER {1} ;\n".format(self.indent, layer_names[layer]))
|
||||||
self.indent += " "
|
self.indent += " "
|
||||||
blockages = self.get_blockages(layer, True)
|
if abstracted:
|
||||||
for b in blockages:
|
blockages = self.blockages[layer]
|
||||||
self.lef_write_shape(b)
|
for b in blockages:
|
||||||
|
self.lef_write_shape(b.rect)
|
||||||
|
else:
|
||||||
|
blockages = self.get_blockages(layer, True)
|
||||||
|
for b in blockages:
|
||||||
|
self.lef_write_shape(b)
|
||||||
self.indent = self.indent[:-3]
|
self.indent = self.indent[:-3]
|
||||||
self.lef.write("{0}END\n".format(self.indent))
|
self.lef.write("{0}END\n".format(self.indent))
|
||||||
|
|
||||||
def lef_write_shape(self, rect):
|
def lef_write_shape(self, obj):
|
||||||
if len(rect) == 2:
|
if len(obj) == 2:
|
||||||
""" Write a LEF rectangle """
|
""" Write a LEF rectangle """
|
||||||
self.lef.write("{0}RECT ".format(self.indent))
|
self.lef.write("{0}RECT ".format(self.indent))
|
||||||
for item in rect:
|
for item in obj:
|
||||||
# print(rect)
|
# print(obj)
|
||||||
self.lef.write(" {0} {1}".format(round(item[0],
|
self.lef.write(" {0} {1}".format(round(item[0],
|
||||||
self.round_grid),
|
self.round_grid),
|
||||||
round(item[1],
|
round(item[1],
|
||||||
|
|
@ -162,12 +219,10 @@ class lef:
|
||||||
else:
|
else:
|
||||||
""" Write a LEF polygon """
|
""" Write a LEF polygon """
|
||||||
self.lef.write("{0}POLYGON ".format(self.indent))
|
self.lef.write("{0}POLYGON ".format(self.indent))
|
||||||
for item in rect:
|
for item in obj:
|
||||||
self.lef.write(" {0} {1}".format(round(item[0],
|
self.lef.write(" {0} {1}".format(round(item[0],
|
||||||
self.round_grid),
|
self.round_grid),
|
||||||
round(item[1],
|
round(item[1],
|
||||||
self.round_grid)))
|
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")
|
self.lef.write(" ;\n")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -139,13 +139,13 @@ class pin_layout:
|
||||||
min_area = drc("{}_minarea".format(self.layer))
|
min_area = drc("{}_minarea".format(self.layer))
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def inflate(self, spacing=None):
|
def inflate(self, spacing=None, multiple=0.5):
|
||||||
"""
|
"""
|
||||||
Inflate the rectangle by the spacing (or other rule)
|
Inflate the rectangle by the spacing (or other rule)
|
||||||
and return the new rectangle.
|
and return the new rectangle.
|
||||||
"""
|
"""
|
||||||
if not spacing:
|
if not spacing:
|
||||||
spacing = 0.5*drc("{0}_to_{0}".format(self.layer))
|
spacing = multiple*drc("{0}_to_{0}".format(self.layer))
|
||||||
|
|
||||||
(ll, ur) = self.rect
|
(ll, ur) = self.rect
|
||||||
spacing = vector(spacing, spacing)
|
spacing = vector(spacing, spacing)
|
||||||
|
|
@ -154,15 +154,23 @@ class pin_layout:
|
||||||
|
|
||||||
return (newll, newur)
|
return (newll, newur)
|
||||||
|
|
||||||
|
def inflated_pin(self, spacing=None, multiple=0.5):
|
||||||
|
"""
|
||||||
|
Inflate the rectangle by the spacing (or other rule)
|
||||||
|
and return the new rectangle.
|
||||||
|
"""
|
||||||
|
inflated_area = self.inflate(spacing, multiple)
|
||||||
|
return pin_layout(self.name, inflated_area, self.layer)
|
||||||
|
|
||||||
def intersection(self, other):
|
def intersection(self, other):
|
||||||
""" Check if a shape overlaps with a rectangle """
|
""" Check if a shape overlaps with a rectangle """
|
||||||
(ll, ur) = self.rect
|
(ll, ur) = self.rect
|
||||||
(oll, our) = other.rect
|
(oll, our) = other.rect
|
||||||
|
|
||||||
min_x = max(ll.x, oll.x)
|
min_x = max(ll.x, oll.x)
|
||||||
max_x = min(ll.x, oll.x)
|
max_x = min(ur.x, our.x)
|
||||||
min_y = max(ll.y, oll.y)
|
min_y = max(ll.y, oll.y)
|
||||||
max_y = min(ll.y, oll.y)
|
max_y = min(ur.y, our.y)
|
||||||
|
|
||||||
return [vector(min_x, min_y), vector(max_x, max_y)]
|
return [vector(min_x, min_y), vector(max_x, max_y)]
|
||||||
|
|
||||||
|
|
@ -578,6 +586,30 @@ class pin_layout:
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def cut(self, shape):
|
||||||
|
"""
|
||||||
|
Return a set of shapes that are this shape minus the argument shape.
|
||||||
|
"""
|
||||||
|
# Make the unique coordinates in X and Y directions
|
||||||
|
x_offsets = sorted([self.lx(), self.rx(), shape.lx(), shape.rx()])
|
||||||
|
y_offsets = sorted([self.by(), self.uy(), shape.by(), shape.uy()])
|
||||||
|
|
||||||
|
new_shapes = []
|
||||||
|
# Create all of the shapes
|
||||||
|
for x1, x2 in zip(x_offsets[0:], x_offsets[1:]):
|
||||||
|
if x1==x2:
|
||||||
|
continue
|
||||||
|
for y1, y2 in zip(y_offsets[0:], y_offsets[1:]):
|
||||||
|
if y1==y2:
|
||||||
|
continue
|
||||||
|
new_shape = pin_layout("", [vector(x1, y1), vector(x2, y2)], self.lpp)
|
||||||
|
# Don't add the existing shape in if it overlaps the pin shape
|
||||||
|
if new_shape.contains(shape):
|
||||||
|
continue
|
||||||
|
new_shapes.append(new_shape)
|
||||||
|
|
||||||
|
return new_shapes
|
||||||
|
|
||||||
def same_lpp(self, lpp1, lpp2):
|
def same_lpp(self, lpp1, lpp2):
|
||||||
"""
|
"""
|
||||||
Check if the layers and purposes are the same.
|
Check if the layers and purposes are the same.
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,11 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
|
||||||
|
|
||||||
def route(self):
|
def route(self):
|
||||||
|
|
||||||
|
global_wl_layer = layer_props.global_bitcell_array.wordline_layer
|
||||||
|
global_wl_pitch = getattr(self, "{}_pitch".format(global_wl_layer))
|
||||||
|
global_wl_pitch_factor = layer_props.global_bitcell_array.wordline_pitch_factor
|
||||||
|
local_wl_layer = layer_props.local_bitcell_array.wordline_layer
|
||||||
|
|
||||||
# Route the global wordlines
|
# Route the global wordlines
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
if port == 0:
|
if port == 0:
|
||||||
|
|
@ -200,9 +205,6 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
|
||||||
|
|
||||||
wordline_pins = self.wl_array.get_inputs()
|
wordline_pins = self.wl_array.get_inputs()
|
||||||
|
|
||||||
wl_layer = layer_props.global_bitcell_array.wordline_layer
|
|
||||||
wl_pitch = getattr(self, "{}_pitch".format(wl_layer))
|
|
||||||
|
|
||||||
for (wl_name, in_pin_name) in zip(wordline_names, wordline_pins):
|
for (wl_name, in_pin_name) in zip(wordline_names, wordline_pins):
|
||||||
# wl_pin = self.bitcell_array_inst.get_pin(wl_name)
|
# wl_pin = self.bitcell_array_inst.get_pin(wl_name)
|
||||||
in_pin = self.wl_insts[port].get_pin(in_pin_name)
|
in_pin = self.wl_insts[port].get_pin(in_pin_name)
|
||||||
|
|
@ -210,23 +212,21 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
|
||||||
y_offset = in_pin.cy()
|
y_offset = in_pin.cy()
|
||||||
|
|
||||||
if port == 0:
|
if port == 0:
|
||||||
y_offset -= 2 * wl_pitch
|
y_offset -= global_wl_pitch_factor * global_wl_pitch
|
||||||
else:
|
else:
|
||||||
y_offset += 2 * wl_pitch
|
y_offset += global_wl_pitch_factor * global_wl_pitch
|
||||||
|
|
||||||
self.add_layout_pin_segment_center(text=wl_name,
|
|
||||||
layer=wl_layer,
|
|
||||||
start=vector(self.wl_insts[port].lx(), y_offset),
|
|
||||||
end=vector(self.wl_insts[port].lx() + self.wl_array.width, y_offset))
|
|
||||||
|
|
||||||
mid = vector(in_pin.cx(), y_offset)
|
mid = vector(in_pin.cx(), y_offset)
|
||||||
self.add_path("m2", [in_pin.center(), mid])
|
|
||||||
|
self.add_layout_pin_rect_center(text=wl_name,
|
||||||
|
layer=global_wl_layer,
|
||||||
|
offset=mid)
|
||||||
|
|
||||||
|
self.add_path(local_wl_layer, [in_pin.center(), mid])
|
||||||
|
|
||||||
self.add_via_stack_center(from_layer=in_pin.layer,
|
self.add_via_stack_center(from_layer=in_pin.layer,
|
||||||
to_layer="m2",
|
to_layer=local_wl_layer,
|
||||||
offset=in_pin.center())
|
offset=mid,
|
||||||
self.add_via_center(self.m2_stack,
|
min_area=True)
|
||||||
offset=mid)
|
|
||||||
|
|
||||||
# Route the buffers
|
# Route the buffers
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,9 @@ class options(optparse.Values):
|
||||||
# Route the input/output pins to the perimeter
|
# Route the input/output pins to the perimeter
|
||||||
perimeter_pins = True
|
perimeter_pins = True
|
||||||
|
|
||||||
|
# Detailed or abstract LEF view
|
||||||
|
detailed_lef = False
|
||||||
|
|
||||||
keep_temp = False
|
keep_temp = False
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -263,13 +263,18 @@ class sram_base(design, verilog, lef):
|
||||||
|
|
||||||
# Add it as an IO pin to the perimeter
|
# Add it as an IO pin to the perimeter
|
||||||
lowest_coord = self.find_lowest_coords()
|
lowest_coord = self.find_lowest_coords()
|
||||||
pin_width = pin.rx() - lowest_coord.x
|
route_width = pin.rx() - lowest_coord.x
|
||||||
|
pin_width = 2 * getattr(self, "{}_width".format(pin.layer))
|
||||||
pin_offset = vector(lowest_coord.x, pin.by())
|
pin_offset = vector(lowest_coord.x, pin.by())
|
||||||
self.add_layout_pin(pin_name,
|
self.add_layout_pin(pin_name,
|
||||||
pin.layer,
|
pin.layer,
|
||||||
pin_offset,
|
pin_offset,
|
||||||
pin_width,
|
pin_width,
|
||||||
pin.height())
|
pin.height())
|
||||||
|
self.add_rect(pin.layer,
|
||||||
|
pin_offset,
|
||||||
|
route_width,
|
||||||
|
pin.height())
|
||||||
|
|
||||||
def route_escape_pins(self):
|
def route_escape_pins(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue