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:
mrg
2022-03-06 09:56:00 -08:00
parent 8b3c10ae79
commit d69e55c2e3
11 changed files with 227 additions and 100 deletions
+53 -36
View File
@@ -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):
"""
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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")
+12 -1
View File
@@ -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"""
+25 -12
View File
@@ -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."""
+16 -2
View File
@@ -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)
+43 -13
View File
@@ -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):
+15 -3
View File
@@ -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"))