mirror of https://github.com/VLSIDA/OpenRAM.git
Reimplement off grid pins.
Long pins aren't accessed on end pins anymore. Fix problem with multiple non-enclosed space causing blockages. Add partial pin offgrid enclosure algorithm.
This commit is contained in:
parent
7195d81736
commit
b1bb9151c4
|
|
@ -419,13 +419,6 @@ class layout():
|
|||
pin.width(),
|
||||
pin.height())
|
||||
|
||||
def copy_layout_pins(self, instance, prefix=""):
|
||||
"""
|
||||
Create a copied version of the layout pin at the current level.
|
||||
You can optionally rename the pin to a new name.
|
||||
"""
|
||||
for pin_name in self.pin_map.keys():
|
||||
self.copy_layout_pin(instance, pin_name, prefix + pin_name)
|
||||
|
||||
def connect_row_locs(self, from_layer, to_layer, locs, name=None, full=False):
|
||||
"""
|
||||
|
|
@ -608,12 +601,11 @@ class layout():
|
|||
|
||||
|
||||
|
||||
def route_vertical_pins(self, name, insts=None, layer=None, xside="cx", yside="cy", num_pins=2, full_width=True):
|
||||
def route_vertical_pins(self, name, insts=None, layer=None, xside="cx", yside="cy", full_width=True):
|
||||
"""
|
||||
Route together all of the pins of a given name that vertically align.
|
||||
Uses local_insts if insts not specified.
|
||||
Uses center of pin by default, or right or left if specified.
|
||||
num_pins specifies whether to add a single pin or multiple pins (equally spaced)
|
||||
TODO: Add equally spaced option for IR drop min, right now just 2
|
||||
"""
|
||||
|
||||
|
|
@ -660,8 +652,10 @@ class layout():
|
|||
|
||||
if last_via:
|
||||
via_width=last_via.mod.second_layer_width
|
||||
via_height=last_via.mod.second_layer_height
|
||||
else:
|
||||
via_width=None
|
||||
via_height=0
|
||||
|
||||
if full_width:
|
||||
bot_y = 0
|
||||
|
|
@ -669,21 +663,19 @@ class layout():
|
|||
else:
|
||||
bot_y = min([pin.by() for (inst,pin) in v])
|
||||
top_y = max([pin.uy() for (inst,pin) in v])
|
||||
top_pos = vector(x, top_y)
|
||||
bot_pos = vector(x, bot_y)
|
||||
top_pos = vector(x, top_y + 0.5 * via_height)
|
||||
bot_pos = vector(x, bot_y - 0.5 * via_height)
|
||||
|
||||
if num_pins==2:
|
||||
self.add_layout_pin_rect_ends(name=name,
|
||||
layer=pin_layer,
|
||||
start=top_pos,
|
||||
end=bot_pos,
|
||||
width=via_width)
|
||||
else:
|
||||
self.add_layout_pin_segment_center(text=name,
|
||||
layer=pin_layer,
|
||||
start=top_pos,
|
||||
end=bot_pos,
|
||||
width=via_width)
|
||||
# self.add_layout_pin_rect_ends(name=name,
|
||||
# layer=pin_layer,
|
||||
# start=top_pos,
|
||||
# end=bot_pos,
|
||||
# width=via_width)
|
||||
self.add_layout_pin_segment_center(text=name,
|
||||
layer=pin_layer,
|
||||
start=top_pos,
|
||||
end=bot_pos,
|
||||
width=via_width)
|
||||
|
||||
|
||||
def add_layout_pin_rect_ends(self, name, layer, start, end, width=None):
|
||||
|
|
@ -707,12 +699,13 @@ class layout():
|
|||
start=bot_rect.rc(),
|
||||
end=top_rect.lc())
|
||||
|
||||
def route_horizontal_pins(self, name, insts=None, layer=None, xside="cx", yside="cy", num_pins=2, full_width=True):
|
||||
return (bot_rect, top_rect)
|
||||
|
||||
def route_horizontal_pins(self, name, insts=None, layer=None, xside="cx", yside="cy", full_width=True):
|
||||
"""
|
||||
Route together all of the pins of a given name that horizontally align.
|
||||
Uses local_insts if insts not specified.
|
||||
Uses center of pin by default, or top or botom if specified.
|
||||
num_pins specifies whether to add a single pin or multiple pins (equally spaced)
|
||||
TODO: Add equally spaced option for IR drop min, right now just 2
|
||||
"""
|
||||
|
||||
|
|
@ -760,8 +753,10 @@ class layout():
|
|||
|
||||
if last_via:
|
||||
via_height=last_via.mod.second_layer_height
|
||||
via_width=last_via.mod.second_layer_width
|
||||
else:
|
||||
via_height=None
|
||||
via_width=0
|
||||
|
||||
if full_width:
|
||||
left_x = 0
|
||||
|
|
@ -769,22 +764,19 @@ class layout():
|
|||
else:
|
||||
left_x = min([pin.lx() for (inst,pin) in v])
|
||||
right_x = max([pin.rx() for (inst,pin) in v])
|
||||
left_pos = vector(left_x, y)
|
||||
right_pos = vector(right_x, y)
|
||||
left_pos = vector(left_x + 0.5 * via_width, y)
|
||||
right_pos = vector(right_x + 0.5 * via_width, y)
|
||||
|
||||
if num_pins==2:
|
||||
self.add_layout_pin_rect_ends(name=name,
|
||||
layer=pin_layer,
|
||||
start=left_pos,
|
||||
end=right_pos,
|
||||
width=via_height)
|
||||
else:
|
||||
# This adds a single big pin
|
||||
self.add_layout_pin_segment_center(text=name,
|
||||
layer=pin_layer,
|
||||
start=left_pos,
|
||||
end=right_pos,
|
||||
width=via_height)
|
||||
# self.add_layout_pin_rect_ends(name=name,
|
||||
# layer=pin_layer,
|
||||
# start=left_pos,
|
||||
# end=right_pos,
|
||||
# width=via_height)
|
||||
self.add_layout_pin_segment_center(text=name,
|
||||
layer=pin_layer,
|
||||
start=left_pos,
|
||||
end=right_pos,
|
||||
width=via_height)
|
||||
|
||||
def add_layout_end_pin_segment_center(self, text, layer, start, end):
|
||||
"""
|
||||
|
|
@ -1123,7 +1115,6 @@ class layout():
|
|||
Add a minimum area retcangle at the given point.
|
||||
Either width or height should be fixed.
|
||||
"""
|
||||
|
||||
min_area = drc("minarea_{}".format(layer))
|
||||
if min_area == 0:
|
||||
return
|
||||
|
|
|
|||
|
|
@ -174,6 +174,10 @@ class pin_layout:
|
|||
|
||||
def intersection(self, other):
|
||||
""" Check if a shape overlaps with a rectangle """
|
||||
|
||||
if not self.overlaps(other):
|
||||
return None
|
||||
|
||||
(ll, ur) = self.rect
|
||||
(oll, our) = other.rect
|
||||
|
||||
|
|
@ -182,6 +186,9 @@ class pin_layout:
|
|||
min_y = max(ll.y, oll.y)
|
||||
max_y = min(ur.y, our.y)
|
||||
|
||||
if max_x - min_x == 0 or max_y - min_y == 0:
|
||||
return None
|
||||
|
||||
return [vector(min_x, min_y), vector(max_x, max_y)]
|
||||
|
||||
def xoverlaps(self, other):
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ class bank(design.design):
|
|||
|
||||
# UPPER LEFT QUADRANT
|
||||
# To the left of the bitcell array above the predecoders and control logic
|
||||
x_offset = self.m2_gap + self.port_address[port].width
|
||||
x_offset = self.decoder_gap + self.port_address[port].width
|
||||
self.port_address_offsets[port] = vector(-x_offset,
|
||||
self.main_bitcell_array_bottom)
|
||||
|
||||
|
|
@ -272,7 +272,7 @@ class bank(design.design):
|
|||
|
||||
# LOWER RIGHT QUADRANT
|
||||
# To the right of the bitcell array
|
||||
x_offset = self.bitcell_array_right + self.port_address[port].width + self.m2_gap
|
||||
x_offset = self.bitcell_array_right + self.port_address[port].width + self.decoder_gap
|
||||
self.port_address_offsets[port] = vector(x_offset,
|
||||
self.main_bitcell_array_bottom)
|
||||
|
||||
|
|
@ -364,9 +364,9 @@ class bank(design.design):
|
|||
self.num_col_addr_lines = 0
|
||||
self.col_addr_bus_width = self.m2_pitch * self.num_col_addr_lines
|
||||
|
||||
# A space for wells or jogging m2
|
||||
self.m2_gap = max(2 * drc("pwell_to_nwell") + drc("nwell_enclose_active"),
|
||||
3 * self.m2_pitch,
|
||||
# Gap between decoder and array
|
||||
self.decoder_gap = max(2 * drc("pwell_to_nwell") + drc("nwell_enclose_active"),
|
||||
2 * self.m2_pitch,
|
||||
drc("nwell_to_nwell"))
|
||||
|
||||
def add_modules(self):
|
||||
|
|
@ -400,11 +400,10 @@ class bank(design.design):
|
|||
self.port_data = []
|
||||
self.bit_offsets = self.get_column_offsets()
|
||||
for port in self.all_ports:
|
||||
temp_pre = factory.create(module_type="port_data",
|
||||
sram_config=self.sram_config,
|
||||
port=port,
|
||||
bit_offsets=self.bit_offsets)
|
||||
self.port_data.append(temp_pre)
|
||||
self.port_data.append(factory.create(module_type="port_data",
|
||||
sram_config=self.sram_config,
|
||||
port=port,
|
||||
bit_offsets=self.bit_offsets))
|
||||
|
||||
if(self.num_banks > 1):
|
||||
self.bank_select = factory.create(module_type="bank_select")
|
||||
|
|
@ -606,15 +605,22 @@ class bank(design.design):
|
|||
|
||||
def route_supplies(self):
|
||||
""" Propagate all vdd/gnd pins up to this level for all modules """
|
||||
|
||||
# Copy only the power pins already on the power layer
|
||||
# (this won't add vias to internal bitcell pins, for example)
|
||||
for inst in self.insts:
|
||||
self.copy_power_pins(inst, "vdd", add_vias=False)
|
||||
self.copy_power_pins(inst, "gnd", add_vias=False)
|
||||
|
||||
# This avoids getting copy errors on vias and other instances
|
||||
all_insts = [self.bitcell_array_inst] + self.port_address_inst + self.port_data_inst
|
||||
if hasattr(self, "column_decoder_inst"):
|
||||
all_insts += self.column_decoder_inst
|
||||
|
||||
for inst in all_insts:
|
||||
self.copy_layout_pin(inst, "vdd")
|
||||
self.copy_layout_pin(inst, "gnd")
|
||||
|
||||
if 'vpb' in self.bitcell_array_inst.mod.pins and 'vnb' in self.bitcell_array_inst.mod.pins:
|
||||
for pin_name, supply_name in zip(['vnb','vpb'],['gnd','vdd']):
|
||||
self.copy_power_pins(self.bitcell_array_inst, pin_name, new_name=supply_name)
|
||||
self.copy_layout_pin(self.bitcell_array_inst, pin_name, new_name=supply_name)
|
||||
|
||||
# If we use the pinvbuf as the decoder, we need to add power pins.
|
||||
# Other decoders already have them.
|
||||
|
|
|
|||
|
|
@ -715,12 +715,17 @@ class control_logic(design.design):
|
|||
pin_layer = self.dff.get_pin("vdd").layer
|
||||
supply_layer = self.supply_stack[2]
|
||||
|
||||
|
||||
# FIXME: We should be able to replace this with route_vertical_pins instead
|
||||
# but we may have to make the logic gates a separate module so that they
|
||||
# have row pins of the same width
|
||||
max_row_x_loc = max([inst.rx() for inst in self.row_end_inst])
|
||||
min_row_x_loc = self.control_x_offset
|
||||
|
||||
vdd_pin_locs = []
|
||||
gnd_pin_locs = []
|
||||
|
||||
last_via = None
|
||||
for inst in self.row_end_inst:
|
||||
pins = inst.get_pins("vdd")
|
||||
for pin in pins:
|
||||
|
|
@ -728,10 +733,10 @@ class control_logic(design.design):
|
|||
row_loc = pin.rc()
|
||||
pin_loc = vector(max_row_x_loc, pin.rc().y)
|
||||
vdd_pin_locs.append(pin_loc)
|
||||
self.add_via_stack_center(from_layer=pin_layer,
|
||||
to_layer=supply_layer,
|
||||
offset=pin_loc,
|
||||
min_area=True)
|
||||
last_via = self.add_via_stack_center(from_layer=pin_layer,
|
||||
to_layer=supply_layer,
|
||||
offset=pin_loc,
|
||||
min_area=True)
|
||||
self.add_path(pin_layer, [row_loc, pin_loc])
|
||||
|
||||
pins = inst.get_pins("gnd")
|
||||
|
|
@ -740,29 +745,38 @@ class control_logic(design.design):
|
|||
row_loc = pin.rc()
|
||||
pin_loc = vector(min_row_x_loc, pin.rc().y)
|
||||
gnd_pin_locs.append(pin_loc)
|
||||
self.add_via_stack_center(from_layer=pin_layer,
|
||||
to_layer=supply_layer,
|
||||
offset=pin_loc,
|
||||
min_area=True)
|
||||
last_via = self.add_via_stack_center(from_layer=pin_layer,
|
||||
to_layer=supply_layer,
|
||||
offset=pin_loc,
|
||||
min_area=True)
|
||||
self.add_path(pin_layer, [row_loc, pin_loc])
|
||||
|
||||
if last_via:
|
||||
via_height=last_via.mod.second_layer_height
|
||||
via_width=last_via.mod.second_layer_width
|
||||
else:
|
||||
via_height=None
|
||||
via_width=0
|
||||
|
||||
min_y = min([x.y for x in vdd_pin_locs])
|
||||
max_y = max([x.y for x in vdd_pin_locs])
|
||||
bot_pos = vector(max_row_x_loc, min_y)
|
||||
top_pos = vector(max_row_x_loc, max_y)
|
||||
bot_pos = vector(max_row_x_loc, min_y - 0.5 * via_height)
|
||||
top_pos = vector(max_row_x_loc, max_y + 0.5 * via_height)
|
||||
self.add_layout_pin_segment_center(text="vdd",
|
||||
layer=supply_layer,
|
||||
start=bot_pos,
|
||||
end=top_pos)
|
||||
end=top_pos,
|
||||
width=via_width)
|
||||
|
||||
min_y = min([x.y for x in gnd_pin_locs])
|
||||
max_y = max([x.y for x in gnd_pin_locs])
|
||||
bot_pos = vector(min_row_x_loc, min_y)
|
||||
top_pos = vector(min_row_x_loc, max_y)
|
||||
bot_pos = vector(min_row_x_loc, min_y - 0.5 * via_height)
|
||||
top_pos = vector(min_row_x_loc, max_y + 0.5 * via_height)
|
||||
self.add_layout_pin_segment_center(text="gnd",
|
||||
layer=supply_layer,
|
||||
start=bot_pos,
|
||||
end=top_pos)
|
||||
end=top_pos,
|
||||
width=via_width)
|
||||
|
||||
self.copy_layout_pin(self.delay_inst, "gnd")
|
||||
self.copy_layout_pin(self.delay_inst, "vdd")
|
||||
|
|
|
|||
|
|
@ -172,25 +172,9 @@ class delay_chain(design.design):
|
|||
self.add_path("m2", [z_pin.center(), mid1_point, mid2_point, next_a_pin.center()])
|
||||
|
||||
def route_supplies(self):
|
||||
# Add power and ground to all the cells except:
|
||||
# the fanout driver, the right-most load
|
||||
# The routing to connect the loads is over the first and last cells
|
||||
# We have an even number of drivers and must only do every other
|
||||
# supply rail
|
||||
if True or OPTS.experimental_power:
|
||||
left_load_insts = [self.load_inst_map[x][0] for x in self.driver_inst_list]
|
||||
right_load_insts = [self.load_inst_map[x][-1] for x in self.driver_inst_list]
|
||||
self.route_vertical_pins("vdd", left_load_insts, xside="lx")
|
||||
self.route_vertical_pins("gnd", right_load_insts, xside="rx")
|
||||
else:
|
||||
for inst in self.driver_inst_list:
|
||||
load_list = self.load_inst_map[inst]
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
pin = load_list[0].get_pin(pin_name)
|
||||
self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0))
|
||||
|
||||
pin = load_list[-2].get_pin(pin_name)
|
||||
self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0))
|
||||
self.route_vertical_pins("vdd", self.driver_inst_list, xside="lx")
|
||||
right_load_insts = [self.load_inst_map[x][-1] for x in self.driver_inst_list]
|
||||
self.route_vertical_pins("gnd", right_load_insts, xside="rx")
|
||||
|
||||
def add_layout_pins(self):
|
||||
|
||||
|
|
|
|||
|
|
@ -595,14 +595,12 @@ class hierarchical_decoder(design.design):
|
|||
# Leave these to route in the port_address
|
||||
all_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst
|
||||
for inst in all_insts:
|
||||
self.copy_layout_pin(inst, "vdd")
|
||||
self.copy_layout_pin(inst, "gnd")
|
||||
self.copy_layout_pin(inst, "vdd")
|
||||
self.copy_layout_pin(inst, "gnd")
|
||||
|
||||
self.route_vertical_pins("vdd", self.and_inst, xside="rx",)
|
||||
self.route_vertical_pins("gnd", self.and_inst, xside="lx",)
|
||||
|
||||
for inst in self.and_inst:
|
||||
for pin in inst.get_pins("vdd"):
|
||||
self.add_power_pin("vdd", pin.rc())
|
||||
for pin in inst.get_pins("gnd"):
|
||||
self.add_power_pin("gnd", pin.lc())
|
||||
|
||||
|
||||
def route_predecode_bus_outputs(self, rail_name, pin, row):
|
||||
|
|
|
|||
|
|
@ -395,7 +395,7 @@ class hierarchical_predecode(design.design):
|
|||
height=top_pin.uy() - self.bus_pitch)
|
||||
# This adds power vias at the top of each cell
|
||||
# (except the last to keep them inside the boundary)
|
||||
for i in self.inv_inst[:-1:2] + self.and_inst[:-1:2]:
|
||||
for i in [self.inv_inst[0], self.inv_inst[-2], self.and_inst[0], self.and_inst[-2]]:
|
||||
pins = i.get_pins(n)
|
||||
for pin in pins:
|
||||
self.copy_power_pin(pin, loc=pin.uc())
|
||||
|
|
|
|||
|
|
@ -162,14 +162,15 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
|
|||
# FIXME: Replace this with a tech specific paramter
|
||||
driver_to_array_spacing = 3 * self.m3_pitch
|
||||
|
||||
self.wl_insts[0].place(vector(0, self.cell.height))
|
||||
self.wl_insts[0].place(vector(0,
|
||||
self.bitcell_array.get_replica_bottom() + self.cell.height))
|
||||
|
||||
self.bitcell_array_inst.place(vector(self.wl_insts[0].rx() + driver_to_array_spacing,
|
||||
0))
|
||||
|
||||
if len(self.all_ports) > 1:
|
||||
self.wl_insts[1].place(vector(self.bitcell_array_inst.rx() + self.wl_array.width + driver_to_array_spacing,
|
||||
2 * self.cell.height + self.wl_array.height),
|
||||
self.bitcell_array.get_replica_top() + self.cell.height),
|
||||
mirror="XY")
|
||||
|
||||
self.height = self.bitcell_array.height
|
||||
|
|
|
|||
|
|
@ -76,22 +76,19 @@ class port_address(design.design):
|
|||
|
||||
def route_supplies(self):
|
||||
""" Propagate all vdd/gnd pins up to this level for all modules """
|
||||
self.route_vertical_pins("vdd", [self.row_decoder_inst])
|
||||
self.route_vertical_pins("gnd", [self.row_decoder_inst])
|
||||
self.route_vertical_pins("vdd", [self.wordline_driver_array_inst])
|
||||
if layer_props.wordline_driver.vertical_supply:
|
||||
self.route_vertical_pins("gnd", [self.wordline_driver_array_inst])
|
||||
self.copy_layout_pin(self.rbl_driver_inst, "vdd")
|
||||
else:
|
||||
rbl_pos = self.rbl_driver_inst.get_pin("vdd").rc()
|
||||
self.add_power_pin("vdd", rbl_pos)
|
||||
self.add_path("m4", [rbl_pos, self.wordline_driver_array_inst.get_pins("vdd")[0].rc()])
|
||||
|
||||
vdd_pins = self.row_decoder_inst.get_pins("vdd") + self.wordline_driver_array_inst.get_pins("vdd")
|
||||
self.connect_row_pins(self.route_layer, vdd_pins)
|
||||
gnd_pins = self.row_decoder_inst.get_pins("gnd") + self.wordline_driver_array_inst.get_pins("gnd")
|
||||
self.connect_row_pins(self.route_layer, gnd_pins)
|
||||
|
||||
self.copy_layout_pin(self.wordline_driver_array_inst, "vdd")
|
||||
self.copy_layout_pin(self.wordline_driver_array_inst, "gnd")
|
||||
|
||||
self.copy_layout_pin(self.row_decoder_inst, "vdd")
|
||||
self.copy_layout_pin(self.row_decoder_inst, "gnd")
|
||||
|
||||
# Also connect the B input of the RBL and_dec to vdd
|
||||
if OPTS.local_array_size == 0:
|
||||
rbl_b_pin = self.rbl_driver_inst.get_pin("B")
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ class precharge_array(design.design):
|
|||
def add_layout_pins(self):
|
||||
|
||||
en_pin = self.pc_cell.get_pin("en_bar")
|
||||
self.route_horizontal_pins("en_bar", layer=self.en_bar_layer, num_pins=1)
|
||||
self.route_horizontal_pins("en_bar", layer=self.en_bar_layer)
|
||||
for inst in self.local_insts:
|
||||
self.add_via_stack_center(from_layer=en_pin.layer,
|
||||
to_layer=self.en_bar_layer,
|
||||
|
|
|
|||
|
|
@ -331,6 +331,7 @@ class replica_bitcell_array(bitcell_base_array):
|
|||
self.translate_all(array_offset.scale(-1, -1))
|
||||
|
||||
# Add extra width on the left and right for the unused WLs
|
||||
|
||||
self.width = self.dummy_col_insts[1].rx() + self.unused_offset.x
|
||||
self.height = self.dummy_row_insts[1].uy()
|
||||
|
||||
|
|
@ -340,6 +341,12 @@ class replica_bitcell_array(bitcell_base_array):
|
|||
|
||||
self.route_unused_wordlines()
|
||||
|
||||
lower_left = self.find_lowest_coords()
|
||||
upper_right = self.find_highest_coords()
|
||||
self.width = upper_right.x - lower_left.x
|
||||
self.height = upper_right.y - lower_left.y
|
||||
self.translate_all(lower_left)
|
||||
|
||||
self.add_boundary()
|
||||
|
||||
self.DRC_LVS()
|
||||
|
|
@ -356,6 +363,18 @@ class replica_bitcell_array(bitcell_base_array):
|
|||
def get_main_array_right(self):
|
||||
return self.bitcell_array_inst.rx()
|
||||
|
||||
def get_replica_top(self):
|
||||
return max([x.uy() for x in self.replica_col_insts if x] + [self.get_main_array_top()])
|
||||
|
||||
def get_replica_bottom(self):
|
||||
return min([x.by() for x in self.replica_col_insts if x] + [self.get_main_array_bottom()])
|
||||
|
||||
def get_replica_left(self):
|
||||
return min([x.lx() for x in self.replica_col_insts if x] + [self.get_main_array_left()])
|
||||
|
||||
def get_replica_right(self):
|
||||
return min([x.rx() for x in self.replica_col_insts if x] + [self.get_main_array_right()])
|
||||
|
||||
def get_column_offsets(self):
|
||||
"""
|
||||
Return an array of the x offsets of all the regular bits
|
||||
|
|
@ -567,14 +586,15 @@ class replica_bitcell_array(bitcell_base_array):
|
|||
top_loc = vector(self.width + offset_multiple * self.vertical_pitch, self.height)
|
||||
|
||||
layer = self.supply_stack[2]
|
||||
self.add_path(layer, [bot_loc, top_loc])
|
||||
|
||||
self.add_layout_pin_rect_center(text=name,
|
||||
layer=layer,
|
||||
offset=top_loc)
|
||||
self.add_layout_pin_rect_center(text=name,
|
||||
layer=layer,
|
||||
offset=bot_loc)
|
||||
# self.add_layout_pin_rect_ends(text=name,
|
||||
# layer=layer,
|
||||
# start=bot_loc,
|
||||
# end=top_loc)
|
||||
self.add_layout_pin_segment_center(text=name,
|
||||
layer=layer,
|
||||
start=bot_loc,
|
||||
end=top_loc)
|
||||
|
||||
return (bot_loc, top_loc)
|
||||
|
||||
|
|
@ -590,14 +610,15 @@ class replica_bitcell_array(bitcell_base_array):
|
|||
right_loc = vector(self.width, self.height + offset_multiple * self.horizontal_pitch)
|
||||
|
||||
layer = self.supply_stack[0]
|
||||
self.add_path(layer, [left_loc, right_loc])
|
||||
|
||||
self.add_layout_pin_rect_center(text=name,
|
||||
layer=layer,
|
||||
offset=left_loc)
|
||||
self.add_layout_pin_rect_center(text=name,
|
||||
layer=layer,
|
||||
offset=right_loc)
|
||||
# self.add_layout_pin_rect_ends(text=name,
|
||||
# layer=layer,
|
||||
# start=left_loc,
|
||||
# end=right_loc)
|
||||
self.add_layout_pin_segment_center(text=name,
|
||||
layer=layer,
|
||||
start=left_loc,
|
||||
end=right_loc)
|
||||
|
||||
return (left_loc, right_loc)
|
||||
|
||||
|
|
|
|||
|
|
@ -77,11 +77,12 @@ class wordline_driver_array(design.design):
|
|||
Add vertical power rails.
|
||||
"""
|
||||
|
||||
for inst in self.wld_inst:
|
||||
for pin in inst.get_pins("vdd"):
|
||||
self.add_power_pin("vdd", pin.rc())
|
||||
#self.copy_layout_pin(inst, "vdd")
|
||||
self.copy_layout_pin(inst, "gnd")
|
||||
if layer_props.wordline_driver.vertical_supply:
|
||||
self.route_vertical_pins("vdd", self.wld_inst)
|
||||
self.route_vertical_pins("gnd", self.wld_inst)
|
||||
else:
|
||||
self.route_vertical_pins("vdd", self.wld_inst, xside="rx",)
|
||||
self.route_vertical_pins("gnd", self.wld_inst, xside="lx",)
|
||||
|
||||
|
||||
def create_drivers(self):
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ class pin_group:
|
|||
# Now add the right name
|
||||
for pin in new_pin_list:
|
||||
pin.name = self.name
|
||||
|
||||
|
||||
debug.check(len(new_pin_list) > 0,
|
||||
"Did not find any enclosures.")
|
||||
|
||||
|
|
@ -424,7 +424,7 @@ class pin_group:
|
|||
debug.check(len(self.grids) > 0, "Cannot seed an grid empty set.")
|
||||
|
||||
common_blockages = self.router.get_blocked_grids() & self.grids
|
||||
|
||||
|
||||
# Start with the ll and make the widest row
|
||||
row = [ll]
|
||||
# Move in dir1 while we can
|
||||
|
|
@ -641,7 +641,7 @@ class pin_group:
|
|||
# way than blockages.
|
||||
blockages = sufficient | insufficient | blockage_in_tracks
|
||||
self.blockages.update(blockages)
|
||||
|
||||
|
||||
# If we have a blockage, we must remove the grids
|
||||
# Remember, this excludes the pin blockages already
|
||||
blocked_grids = self.router.get_blocked_grids()
|
||||
|
|
|
|||
|
|
@ -229,9 +229,9 @@ class router(router_tech):
|
|||
|
||||
# Enclose the continguous grid units in a metal
|
||||
# rectangle to fix some DRCs
|
||||
start_time = datetime.now()
|
||||
self.enclose_pins()
|
||||
print_time("Enclosing pins", datetime.now(), start_time, 4)
|
||||
#start_time = datetime.now()
|
||||
#self.enclose_pins()
|
||||
#print_time("Enclosing pins", datetime.now(), start_time, 4)
|
||||
|
||||
# MRG: Removing this code for now. The later compute enclosure code
|
||||
# assumes that all pins are touching and this may produce sets of pins
|
||||
|
|
@ -670,6 +670,25 @@ class router(router_tech):
|
|||
|
||||
return set([best_coord])
|
||||
|
||||
def divide_pin_to_tracks(self, pin, tracks):
|
||||
"""
|
||||
Return a list of pin shape parts that are in the tracks.
|
||||
"""
|
||||
overlap_pins = []
|
||||
for track in tracks:
|
||||
track_pin = self.convert_track_to_shape_pin(track)
|
||||
overlap_rect = track_pin.intersection(pin)
|
||||
if not overlap_rect:
|
||||
continue
|
||||
else:
|
||||
overlap_pin = pin_layout(pin.name,
|
||||
overlap_rect,
|
||||
pin.layer)
|
||||
overlap_pins.append(overlap_pin)
|
||||
|
||||
return overlap_pins
|
||||
|
||||
|
||||
def convert_pin_coord_to_tracks(self, pin, coord):
|
||||
"""
|
||||
Return all tracks that an inflated pin overlaps
|
||||
|
|
@ -893,6 +912,8 @@ class router(router_tech):
|
|||
This will mark the grids for all pin components as a source.
|
||||
Marking as source or target also clears blockage status.
|
||||
"""
|
||||
self.source_name = pin_name
|
||||
self.source_components = []
|
||||
for i in range(self.num_pin_components(pin_name)):
|
||||
self.add_pin_component_source(pin_name, i)
|
||||
|
||||
|
|
@ -904,6 +925,8 @@ class router(router_tech):
|
|||
This will mark the grids for all pin components as a target.
|
||||
Marking as source or target also clears blockage status.
|
||||
"""
|
||||
self.target_name = pin_name
|
||||
self.target_components = []
|
||||
for i in range(self.num_pin_components(pin_name)):
|
||||
self.add_pin_component_target(pin_name, i)
|
||||
|
||||
|
|
@ -1009,6 +1032,8 @@ class router(router_tech):
|
|||
"""
|
||||
This will mark all the cells on the perimeter of the original layout as a target.
|
||||
"""
|
||||
self.target_name = ""
|
||||
self.target_components = []
|
||||
self.rg.add_perimeter_target(side=side)
|
||||
|
||||
def num_pin_components(self, pin_name):
|
||||
|
|
@ -1017,6 +1042,15 @@ class router(router_tech):
|
|||
"""
|
||||
return len(self.pin_groups[pin_name])
|
||||
|
||||
def set_pin_component_source(self, pin_name, index):
|
||||
"""
|
||||
Add the pin component but also set it as the exclusive one.
|
||||
Used by supply routing with multiple components.
|
||||
"""
|
||||
self.source_name = pin_name
|
||||
self.source_components = []
|
||||
self.add_pin_component_source(pin_name, index)
|
||||
|
||||
def add_pin_component_source(self, pin_name, index):
|
||||
"""
|
||||
This will mark only the pin tracks
|
||||
|
|
@ -1026,6 +1060,7 @@ class router(router_tech):
|
|||
debug.check(index<self.num_pin_components(pin_name),
|
||||
"Pin component index too large.")
|
||||
|
||||
self.source_components.append(index)
|
||||
pin_in_tracks = self.pin_groups[pin_name][index].grids
|
||||
debug.info(3,"Set source: " + str(pin_name) + " " + str(pin_in_tracks))
|
||||
self.rg.add_source(pin_in_tracks)
|
||||
|
|
@ -1038,6 +1073,15 @@ class router(router_tech):
|
|||
self.rg.set_target(p)
|
||||
self.rg.set_blocked(p, False)
|
||||
|
||||
def set_pin_component_target(self, pin_name, index):
|
||||
"""
|
||||
Add the pin component but also set it as the exclusive one.
|
||||
Used by supply routing with multiple components.
|
||||
"""
|
||||
self.target_name = pin_name
|
||||
self.target_components = []
|
||||
self.add_pin_component_target(pin_name, index)
|
||||
|
||||
def add_pin_component_target(self, pin_name, index):
|
||||
"""
|
||||
This will mark only the pin tracks
|
||||
|
|
@ -1046,6 +1090,7 @@ class router(router_tech):
|
|||
"""
|
||||
debug.check(index<self.num_pin_components(pin_name),"Pin component index too large.")
|
||||
|
||||
self.target_components.append(index)
|
||||
pin_in_tracks = self.pin_groups[pin_name][index].grids
|
||||
debug.info(3, "Set target: " + str(pin_name) + " " + str(pin_in_tracks))
|
||||
self.rg.add_target(pin_in_tracks)
|
||||
|
|
@ -1093,25 +1138,71 @@ class router(router_tech):
|
|||
"""
|
||||
Add the current wire route to the given design instance.
|
||||
"""
|
||||
path = self.prepare_path(path)
|
||||
prepared_path = self.prepare_path(path)
|
||||
|
||||
debug.info(4, "Adding route: {}".format(str(path)))
|
||||
# If it is only a square, add an enclosure to the track
|
||||
if len(path) == 1:
|
||||
self.add_single_enclosure(path[0][0])
|
||||
debug.info(4, "Adding route: {}".format(str(prepared_path)))
|
||||
|
||||
# convert the path back to absolute units from tracks
|
||||
# This assumes 1-track wide again
|
||||
abs_path = [self.convert_point_to_units(x[0]) for x in prepared_path]
|
||||
|
||||
if len(self.layers) > 1:
|
||||
self.cell.add_route(layers=self.layers,
|
||||
coordinates=abs_path,
|
||||
layer_widths=self.layer_widths)
|
||||
else:
|
||||
# convert the path back to absolute units from tracks
|
||||
# This assumes 1-track wide again
|
||||
abs_path = [self.convert_point_to_units(x[0]) for x in path]
|
||||
# Otherwise, add the route which includes enclosures
|
||||
if len(self.layers) > 1:
|
||||
self.cell.add_route(layers=self.layers,
|
||||
coordinates=abs_path,
|
||||
layer_widths=self.layer_widths)
|
||||
else:
|
||||
self.cell.add_path(layer=self.layers[0],
|
||||
coordinates=abs_path,
|
||||
width=self.layer_widths[0])
|
||||
self.cell.add_path(layer=self.layers[0],
|
||||
coordinates=abs_path,
|
||||
width=self.layer_widths[0])
|
||||
|
||||
def create_route_connector(self, path_tracks, pin_name, components):
|
||||
"""
|
||||
Find a rectangle to connect the track and the off-grid pin of a component.
|
||||
"""
|
||||
|
||||
if len(path_tracks) == 0 or len(components) == 0:
|
||||
return
|
||||
|
||||
# Convert the off-grid pin into parts in each routing grid
|
||||
offgrid_pin_parts = []
|
||||
for component in components:
|
||||
pg = self.pin_groups[pin_name][component]
|
||||
for pin in pg.pins:
|
||||
partial_pin_parts = self.divide_pin_to_tracks(pin, pg.grids)
|
||||
offgrid_pin_parts.extend(partial_pin_parts)
|
||||
|
||||
# Find the track pin
|
||||
track_pins = [self.convert_tracks_to_pin(x) for x in path_tracks]
|
||||
|
||||
# Find closest part
|
||||
closest_track_pin, closest_part_pin = self.find_closest_pin(track_pins, offgrid_pin_parts)
|
||||
|
||||
# Find the bbox of the on-grid track and the off-grid pin part
|
||||
closest_track_pin.bbox([closest_part_pin])
|
||||
|
||||
# Connect to off grid pin to track pin with closest shape
|
||||
self.cell.add_rect(layer=closest_track_pin.layer,
|
||||
offset=closest_track_pin.ll(),
|
||||
width=closest_track_pin.width(),
|
||||
height=closest_track_pin.height())
|
||||
|
||||
def find_closest_pin(self, first_list, second_list):
|
||||
"""
|
||||
Find the closest pin in the lists. Does a stupid O(n^2).
|
||||
"""
|
||||
min_dist = None
|
||||
min_item = None
|
||||
for pin1 in first_list:
|
||||
for pin2 in second_list:
|
||||
if pin1.layer != pin2.layer:
|
||||
continue
|
||||
new_dist = pin1.distance(pin2)
|
||||
if not min_item or new_dist < min_dist:
|
||||
min_item = (pin1, pin2)
|
||||
min_dist = new_dist
|
||||
|
||||
return min_item
|
||||
|
||||
|
||||
def add_single_enclosure(self, track):
|
||||
"""
|
||||
|
|
@ -1192,7 +1283,15 @@ class router(router_tech):
|
|||
|
||||
self.paths.append(grid_utils.flatten_set(path))
|
||||
self.add_route(path)
|
||||
self.create_route_connector(path,
|
||||
self.source_name,
|
||||
self.source_components)
|
||||
self.create_route_connector(path,
|
||||
self.target_name,
|
||||
self.target_components)
|
||||
self.path_blockages.append(self.paths[-1])
|
||||
#self.write_debug_gds("debug_route.gds", False)
|
||||
#breakpoint()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ class supply_tree_router(router):
|
|||
print("DST {}: ".format(dest) + str(self.pin_groups[pin_name][dest].grids) + str(self.pin_groups[pin_name][dest].blockages))
|
||||
self.write_debug_gds("post_{0}_{1}.gds".format(src, dest), False)
|
||||
|
||||
#self.write_debug_gds("final_tree_router_{}.gds".format(pin_name), False)
|
||||
self.write_debug_gds("final_tree_router_{}.gds".format(pin_name), False)
|
||||
#return
|
||||
|
||||
def route_signal(self, pin_name, src_idx, dest_idx):
|
||||
|
|
@ -180,11 +180,11 @@ class supply_tree_router(router):
|
|||
|
||||
# Add the single component of the pin as the source
|
||||
# which unmarks it as a blockage too
|
||||
self.add_pin_component_source(pin_name, src_idx)
|
||||
self.set_pin_component_source(pin_name, src_idx)
|
||||
|
||||
# Marks all pin components except index as target
|
||||
# which unmarks it as a blockage too
|
||||
self.add_pin_component_target(pin_name, dest_idx)
|
||||
self.set_pin_component_target(pin_name, dest_idx)
|
||||
|
||||
# Actually run the A* router
|
||||
if self.run_router(detour_scale=detour_scale):
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ class sram_base(design, verilog, lef):
|
|||
|
||||
self.add_lvs_correspondence_points()
|
||||
|
||||
self.offset_all_coordinates()
|
||||
#self.offset_all_coordinates()
|
||||
|
||||
highest_coord = self.find_highest_coords()
|
||||
self.width = highest_coord[0]
|
||||
|
|
|
|||
|
|
@ -14,6 +14,6 @@ tech_name = OPTS.tech_name
|
|||
nominal_corner_only = True
|
||||
check_lvsdrc = True
|
||||
|
||||
route_supplies = False
|
||||
#route_supplies = False
|
||||
|
||||
output_name = "sram"
|
||||
|
|
|
|||
Loading…
Reference in New Issue