Update modules to use variable bit offsets.

Bitcell arrays can return the bit offsets.
Port data and submodules can use offsets for spacing.
Default spacing for port data if no offsets given.
This commit is contained in:
mrg 2020-09-11 15:36:22 -07:00
parent c58741c44f
commit 8909ad7165
11 changed files with 116 additions and 47 deletions

View File

@ -191,11 +191,17 @@ class bank(design.design):
self.main_bitcell_array_left = self.bitcell_array.get_main_array_left()
# Just past the dummy row and replica row
self.main_bitcell_array_bottom = self.bitcell_array.get_main_array_bottom()
self.compute_instance_port0_offsets()
if len(self.all_ports)==2:
self.compute_instance_port1_offsets()
def get_column_offsets(self):
"""
Return an array of the x offsets of all the regular bits
"""
return self.bitcell_array.get_column_offsets()
def compute_instance_port0_offsets(self):
"""
Compute the instance offsets for port0 on the left/bottom of the bank.
@ -355,14 +361,6 @@ class bank(design.design):
def add_modules(self):
""" Add all the modules using the class loader """
self.port_data = []
for port in self.all_ports:
temp_pre = factory.create(module_type="port_data",
sram_config=self.sram_config,
port=port)
self.port_data.append(temp_pre)
self.add_mod(self.port_data[port])
self.port_address = factory.create(module_type="port_address",
cols=self.num_cols + self.num_spare_cols,
@ -392,6 +390,15 @@ class bank(design.design):
cols=self.num_cols + self.num_spare_cols,
rows=self.num_rows)
self.add_mod(self.bitcell_array)
self.port_data = []
for port in self.all_ports:
temp_pre = factory.create(module_type="port_data",
sram_config=self.sram_config,
port=port,
bit_offsets=self.bitcell_array.get_column_offsets())
self.port_data.append(temp_pre)
self.add_mod(self.port_data[port])
if(self.num_banks > 1):
self.bank_select = factory.create(module_type="bank_select")
@ -432,6 +439,7 @@ class bank(design.design):
for port in self.all_ports:
self.port_data_inst[port]=self.add_inst(name="port_data{}".format(port),
mod=self.port_data[port])
temp = []
temp.extend(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)])
temp.extend(self.bitcell_array.get_bitline_names(port))

View File

@ -206,3 +206,9 @@ class bitcell_base_array(design.design):
mirror=dir_key)
yoffset += self.cell.height
xoffset += self.cell.width
def get_column_offsets(self):
"""
Return an array of the x offsets of all the regular bits
"""
return [self.cell_inst[0, col].lx() for col in range(self.column_size)]

View File

@ -253,4 +253,12 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
def get_main_array_right(self):
return self.local_insts[-1].offset.x + self.local_mods[-1].get_main_array_right()
def get_column_offsets(self):
"""
Return an array of the x offsets of all the regular bits
"""
offsets = []
for inst in self.local_insts:
offsets.extend(inst.lx() + inst.mod.get_column_offsets())
return offsets

View File

@ -244,14 +244,21 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
self.add_path(out_pin.layer, [out_loc, mid_loc, in_loc])
def get_main_array_top(self):
return self.bitcell_array_inst.offset.y + self.bitcell_array.get_main_array_top()
return self.bitcell_array_inst.by() + self.bitcell_array.get_main_array_top()
def get_main_array_bottom(self):
return self.bitcell_array_inst.offset.y + self.bitcell_array.get_main_array_bottom()
return self.bitcell_array_inst.by() + self.bitcell_array.get_main_array_bottom()
def get_main_array_left(self):
return self.bitcell_array_inst.offset.x + self.bitcell_array.get_main_array_left()
return self.bitcell_array_inst.lx() + self.bitcell_array.get_main_array_left()
def get_main_array_right(self):
return self.bitcell_array_inst.offset.x + self.bitcell_array.get_main_array_right()
return self.bitcell_array_inst.lx() + self.bitcell_array.get_main_array_right()
def get_column_offsets(self):
"""
Return an array of the x offsets of all the regular bits
"""
# must add the offset of the instance
return [self.bitcell_array_inst.lx() + x for x in self.bitcell_array.get_column_offsets()]

View File

@ -18,7 +18,7 @@ class port_data(design.design):
Port 0 always has the RBL on the left while port 1 is on the right.
"""
def __init__(self, sram_config, port, name=""):
def __init__(self, sram_config, port, bit_offsets=None, name=""):
sram_config.set_local_config(self)
self.port = port
@ -30,6 +30,14 @@ class port_data(design.design):
if self.num_spare_cols is None:
self.num_spare_cols = 0
if not bit_offsets:
bitcell = factory.create(module_type="bitcell")
self.bit_offsets = []
for i in range(self.num_cols + self.num_spare_cols):
self.bit_offsets.append(i * bitcell.width)
else:
self.bit_offsets = bit_offsets
if name == "":
name = "port_data_{0}".format(self.port)
super().__init__(name)
@ -181,6 +189,7 @@ class port_data(design.design):
# and mirroring happens correctly
self.precharge_array = factory.create(module_type="precharge_array",
columns=self.num_cols + self.num_spare_cols + 1,
offsets=self.bit_offsets,
bitcell_bl=self.bl_names[self.port],
bitcell_br=self.br_names[self.port],
column_offset=self.port - 1)
@ -190,6 +199,7 @@ class port_data(design.design):
# RBLs don't get a sense amp
self.sense_amp_array = factory.create(module_type="sense_amp_array",
word_size=self.word_size,
offsets=self.bit_offsets,
words_per_row=self.words_per_row,
num_spare_cols=self.num_spare_cols)
self.add_mod(self.sense_amp_array)
@ -201,6 +211,7 @@ class port_data(design.design):
self.column_mux_array = factory.create(module_type="column_mux_array",
columns=self.num_cols,
word_size=self.word_size,
offsets=self.bit_offsets,
bitcell_bl=self.bl_names[self.port],
bitcell_br=self.br_names[self.port])
self.add_mod(self.column_mux_array)
@ -212,6 +223,7 @@ class port_data(design.design):
self.write_driver_array = factory.create(module_type="write_driver_array",
columns=self.num_cols,
word_size=self.word_size,
offsets=self.bit_offsets,
write_size=self.write_size,
num_spare_cols=self.num_spare_cols)
self.add_mod(self.write_driver_array)

View File

@ -10,7 +10,7 @@ import debug
from vector import vector
from sram_factory import factory
from globals import OPTS
from tech import layer
from tech import cell_properties
class precharge_array(design.design):
@ -19,12 +19,13 @@ class precharge_array(design.design):
of bit line columns, height is the height of the bit-cell array.
"""
def __init__(self, name, columns, size=1, bitcell_bl="bl", bitcell_br="br", column_offset=0):
def __init__(self, name, columns, offsets=None, size=1, bitcell_bl="bl", bitcell_br="br", column_offset=0):
super().__init__(name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("cols: {0} size: {1} bl: {2} br: {3}".format(columns, size, bitcell_bl, bitcell_br))
self.columns = columns
self.offsets = offsets
self.size = size
self.bitcell_bl = bitcell_bl
self.bitcell_br = bitcell_br
@ -62,10 +63,11 @@ class precharge_array(design.design):
self.create_insts()
def create_layout(self):
self.width = self.columns * self.pc_cell.width
self.place_insts()
self.width = self.offsets[-1] + self.pc_cell.width
self.height = self.pc_cell.height
self.place_insts()
self.add_layout_pins()
self.add_boundary()
self.DRC_LVS()
@ -112,15 +114,18 @@ class precharge_array(design.design):
def place_insts(self):
""" Places precharge array by horizontally tiling the precharge cell"""
from tech import cell_properties
xoffset = 0
for i in range(self.columns):
tempx = xoffset
# Default to single spaced columns
if not self.offsets:
self.offsets = [n * self.pc_cell.width for n in range(self.columns)]
for i, xoffset in enumerate(self.offsets):
if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2:
mirror = "MY"
tempx = tempx + self.pc_cell.width
tempx = xoffset + self.pc_cell.width
else:
mirror = ""
tempx = xoffset
offset = vector(tempx, 0)
self.local_insts[i].place(offset=offset, mirror=mirror)

View File

@ -342,7 +342,14 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
def get_main_array_right(self):
return self.bitcell_array_inst.rx()
def get_column_offsets(self):
"""
Return an array of the x offsets of all the regular bits
"""
# This works because the instance of the module is placed at 0,0
return self.bitcell_array.get_column_offsets()
def add_replica_columns(self):
""" Add replica columns on left and right of array """

View File

@ -20,7 +20,7 @@ class sense_amp_array(design.design):
Dynamically generated sense amp array for all bitlines.
"""
def __init__(self, name, word_size, words_per_row, num_spare_cols=None, column_offset=0):
def __init__(self, name, word_size, words_per_row, offsets=None, num_spare_cols=None, column_offset=0):
super().__init__(name)
debug.info(1, "Creating {0}".format(self.name))
@ -29,6 +29,7 @@ class sense_amp_array(design.design):
self.word_size = word_size
self.words_per_row = words_per_row
self.offsets = offsets
if not num_spare_cols:
self.num_spare_cols = 0
else:

View File

@ -11,7 +11,7 @@ from tech import layer, preferred_directions
from vector import vector
from sram_factory import factory
from globals import OPTS
import logical_effort
from tech import cell_properties
class single_level_column_mux_array(design.design):
@ -20,13 +20,14 @@ class single_level_column_mux_array(design.design):
Array of column mux to read the bitlines through the 6T.
"""
def __init__(self, name, columns, word_size, bitcell_bl="bl", bitcell_br="br", column_offset=0):
def __init__(self, name, columns, word_size, offsets=None, bitcell_bl="bl", bitcell_br="br", column_offset=0):
super().__init__(name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("cols: {0} word_size: {1} bl: {2} br: {3}".format(columns, word_size, bitcell_bl, bitcell_br))
self.columns = columns
self.word_size = word_size
self.offsets = offsets
self.words_per_row = int(self.columns / self.word_size)
self.bitcell_bl = bitcell_bl
self.bitcell_br = bitcell_br
@ -116,9 +117,13 @@ class single_level_column_mux_array(design.design):
"gnd"])
def place_array(self):
from tech import cell_properties
# Default to single spaced columns
if not self.offsets:
self.offsets = [n * self.mux.width for n in range(self.columns)]
# For every column, add a pass gate
for col_num in range(self.columns):
for col_num, xoffset in enumerate(self.offsets):
xoffset = col_num * self.mux.width
if cell_properties.bitcell.mirror.y and (col_num + self.column_offset) % 2:
mirror = "MY"

View File

@ -11,6 +11,7 @@ from tech import drc
from sram_factory import factory
from vector import vector
from globals import OPTS
from tech import cell_properties
class write_driver_array(design.design):
@ -19,7 +20,7 @@ class write_driver_array(design.design):
Dynamically generated write driver array of all bitlines.
"""
def __init__(self, name, columns, word_size, num_spare_cols=None, write_size=None, column_offset=0):
def __init__(self, name, columns, word_size, offsets=None, num_spare_cols=None, write_size=None, column_offset=0):
super().__init__(name)
debug.info(1, "Creating {0}".format(self.name))
@ -29,6 +30,7 @@ class write_driver_array(design.design):
self.columns = columns
self.word_size = word_size
self.write_size = write_size
self.offsets = offsets
self.column_offset = column_offset
self.words_per_row = int(columns / word_size)
if not num_spare_cols:
@ -155,30 +157,32 @@ class write_driver_array(design.design):
self.en_name + "_{0}".format(i + offset), "vdd", "gnd"])
def place_write_array(self):
from tech import cell_properties
if self.bitcell.width > self.driver.width:
self.driver_spacing = self.bitcell.width
else:
self.driver_spacing = self.driver.width
for i in range(0, self.columns, self.words_per_row):
index = int(i / self.words_per_row)
xoffset = i * self.driver_spacing
if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2:
if not self.offsets:
self.offsets = []
for i in range(self.columns + self.num_spare_cols):
self.offsets.append(i * self.driver_spacing)
for i, xoffset in enumerate(self.offsets[0:self.columns:self.words_per_row]):
if cell_properties.bitcell.mirror.y and (i * self.words_per_row + self.column_offset) % 2:
mirror = "MY"
xoffset = xoffset + self.driver.width
else:
mirror = ""
base = vector(xoffset, 0)
self.driver_insts[index].place(offset=base, mirror=mirror)
self.driver_insts[i].place(offset=base, mirror=mirror)
# place spare write drivers (if spare columns are specified)
for i in range(self.num_spare_cols):
for i, xoffset in enumerate(self.offsets[self.columns:]):
index = self.word_size + i
xoffset = (self.columns + i) * self.driver_spacing
if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2:
if cell_properties.bitcell.mirror.y and (index + self.column_offset) % 2:
mirror = "MY"
xoffset = xoffset + self.driver.width
else:

View File

@ -18,7 +18,7 @@ class write_mask_and_array(design.design):
The write mask AND array goes between the write driver array and the sense amp array.
"""
def __init__(self, name, columns, word_size, write_size, column_offset=0):
def __init__(self, name, columns, word_size, write_size, offsets=None, column_offset=0):
super().__init__(name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("columns: {0}".format(columns))
@ -28,6 +28,7 @@ class write_mask_and_array(design.design):
self.columns = columns
self.word_size = word_size
self.write_size = write_size
self.offsets = offsets
self.column_offset = column_offset
self.words_per_row = int(columns / word_size)
self.num_wmasks = int(word_size / write_size)
@ -90,12 +91,17 @@ class write_mask_and_array(design.design):
debug.check(self.wmask_en_len >= self.and2.width,
"Write mask AND is wider than the corresponding write drivers {0} vs {1}.".format(self.and2.width,
self.wmask_en_len))
self.width = self.bitcell.width * self.columns
if not self.offsets:
self.offsets = []
for i in range(self.columns):
self.offsets.append(i * self.driver_spacing)
self.width = self.offsets[-1] + self.driver_spacing
self.height = self.and2.height
write_bits = self.columns / self.num_wmasks
for i in range(self.num_wmasks):
base = vector(i * self.wmask_en_len, 0)
base = vector(self.offsets[int(i * write_bits)], 0)
self.and2_insts[i].place(base)
def add_layout_pins(self):