mirror of https://github.com/VLSIDA/OpenRAM.git
Power routing changes.
Make the power rails an "experimental_power" option and conditional. Rename route_vdd_gnd to route_supplies everywhere for consistency.
This commit is contained in:
parent
8b3c10ae79
commit
d69e55c2e3
|
|
@ -478,17 +478,17 @@ class layout():
|
|||
|
||||
top_pos = vector(x, top_y)
|
||||
bot_pos = vector(x, bot_y)
|
||||
self.add_segment_center(layer=pin_layer,
|
||||
start=bot_pos,
|
||||
end=top_pos,
|
||||
width=via_width)
|
||||
|
||||
self.add_layout_pin_rect_center(text=name,
|
||||
layer=pin_layer,
|
||||
offset=top_pos)
|
||||
rect = self.add_layout_pin_rect_center(text=name,
|
||||
layer=pin_layer,
|
||||
offset=top_pos)
|
||||
# self.add_layout_pin_rect_center(text=name,
|
||||
# layer=pin_layer,
|
||||
# offset=bot_pos)
|
||||
self.add_segment_center(layer=pin_layer,
|
||||
start=vector(rect.cx(), bot_pos.y),
|
||||
end=rect.bc(),
|
||||
width=via_width)
|
||||
|
||||
|
||||
|
||||
def route_horizontal_pins(self, name, insts=None, layer=None, xside="cx", yside="cy"):
|
||||
|
|
@ -543,17 +543,21 @@ class layout():
|
|||
|
||||
left_pos = vector(left_x, y)
|
||||
right_pos = vector(right_x, y)
|
||||
self.add_segment_center(layer=pin_layer,
|
||||
start=left_pos,
|
||||
end=right_pos,
|
||||
width=via_height)
|
||||
|
||||
self.add_layout_pin_rect_center(text=name,
|
||||
layer=pin_layer,
|
||||
offset=left_pos)
|
||||
rect = self.add_layout_pin_rect_center(text=name,
|
||||
layer=pin_layer,
|
||||
offset=left_pos)
|
||||
# self.add_layout_pin_rect_center(text=name,
|
||||
# layer=pin_layer,
|
||||
# offset=right_pos)
|
||||
# This is made to not overlap with the pin above
|
||||
# so that the power router will only select a small pin.
|
||||
# Otherwise it adds big blockages over the rails.
|
||||
self.add_segment_center(layer=pin_layer,
|
||||
start=rect.rc(),
|
||||
end=vector(right_pos.x, rect.cy()),
|
||||
width=via_height)
|
||||
|
||||
|
||||
def add_layout_pin_segment_center(self, text, layer, start, end, width=None):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ class hierarchical_decoder(design.design):
|
|||
|
||||
self.width = self.and_inst[0].rx()
|
||||
|
||||
self.route_vdd_gnd()
|
||||
self.route_supplies()
|
||||
|
||||
self.add_boundary()
|
||||
self.DRC_LVS()
|
||||
|
|
@ -589,50 +589,67 @@ class hierarchical_decoder(design.design):
|
|||
output_index)
|
||||
output_index = output_index + 1
|
||||
|
||||
def route_vdd_gnd(self):
|
||||
def route_supplies(self):
|
||||
"""
|
||||
Add a pin for each row of vdd/gnd which are
|
||||
must-connects next level up.
|
||||
"""
|
||||
if layer_props.hierarchical_decoder.vertical_supply:
|
||||
pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst
|
||||
self.route_vertical_pins("vdd", insts=pre_insts, yside="by")
|
||||
self.route_vertical_pins("gnd", insts=pre_insts, yside="by")
|
||||
self.route_vertical_pins("vdd", insts=self.and_inst, yside="by")
|
||||
self.route_vertical_pins("gnd", insts=self.and_inst, yside="by")
|
||||
return
|
||||
for n in ["vdd", "gnd"]:
|
||||
pins = self.and_inst[0].get_pins(n)
|
||||
for pin in pins:
|
||||
self.add_rect(layer=pin.layer,
|
||||
offset=pin.ll() + vector(0, self.bus_space),
|
||||
width=pin.width(),
|
||||
height=self.height - 2 * self.bus_space)
|
||||
|
||||
# This adds power vias at the top of each cell
|
||||
# (except the last to keep them inside the boundary)
|
||||
for i in self.and_inst[:-1]:
|
||||
pins = i.get_pins(n)
|
||||
for pin in pins:
|
||||
self.copy_power_pin(pin, loc=pin.uc())
|
||||
# This is an experiment with power rails
|
||||
if OPTS.experimental_power:
|
||||
if layer_props.hierarchical_decoder.vertical_supply:
|
||||
pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst
|
||||
self.route_vertical_pins("vdd", insts=pre_insts, yside="by")
|
||||
self.route_vertical_pins("gnd", insts=pre_insts, yside="by")
|
||||
self.route_vertical_pins("vdd", insts=self.and_inst, yside="by")
|
||||
self.route_vertical_pins("gnd", insts=self.and_inst, yside="by")
|
||||
else:
|
||||
pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst
|
||||
self.route_vertical_pins("vdd", insts=pre_insts)
|
||||
self.route_vertical_pins("gnd", insts=pre_insts)
|
||||
self.route_vertical_pins("vdd", insts=self.and_inst, xside="rx")
|
||||
self.route_vertical_pins("gnd", insts=self.and_inst, xside="lx")
|
||||
|
||||
for i in self.pre2x4_inst + self.pre3x8_inst:
|
||||
self.copy_layout_pin(i, n)
|
||||
# Widen the rails to cover any gap
|
||||
for inst in self.and_inst:
|
||||
for name in ["vdd", "gnd"]:
|
||||
supply_pin = inst.get_pin(name)
|
||||
self.add_segment_center(layer=supply_pin.layer,
|
||||
start=vector(0, supply_pin.cy()),
|
||||
end=vector(self.width, supply_pin.cy()))
|
||||
else:
|
||||
pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst
|
||||
self.route_vertical_pins("vdd", insts=pre_insts)
|
||||
self.route_vertical_pins("gnd", insts=pre_insts)
|
||||
self.route_vertical_pins("vdd", insts=self.and_inst, xside="rx")
|
||||
self.route_vertical_pins("gnd", insts=self.and_inst, xside="lx")
|
||||
if layer_props.hierarchical_decoder.vertical_supply:
|
||||
for n in ["vdd", "gnd"]:
|
||||
pins = self.and_inst[0].get_pins(n)
|
||||
for pin in pins:
|
||||
self.add_rect(layer=pin.layer,
|
||||
offset=pin.ll() + vector(0, self.bus_space),
|
||||
width=pin.width(),
|
||||
height=self.height - 2 * self.bus_space)
|
||||
|
||||
# Widen the rails to cover any gap
|
||||
for inst in self.and_inst:
|
||||
for name in ["vdd", "gnd"]:
|
||||
supply_pin = inst.get_pin(name)
|
||||
self.add_segment_center(layer=supply_pin.layer,
|
||||
start=vector(0, supply_pin.cy()),
|
||||
end=vector(self.width, supply_pin.cy()))
|
||||
# This adds power vias at the top of each cell
|
||||
# (except the last to keep them inside the boundary)
|
||||
for i in self.and_inst[:-1]:
|
||||
pins = i.get_pins(n)
|
||||
for pin in pins:
|
||||
self.copy_power_pin(pin, loc=pin.uc())
|
||||
|
||||
for i in self.pre2x4_inst + self.pre3x8_inst:
|
||||
self.copy_layout_pin(i, n)
|
||||
else:
|
||||
# The vias will be placed at the right of the cells.
|
||||
xoffset = max(x.rx() for x in self.and_inst) + 0.5 * self.m1_space
|
||||
for row in range(0, self.num_outputs):
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
# The nand and inv are the same height rows...
|
||||
supply_pin = self.and_inst[row].get_pin(pin_name)
|
||||
pin_pos = vector(xoffset, supply_pin.cy())
|
||||
self.copy_power_pin(supply_pin, loc=pin_pos)
|
||||
|
||||
# Copy the pins from the predecoders
|
||||
for pre in self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst:
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
self.copy_layout_pin(pre, pin_name)
|
||||
|
||||
def route_predecode_bus_outputs(self, rail_name, pin, row):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ class hierarchical_predecode(design.design):
|
|||
self.route_output_inverters()
|
||||
self.route_inputs_to_rails()
|
||||
self.route_output_ands()
|
||||
self.route_vdd_gnd()
|
||||
self.route_supplies()
|
||||
|
||||
def route_inputs_to_rails(self):
|
||||
""" Route the uninverted inputs to the second set of rails """
|
||||
|
|
@ -378,7 +378,7 @@ class hierarchical_predecode(design.design):
|
|||
offset=pin_pos,
|
||||
directions=direction)
|
||||
|
||||
def route_vdd_gnd(self):
|
||||
def route_supplies(self):
|
||||
""" Add a pin for each row of vdd/gnd which are must-connects next level up. """
|
||||
|
||||
# We may ahve vertical power supply rails
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ class port_address(design.design):
|
|||
|
||||
# This m4_pitch corresponds to the offset space for jog routing in the
|
||||
# wordline_driver_array
|
||||
rbl_driver_offset = wordline_driver_array_offset + vector(self.m4_pitch, 0)
|
||||
rbl_driver_offset = wordline_driver_array_offset + vector(2 * self.m4_pitch, 0)
|
||||
|
||||
if self.port == 0:
|
||||
self.rbl_driver_inst.place(rbl_driver_offset, "MX")
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ class precharge_array(design.design):
|
|||
self.height = self.pc_cell.height
|
||||
|
||||
self.add_layout_pins()
|
||||
self.route_supplies()
|
||||
self.add_boundary()
|
||||
self.DRC_LVS()
|
||||
|
||||
|
|
@ -81,14 +82,24 @@ 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)
|
||||
self.route_horizontal_pins("vdd")
|
||||
for inst in self.local_insts:
|
||||
self.add_via_stack_center(from_layer=en_pin.layer,
|
||||
to_layer=self.en_bar_layer,
|
||||
offset=inst.get_pin("en_bar").center())
|
||||
|
||||
for i in range(len(self.local_insts)):
|
||||
inst = self.local_insts[i]
|
||||
self.copy_layout_pin(inst, "bl", "bl_{0}".format(i))
|
||||
self.copy_layout_pin(inst, "br", "br_{0}".format(i))
|
||||
|
||||
def route_supplies(self):
|
||||
if OPTS.experimental_power:
|
||||
self.route_horizontal_pins("vdd")
|
||||
else:
|
||||
for inst in self.local_insts:
|
||||
self.copy_layout_pin(inst, "vdd")
|
||||
|
||||
def create_insts(self):
|
||||
"""Creates a precharge array by horizontally tiling the precharge cell"""
|
||||
|
|
|
|||
|
|
@ -462,20 +462,33 @@ class replica_bitcell_array(bitcell_base_array):
|
|||
# replica column should only have a vdd/gnd in the dummy cell on top/bottom
|
||||
supply_insts = self.dummy_col_insts + self.dummy_row_insts
|
||||
|
||||
for pin_name in self.supplies:
|
||||
#self.route_vertical_pins(name=pin_name, insts=supply_insts)
|
||||
self.route_horizontal_pins(name=pin_name, insts=supply_insts)
|
||||
|
||||
#self.route_vertical_pins(name=pin_name, insts=self.replica_col_insts)
|
||||
#self.route_horizontal_pins(name=pin_name, insts=self.replica_col_insts)
|
||||
for inst in supply_insts:
|
||||
pin_list = inst.get_pins(pin_name)
|
||||
for pin in pin_list:
|
||||
self.copy_power_pin(pin)
|
||||
if OPTS.experimental_power:
|
||||
for pin_name in self.supplies:
|
||||
#self.route_vertical_pins(name=pin_name, insts=supply_insts)
|
||||
self.route_horizontal_pins(name=pin_name, insts=supply_insts)
|
||||
|
||||
#self.route_vertical_pins(name=pin_name, insts=self.replica_col_insts)
|
||||
#self.route_horizontal_pins(name=pin_name, insts=self.replica_col_insts)
|
||||
for inst in supply_insts:
|
||||
pin_list = inst.get_pins(pin_name)
|
||||
for pin in pin_list:
|
||||
self.copy_power_pin(pin)
|
||||
|
||||
for inst in self.replica_col_insts:
|
||||
if inst:
|
||||
self.copy_layout_pin(inst, pin_name)
|
||||
else:
|
||||
for pin_name in self.supplies:
|
||||
for inst in supply_insts:
|
||||
pin_list = inst.get_pins(pin_name)
|
||||
for pin in pin_list:
|
||||
self.copy_power_pin(pin)
|
||||
|
||||
for inst in self.replica_col_insts:
|
||||
if inst:
|
||||
self.copy_layout_pin(inst, pin_name)
|
||||
|
||||
for inst in self.replica_col_insts:
|
||||
if inst:
|
||||
self.copy_layout_pin(inst, pin_name)
|
||||
|
||||
def analytical_power(self, corner, load):
|
||||
"""Power of Bitcell array and bitline in nW."""
|
||||
|
|
|
|||
|
|
@ -75,8 +75,8 @@ class sense_amp_array(design.design):
|
|||
self.width = self.local_insts[-1].rx()
|
||||
|
||||
self.add_layout_pins()
|
||||
self.route_horizontal_pins("vdd")
|
||||
self.route_horizontal_pins("gnd")
|
||||
|
||||
self.route_supplies()
|
||||
self.route_rails()
|
||||
|
||||
self.add_boundary()
|
||||
|
|
@ -173,6 +173,20 @@ class sense_amp_array(design.design):
|
|||
width=dout_pin.width(),
|
||||
height=dout_pin.height())
|
||||
|
||||
def route_supplies(self):
|
||||
if OPTS.experimental_power:
|
||||
self.route_horizontal_pins("vdd")
|
||||
self.route_horizontal_pins("gnd")
|
||||
else:
|
||||
for i in range(len(self.local_insts)):
|
||||
inst = self.local_insts[i]
|
||||
|
||||
for gnd_pin in inst.get_pins("gnd"):
|
||||
self.copy_power_pin(gnd_pin)
|
||||
|
||||
for vdd_pin in inst.get_pins("vdd"):
|
||||
self.copy_power_pin(vdd_pin)
|
||||
|
||||
def route_rails(self):
|
||||
# Add enable across the array
|
||||
en_pin = self.amp.get_pin(self.amp.en_name)
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class wordline_driver_array(design.design):
|
|||
|
||||
self.place_drivers()
|
||||
self.route_layout()
|
||||
self.offset_x_coordinates(vector(-self.m4_pitch, 0))
|
||||
self.offset_x_coordinates(vector(-2*self.m4_pitch, 0))
|
||||
|
||||
# Leave a well gap to separate the bitcell array well from this well
|
||||
well_gap = 2 * drc("pwell_to_nwell") + drc("nwell_enclose_active")
|
||||
|
|
@ -76,20 +76,50 @@ class wordline_driver_array(design.design):
|
|||
"""
|
||||
Add vertical power rails.
|
||||
"""
|
||||
if layer_props.wordline_driver.vertical_supply:
|
||||
self.route_vertical_pins("vdd", insts=self.wld_inst)
|
||||
self.route_vertical_pins("gnd", insts=self.wld_inst)
|
||||
else:
|
||||
self.route_vertical_pins("vdd", insts=self.wld_inst, xside="lx")
|
||||
self.route_vertical_pins("gnd", insts=self.wld_inst, xside="rx")
|
||||
|
||||
# Widen the rails to cover any gap
|
||||
for num in range(self.rows):
|
||||
# Experiment with power straps
|
||||
if OPTS.experimental_power:
|
||||
if layer_props.wordline_driver.vertical_supply:
|
||||
self.route_vertical_pins("vdd", insts=self.wld_inst)
|
||||
self.route_vertical_pins("gnd", insts=self.wld_inst)
|
||||
else:
|
||||
self.route_vertical_pins("vdd", insts=self.wld_inst, xside="lx")
|
||||
self.route_vertical_pins("gnd", insts=self.wld_inst, xside="rx")
|
||||
|
||||
# Widen the rails to cover any gap
|
||||
for num in range(self.rows):
|
||||
for name in ["vdd", "gnd"]:
|
||||
supply_pin = self.wld_inst[num].get_pin(name)
|
||||
self.add_segment_center(layer=supply_pin.layer,
|
||||
start=vector(0, supply_pin.cy()),
|
||||
end=vector(self.width, supply_pin.cy()))
|
||||
else:
|
||||
if layer_props.wordline_driver.vertical_supply:
|
||||
for name in ["vdd", "gnd"]:
|
||||
supply_pin = self.wld_inst[num].get_pin(name)
|
||||
self.add_segment_center(layer=supply_pin.layer,
|
||||
start=vector(0, supply_pin.cy()),
|
||||
end=vector(self.width, supply_pin.cy()))
|
||||
supply_pins = self.wld_inst[0].get_pins(name)
|
||||
for pin in supply_pins:
|
||||
self.add_layout_pin_segment_center(text=name,
|
||||
layer=pin.layer,
|
||||
start=pin.bc(),
|
||||
end=vector(pin.cx(), self.height))
|
||||
else:
|
||||
# Find the x offsets for where the vias/pins should be placed
|
||||
xoffset_list = [self.wld_inst[0].rx()]
|
||||
for num in range(self.rows):
|
||||
# this will result in duplicate polygons for rails, but who cares
|
||||
|
||||
# use the inverter offset even though it will be the and's too
|
||||
(gate_offset, y_dir) = self.get_gate_offset(0,
|
||||
self.wl_driver.height,
|
||||
num)
|
||||
# Route both supplies
|
||||
for name in ["vdd", "gnd"]:
|
||||
supply_pin = self.wld_inst[num].get_pin(name)
|
||||
|
||||
# Add pins in two locations
|
||||
for xoffset in xoffset_list:
|
||||
pin_pos = vector(xoffset, supply_pin.cy())
|
||||
self.copy_power_pin(supply_pin, loc=pin_pos)
|
||||
|
||||
|
||||
def create_drivers(self):
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ class write_driver_array(design.design):
|
|||
self.width = self.local_insts[-1].rx()
|
||||
self.height = self.driver.height
|
||||
self.add_layout_pins()
|
||||
self.route_supplies()
|
||||
self.add_boundary()
|
||||
self.DRC_LVS()
|
||||
|
||||
|
|
@ -204,9 +205,6 @@ class write_driver_array(design.design):
|
|||
width=br_pin.width(),
|
||||
height=br_pin.height())
|
||||
|
||||
self.route_horizontal_pins("vdd")
|
||||
self.route_horizontal_pins("gnd")
|
||||
|
||||
if self.write_size:
|
||||
for bit in range(self.num_wmasks):
|
||||
inst = self.local_insts[bit * self.write_size]
|
||||
|
|
@ -256,3 +254,17 @@ class write_driver_array(design.design):
|
|||
layer="m1",
|
||||
offset=inst.get_pin(inst.mod.en_name).ll().scale(0, 1),
|
||||
width=self.width)
|
||||
|
||||
def route_supplies(self):
|
||||
if OPTS.experimental_power:
|
||||
self.route_horizontal_pins("vdd")
|
||||
self.route_horizontal_pins("gnd")
|
||||
else:
|
||||
for i in range(self.word_size + self.num_spare_cols):
|
||||
inst = self.local_insts[i]
|
||||
for n in ["vdd", "gnd"]:
|
||||
pin_list = inst.get_pins(n)
|
||||
for pin in pin_list:
|
||||
self.copy_power_pin(pin, directions=("V", "V"))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -197,3 +197,6 @@ class options(optparse.Values):
|
|||
write_driver_array = "write_driver_array"
|
||||
write_driver = "write_driver"
|
||||
write_mask_and_array = "write_mask_and_array"
|
||||
|
||||
# Non-public options
|
||||
experimental_power = False
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ class precharge(design.design):
|
|||
self.connect_poly()
|
||||
self.route_en()
|
||||
self.place_nwell_and_contact()
|
||||
self.route_vdd()
|
||||
self.route_supplies()
|
||||
self.route_bitlines()
|
||||
self.connect_to_bitlines()
|
||||
self.add_boundary()
|
||||
|
|
@ -91,28 +91,51 @@ class precharge(design.design):
|
|||
mults=self.ptx_mults,
|
||||
tx_type="pmos")
|
||||
|
||||
def route_vdd(self):
|
||||
def route_supplies(self):
|
||||
"""
|
||||
Adds a vdd rail at the top of the cell
|
||||
"""
|
||||
|
||||
pmos_pin = self.upper_pmos2_inst.get_pin("S")
|
||||
pmos_pos = pmos_pin.center()
|
||||
self.add_path(pmos_pin.layer, [pmos_pos, self.well_contact_pos])
|
||||
if OPTS.experimental_power:
|
||||
pmos_pin = self.upper_pmos2_inst.get_pin("S")
|
||||
pmos_pos = pmos_pin.center()
|
||||
self.add_path(pmos_pin.layer, [pmos_pos, self.well_contact_pos])
|
||||
|
||||
self.add_via_stack_center(from_layer=pmos_pin.layer,
|
||||
to_layer=self.supply_stack[0],
|
||||
offset=self.well_contact_pos,
|
||||
directions=("V", "V"))
|
||||
|
||||
self.add_min_area_rect_center(layer=self.en_layer,
|
||||
self.add_via_stack_center(from_layer=pmos_pin.layer,
|
||||
to_layer=self.supply_stack[0],
|
||||
offset=self.well_contact_pos,
|
||||
width=self.well_contact.mod.second_layer_width)
|
||||
directions=("V", "V"))
|
||||
|
||||
self.add_layout_pin_rect_center(text="vdd",
|
||||
layer=self.supply_stack[0],
|
||||
offset=self.well_contact_pos)
|
||||
self.add_min_area_rect_center(layer=self.en_layer,
|
||||
offset=self.well_contact_pos,
|
||||
width=self.well_contact.mod.second_layer_width)
|
||||
|
||||
self.add_layout_pin_rect_center(text="vdd",
|
||||
layer=self.supply_stack[0],
|
||||
offset=self.well_contact_pos)
|
||||
else:
|
||||
# Adds the rail across the width of the cell
|
||||
vdd_position = vector(0.5 * self.width, self.height)
|
||||
layer_width = drc("minwidth_" + self.en_layer)
|
||||
self.add_rect_center(layer=self.en_layer,
|
||||
offset=vdd_position,
|
||||
width=self.width,
|
||||
height=layer_width)
|
||||
|
||||
pmos_pin = self.upper_pmos2_inst.get_pin("S")
|
||||
|
||||
# center of vdd rail
|
||||
pmos_vdd_pos = vector(pmos_pin.cx(), vdd_position.y)
|
||||
self.add_path(self.en_layer, [pmos_pin.center(), pmos_vdd_pos])
|
||||
|
||||
self.add_power_pin("vdd",
|
||||
self.well_contact_pos,
|
||||
directions=("V", "V"))
|
||||
|
||||
self.add_via_stack_center(from_layer=pmos_pin.layer,
|
||||
to_layer=self.en_layer,
|
||||
offset=pmos_pin.center(),
|
||||
directions=("V", "V"))
|
||||
|
||||
def create_ptx(self):
|
||||
"""
|
||||
|
|
|
|||
Loading…
Reference in New Issue