mirror of
https://github.com/VLSIDA/OpenRAM.git
synced 2026-09-04 08:44:12 +02:00
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:
+20
-14
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user