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)
|
top_pos = vector(x, top_y)
|
||||||
bot_pos = vector(x, bot_y)
|
bot_pos = vector(x, bot_y)
|
||||||
self.add_segment_center(layer=pin_layer,
|
rect = self.add_layout_pin_rect_center(text=name,
|
||||||
start=bot_pos,
|
layer=pin_layer,
|
||||||
end=top_pos,
|
offset=top_pos)
|
||||||
width=via_width)
|
|
||||||
|
|
||||||
self.add_layout_pin_rect_center(text=name,
|
|
||||||
layer=pin_layer,
|
|
||||||
offset=top_pos)
|
|
||||||
# self.add_layout_pin_rect_center(text=name,
|
# self.add_layout_pin_rect_center(text=name,
|
||||||
# layer=pin_layer,
|
# layer=pin_layer,
|
||||||
# offset=bot_pos)
|
# 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"):
|
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)
|
left_pos = vector(left_x, y)
|
||||||
right_pos = vector(right_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,
|
rect = self.add_layout_pin_rect_center(text=name,
|
||||||
layer=pin_layer,
|
layer=pin_layer,
|
||||||
offset=left_pos)
|
offset=left_pos)
|
||||||
# self.add_layout_pin_rect_center(text=name,
|
# self.add_layout_pin_rect_center(text=name,
|
||||||
# layer=pin_layer,
|
# layer=pin_layer,
|
||||||
# offset=right_pos)
|
# 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):
|
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.width = self.and_inst[0].rx()
|
||||||
|
|
||||||
self.route_vdd_gnd()
|
self.route_supplies()
|
||||||
|
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
@ -589,50 +589,67 @@ class hierarchical_decoder(design.design):
|
||||||
output_index)
|
output_index)
|
||||||
output_index = output_index + 1
|
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
|
Add a pin for each row of vdd/gnd which are
|
||||||
must-connects next level up.
|
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
|
# This is an experiment with power rails
|
||||||
# (except the last to keep them inside the boundary)
|
if OPTS.experimental_power:
|
||||||
for i in self.and_inst[:-1]:
|
if layer_props.hierarchical_decoder.vertical_supply:
|
||||||
pins = i.get_pins(n)
|
pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst
|
||||||
for pin in pins:
|
self.route_vertical_pins("vdd", insts=pre_insts, yside="by")
|
||||||
self.copy_power_pin(pin, loc=pin.uc())
|
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:
|
# Widen the rails to cover any gap
|
||||||
self.copy_layout_pin(i, n)
|
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:
|
else:
|
||||||
pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst
|
if layer_props.hierarchical_decoder.vertical_supply:
|
||||||
self.route_vertical_pins("vdd", insts=pre_insts)
|
for n in ["vdd", "gnd"]:
|
||||||
self.route_vertical_pins("gnd", insts=pre_insts)
|
pins = self.and_inst[0].get_pins(n)
|
||||||
self.route_vertical_pins("vdd", insts=self.and_inst, xside="rx")
|
for pin in pins:
|
||||||
self.route_vertical_pins("gnd", insts=self.and_inst, xside="lx")
|
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
|
# This adds power vias at the top of each cell
|
||||||
for inst in self.and_inst:
|
# (except the last to keep them inside the boundary)
|
||||||
for name in ["vdd", "gnd"]:
|
for i in self.and_inst[:-1]:
|
||||||
supply_pin = inst.get_pin(name)
|
pins = i.get_pins(n)
|
||||||
self.add_segment_center(layer=supply_pin.layer,
|
for pin in pins:
|
||||||
start=vector(0, supply_pin.cy()),
|
self.copy_power_pin(pin, loc=pin.uc())
|
||||||
end=vector(self.width, supply_pin.cy()))
|
|
||||||
|
|
||||||
|
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):
|
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_output_inverters()
|
||||||
self.route_inputs_to_rails()
|
self.route_inputs_to_rails()
|
||||||
self.route_output_ands()
|
self.route_output_ands()
|
||||||
self.route_vdd_gnd()
|
self.route_supplies()
|
||||||
|
|
||||||
def route_inputs_to_rails(self):
|
def route_inputs_to_rails(self):
|
||||||
""" Route the uninverted inputs to the second set of rails """
|
""" Route the uninverted inputs to the second set of rails """
|
||||||
|
|
@ -378,7 +378,7 @@ class hierarchical_predecode(design.design):
|
||||||
offset=pin_pos,
|
offset=pin_pos,
|
||||||
directions=direction)
|
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. """
|
""" Add a pin for each row of vdd/gnd which are must-connects next level up. """
|
||||||
|
|
||||||
# We may ahve vertical power supply rails
|
# 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
|
# This m4_pitch corresponds to the offset space for jog routing in the
|
||||||
# wordline_driver_array
|
# 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:
|
if self.port == 0:
|
||||||
self.rbl_driver_inst.place(rbl_driver_offset, "MX")
|
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.height = self.pc_cell.height
|
||||||
|
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
|
self.route_supplies()
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
|
|
@ -81,14 +82,24 @@ class precharge_array(design.design):
|
||||||
|
|
||||||
def add_layout_pins(self):
|
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("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)):
|
for i in range(len(self.local_insts)):
|
||||||
inst = self.local_insts[i]
|
inst = self.local_insts[i]
|
||||||
self.copy_layout_pin(inst, "bl", "bl_{0}".format(i))
|
self.copy_layout_pin(inst, "bl", "bl_{0}".format(i))
|
||||||
self.copy_layout_pin(inst, "br", "br_{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):
|
def create_insts(self):
|
||||||
"""Creates a precharge array by horizontally tiling the precharge cell"""
|
"""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
|
# 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
|
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)
|
if OPTS.experimental_power:
|
||||||
#self.route_horizontal_pins(name=pin_name, insts=self.replica_col_insts)
|
for pin_name in self.supplies:
|
||||||
for inst in supply_insts:
|
#self.route_vertical_pins(name=pin_name, insts=supply_insts)
|
||||||
pin_list = inst.get_pins(pin_name)
|
self.route_horizontal_pins(name=pin_name, insts=supply_insts)
|
||||||
for pin in pin_list:
|
|
||||||
self.copy_power_pin(pin)
|
#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):
|
def analytical_power(self, corner, load):
|
||||||
"""Power of Bitcell array and bitline in nW."""
|
"""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.width = self.local_insts[-1].rx()
|
||||||
|
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
self.route_horizontal_pins("vdd")
|
|
||||||
self.route_horizontal_pins("gnd")
|
self.route_supplies()
|
||||||
self.route_rails()
|
self.route_rails()
|
||||||
|
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
|
|
@ -173,6 +173,20 @@ class sense_amp_array(design.design):
|
||||||
width=dout_pin.width(),
|
width=dout_pin.width(),
|
||||||
height=dout_pin.height())
|
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):
|
def route_rails(self):
|
||||||
# Add enable across the array
|
# Add enable across the array
|
||||||
en_pin = self.amp.get_pin(self.amp.en_name)
|
en_pin = self.amp.get_pin(self.amp.en_name)
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ class wordline_driver_array(design.design):
|
||||||
|
|
||||||
self.place_drivers()
|
self.place_drivers()
|
||||||
self.route_layout()
|
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
|
# Leave a well gap to separate the bitcell array well from this well
|
||||||
well_gap = 2 * drc("pwell_to_nwell") + drc("nwell_enclose_active")
|
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.
|
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
|
# Experiment with power straps
|
||||||
for num in range(self.rows):
|
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"]:
|
for name in ["vdd", "gnd"]:
|
||||||
supply_pin = self.wld_inst[num].get_pin(name)
|
supply_pins = self.wld_inst[0].get_pins(name)
|
||||||
self.add_segment_center(layer=supply_pin.layer,
|
for pin in supply_pins:
|
||||||
start=vector(0, supply_pin.cy()),
|
self.add_layout_pin_segment_center(text=name,
|
||||||
end=vector(self.width, supply_pin.cy()))
|
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):
|
def create_drivers(self):
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ class write_driver_array(design.design):
|
||||||
self.width = self.local_insts[-1].rx()
|
self.width = self.local_insts[-1].rx()
|
||||||
self.height = self.driver.height
|
self.height = self.driver.height
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
|
self.route_supplies()
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
|
|
@ -204,9 +205,6 @@ class write_driver_array(design.design):
|
||||||
width=br_pin.width(),
|
width=br_pin.width(),
|
||||||
height=br_pin.height())
|
height=br_pin.height())
|
||||||
|
|
||||||
self.route_horizontal_pins("vdd")
|
|
||||||
self.route_horizontal_pins("gnd")
|
|
||||||
|
|
||||||
if self.write_size:
|
if self.write_size:
|
||||||
for bit in range(self.num_wmasks):
|
for bit in range(self.num_wmasks):
|
||||||
inst = self.local_insts[bit * self.write_size]
|
inst = self.local_insts[bit * self.write_size]
|
||||||
|
|
@ -256,3 +254,17 @@ class write_driver_array(design.design):
|
||||||
layer="m1",
|
layer="m1",
|
||||||
offset=inst.get_pin(inst.mod.en_name).ll().scale(0, 1),
|
offset=inst.get_pin(inst.mod.en_name).ll().scale(0, 1),
|
||||||
width=self.width)
|
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_array = "write_driver_array"
|
||||||
write_driver = "write_driver"
|
write_driver = "write_driver"
|
||||||
write_mask_and_array = "write_mask_and_array"
|
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.connect_poly()
|
||||||
self.route_en()
|
self.route_en()
|
||||||
self.place_nwell_and_contact()
|
self.place_nwell_and_contact()
|
||||||
self.route_vdd()
|
self.route_supplies()
|
||||||
self.route_bitlines()
|
self.route_bitlines()
|
||||||
self.connect_to_bitlines()
|
self.connect_to_bitlines()
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
|
|
@ -91,28 +91,51 @@ class precharge(design.design):
|
||||||
mults=self.ptx_mults,
|
mults=self.ptx_mults,
|
||||||
tx_type="pmos")
|
tx_type="pmos")
|
||||||
|
|
||||||
def route_vdd(self):
|
def route_supplies(self):
|
||||||
"""
|
"""
|
||||||
Adds a vdd rail at the top of the cell
|
Adds a vdd rail at the top of the cell
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pmos_pin = self.upper_pmos2_inst.get_pin("S")
|
if OPTS.experimental_power:
|
||||||
pmos_pos = pmos_pin.center()
|
pmos_pin = self.upper_pmos2_inst.get_pin("S")
|
||||||
self.add_path(pmos_pin.layer, [pmos_pos, self.well_contact_pos])
|
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,
|
self.add_via_stack_center(from_layer=pmos_pin.layer,
|
||||||
to_layer=self.supply_stack[0],
|
to_layer=self.supply_stack[0],
|
||||||
offset=self.well_contact_pos,
|
|
||||||
directions=("V", "V"))
|
|
||||||
|
|
||||||
self.add_min_area_rect_center(layer=self.en_layer,
|
|
||||||
offset=self.well_contact_pos,
|
offset=self.well_contact_pos,
|
||||||
width=self.well_contact.mod.second_layer_width)
|
directions=("V", "V"))
|
||||||
|
|
||||||
self.add_layout_pin_rect_center(text="vdd",
|
self.add_min_area_rect_center(layer=self.en_layer,
|
||||||
layer=self.supply_stack[0],
|
offset=self.well_contact_pos,
|
||||||
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):
|
def create_ptx(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue