Rework replica_bitcell_array supplies

Uses layer and direction preferences in tech file.
Places straps on left/right or top/bottom.
This commit is contained in:
mrg 2022-04-19 08:50:11 -07:00
parent 5e546ee974
commit 64f2f90664
11 changed files with 210 additions and 61 deletions

View File

@ -156,6 +156,16 @@ class bitcell(cell):
self.storage_nets = storage_nets
self.wl_layer = "m1"
self.wl_dir = "H"
self.bl_layer = "m2"
self.bl_dir = "V"
self.vdd_layer = "m1"
self.vdd_dir = "H"
self.gnd_layer = "m1"
self.gnd_dir = "H"
class cell_properties():
"""

View File

@ -673,9 +673,9 @@ class layout():
bot_pos = vector(x, bot_y)
if num_pins==2:
self.add_layout_pin_rect_ends(name=name,
layer=pin_layer,
start=top_pos,
self.add_layout_pin_rect_ends(name=name,
layer=pin_layer,
start=top_pos,
end=bot_pos,
width=via_width)
else:
@ -689,10 +689,10 @@ class layout():
def add_layout_pin_rect_ends(self, name, layer, start, end, width=None):
# This adds pins on the end connected by a segment
top_rect = self.add_layout_pin_rect_center(text=name,
top_rect = self.add_layout_pin_rect_center(text=name,
layer=layer,
offset=start)
bot_rect = self.add_layout_pin_rect_center(text=name,
bot_rect = self.add_layout_pin_rect_center(text=name,
layer=layer,
offset=end)
# This is made to not overlap with the pin above
@ -773,9 +773,9 @@ class layout():
right_pos = vector(right_x, y)
if num_pins==2:
self.add_layout_pin_rect_ends(name=name,
layer=pin_layer,
start=left_pos,
self.add_layout_pin_rect_ends(name=name,
layer=pin_layer,
start=left_pos,
end=right_pos,
width=via_height)
else:
@ -812,7 +812,6 @@ class layout():
end=end_pin.bc())
else:
debug.error("Cannot have a point pin.", -1)
def add_layout_pin_segment_center(self, text, layer, start, end, width=None):
"""

View File

@ -99,4 +99,4 @@ class col_cap_array(bitcell_base_array):
inst = self.cell_inst[row, col]
for pin_name in ["vdd", "gnd"]:
for pin in inst.get_pins(pin_name):
self.copy_power_pin(pin)
self.copy_layout_pin(inst, pin_name)

View File

@ -145,6 +145,15 @@ class dff_buf_array(design.design):
return dout_bar_name
def route_supplies(self):
for row in range(self.rows):
vdd0_pin=self.dff_insts[row, 0].get_pin("vdd")
vddn_pin=self.dff_insts[row, self.columns - 1].get_pin("vdd")
self.add_path(vdd0_pin.layer, [vdd0_pin.lc(), vddn_pin.rc()], width=vdd0_pin.height())
gnd0_pin=self.dff_insts[row, 0].get_pin("gnd")
gndn_pin=self.dff_insts[row, self.columns - 1].get_pin("gnd")
self.add_path(gnd0_pin.layer, [gnd0_pin.lc(), gndn_pin.rc()], width=gnd0_pin.height())
if OPTS.experimental_power and self.rows > 1:
# Vertical straps on ends if multiple rows
left_dff_insts = [self.dff_insts[x, 0] for x in range(self.rows)]

View File

@ -6,7 +6,8 @@
import debug
from bitcell_base_array import bitcell_base_array
from tech import drc, spice, cell_properties
from tech import drc, spice, preferred_directions
from tech import cell_properties as props
from vector import vector
from globals import OPTS
from sram_factory import factory
@ -309,7 +310,7 @@ class replica_bitcell_array(bitcell_base_array):
# row-based or column based power and ground lines.
self.vertical_pitch = getattr(self, "{}_pitch".format(self.supply_stack[0]))
self.horizontal_pitch = getattr(self, "{}_pitch".format(self.supply_stack[2]))
self.unused_offset = vector(2 * self.horizontal_pitch, 2 * self.vertical_pitch)
self.unused_offset = vector(0.25, 0.25)
# This is a bitcell x bitcell offset to scale
self.bitcell_offset = vector(self.cell.width, self.cell.height)
@ -461,38 +462,67 @@ class replica_bitcell_array(bitcell_base_array):
def route_supplies(self):
bitcell = getattr(props, "bitcell_{}port".format(OPTS.num_ports))
wl_layer = bitcell.wl_layer
wl_dir = bitcell.wl_dir
bl_layer = bitcell.bl_layer
bl_dir = bitcell.bl_dir
vdd_layer = bitcell.vdd_layer
vdd_dir = bitcell.vdd_dir
gnd_layer = bitcell.gnd_layer
gnd_dir = bitcell.gnd_dir
# vdd/gnd are only connected in the perimeter cells
# 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
vdd_leftx = 0
vdd_rightx = 0
gnd_leftx = 0
gnd_rightx = 0
# For the wordlines
top_bot_mult = 1
left_right_mult = 1
vdd_locs = []
gnd_locs = []
# There are always vertical pins for the WLs on the left/right if we have unused wordlines
self.left_gnd_locs = self.route_side_pin("gnd", "left", left_right_mult)
self.right_gnd_locs = self.route_side_pin("gnd","right", left_right_mult)
left_right_mult = 3
if gnd_dir == "V":
self.top_gnd_locs = self.route_side_pin("gnd", "top", top_bot_mult)
self.bot_gnd_locs = self.route_side_pin("gnd", "bot", top_bot_mult)
top_bot_mult = 3
if vdd_dir == "V":
self.top_vdd_locs = self.route_side_pin("vdd", "top", top_bot_mult)
self.bot_vdd_locs = self.route_side_pin("vdd", "bot", top_bot_mult)
elif vdd_dir == "H":
self.left_vdd_locs = self.route_side_pin("vdd", "left", left_right_mult)
self.right_vdd_locs = self.route_side_pin("vdd", "right", left_right_mult)
else:
debug.error("Invalid vdd direction {}".format(vdd_dir), -1)
for inst in supply_insts:
for pin in inst.get_pins("vdd"):
(vdd_leftx, vdd_rightx) = self.connect_pin(pin, 2.5)
if vdd_dir == "V":
self.connect_side_pin(pin, "top", self.top_vdd_locs[0].y)
self.connect_side_pin(pin, "bot", self.bot_vdd_locs[0].y)
elif vdd_dir == "H":
self.connect_side_pin(pin, "left", self.left_vdd_locs[0].x)
self.connect_side_pin(pin, "right", self.right_vdd_locs[0].x)
for inst in supply_insts:
for pin in inst.get_pins("gnd"):
(gnd_leftx, gnd_rightx) = self.connect_pin(pin)
self.add_layout_end_pin_segment_center(text="vdd",
layer=self.supply_stack[2],
start=vector(vdd_leftx, 0),
end=vector(vdd_leftx, self.height))
self.add_layout_end_pin_segment_center(text="vdd",
layer=self.supply_stack[2],
start=vector(vdd_rightx, 0),
end=vector(vdd_rightx, self.height))
self.add_layout_end_pin_segment_center(text="gnd",
layer=self.supply_stack[2],
start=vector(gnd_leftx, 0),
end=vector(gnd_leftx, self.height))
self.add_layout_end_pin_segment_center(text="gnd",
layer=self.supply_stack[2],
start=vector(gnd_rightx, 0),
end=vector(gnd_rightx, self.height))
if gnd_dir == "V":
self.connect_side_pin(pin, "top", self.top_gnd_locs[0].y)
self.connect_side_pin(pin, "bot", self.bot_gnd_locs[0].y)
elif gnd_dir == "H":
self.connect_side_pin(pin, "left", self.left_gnd_locs[0].x)
self.connect_side_pin(pin, "right", self.right_gnd_locs[0].x)
def route_unused_wordlines(self):
@ -501,41 +531,120 @@ class replica_bitcell_array(bitcell_base_array):
for inst in self.dummy_row_insts:
for wl_name in self.col_cap_top.get_wordline_names():
pin = inst.get_pin(wl_name)
self.connect_pin(pin)
self.connect_side_pin(pin, "left", self.left_gnd_locs[0].x)
self.connect_side_pin(pin, "right", self.right_gnd_locs[0].x)
# Ground the unused replica wordlines
for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts):
for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()):
if wl_name in self.gnd_wordline_names:
pin = inst.get_pin(pin_name)
self.connect_pin(pin)
self.connect_side_pin(pin, "left", self.left_gnd_locs[0].x)
self.connect_side_pin(pin, "right", self.right_gnd_locs[0].x)
def route_side_pin(self, name, side, offset_multiple=1):
"""
Routes a vertical or horizontal pin on the side of the bbox.
The multiple specifies how many track offsets to be away from the side assuming
(0,0) (self.width, self.height)
"""
if side in ["left", "right"]:
return self.route_vertical_side_pin(name, side, offset_multiple)
elif side in ["top", "bottom", "bot"]:
return self.route_horizontal_side_pin(name, side, offset_multiple)
else:
debug.error("Invalid side {}".format(side), -1)
def connect_pin(self, pin, offset_multiple=1):
def route_vertical_side_pin(self, name, side, offset_multiple=1):
"""
Routes a vertical pin on the side of the bbox.
"""
if side == "left":
bot_loc = vector(-offset_multiple * self.vertical_pitch, 0)
top_loc = vector(-offset_multiple * self.vertical_pitch, self.height)
elif side == "right":
bot_loc = vector(self.width + offset_multiple * self.vertical_pitch, 0)
top_loc = vector(self.width + offset_multiple * self.vertical_pitch, self.height)
pin_layer = pin.layer
layer = self.supply_stack[2]
self.add_path(layer, [bot_loc, top_loc])
left_pin_loc = vector(self.dummy_col_insts[0].lx(), pin.cy())
right_pin_loc = vector(self.dummy_col_insts[1].rx(), pin.cy())
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)
return (bot_loc, top_loc)
def route_horizontal_side_pin(self, name, side, offset_multiple=1):
"""
Routes a horizontal pin on the side of the bbox.
"""
if side in ["bottom", "bot"]:
left_loc = vector(0, -offset_multiple * self.horizontal_pitch)
right_loc = vector(self.width, -offset_multiple * self.horizontal_pitch)
elif side == "top":
left_loc = vector(0, self.height + offset_multiple * self.horizontal_pitch)
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)
return (left_loc, right_loc)
def connect_side_pin(self, pin, side, offset):
"""
Used to connect horizontal layers of pins to the left/right straps
locs provides the offsets of the pin strip end points.
"""
if side in ["left", "right"]:
self.connect_vertical_side_pin(pin, side, offset)
elif side in ["top", "bottom", "bot"]:
self.connect_horizontal_side_pin(pin, side, offset)
else:
debug.error("Invalid side {}".format(side), -1)
def connect_horizontal_side_pin(self, pin, side, yoffset):
"""
Used to connect vertical layers of pins to the top/bottom horizontal straps
"""
cell_loc = pin.center()
pin_loc = vector(cell_loc.x, yoffset)
# Place the pins a track outside of the array
left_loc = left_pin_loc - vector(offset_multiple * self.horizontal_pitch, 0)
right_loc = right_pin_loc + vector(offset_multiple * self.horizontal_pitch, 0)
self.add_via_stack_center(offset=left_loc,
from_layer=pin_layer,
to_layer=self.supply_stack[2],
directions=("H", "H"))
self.add_via_stack_center(offset=right_loc,
from_layer=pin_layer,
self.add_via_stack_center(offset=pin_loc,
from_layer=pin.layer,
to_layer=self.supply_stack[0],
directions=("V", "V"))
# Add a path to connect to the array
self.add_path(pin.layer, [cell_loc, pin_loc])
def connect_vertical_side_pin(self, pin, side, xoffset):
"""
Used to connect vertical layers of pins to the top/bottom vertical straps
"""
cell_loc = pin.center()
pin_loc = vector(xoffset, cell_loc.y)
# Place the pins a track outside of the array
self.add_via_stack_center(offset=pin_loc,
from_layer=pin.layer,
to_layer=self.supply_stack[2],
directions=("H", "H"))
# Add a path to connect to the array
self.add_path(pin_layer, [left_loc, right_loc])
return (left_loc.x, right_loc.x)
self.add_path(pin.layer, [cell_loc, pin_loc])
def analytical_power(self, corner, load):
"""Power of Bitcell array and bitline in nW."""

View File

@ -106,10 +106,13 @@ class row_cap_array(bitcell_base_array):
width=self.width,
height=wl_pin.height())
# Add vdd/gnd via stacks
for row in range(1, self.row_size - 1):
for col in range(self.column_size):
inst = self.cell_inst[row, col]
for pin_name in ["vdd", "gnd"]:
for pin in inst.get_pins(pin_name):
self.copy_power_pin(pin)
self.add_layout_pin(text=pin_name,
layer=pin.layer,
offset=pin.ll(),
width=pin.width(),
height=pin.height())

View File

@ -74,9 +74,8 @@ for path in output_files:
from sram import sram
s = sram(name=OPTS.output_name,
s = sram(name=OPTS.output_name,
sram_config=c)
# Output the files for the resulting SRAM
s.save()

View File

@ -14,4 +14,6 @@ tech_name = OPTS.tech_name
nominal_corner_only = True
check_lvsdrc = True
route_supplies = False
output_name = "sram"

View File

@ -31,7 +31,6 @@ tech_modules = module_type()
# Custom cell properties
###################################################
cell_properties = cell_properties()
cell_properties.bitcell_power_pin_directions = ("V", "V")
###################################################
# Custom cell properties

View File

@ -30,6 +30,8 @@ tech_modules = module_type()
# Custom cell properties
###################################################
cell_properties = cell_properties()
cell_properties.bitcell_1port.gnd_layer = "m2"
cell_properties.bitcell_1port.gnd_dir = "V"
###################################################
# Custom cell properties

View File

@ -86,6 +86,13 @@ cell_properties.bitcell_1port.port_map = {'bl': 'BL',
'vpb': 'VPB',
'gnd': 'VGND'}
cell_properties.bitcell_1port.wl_layer = "m2"
cell_properties.bitcell_1port.bl_layer = "m1"
cell_properties.bitcell_1port.vdd_layer = "m1"
cell_properties.bitcell_1port.vdd_dir = "V"
cell_properties.bitcell_1port.gnd_layer = "m2"
cell_properties.bitcell_1port.gnd_dir = "H"
cell_properties.bitcell_2port.mirror.x = True
cell_properties.bitcell_2port.mirror.y = True
cell_properties.bitcell_2port.end_caps = True
@ -98,6 +105,16 @@ cell_properties.bitcell_2port.port_map = {'bl0': 'BL0',
'wl1': 'WL1',
'vdd': 'VDD',
'gnd': 'GND'}
cell_properties.bitcell_1port.wl_layer = "m2"
cell_properties.bitcell_1port.vdd_layer = "m2"
cell_properties.bitcell_1port.vdd_dir = "H"
cell_properties.bitcell_1port.gnd_layer = "m2"
cell_properties.bitcell_1port.gnd_dir = "H"
cell_properties.bitcell_2port.wl_layer = "m2"
cell_properties.bitcell_2port.vdd_layer = "m1"
cell_properties.bitcell_2port.vdd_dir = "H"
cell_properties.bitcell_2port.gnd_layer = "m2"
cell_properties.bitcell_2port.gnd_dir = "H"
cell_properties.col_cap_1port_bitcell = cell(['br', 'vdd', 'gnd', 'bl', 'gate'],
['INPUT', 'POWER', 'GROUND', 'INPUT', 'INPUT'],