Abstracted LEF added. Params for array wordline layers.

This commit is contained in:
mrg 2021-04-21 10:07:37 -07:00
parent 584349c911
commit f45efe3db6
7 changed files with 139 additions and 41 deletions

View File

@ -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")

View File

@ -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,

View File

@ -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")

View File

@ -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.

View File

@ -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:

View File

@ -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

View File

@ -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):
""" """