Draft local and global arrays. Ensure rows before cols in usage.

This commit is contained in:
mrg 2020-07-23 14:43:14 -07:00
parent 58846a4a25
commit e1967dc548
12 changed files with 328 additions and 21 deletions

View File

@ -17,8 +17,8 @@ class bitcell_array(bitcell_base_array):
and word line is connected by abutment.
Connects the word lines and bit lines.
"""
def __init__(self, cols, rows, name, column_offset=0):
super().__init__(cols, rows, name, column_offset)
def __init__(self, rows, cols, column_offset=0, name=""):
super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name)
self.create_netlist()
if not OPTS.netlist_only:
@ -57,8 +57,8 @@ class bitcell_array(bitcell_base_array):
name = "bit_r{0}_c{1}".format(row, col)
self.cell_inst[row, col]=self.add_inst(name=name,
mod=self.cell)
self.connect_inst(self.get_bitcell_pins(col, row))
self.connect_inst(self.get_bitcell_pins(row, col))
def analytical_power(self, corner, load):
"""Power of Bitcell array and bitline in nW."""

View File

@ -14,7 +14,7 @@ class bitcell_base_array(design.design):
"""
Abstract base class for bitcell-arrays -- bitcell, dummy
"""
def __init__(self, cols, rows, name, column_offset):
def __init__(self, name, rows, cols, column_offset):
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))
@ -61,7 +61,7 @@ class bitcell_base_array(design.design):
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def get_bitcell_pins(self, col, row):
def get_bitcell_pins(self, row, col):
""" Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array """

View File

@ -50,9 +50,9 @@ class col_cap_array(bitcell_base_array):
name = "bit_r{0}_c{1}".format(row, col)
self.cell_inst[row, col]=self.add_inst(name=name,
mod=self.dummy_cell)
self.connect_inst(self.get_bitcell_pins(col, row))
self.connect_inst(self.get_bitcell_pins(row, col))
def get_bitcell_pins(self, col, row):
def get_bitcell_pins(self, row, col):
"""
Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array

View File

@ -12,8 +12,8 @@ class dummy_array(bitcell_base_array):
"""
Generate a dummy row/column for the replica array.
"""
def __init__(self, cols, rows, column_offset=0, mirror=0, name=""):
super().__init__(cols, rows, name, column_offset)
def __init__(self, rows, cols, column_offset=0, mirror=0, name=""):
super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name)
self.mirror = mirror
self.create_netlist()
@ -51,7 +51,7 @@ class dummy_array(bitcell_base_array):
name = "bit_r{0}_c{1}".format(row, col)
self.cell_inst[row, col]=self.add_inst(name=name,
mod=self.dummy_cell)
self.connect_inst(self.get_bitcell_pins(col, row))
self.connect_inst(self.get_bitcell_pins(row, col))
def input_load(self):
wl_wire = self.gen_wl_wire()

View File

@ -0,0 +1,66 @@
# 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.
#
from bitcell_base_array import bitcell_base_array
from tech import drc, spice
from globals import OPTS
from sram_factory import factory
import debug
class global_bitcell_array(bitcell_base_array):
"""
Creates a global bitcell array with a number
of local arrays of a sizes given by a tuple in the list.
"""
def __init__(self, sizes, name=""):
# Each bank will have the same number of rows
self.rows = sizes[0][0]
for (r, c) in sizes:
debug.check(r[0] == self.rows, "Cannot have non-uniform number of rows in global array.")
# The total of all columns will be the number of columns
self.cols = sum(x[1] for x in sizes)
self.sizes = sizes
super().__init__(rows=self.rows, cols=self.cols, name=name)
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
""" Create and connect the netlist """
self.add_modules()
self.add_pins()
self.create_instances()
def create_layout(self):
self.place()
self.add_layout_pins()
self.add_boundary()
self.DRC_LVS()
def add_modules(self):
""" Add the modules used in this design """
self.local_mods = []
for (row, col) in self.sizes:
la = factory.create(module_type="local_bitcell_array", rows=row, cols=col)
self.add_mod(la)
self.local_mods.append(la)
def create_instances(self):
""" Create the module instances used in this design """
self.local_inst = {}
for i in range(self.sizes):
name = "local_array_{0}".format(i)
self.local_inst.append(self.add_inst(name=name,
mod=self.local_mods[i])
self.connect_inst(self.get_bitcell_pins(row, col))

View File

@ -0,0 +1,66 @@
# 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.
#
from bitcell_base_array import bitcell_base_array
from tech import drc, spice
from globals import OPTS
from sram_factory import factory
class local_bitcell_array(bitcell_base_array):
"""
A local wordline array is a bitcell array with a wordline driver.
This can either be a single aray on its own if there is no hierarchical WL
or it can be combined into a larger array with hierarchical WL.
"""
def __init__(self, name, rows, cols):
super().__init__(name, rows, cols)
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
# We don't offset this because we need to align
# the replica bitcell in the control logic
# self.offset_all_coordinates()
def create_netlist(self):
""" Create and connect the netlist """
self.add_modules()
self.add_pins()
self.create_instances()
def create_layout(self):
self.place_array("bit_r{0}_c{1}")
self.add_layout_pins()
self.add_boundary()
self.DRC_LVS()
def add_modules(self):
""" Add the modules used in this design """
self.bit_array = factory.create(module_type="bitcell_array",
rows=self.rows,
cols=self.cols,
column_offset=self.column_offset)
self.add_mod(self.bit_array)
self.wl_array = factory.create(module_type="wordline_driver_array",
rows=self.rows,
cols=self.cols)
self.add_mod(self.wl_array)
def create_instances(self):
""" Create the module instances used in this design """
self.bitcell_inst = self.add_inst(mod=self.bitcell_array)
self.connect_inst(self.get_bitcell_pins(row, col))
self.wl_inst = self.add_inst(mod=self.wl_array)
self.connect_inst(self.get_bitcell_pins(row, col))

View File

@ -21,7 +21,7 @@ class replica_bitcell_array(design.design):
Requires a regular bitcell array, replica bitcell, and dummy
bitcell (Bl/BR disconnected).
"""
def __init__(self, cols, rows, left_rbl, right_rbl, bitcell_ports, name):
def __init__(self, rows, cols, left_rbl, right_rbl, bitcell_ports, 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))

View File

@ -102,22 +102,22 @@ class replica_column(design.design):
if (row > self.left_rbl and row < self.total_size - self.right_rbl - 1):
self.cell_inst[row]=self.add_inst(name=name,
mod=self.replica_cell)
self.connect_inst(self.get_bitcell_pins(0, row))
self.connect_inst(self.get_bitcell_pins(row, 0))
elif row==self.replica_bit:
self.cell_inst[row]=self.add_inst(name=name,
mod=self.replica_cell)
self.connect_inst(self.get_bitcell_pins(0, row))
self.connect_inst(self.get_bitcell_pins(row, 0))
elif (row == 0 or row == self.total_size - 1):
self.cell_inst[row]=self.add_inst(name=name,
mod=self.edge_cell)
if end_caps_enabled:
self.connect_inst(self.get_bitcell_pins_col_cap(0, row))
self.connect_inst(self.get_bitcell_pins_col_cap(row, 0))
else:
self.connect_inst(self.get_bitcell_pins(0, row))
self.connect_inst(self.get_bitcell_pins(row, 0))
else:
self.cell_inst[row]=self.add_inst(name=name,
mod=self.dummy_cell)
self.connect_inst(self.get_bitcell_pins(0, row))
self.connect_inst(self.get_bitcell_pins(row, 0))
def place_instances(self):
from tech import cell_properties
@ -191,7 +191,7 @@ class replica_column(design.design):
else:
self.copy_layout_pin(inst, pin_name)
def get_bitcell_pins(self, col, row):
def get_bitcell_pins(self, row, col):
""" Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array """
@ -208,7 +208,7 @@ class replica_column(design.design):
return bitcell_pins
def get_bitcell_pins_col_cap(self, col, row):
def get_bitcell_pins_col_cap(self, row, col):
""" Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array """

View File

@ -49,9 +49,9 @@ class row_cap_array(bitcell_base_array):
name = "bit_r{0}_c{1}".format(row, col)
self.cell_inst[row, col]=self.add_inst(name=name,
mod=self.dummy_cell)
self.connect_inst(self.get_bitcell_pins(col, row))
self.connect_inst(self.get_bitcell_pins(row, col))
def get_bitcell_pins(self, col, row):
def get_bitcell_pins(self, row, col):
"""
Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array

View File

@ -0,0 +1,137 @@
# 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
from tech import drc, layer
from vector import vector
from sram_factory import factory
from globals import OPTS
class wordline_buffer_array(design.design):
"""
Creates a Wordline Buffer/Inverter array
"""
def __init__(self, name, rows, cols):
design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
self.rows = rows
self.cols = cols
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
self.add_modules()
self.add_pins()
self.create_drivers()
def create_layout(self):
if "li" in layer:
self.route_layer = "li"
else:
self.route_layer = "m1"
self.place_drivers()
self.route_layout()
self.route_vdd_gnd()
self.offset_all_coordinates()
self.add_boundary()
self.DRC_LVS()
def add_pins(self):
# inputs to wordline_driver.
for i in range(self.rows):
self.add_pin("in_{0}".format(i), "INPUT")
# Outputs from wordline_driver.
for i in range(self.rows):
self.add_pin("wl_{0}".format(i), "OUTPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def add_modules(self):
self.wl_driver = factory.create(module_type="inv_dec",
size=self.cols)
self.add_mod(self.wl_driver)
def route_vdd_gnd(self):
"""
Add a pin for each row of vdd/gnd which
are must-connects next level up.
"""
if OPTS.tech_name == "sky130":
for name in ["vdd", "gnd"]:
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.add_power_pin(name, pin_pos)
def create_drivers(self):
self.wld_inst = []
for row in range(self.rows):
self.wld_inst.append(self.add_inst(name="wld{0}".format(row),
mod=self.wl_driver))
self.connect_inst(["in_{0}".format(row),
"wl_{0}".format(row),
"vdd", "gnd"])
def place_drivers(self):
for row in range(self.rows):
if (row % 2):
y_offset = self.wl_driver.height * (row + 1)
inst_mirror = "MX"
else:
y_offset = self.wl_driver.height * row
inst_mirror = "R0"
offset = [0, y_offset]
self.wld_inst[row].place(offset=offset,
mirror=inst_mirror)
self.width = self.wl_driver.width
self.height = self.wl_driver.height * self.rows
def route_layout(self):
""" Route all of the signals """
for row in range(self.rows):
inst = self.wld_inst[row]
self.copy_layout_pin(inst, "A", "in_{0}".format(row))
# output each WL on the right
wl_offset = inst.get_pin("Z").rc()
self.add_layout_pin_segment_center(text="wl_{0}".format(row),
layer=self.route_layer,
start=wl_offset,
end=wl_offset - vector(self.m1_width, 0))

View File

@ -12,6 +12,7 @@ from vector import vector
from sram_factory import factory
from globals import OPTS
class wordline_driver_array(design.design):
"""
Creates a Wordline Driver

View File

@ -0,0 +1,37 @@
#!/usr/bin/env python3
# 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 unittest
from testutils import *
import sys,os
sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
from sram_factory import factory
import debug
class wordline_buffer_array_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
# check wordline driver for single port
debug.info(2, "Checking driver")
tx = factory.create(module_type="wordline_buffer_array", rows=8, cols=32)
self.local_check(tx)
globals.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())