Bitcell arrays: Create abstract base class

a lot of functions of dummy- and bitcell-array are either copy-pasted or
have just slight differences. Merge all of those into an abstract base
class such that we don't have too much duplicate code.

Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
This commit is contained in:
Bastian Koppelmann 2020-01-27 11:53:29 +01:00
parent e62beae805
commit 3fb2b9c1c3
3 changed files with 115 additions and 177 deletions

View File

@ -0,0 +1,107 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import debug
import design
class bitcell_base_array(design.design):
"""
Abstract base class for bitcell-arrays -- bitcell, dummy
"""
def __init__(self, cols, rows, name):
design.design.__init__(self, name)
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
self.column_size = cols
self.row_size = rows
def add_pins(self):
row_list = self.cell.get_all_wl_names()
column_list = self.cell.get_all_bitline_names()
for col in range(self.column_size):
for cell_column in column_list:
self.add_pin(cell_column+"_{0}".format(col), "INOUT")
for row in range(self.row_size):
for cell_row in row_list:
self.add_pin(cell_row+"_{0}".format(row), "INPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def get_bitcell_pins(self, col, row):
""" Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array """
bitcell_pins = []
pin_names = self.cell.get_all_bitline_names()
for pin in pin_names:
bitcell_pins.append(pin+"_{0}".format(col))
pin_names = self.cell.get_all_wl_names()
for pin in pin_names:
bitcell_pins.append(pin+"_{0}".format(row))
bitcell_pins.append("vdd")
bitcell_pins.append("gnd")
return bitcell_pins
def add_layout_pins(self):
""" Add the layout pins """
row_list = self.cell.get_all_wl_names()
column_list = self.cell.get_all_bitline_names()
for col in range(self.column_size):
for cell_column in column_list:
bl_pin = self.cell_inst[0,col].get_pin(cell_column)
self.add_layout_pin(text=cell_column+"_{0}".format(col),
layer=bl_pin.layer,
offset=bl_pin.ll().scale(1,0),
width=bl_pin.width(),
height=self.height)
for row in range(self.row_size):
for cell_row in row_list:
wl_pin = self.cell_inst[row,0].get_pin(cell_row)
self.add_layout_pin(text=cell_row+"_{0}".format(row),
layer=wl_pin.layer,
offset=wl_pin.ll().scale(0,1),
width=self.width,
height=wl_pin.height())
# For every second row and column, add a via for gnd and vdd
for row in range(self.row_size):
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.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer)
def place_array(self, name_template, row_offset=0):
# We increase it by a well enclosure so the precharges don't overlap our wells
self.height = self.row_size*self.cell.height
self.width = self.column_size*self.cell.width
xoffset = 0.0
for col in range(self.column_size):
yoffset = 0.0
for row in range(self.row_size):
name = name_template.format(row, col)
if (row + row_offset) % 2:
tempy = yoffset + self.cell.height
dir_key = "MX"
else:
tempy = yoffset
dir_key = ""
self.cell_inst[row,col].place(offset=[xoffset, tempy],
mirror=dir_key)
yoffset += self.cell.height
xoffset += self.cell.width

View File

@ -7,25 +7,21 @@
# #
import debug import debug
import design import design
from base_array import bitcell_base_array
from tech import drc, spice from tech import drc, spice
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
import logical_effort import logical_effort
class bitcell_array(design.design): class bitcell_array(bitcell_base_array):
""" """
Creates a rows x cols array of memory cells. Assumes bit-lines Creates a rows x cols array of memory cells. Assumes bit-lines
and word line is connected by abutment. and word line is connected by abutment.
Connects the word lines and bit lines. Connects the word lines and bit lines.
""" """
def __init__(self, cols, rows, name): def __init__(self, cols, rows, name):
design.design.__init__(self, name) super().__init__(cols, rows, name)
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
self.column_size = cols
self.row_size = rows
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
@ -44,27 +40,7 @@ class bitcell_array(design.design):
def create_layout(self): def create_layout(self):
# We increase it by a well enclosure so the precharges don't overlap our wells self.place_array("bit_r{0}_c{1}")
self.height = self.row_size*self.cell.height
self.width = self.column_size*self.cell.width
xoffset = 0.0
for col in range(self.column_size):
yoffset = 0.0
for row in range(self.row_size):
name = "bit_r{0}_c{1}".format(row, col)
if row % 2:
tempy = yoffset + self.cell.height
dir_key = "MX"
else:
tempy = yoffset
dir_key = ""
self.cell_inst[row,col].place(offset=[xoffset, tempy],
mirror=dir_key)
yoffset += self.cell.height
xoffset += self.cell.width
self.add_layout_pins() self.add_layout_pins()
@ -72,41 +48,13 @@ class bitcell_array(design.design):
self.DRC_LVS() self.DRC_LVS()
def add_pins(self):
row_list = self.cell.get_all_wl_names()
column_list = self.cell.get_all_bitline_names()
for col in range(self.column_size):
for cell_column in column_list:
self.add_pin(cell_column+"_{0}".format(col), "INOUT")
for row in range(self.row_size):
for cell_row in row_list:
self.add_pin(cell_row+"_{0}".format(row), "INPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def add_modules(self): def add_modules(self):
""" Add the modules used in this design """ """ Add the modules used in this design """
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type="bitcell")
self.add_mod(self.cell) self.add_mod(self.cell)
def get_bitcell_pins(self, col, row):
""" Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array """
bitcell_pins = []
pin_names = self.cell.get_all_bitline_names()
for pin in pin_names:
bitcell_pins.append(pin+"_{0}".format(col))
pin_names = self.cell.get_all_wl_names()
for pin in pin_names:
bitcell_pins.append(pin+"_{0}".format(row))
bitcell_pins.append("vdd")
bitcell_pins.append("gnd")
return bitcell_pins
def create_instances(self): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """
self.cell_inst = {} self.cell_inst = {}
@ -117,37 +65,6 @@ class bitcell_array(design.design):
mod=self.cell) mod=self.cell)
self.connect_inst(self.get_bitcell_pins(col, row)) self.connect_inst(self.get_bitcell_pins(col, row))
def add_layout_pins(self):
""" Add the layout pins """
row_list = self.cell.get_all_wl_names()
column_list = self.cell.get_all_bitline_names()
for col in range(self.column_size):
for cell_column in column_list:
bl_pin = self.cell_inst[0,col].get_pin(cell_column)
self.add_layout_pin(text=cell_column+"_{0}".format(col),
layer=bl_pin.layer,
offset=bl_pin.ll().scale(1,0),
width=bl_pin.width(),
height=self.height)
for row in range(self.row_size):
for cell_row in row_list:
wl_pin = self.cell_inst[row,0].get_pin(cell_row)
self.add_layout_pin(text=cell_row+"_{0}".format(row),
layer=wl_pin.layer,
offset=wl_pin.ll().scale(0,1),
width=self.width,
height=wl_pin.height())
# For every second row and column, add a via for gnd and vdd
for row in range(self.row_size):
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.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer)
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."""

View File

@ -5,23 +5,19 @@
# #
import debug import debug
import design import design
from base_array import bitcell_base_array
from tech import drc from tech import drc
import contact import contact
from sram_factory import factory from sram_factory import factory
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
class dummy_array(design.design): class dummy_array(bitcell_base_array):
""" """
Generate a dummy row/column for the replica array. Generate a dummy row/column for the replica array.
""" """
def __init__(self, cols, rows, mirror=0, name=""): def __init__(self, cols, rows, mirror=0, name=""):
design.design.__init__(self, name) super().__init__(cols, rows, name)
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
self.column_size = cols
self.row_size = rows
self.mirror = mirror self.mirror = mirror
self.create_netlist() self.create_netlist()
@ -37,27 +33,7 @@ class dummy_array(design.design):
def create_layout(self): def create_layout(self):
# We increase it by a well enclosure so the precharges don't overlap our wells self.place_array("dummy_r{0}_c{1}", self.mirror)
self.height = self.row_size*self.dummy_cell.height
self.width = self.column_size*self.dummy_cell.width
xoffset = 0.0
for col in range(self.column_size):
yoffset = 0.0
for row in range(self.row_size):
name = "dummy_r{0}_c{1}".format(row, col)
if (row+self.mirror) % 2:
tempy = yoffset + self.dummy_cell.height
dir_key = "MX"
else:
tempy = yoffset
dir_key = ""
self.cell_inst[row,col].place(offset=[xoffset, tempy],
mirror=dir_key)
yoffset += self.dummy_cell.height
xoffset += self.dummy_cell.width
self.add_layout_pins() self.add_layout_pins()
@ -65,18 +41,6 @@ class dummy_array(design.design):
self.DRC_LVS() self.DRC_LVS()
def add_pins(self):
row_list = self.cell.get_all_wl_names()
column_list = self.cell.get_all_bitline_names()
for col in range(self.column_size):
for cell_column in column_list:
self.add_pin(cell_column+"_{0}".format(col), "INOUT")
for row in range(self.row_size):
for cell_row in row_list:
self.add_pin(cell_row+"_{0}".format(row), "INPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def add_modules(self): def add_modules(self):
""" Add the modules used in this design """ """ Add the modules used in this design """
self.dummy_cell = factory.create(module_type="dummy_bitcell") self.dummy_cell = factory.create(module_type="dummy_bitcell")
@ -84,23 +48,6 @@ class dummy_array(design.design):
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type="bitcell")
def get_bitcell_pins(self, col, row):
""" Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array """
bitcell_pins = []
pin_names = self.cell.get_all_bitline_names()
for pin in pin_names:
bitcell_pins.append(pin+"_{0}".format(col))
pin_names = self.cell.get_all_wl_names()
for pin in pin_names:
bitcell_pins.append(pin+"_{0}".format(row))
bitcell_pins.append("vdd")
bitcell_pins.append("gnd")
return bitcell_pins
def create_instances(self): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """
@ -111,39 +58,6 @@ class dummy_array(design.design):
self.cell_inst[row,col]=self.add_inst(name=name, self.cell_inst[row,col]=self.add_inst(name=name,
mod=self.dummy_cell) mod=self.dummy_cell)
self.connect_inst(self.get_bitcell_pins(col, row)) self.connect_inst(self.get_bitcell_pins(col, row))
def add_layout_pins(self):
""" Add the layout pins """
row_list = self.cell.get_all_wl_names()
column_list = self.cell.get_all_bitline_names()
for col in range(self.column_size):
for cell_column in column_list:
bl_pin = self.cell_inst[0,col].get_pin(cell_column)
self.add_layout_pin(text=cell_column+"_{0}".format(col),
layer="m2",
offset=bl_pin.ll(),
width=bl_pin.width(),
height=self.height)
for row in range(self.row_size):
for cell_row in row_list:
wl_pin = self.cell_inst[row,0].get_pin(cell_row)
self.add_layout_pin(text=cell_row+"_{0}".format(row),
layer="m1",
offset=wl_pin.ll(),
width=self.width,
height=wl_pin.height())
# For every second row and column, add a via for gnd and vdd
for row in range(self.row_size):
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.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer)
def input_load(self): def input_load(self):
wl_wire = self.gen_wl_wire() wl_wire = self.gen_wl_wire()