mirror of https://github.com/VLSIDA/OpenRAM.git
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:
parent
c58741c44f
commit
8909ad7165
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()]
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 """
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
Loading…
Reference in New Issue