mirror of https://github.com/VLSIDA/OpenRAM.git
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:
parent
5e546ee974
commit
64f2f90664
|
|
@ -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():
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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."""
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -14,4 +14,6 @@ tech_name = OPTS.tech_name
|
|||
nominal_corner_only = True
|
||||
check_lvsdrc = True
|
||||
|
||||
route_supplies = False
|
||||
|
||||
output_name = "sram"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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'],
|
||||
|
|
|
|||
Loading…
Reference in New Issue