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:
mrg
2022-05-02 15:43:14 -07:00
parent 7195d81736
commit b1bb9151c4
17 changed files with 274 additions and 155 deletions
+20 -14
View File
@@ -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.
+28 -14
View File
@@ -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")
+3 -19
View File
@@ -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):
+5 -7
View File
@@ -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):
+1 -1
View File
@@ -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())
+3 -2
View File
@@ -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
+6 -9
View File
@@ -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")
+1 -1
View File
@@ -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,
+35 -14
View File
@@ -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)
+6 -5
View File
@@ -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):