Merge branch 'dev' into discrete_models

This commit is contained in:
jcirimel 2020-06-06 01:48:06 -07:00
commit 5d5ed552e3
54 changed files with 312 additions and 390 deletions

View File

@ -450,26 +450,27 @@ class layout():
path=coordinates, path=coordinates,
layer_widths=layer_widths) layer_widths=layer_widths)
def add_zjog(self, layer, start, end, first_direction="H", fixed_offset=None): def add_zjog(self, layer, start, end, first_direction="H", var_offset=0.5, fixed_offset=None):
""" """
Add a simple jog at the halfway point. Add a simple jog at the halfway point.
If layer is a single value, it is a path. If layer is a single value, it is a path.
If layer is a tuple, it is a wire with preferred directions. If layer is a tuple, it is a wire with preferred directions.
""" """
neg_offset = 1.0 - var_offset
# vertical first # vertical first
if first_direction == "V": if first_direction == "V":
if fixed_offset: if fixed_offset:
mid1 = vector(start.x, fixed_offset) mid1 = vector(start.x, fixed_offset)
else: else:
mid1 = vector(start.x, 0.5 * start.y + 0.5 * end.y) mid1 = vector(start.x, neg_offset * start.y + var_offset * end.y)
mid2 = vector(end.x, mid1.y) mid2 = vector(end.x, mid1.y)
# horizontal first # horizontal first
elif first_direction == "H": elif first_direction == "H":
if fixed_offset: if fixed_offset:
mid1 = vector(fixed_offset, start.y) mid1 = vector(fixed_offset, start.y)
else: else:
mid1 = vector(0.5 * start.x + 0.5 * end.x, start.y) mid1 = vector(neg_offset * start.x + var_offset * end.x, start.y)
mid2 = vector(mid1, end.y) mid2 = vector(mid1, end.y)
else: else:
debug.error("Invalid direction for jog -- must be H or V.") debug.error("Invalid direction for jog -- must be H or V.")

View File

@ -214,25 +214,18 @@ def setup_bitcell():
if OPTS.num_r_ports > 0: if OPTS.num_r_ports > 0:
ports += "{}r".format(OPTS.num_r_ports) ports += "{}r".format(OPTS.num_r_ports)
OPTS.bitcell = "bitcell_"+ports if ports != "":
OPTS.replica_bitcell = "replica_bitcell_"+ports OPTS.bitcell_suffix = "_" + ports
OPTS.dummy_bitcell = "dummy_bitcell_"+ports OPTS.bitcell = "bitcell" + OPTS.bitcell_suffix
else:
OPTS.replica_bitcell = "replica_" + OPTS.bitcell
OPTS.replica_bitcell = "dummy_" + OPTS.bitcell
# See if bitcell exists # See if bitcell exists
try: try:
__import__(OPTS.bitcell) __import__(OPTS.bitcell)
__import__(OPTS.replica_bitcell)
__import__(OPTS.dummy_bitcell)
except ImportError: except ImportError:
# Use the pbitcell if we couldn't find a custom bitcell # Use the pbitcell if we couldn't find a custom bitcell
# or its custom replica bitcell # or its custom replica bitcell
# Use the pbitcell (and give a warning if not in unit test mode) # Use the pbitcell (and give a warning if not in unit test mode)
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
OPTS.replica_bitcell = "dummy_pbitcell"
if not OPTS.is_unit_test: if not OPTS.is_unit_test:
debug.warning("Using the parameterized bitcell which may have suboptimal density.") debug.warning("Using the parameterized bitcell which may have suboptimal density.")
debug.info(1, "Using bitcell: {}".format(OPTS.bitcell)) debug.info(1, "Using bitcell: {}".format(OPTS.bitcell))

View File

@ -798,22 +798,34 @@ class bank(design.design):
for row in range(self.num_rows): for row in range(self.num_rows):
# The mid guarantees we exit the input cell to the right. # The mid guarantees we exit the input cell to the right.
driver_wl_pos = self.port_address_inst[port].get_pin("wl_{}".format(row)).rc() driver_wl_pin = self.port_address_inst[port].get_pin("wl_{}".format(row))
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port] + "_{}".format(row)).lc() driver_wl_pos = driver_wl_pin.rc()
bitcell_wl_pin = self.bitcell_array_inst.get_pin(self.wl_names[port] + "_{}".format(row))
bitcell_wl_pos = bitcell_wl_pin.lc()
mid1 = driver_wl_pos.scale(0, 1) + vector(0.5 * self.port_address_inst[port].rx() + 0.5 * self.bitcell_array_inst.lx(), 0) mid1 = driver_wl_pos.scale(0, 1) + vector(0.5 * self.port_address_inst[port].rx() + 0.5 * self.bitcell_array_inst.lx(), 0)
mid2 = mid1.scale(1, 0) + bitcell_wl_pos.scale(0.5, 1) mid2 = mid1.scale(1, 0) + bitcell_wl_pos.scale(0.5, 1)
self.add_path("m1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) self.add_path(driver_wl_pin.layer, [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
self.add_via_stack_center(from_layer=driver_wl_pin.layer,
to_layer=bitcell_wl_pin.layer,
offset=bitcell_wl_pos,
directions=("H", "H"))
def route_port_address_right(self, port): def route_port_address_right(self, port):
""" Connecting Wordline driver output to Bitcell WL connection """ """ Connecting Wordline driver output to Bitcell WL connection """
for row in range(self.num_rows): for row in range(self.num_rows):
# The mid guarantees we exit the input cell to the right. # The mid guarantees we exit the input cell to the right.
driver_wl_pos = self.port_address_inst[port].get_pin("wl_{}".format(row)).lc() driver_wl_pin = self.port_address_inst[port].get_pin("wl_{}".format(row))
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port] + "_{}".format(row)).rc() driver_wl_pos = driver_wl_pin.lc()
bitcell_wl_pin = self.bitcell_array_inst.get_pin(self.wl_names[port] + "_{}".format(row))
bitcell_wl_pos = bitcell_wl_pin.rc()
mid1 = driver_wl_pos.scale(0, 1) + vector(0.5 * self.port_address_inst[port].lx() + 0.5 * self.bitcell_array_inst.rx(), 0) mid1 = driver_wl_pos.scale(0, 1) + vector(0.5 * self.port_address_inst[port].lx() + 0.5 * self.bitcell_array_inst.rx(), 0)
mid2 = mid1.scale(1, 0) + bitcell_wl_pos.scale(0, 1) mid2 = mid1.scale(1, 0) + bitcell_wl_pos.scale(0, 1)
self.add_path("m1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) self.add_path(driver_wl_pin.layer, [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
self.add_via_stack_center(from_layer=driver_wl_pin.layer,
to_layer=bitcell_wl_pin.layer,
offset=bitcell_wl_pos,
directions=("H", "H"))
def route_column_address_lines(self, port): def route_column_address_lines(self, port):
""" Connecting the select lines of column mux to the address bus """ """ Connecting the select lines of column mux to the address bus """

View File

@ -8,6 +8,7 @@ from sram_factory import factory
from globals import OPTS from globals import OPTS
from tech import cell_properties from tech import cell_properties
class col_cap_array(bitcell_base_array): class col_cap_array(bitcell_base_array):
""" """
Generate a dummy row/column for the replica array. Generate a dummy row/column for the replica array.
@ -35,8 +36,7 @@ class col_cap_array(bitcell_base_array):
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="col_cap_bitcell_1rw_1r") # TODO: make module_type generic self.dummy_cell = factory.create(module_type="col_cap_{}".format(OPTS.bitcell))
self.dummy_cell = factory.create(module_type="col_cap_bitcell")
self.add_mod(self.dummy_cell) self.add_mod(self.dummy_cell)
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type="bitcell")

View File

@ -38,19 +38,18 @@ class dummy_array(bitcell_base_array):
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_{}".format(OPTS.bitcell))
self.add_mod(self.dummy_cell) self.add_mod(self.dummy_cell)
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type="bitcell")
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 = {}
for col in range(self.column_size): for col in range(self.column_size):
for row in range(self.row_size): for row in range(self.row_size):
name = "bit_r{0}_c{1}".format(row, col) name = "bit_r{0}_c{1}".format(row, col)
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))
@ -60,7 +59,7 @@ class dummy_array(bitcell_base_array):
def get_wordline_cin(self): def get_wordline_cin(self):
"""Get the relative input capacitance from the wordline connections in all the bitcell""" """Get the relative input capacitance from the wordline connections in all the bitcell"""
#A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns # A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns
bitcell_wl_cin = self.cell.get_wl_cin() bitcell_wl_cin = self.cell.get_wl_cin()
total_cin = bitcell_wl_cin * self.column_size total_cin = bitcell_wl_cin * self.column_size
return total_cin return total_cin

View File

@ -48,11 +48,18 @@ class hierarchical_decoder(design.design):
self.setup_layout_constants() self.setup_layout_constants()
self.place_pre_decoder() self.place_pre_decoder()
self.place_row_decoder() self.place_row_decoder()
self.height = max(self.predecoder_height, self.row_decoder_height) + self.bus_space
self.route_inputs() self.route_inputs()
self.route_outputs() self.route_outputs()
self.route_decoder_bus() self.route_decoder_bus()
self.route_vdd_gnd() self.route_vdd_gnd()
self.offset_all_coordinates() self.offset_all_coordinates()
self.width = self.and_inst[0].rx() + self.m1_space
self.add_boundary() self.add_boundary()
self.DRC_LVS() self.DRC_LVS()
@ -178,21 +185,6 @@ class hierarchical_decoder(design.design):
# Extra bus space for supply contacts # Extra bus space for supply contacts
self.input_routing_width = self.num_inputs * self.bus_pitch + self.bus_space self.input_routing_width = self.num_inputs * self.bus_pitch + self.bus_space
# Calculates height and width of row-decoder
# Calculates height and width of hierarchical decoder
# Add extra pitch for good measure
self.height = max(self.predecoder_height, self.row_decoder_height) + self.bus_space
if (self.num_inputs == 4 or self.num_inputs == 5):
self.nand_width = self.and2.width
else:
self.nand_width = self.and3.width
self.width = self.input_routing_width \
+ self.predecoder_width \
+ self.internal_routing_width \
+ self.nand_width \
+ self.m1_space
def route_inputs(self): def route_inputs(self):
""" Create input bus for the predecoders """ """ Create input bus for the predecoders """
# Find the left-most predecoder # Find the left-most predecoder

View File

@ -93,7 +93,7 @@ class port_address(design.design):
decoder_out_pos = decoder_out_pin.rc() decoder_out_pos = decoder_out_pin.rc()
driver_in_pin = self.wordline_driver_inst.get_pin("in_{}".format(row)) driver_in_pin = self.wordline_driver_inst.get_pin("in_{}".format(row))
driver_in_pos = driver_in_pin.lc() driver_in_pos = driver_in_pin.lc()
self.add_zjog(self.route_layer, decoder_out_pos, driver_in_pos) self.add_zjog(self.route_layer, decoder_out_pos, driver_in_pos, var_offset=0.3)
self.add_via_stack_center(from_layer=decoder_out_pin.layer, self.add_via_stack_center(from_layer=decoder_out_pin.layer,
to_layer=self.route_layer, to_layer=self.route_layer,

View File

@ -178,14 +178,17 @@ class port_data(design.design):
# Extra column +1 is for RBL # Extra column +1 is for RBL
# Precharge will be shifted left if needed # Precharge will be shifted left if needed
# Column offset is set to port so extra column can be on left or right
# and mirroring happens correctly
self.precharge_array = factory.create(module_type="precharge_array", self.precharge_array = factory.create(module_type="precharge_array",
columns=self.num_cols + 1, columns=self.num_cols + 1,
port=self.port,
bitcell_bl=self.bl_names[self.port], bitcell_bl=self.bl_names[self.port],
bitcell_br=self.br_names[self.port]) bitcell_br=self.br_names[self.port],
column_offset=self.port - 1)
self.add_mod(self.precharge_array) self.add_mod(self.precharge_array)
if self.port in self.read_ports: if self.port in self.read_ports:
# RBLs don't get a sense amp
self.sense_amp_array = factory.create(module_type="sense_amp_array", self.sense_amp_array = factory.create(module_type="sense_amp_array",
word_size=self.word_size, word_size=self.word_size,
words_per_row=self.words_per_row) words_per_row=self.words_per_row)
@ -194,9 +197,9 @@ class port_data(design.design):
self.sense_amp_array = None self.sense_amp_array = None
if self.col_addr_size > 0: if self.col_addr_size > 0:
# RBLs dont get a col mux
self.column_mux_array = factory.create(module_type="column_mux_array", self.column_mux_array = factory.create(module_type="column_mux_array",
columns=self.num_cols, columns=self.num_cols,
port=self.port,
word_size=self.word_size, word_size=self.word_size,
bitcell_bl=self.bl_names[self.port], bitcell_bl=self.bl_names[self.port],
bitcell_br=self.br_names[self.port]) bitcell_br=self.br_names[self.port])
@ -205,17 +208,18 @@ class port_data(design.design):
self.column_mux_array = None self.column_mux_array = None
if self.port in self.write_ports: if self.port in self.write_ports:
# RBLs dont get a write driver
self.write_driver_array = factory.create(module_type="write_driver_array", self.write_driver_array = factory.create(module_type="write_driver_array",
columns=self.num_cols, columns=self.num_cols,
word_size=self.word_size, word_size=self.word_size,
write_size=self.write_size) write_size=self.write_size)
self.add_mod(self.write_driver_array) self.add_mod(self.write_driver_array)
if self.write_size is not None: if self.write_size is not None:
# RBLs don't get a write mask
self.write_mask_and_array = factory.create(module_type="write_mask_and_array", self.write_mask_and_array = factory.create(module_type="write_mask_and_array",
columns=self.num_cols, columns=self.num_cols,
word_size=self.word_size, word_size=self.word_size,
write_size=self.write_size, write_size=self.write_size)
port = self.port)
self.add_mod(self.write_mask_and_array) self.add_mod(self.write_mask_and_array)
else: else:
self.write_mask_and_array = None self.write_mask_and_array = None
@ -248,13 +252,6 @@ class port_data(design.design):
self.precharge = factory.create(module_type="precharge", self.precharge = factory.create(module_type="precharge",
bitcell_bl=self.bl_names[0], bitcell_bl=self.bl_names[0],
bitcell_br=self.br_names[0]) bitcell_br=self.br_names[0])
# We create a dummy here to get bl/br names to add those pins to this
# module, which happens before we create the real precharge_array
self.precharge_array = factory.create(module_type="precharge_array",
columns=self.num_cols + 1,
port=self.port,
bitcell_bl=self.bl_names[self.port],
bitcell_br=self.br_names[self.port])
def create_precharge_array(self): def create_precharge_array(self):
""" Creating Precharge """ """ Creating Precharge """
@ -732,8 +729,8 @@ class port_data(design.design):
top_bl, top_br = top_bl_pin.bc(), top_br_pin.bc() top_bl, top_br = top_bl_pin.bc(), top_br_pin.bc()
layer_pitch = getattr(self, "{}_pitch".format(top_bl_pin.layer)) layer_pitch = getattr(self, "{}_pitch".format(top_bl_pin.layer))
self.add_zjog(bot_bl_pin.layer, bot_bl, top_bl, "V", top_bl_pin.by() - layer_pitch) self.add_zjog(bot_bl_pin.layer, bot_bl, top_bl, "V", fixed_offset=top_bl_pin.by() - layer_pitch)
self.add_zjog(bot_br_pin.layer, bot_br, top_br, "V", top_bl_pin.by() - 2 * layer_pitch) self.add_zjog(bot_br_pin.layer, bot_br, top_br, "V", fixed_offset=top_bl_pin.by() - 2 * layer_pitch)
def graph_exclude_precharge(self): def graph_exclude_precharge(self):
"""Precharge adds a loop between bitlines, can be excluded to reduce complexity""" """Precharge adds a loop between bitlines, can be excluded to reduce complexity"""

View File

@ -18,16 +18,16 @@ class precharge_array(design.design):
of bit line columns, height is the height of the bit-cell array. of bit line columns, height is the height of the bit-cell array.
""" """
def __init__(self, name, columns, port, size=1, bitcell_bl="bl", bitcell_br="br"): def __init__(self, name, columns, size=1, bitcell_bl="bl", bitcell_br="br", column_offset=0):
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.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.add_comment("cols: {0} size: {1} bl: {2} br: {3}".format(columns, size, bitcell_bl, bitcell_br))
self.columns = columns self.columns = columns
self.size = size self.size = size
self.port = port
self.bitcell_bl = bitcell_bl self.bitcell_bl = bitcell_bl
self.bitcell_br = bitcell_br self.bitcell_br = bitcell_br
self.column_offset = column_offset
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
@ -106,7 +106,7 @@ class precharge_array(design.design):
xoffset = 0 xoffset = 0
for i in range(self.columns): for i in range(self.columns):
tempx = xoffset tempx = xoffset
if cell_properties.bitcell.mirror.y and (i + 1 + self.port) % 2: if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2:
mirror = "MY" mirror = "MY"
tempx = tempx + self.pc_cell.width tempx = tempx + self.pc_cell.width
else: else:

View File

@ -32,8 +32,10 @@ class replica_bitcell_array(design.design):
self.right_rbl = right_rbl self.right_rbl = right_rbl
self.bitcell_ports = bitcell_ports self.bitcell_ports = bitcell_ports
debug.check(left_rbl+right_rbl==len(self.all_ports),"Invalid number of RBLs for port configuration.") debug.check(left_rbl + right_rbl == len(self.all_ports),
debug.check(left_rbl+right_rbl==len(self.bitcell_ports),"Bitcell ports must match total RBLs.") "Invalid number of RBLs for port configuration.")
debug.check(left_rbl + right_rbl == len(self.bitcell_ports),
"Bitcell ports must match total RBLs.")
# Two dummy rows/cols plus replica for each port # Two dummy rows/cols plus replica for each port
self.extra_rows = 2 + left_rbl + right_rbl self.extra_rows = 2 + left_rbl + right_rbl
@ -45,8 +47,7 @@ class replica_bitcell_array(design.design):
# We don't offset this because we need to align # We don't offset this because we need to align
# the replica bitcell in the control logic # the replica bitcell in the control logic
#self.offset_all_coordinates() # self.offset_all_coordinates()
def create_netlist(self): def create_netlist(self):
""" Create and connect the netlist """ """ Create and connect the netlist """
@ -90,15 +91,15 @@ class replica_bitcell_array(design.design):
# Replica bitlines # Replica bitlines
self.replica_columns = {} self.replica_columns = {}
for bit in range(self.left_rbl+self.right_rbl): for bit in range(self.left_rbl + self.right_rbl):
# Creating left_rbl # Creating left_rbl
if bit<self.left_rbl: if bit<self.left_rbl:
replica_bit = bit+1 replica_bit = bit + 1
# dummy column # dummy column
column_offset = self.left_rbl - bit column_offset = self.left_rbl - bit
# Creating right_rbl # Creating right_rbl
else: else:
replica_bit = bit+self.row_size+1 replica_bit = bit + self.row_size + 1
# dummy column + replica column + bitcell colums # dummy column + replica column + bitcell colums
column_offset = self.left_rbl - bit + self.row_size column_offset = self.left_rbl - bit + self.row_size
self.replica_columns[bit] = factory.create(module_type="replica_column", self.replica_columns[bit] = factory.create(module_type="replica_column",
@ -118,7 +119,6 @@ class replica_bitcell_array(design.design):
mirror=0) mirror=0)
self.add_mod(self.dummy_row) self.add_mod(self.dummy_row)
# If there are bitcell end caps, replace the dummy cells on the edge of the bitcell array with end caps. # If there are bitcell end caps, replace the dummy cells on the edge of the bitcell array with end caps.
try: try:
end_caps_enabled = cell_properties.bitcell.end_caps end_caps_enabled = cell_properties.bitcell.end_caps
@ -131,7 +131,7 @@ class replica_bitcell_array(design.design):
self.edge_row = factory.create(module_type=edge_row_module_type, self.edge_row = factory.create(module_type=edge_row_module_type,
cols=self.column_size, cols=self.column_size,
rows=1, rows=1,
# dummy column + left replica column # dummy column + left replica column(s)
column_offset=1 + self.left_rbl, column_offset=1 + self.left_rbl,
mirror=0) mirror=0)
self.add_mod(self.edge_row) self.add_mod(self.edge_row)
@ -143,18 +143,18 @@ class replica_bitcell_array(design.design):
cols=1, cols=1,
column_offset=0, column_offset=0,
rows=self.row_size + self.extra_rows, rows=self.row_size + self.extra_rows,
mirror=(self.left_rbl+1)%2) mirror=(self.left_rbl + 1) % 2)
self.add_mod(self.edge_col_left) self.add_mod(self.edge_col_left)
self.edge_col_right = factory.create(module_type=edge_col_module_type, self.edge_col_right = factory.create(module_type=edge_col_module_type,
cols=1, cols=1,
# dummy column # dummy column
# + left replica column # + left replica column(s)
# + bitcell columns # + bitcell columns
# + right replica column # + right replica column(s)
column_offset=1 + self.left_rbl + self.column_size + self.right_rbl, column_offset = 1 + self.left_rbl + self.column_size + self.right_rbl,
rows=self.row_size + self.extra_rows, rows=self.row_size + self.extra_rows,
mirror=(self.left_rbl+1)%2) mirror=(self.left_rbl + 1) %2)
self.add_mod(self.edge_col_right) self.add_mod(self.edge_col_right)
def add_pins(self): def add_pins(self):
@ -162,8 +162,8 @@ class replica_bitcell_array(design.design):
self.bitcell_array_bl_names = self.bitcell_array.get_all_bitline_names() self.bitcell_array_bl_names = self.bitcell_array.get_all_bitline_names()
# These are the non-indexed names # These are the non-indexed names
self.dummy_cell_wl_names = ["dummy_"+x for x in self.cell.get_all_wl_names()] self.dummy_cell_wl_names = ["dummy_" + x for x in self.cell.get_all_wl_names()]
self.dummy_cell_bl_names = ["dummy_"+x for x in self.cell.get_all_bitline_names()] self.dummy_cell_bl_names = ["dummy_" + x for x in self.cell.get_all_bitline_names()]
self.dummy_row_bl_names = self.bitcell_array_bl_names self.dummy_row_bl_names = self.bitcell_array_bl_names
# A dictionary because some ports may have nothing # A dictionary because some ports may have nothing
@ -177,16 +177,16 @@ class replica_bitcell_array(design.design):
# Left port WLs (one dummy for each port when we allow >1 port) # Left port WLs (one dummy for each port when we allow >1 port)
for port in range(self.left_rbl): for port in range(self.left_rbl):
# Make names for all RBLs # Make names for all RBLs
wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x),port) for x in range(len(self.cell.get_all_wl_names()))] wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x), port) for x in range(len(self.cell.get_all_wl_names()))]
# Keep track of the pin that is the RBL # Keep track of the pin that is the RBL
self.rbl_wl_names[port]=wl_names[self.bitcell_ports[port]] self.rbl_wl_names[port]=wl_names[self.bitcell_ports[port]]
self.replica_col_wl_names.extend(wl_names) self.replica_col_wl_names.extend(wl_names)
# Regular WLs # Regular WLs
self.replica_col_wl_names.extend(self.bitcell_array_wl_names) self.replica_col_wl_names.extend(self.bitcell_array_wl_names)
# Right port WLs (one dummy for each port when we allow >1 port) # Right port WLs (one dummy for each port when we allow >1 port)
for port in range(self.left_rbl,self.left_rbl+self.right_rbl): for port in range(self.left_rbl, self.left_rbl + self.right_rbl):
# Make names for all RBLs # Make names for all RBLs
wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x),port) for x in range(len(self.cell.get_all_wl_names()))] wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x), port) for x in range(len(self.cell.get_all_wl_names()))]
# Keep track of the pin that is the RBL # Keep track of the pin that is the RBL
self.rbl_wl_names[port]=wl_names[self.bitcell_ports[port]] self.rbl_wl_names[port]=wl_names[self.bitcell_ports[port]]
self.replica_col_wl_names.extend(wl_names) self.replica_col_wl_names.extend(wl_names)
@ -195,14 +195,13 @@ class replica_bitcell_array(design.design):
# Left/right dummy columns are connected identically to the replica column # Left/right dummy columns are connected identically to the replica column
self.dummy_col_wl_names = self.replica_col_wl_names self.dummy_col_wl_names = self.replica_col_wl_names
# Per port bitline names # Per port bitline names
self.replica_bl_names = {} self.replica_bl_names = {}
self.replica_wl_names = {} self.replica_wl_names = {}
# Array of all port bitline names # Array of all port bitline names
for port in range(self.left_rbl+self.right_rbl): for port in range(self.left_rbl + self.right_rbl):
left_names=["rbl_{0}_{1}".format(self.cell.get_bl_name(x),port) for x in range(len(self.all_ports))] left_names=["rbl_{0}_{1}".format(self.cell.get_bl_name(x), port) for x in range(len(self.all_ports))]
right_names=["rbl_{0}_{1}".format(self.cell.get_br_name(x),port) for x in range(len(self.all_ports))] right_names=["rbl_{0}_{1}".format(self.cell.get_br_name(x), port) for x in range(len(self.all_ports))]
# Keep track of the left pins that are the RBL # Keep track of the left pins that are the RBL
self.rbl_bl_names[port]=left_names[self.bitcell_ports[port]] self.rbl_bl_names[port]=left_names[self.bitcell_ports[port]]
self.rbl_br_names[port]=right_names[self.bitcell_ports[port]] self.rbl_br_names[port]=right_names[self.bitcell_ports[port]]
@ -210,28 +209,25 @@ class replica_bitcell_array(design.design):
bl_names = [x for t in zip(left_names, right_names) for x in t] bl_names = [x for t in zip(left_names, right_names) for x in t]
self.replica_bl_names[port] = bl_names self.replica_bl_names[port] = bl_names
wl_names = ["rbl_{0}_{1}".format(x,port) for x in self.cell.get_all_wl_names()] wl_names = ["rbl_{0}_{1}".format(x, port) for x in self.cell.get_all_wl_names()]
#wl_names[port] = "rbl_wl{}".format(port)
self.replica_wl_names[port] = wl_names self.replica_wl_names[port] = wl_names
# External pins # External pins
self.add_pin_list(self.bitcell_array_bl_names, "INOUT") self.add_pin_list(self.bitcell_array_bl_names, "INOUT")
# Need to sort by port order since dictionary values may not be in order # Need to sort by port order since dictionary values may not be in order
bl_names = [self.rbl_bl_names[x] for x in sorted(self.rbl_bl_names.keys())] bl_names = [self.rbl_bl_names[x] for x in sorted(self.rbl_bl_names.keys())]
br_names = [self.rbl_br_names[x] for x in sorted(self.rbl_br_names.keys())] br_names = [self.rbl_br_names[x] for x in sorted(self.rbl_br_names.keys())]
for (bl_name,br_name) in zip(bl_names,br_names): for (bl_name, br_name) in zip(bl_names, br_names):
self.add_pin(bl_name,"OUTPUT") self.add_pin(bl_name, "OUTPUT")
self.add_pin(br_name,"OUTPUT") self.add_pin(br_name, "OUTPUT")
self.add_pin_list(self.bitcell_array_wl_names, "INPUT") self.add_pin_list(self.bitcell_array_wl_names, "INPUT")
# Need to sort by port order since dictionary values may not be in order # Need to sort by port order since dictionary values may not be in order
wl_names = [self.rbl_wl_names[x] for x in sorted(self.rbl_wl_names.keys())] wl_names = [self.rbl_wl_names[x] for x in sorted(self.rbl_wl_names.keys())]
for pin_name in wl_names: for pin_name in wl_names:
self.add_pin(pin_name,"INPUT") self.add_pin(pin_name, "INPUT")
self.add_pin("vdd", "POWER") self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND") self.add_pin("gnd", "GROUND")
def create_instances(self): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """
@ -247,77 +243,75 @@ class replica_bitcell_array(design.design):
# Replica columns # Replica columns
self.replica_col_inst = {} self.replica_col_inst = {}
for port in range(self.left_rbl+self.right_rbl): for port in range(self.left_rbl + self.right_rbl):
self.replica_col_inst[port]=self.add_inst(name="replica_col_{}".format(port), self.replica_col_inst[port]=self.add_inst(name="replica_col_{}".format(port),
mod=self.replica_columns[port]) mod=self.replica_columns[port])
self.connect_inst(self.replica_bl_names[port] + self.replica_col_wl_names + supplies) self.connect_inst(self.replica_bl_names[port] + self.replica_col_wl_names + supplies)
# Dummy rows under the bitcell array (connected with with the replica cell wl) # Dummy rows under the bitcell array (connected with with the replica cell wl)
self.dummy_row_replica_inst = {} self.dummy_row_replica_inst = {}
for port in range(self.left_rbl+self.right_rbl): for port in range(self.left_rbl + self.right_rbl):
self.dummy_row_replica_inst[port]=self.add_inst(name="dummy_row_{}".format(port), self.dummy_row_replica_inst[port]=self.add_inst(name="dummy_row_{}".format(port),
mod=self.dummy_row) mod=self.dummy_row)
self.connect_inst(self.dummy_row_bl_names + self.replica_wl_names[port] + supplies) self.connect_inst(self.dummy_row_bl_names + self.replica_wl_names[port] + supplies)
# Top/bottom dummy rows or col caps # Top/bottom dummy rows or col caps
self.dummy_row_bot_inst=self.add_inst(name="dummy_row_bot", self.dummy_row_bot_inst=self.add_inst(name="dummy_row_bot",
mod=self.edge_row) mod=self.edge_row)
self.connect_inst(self.dummy_row_bl_names + [x+"_bot" for x in self.dummy_cell_wl_names] + supplies) self.connect_inst(self.dummy_row_bl_names + [x + "_bot" for x in self.dummy_cell_wl_names] + supplies)
self.dummy_row_top_inst=self.add_inst(name="dummy_row_top", self.dummy_row_top_inst=self.add_inst(name="dummy_row_top",
mod=self.edge_row) mod=self.edge_row)
self.connect_inst(self.dummy_row_bl_names + [x+"_top" for x in self.dummy_cell_wl_names] + supplies) self.connect_inst(self.dummy_row_bl_names + [x + "_top" for x in self.dummy_cell_wl_names] + supplies)
# Left/right Dummy columns # Left/right Dummy columns
self.dummy_col_left_inst=self.add_inst(name="dummy_col_left", self.dummy_col_left_inst=self.add_inst(name="dummy_col_left",
mod=self.edge_col_left) mod=self.edge_col_left)
self.connect_inst([x+"_left" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies) self.connect_inst([x + "_left" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies)
self.dummy_col_right_inst=self.add_inst(name="dummy_col_right", self.dummy_col_right_inst=self.add_inst(name="dummy_col_right",
mod=self.edge_col_right) mod=self.edge_col_right)
self.connect_inst([x+"_right" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies) self.connect_inst([x + "_right" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies)
def create_layout(self): def create_layout(self):
self.height = (self.row_size+self.extra_rows)*self.dummy_row.height self.height = (self.row_size + self.extra_rows) * self.dummy_row.height
self.width = (self.column_size+self.extra_cols)*self.cell.width self.width = (self.column_size + self.extra_cols) * self.cell.width
# This is a bitcell x bitcell offset to scale # This is a bitcell x bitcell offset to scale
offset = vector(self.cell.width, self.cell.height) offset = vector(self.cell.width, self.cell.height)
self.bitcell_array_inst.place(offset=[0,0]) self.bitcell_array_inst.place(offset=[0, 0])
# To the left of the bitcell array # To the left of the bitcell array
for bit in range(self.left_rbl): for bit in range(self.left_rbl):
self.replica_col_inst[bit].place(offset=offset.scale(-bit-1,-self.left_rbl-1)) self.replica_col_inst[bit].place(offset=offset.scale(-bit - 1, -self.left_rbl - 1))
# To the right of the bitcell array # To the right of the bitcell array
for bit in range(self.right_rbl): for bit in range(self.right_rbl):
self.replica_col_inst[self.left_rbl+bit].place(offset=offset.scale(bit,-self.left_rbl-1)+self.bitcell_array_inst.lr()) self.replica_col_inst[self.left_rbl + bit].place(offset=offset.scale(bit, -self.left_rbl - 1) + self.bitcell_array_inst.lr())
# FIXME: These depend on the array size itself
# Far top dummy row (first row above array is NOT flipped) # Far top dummy row (first row above array is NOT flipped)
flip_dummy = self.right_rbl%2 flip_dummy = self.right_rbl % 2
self.dummy_row_top_inst.place(offset=offset.scale(0,self.right_rbl+flip_dummy)+self.bitcell_array_inst.ul(), self.dummy_row_top_inst.place(offset=offset.scale(0, self.right_rbl + flip_dummy) + self.bitcell_array_inst.ul(),
mirror="MX" if flip_dummy else "R0") mirror="MX" if flip_dummy else "R0")
# FIXME: These depend on the array size itself
# Far bottom dummy row (first row below array IS flipped) # Far bottom dummy row (first row below array IS flipped)
flip_dummy = (self.left_rbl+1)%2 flip_dummy = (self.left_rbl + 1) % 2
self.dummy_row_bot_inst.place(offset=offset.scale(0,-self.left_rbl-1+flip_dummy), self.dummy_row_bot_inst.place(offset=offset.scale(0, -self.left_rbl - 1 + flip_dummy),
mirror="MX" if flip_dummy else "R0") mirror="MX" if flip_dummy else "R0")
# Far left dummy col # Far left dummy col
self.dummy_col_left_inst.place(offset=offset.scale(-self.left_rbl-1,-self.left_rbl-1)) self.dummy_col_left_inst.place(offset=offset.scale(-self.left_rbl - 1, -self.left_rbl - 1))
# Far right dummy col # Far right dummy col
self.dummy_col_right_inst.place(offset=offset.scale(self.right_rbl,-self.left_rbl-1)+self.bitcell_array_inst.lr()) self.dummy_col_right_inst.place(offset=offset.scale(self.right_rbl, -self.left_rbl - 1) + self.bitcell_array_inst.lr())
# Replica dummy rows # Replica dummy rows
for bit in range(self.left_rbl): for bit in range(self.left_rbl):
self.dummy_row_replica_inst[bit].place(offset=offset.scale(0,-bit-bit%2), self.dummy_row_replica_inst[bit].place(offset=offset.scale(0, -bit - bit % 2),
mirror="R0" if bit%2 else "MX") mirror="R0" if bit % 2 else "MX")
for bit in range(self.right_rbl): for bit in range(self.right_rbl):
self.dummy_row_replica_inst[self.left_rbl+bit].place(offset=offset.scale(0,bit+bit%2)+self.bitcell_array_inst.ul(), self.dummy_row_replica_inst[self.left_rbl + bit].place(offset=offset.scale(0, bit + bit % 2) + self.bitcell_array_inst.ul(),
mirror="MX" if bit%2 else "R0") mirror="MX" if bit % 2 else "R0")
self.translate_all(offset.scale(-1 - self.left_rbl, -1 - self.left_rbl))
self.translate_all(offset.scale(-1-self.left_rbl,-1-self.left_rbl))
self.add_layout_pins() self.add_layout_pins()
@ -325,7 +319,6 @@ class replica_bitcell_array(design.design):
self.DRC_LVS() self.DRC_LVS()
def add_layout_pins(self): def add_layout_pins(self):
""" Add the layout pins """ """ Add the layout pins """
@ -338,7 +331,7 @@ class replica_bitcell_array(design.design):
for pin in pin_list: for pin in pin_list:
self.add_layout_pin(text=pin_name, self.add_layout_pin(text=pin_name,
layer=pin.layer, layer=pin.layer,
offset=pin.ll().scale(0,1), offset=pin.ll().scale(0, 1),
width=self.width, width=self.width,
height=pin.height()) height=pin.height())
for bitline in self.bitcell_array_bl_names: for bitline in self.bitcell_array_bl_names:
@ -347,17 +340,16 @@ class replica_bitcell_array(design.design):
for pin in pin_list: for pin in pin_list:
self.add_layout_pin(text=pin_name, self.add_layout_pin(text=pin_name,
layer=pin.layer, layer=pin.layer,
offset=pin.ll().scale(1,0), offset=pin.ll().scale(1, 0),
width=pin.width(), width=pin.width(),
height=self.height) height=self.height)
# Replica wordlines # Replica wordlines
for port in range(self.left_rbl+self.right_rbl): for port in range(self.left_rbl + self.right_rbl):
inst = self.replica_col_inst[port] inst = self.replica_col_inst[port]
for (pin_name,wl_name) in zip(self.cell.get_all_wl_names(),self.replica_wl_names[port]): for (pin_name, wl_name) in zip(self.cell.get_all_wl_names(), self.replica_wl_names[port]):
# +1 for dummy row # +1 for dummy row
pin_bit = port+1 pin_bit = port + 1
# +row_size if above the array # +row_size if above the array
if port>=self.left_rbl: if port>=self.left_rbl:
pin_bit += self.row_size pin_bit += self.row_size
@ -367,7 +359,7 @@ class replica_bitcell_array(design.design):
if wl_name in self.rbl_wl_names.values(): if wl_name in self.rbl_wl_names.values():
self.add_layout_pin(text=wl_name, self.add_layout_pin(text=wl_name,
layer=pin.layer, layer=pin.layer,
offset=pin.ll().scale(0,1), offset=pin.ll().scale(0, 1),
width=self.width, width=self.width,
height=pin.height()) height=pin.height())
@ -416,8 +408,6 @@ class replica_bitcell_array(design.design):
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."""
from tech import drc, parameter
# Dynamic Power from Bitline # Dynamic Power from Bitline
bl_wire = self.gen_bl_wire() bl_wire = self.gen_bl_wire()
cell_load = 2 * bl_wire.return_input_cap() cell_load = 2 * bl_wire.return_input_cap()
@ -425,10 +415,10 @@ class replica_bitcell_array(design.design):
freq = spice["default_event_frequency"] freq = spice["default_event_frequency"]
bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing) bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing)
#Calculate the bitcell power which currently only includes leakage # Calculate the bitcell power which currently only includes leakage
cell_power = self.cell.analytical_power(corner, load) cell_power = self.cell.analytical_power(corner, load)
#Leakage power grows with entire array and bitlines. # Leakage power grows with entire array and bitlines.
total_power = self.return_power(cell_power.dynamic + bitline_dynamic * self.column_size, total_power = self.return_power(cell_power.dynamic + bitline_dynamic * self.column_size,
cell_power.leakage * self.column_size * self.row_size) cell_power.leakage * self.column_size * self.row_size)
return total_power return total_power
@ -439,13 +429,13 @@ class replica_bitcell_array(design.design):
else: else:
height = self.height height = self.height
bl_pos = 0 bl_pos = 0
bl_wire = self.generate_rc_net(int(self.row_size-bl_pos), height, drc("minwidth_m1")) bl_wire = self.generate_rc_net(int(self.row_size - bl_pos), height, drc("minwidth_m1"))
bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell
return bl_wire return bl_wire
def get_wordline_cin(self): def get_wordline_cin(self):
"""Get the relative input capacitance from the wordline connections in all the bitcell""" """Get the relative input capacitance from the wordline connections in all the bitcell"""
#A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns # A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns
bitcell_wl_cin = self.cell.get_wl_cin() bitcell_wl_cin = self.cell.get_wl_cin()
total_cin = bitcell_wl_cin * self.column_size total_cin = bitcell_wl_cin * self.column_size
return total_cin return total_cin
@ -457,9 +447,9 @@ class replica_bitcell_array(design.design):
def graph_exclude_replica_col_bits(self): def graph_exclude_replica_col_bits(self):
"""Exclude all replica/dummy cells in the replica columns except the replica bit.""" """Exclude all replica/dummy cells in the replica columns except the replica bit."""
for port in range(self.left_rbl+self.right_rbl): for port in range(self.left_rbl + self.right_rbl):
self.replica_columns[port].exclude_all_but_replica() self.replica_columns[port].exclude_all_but_replica()
def get_cell_name(self, inst_name, row, col): def get_cell_name(self, inst_name, row, col):
"""Gets the spice name of the target bitcell.""" """Gets the spice name of the target bitcell."""
return self.bitcell_array.get_cell_name(inst_name+'.x'+self.bitcell_array_inst.name, row, col) return self.bitcell_array.get_cell_name(inst_name + '.x' + self.bitcell_array_inst.name, row, col)

View File

@ -5,12 +5,12 @@
# #
import debug import debug
import design import design
from tech import drc, cell_properties from tech import cell_properties
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 replica_column(design.design): class replica_column(design.design):
""" """
Generate a replica bitline column for the replica array. Generate a replica bitline column for the replica array.
@ -29,11 +29,12 @@ class replica_column(design.design):
self.right_rbl = right_rbl self.right_rbl = right_rbl
self.replica_bit = replica_bit self.replica_bit = replica_bit
# left, right, regular rows plus top/bottom dummy cells # left, right, regular rows plus top/bottom dummy cells
self.total_size = self.left_rbl+rows+self.right_rbl+2 self.total_size = self.left_rbl + rows + self.right_rbl + 2
self.column_offset = column_offset self.column_offset = column_offset
debug.check(replica_bit!=0 and replica_bit!=rows,"Replica bit cannot be the dummy row.") debug.check(replica_bit != 0 and replica_bit != rows,
debug.check(replica_bit<=left_rbl or replica_bit>=self.total_size-right_rbl-1, "Replica bit cannot be the dummy row.")
debug.check(replica_bit <= left_rbl or replica_bit >= self.total_size - right_rbl - 1,
"Replica bit cannot be in the regular array.") "Replica bit cannot be in the regular array.")
self.create_netlist() self.create_netlist()
@ -46,7 +47,7 @@ class replica_column(design.design):
self.create_instances() self.create_instances()
def create_layout(self): def create_layout(self):
self.height = self.total_size*self.cell.height self.height = self.total_size * self.cell.height
self.width = self.cell.width self.width = self.cell.width
self.place_instances() self.place_instances()
@ -58,25 +59,25 @@ class replica_column(design.design):
for bl_name in self.cell.get_all_bitline_names(): for bl_name in self.cell.get_all_bitline_names():
# In the replica column, these are only outputs! # In the replica column, these are only outputs!
self.add_pin("{0}_{1}".format(bl_name,0), "OUTPUT") self.add_pin("{0}_{1}".format(bl_name, 0), "OUTPUT")
for row in range(self.total_size): for row in range(self.total_size):
for wl_name in self.cell.get_all_wl_names(): for wl_name in self.cell.get_all_wl_names():
self.add_pin("{0}_{1}".format(wl_name,row), "INPUT") self.add_pin("{0}_{1}".format(wl_name, row), "INPUT")
self.add_pin("vdd", "POWER") self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND") self.add_pin("gnd", "GROUND")
def add_modules(self): def add_modules(self):
self.replica_cell = factory.create(module_type="replica_bitcell") self.replica_cell = factory.create(module_type="replica_{}".format(OPTS.bitcell))
self.add_mod(self.replica_cell) self.add_mod(self.replica_cell)
self.dummy_cell = factory.create(module_type="dummy_bitcell") self.dummy_cell = factory.create(module_type="dummy_{}".format(OPTS.bitcell))
self.add_mod(self.dummy_cell) self.add_mod(self.dummy_cell)
try: try:
edge_module_type = ("col_cap_bitcell" if cell_properties.bitcell.end_caps else "dummy_bitcell") edge_module_type = ("col_cap" if cell_properties.bitcell.end_caps else "dummy")
except AttributeError: except AttributeError:
edge_module_type = "dummy_bitcell" edge_module_type = "dummy"
self.edge_cell = factory.create(module_type=edge_module_type) self.edge_cell = factory.create(module_type=edge_module_type + "_" + OPTS.bitcell)
self.add_mod(self.edge_cell) self.add_mod(self.edge_cell)
# Used for pin names only # Used for pin names only
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type="bitcell")
@ -94,7 +95,7 @@ class replica_column(design.design):
# Top/bottom cell are always dummy cells. # Top/bottom cell are always dummy cells.
# Regular array cells are replica cells (>left_rbl and <rows-right_rbl) # Regular array cells are replica cells (>left_rbl and <rows-right_rbl)
# Replic bit specifies which other bit (in the full range (0,rows) to make a replica cell. # Replic bit specifies which other bit (in the full range (0,rows) to make a replica cell.
if (row>self.left_rbl and row<self.total_size-self.right_rbl-1): if (row > self.left_rbl and row < self.total_size - self.right_rbl - 1):
self.cell_inst[row]=self.add_inst(name=name, self.cell_inst[row]=self.add_inst(name=name,
mod=self.replica_cell) mod=self.replica_cell)
self.connect_inst(self.get_bitcell_pins(0, row)) self.connect_inst(self.get_bitcell_pins(0, row))
@ -118,7 +119,7 @@ class replica_column(design.design):
from tech import cell_properties from tech import cell_properties
# Flip the mirrors if we have an odd number of replica+dummy rows at the bottom # Flip the mirrors if we have an odd number of replica+dummy rows at the bottom
# so that we will start with mirroring rather than not mirroring # so that we will start with mirroring rather than not mirroring
rbl_offset = (self.left_rbl+1)%2 rbl_offset = (self.left_rbl + 1) %2
# if our bitcells are mirrored on the y axis, check if we are in global # if our bitcells are mirrored on the y axis, check if we are in global
# column that needs to be flipped. # column that needs to be flipped.
@ -129,12 +130,10 @@ class replica_column(design.design):
xoffset = self.replica_cell.width xoffset = self.replica_cell.width
for row in range(self.total_size): for row in range(self.total_size):
dir_x = False # name = "bit_r{0}_{1}".format(row, "rbl")
name = "bit_r{0}_{1}".format(row,"rbl") dir_x = cell_properties.bitcell.mirror.x and (row + rbl_offset) % 2
if cell_properties.bitcell.mirror.x and (row+rbl_offset)%2:
dir_x = True
offset = vector(xoffset,self.cell.height*(row+(row+rbl_offset)%2)) offset = vector(xoffset, self.cell.height * (row + (row + rbl_offset) % 2))
if dir_x and dir_y: if dir_x and dir_y:
dir_key = "XY" dir_key = "XY"
@ -174,9 +173,9 @@ class replica_column(design.design):
for row in range(row_range_min, row_range_max): for row in range(row_range_min, row_range_max):
for wl_name in self.cell.get_all_wl_names(): for wl_name in self.cell.get_all_wl_names():
wl_pin = self.cell_inst[row].get_pin(wl_name) wl_pin = self.cell_inst[row].get_pin(wl_name)
self.add_layout_pin(text="{0}_{1}".format(wl_name,row), self.add_layout_pin(text="{0}_{1}".format(wl_name, row),
layer=wl_pin.layer, layer=wl_pin.layer,
offset=wl_pin.ll().scale(0,1), offset=wl_pin.ll().scale(0, 1),
width=self.width, width=self.width,
height=wl_pin.height()) height=wl_pin.height())
@ -194,10 +193,10 @@ class replica_column(design.design):
pin_names = self.cell.get_all_bitline_names() pin_names = self.cell.get_all_bitline_names()
for pin in pin_names: for pin in pin_names:
bitcell_pins.append(pin+"_{0}".format(col)) bitcell_pins.append(pin + "_{0}".format(col))
pin_names = self.cell.get_all_wl_names() pin_names = self.cell.get_all_wl_names()
for pin in pin_names: for pin in pin_names:
bitcell_pins.append(pin+"_{0}".format(row)) bitcell_pins.append(pin + "_{0}".format(row))
bitcell_pins.append("vdd") bitcell_pins.append("vdd")
bitcell_pins.append("gnd") bitcell_pins.append("gnd")
@ -211,12 +210,11 @@ class replica_column(design.design):
pin_names = self.cell.get_all_bitline_names() pin_names = self.cell.get_all_bitline_names()
for pin in pin_names: for pin in pin_names:
bitcell_pins.append(pin+"_{0}".format(col)) bitcell_pins.append(pin + "_{0}".format(col))
bitcell_pins.append("vdd") bitcell_pins.append("vdd")
return bitcell_pins return bitcell_pins
def exclude_all_but_replica(self): def exclude_all_but_replica(self):
"""Excludes all bits except the replica cell (self.replica_bit).""" """Excludes all bits except the replica cell (self.replica_bit)."""

View File

@ -35,7 +35,7 @@ class row_cap_array(bitcell_base_array):
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="row_cap_bitcell_1rw_1r") # TODO: make module_type generic self.dummy_cell = factory.create(module_type="row_cap_{}".format(OPTS.bitcell))
self.add_mod(self.dummy_cell) self.add_mod(self.dummy_cell)
self.cell = factory.create(module_type="bitcell") self.cell = factory.create(module_type="bitcell")

View File

@ -20,7 +20,7 @@ class sense_amp_array(design.design):
Dynamically generated sense amp array for all bitlines. Dynamically generated sense amp array for all bitlines.
""" """
def __init__(self, name, word_size, words_per_row): def __init__(self, name, word_size, words_per_row, column_offset=0):
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name)) debug.info(1, "Creating {0}".format(self.name))
self.add_comment("word_size {0}".format(word_size)) self.add_comment("word_size {0}".format(word_size))
@ -28,6 +28,7 @@ class sense_amp_array(design.design):
self.word_size = word_size self.word_size = word_size
self.words_per_row = words_per_row self.words_per_row = words_per_row
self.column_offset = column_offset
self.row_size = self.word_size * self.words_per_row self.row_size = self.word_size * self.words_per_row
self.create_netlist() self.create_netlist()
@ -102,25 +103,22 @@ class sense_amp_array(design.design):
def place_sense_amp_array(self): def place_sense_amp_array(self):
from tech import cell_properties from tech import cell_properties
if self.bitcell.width > self.amp.width: if self.bitcell.width > self.amp.width:
amp_spacing = self.bitcell.width * self.words_per_row amp_spacing = self.bitcell.width
else: else:
amp_spacing = self.amp.width * self.words_per_row amp_spacing = self.amp.width
for i in range(0, self.word_size): for i in range(0, self.row_size, self.words_per_row):
xoffset = amp_spacing * i index = int(i / self.words_per_row)
xoffset = i * amp_spacing
# align the xoffset to the grid of bitcells. This way we if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2:
# know when to do the mirroring.
grid_x = int(xoffset / self.amp.width)
if cell_properties.bitcell.mirror.y and grid_x % 2:
mirror = "MY" mirror = "MY"
xoffset = xoffset + self.amp.width xoffset = xoffset + self.amp.width
else: else:
mirror = "" mirror = ""
amp_position = vector(xoffset, 0) amp_position = vector(xoffset, 0)
self.local_insts[i].place(offset=amp_position, mirror=mirror) self.local_insts[index].place(offset=amp_position, mirror=mirror)
def add_layout_pins(self): def add_layout_pins(self):
for i in range(len(self.local_insts)): for i in range(len(self.local_insts)):

View File

@ -20,17 +20,17 @@ class single_level_column_mux_array(design.design):
Array of column mux to read the bitlines through the 6T. Array of column mux to read the bitlines through the 6T.
""" """
def __init__(self, name, columns, port, word_size, bitcell_bl="bl", bitcell_br="br"): def __init__(self, name, columns, word_size, bitcell_bl="bl", bitcell_br="br", column_offset=0):
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.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.add_comment("cols: {0} word_size: {1} bl: {2} br: {3}".format(columns, word_size, bitcell_bl, bitcell_br))
self.columns = columns self.columns = columns
self.port = port
self.word_size = word_size self.word_size = word_size
self.words_per_row = int(self.columns / self.word_size) self.words_per_row = int(self.columns / self.word_size)
self.bitcell_bl = bitcell_bl self.bitcell_bl = bitcell_bl
self.bitcell_br = bitcell_br self.bitcell_br = bitcell_br
self.column_offset = column_offset
if "li" in layer: if "li" in layer:
self.col_mux_stack = self.li_stack self.col_mux_stack = self.li_stack
@ -118,7 +118,7 @@ class single_level_column_mux_array(design.design):
# For every column, add a pass gate # For every column, add a pass gate
for col_num in range(self.columns): for col_num in range(self.columns):
xoffset = col_num * self.mux.width xoffset = col_num * self.mux.width
if cell_properties.bitcell.mirror.y and (col_num + self.port) % 2: if cell_properties.bitcell.mirror.y and (col_num + self.column_offset) % 2:
mirror = "MY" mirror = "MY"
xoffset = xoffset + self.mux.width xoffset = xoffset + self.mux.width
else: else:

View File

@ -18,7 +18,7 @@ class write_driver_array(design.design):
Dynamically generated write driver array of all bitlines. Dynamically generated write driver array of all bitlines.
""" """
def __init__(self, name, columns, word_size, write_size=None): def __init__(self, name, columns, word_size, write_size=None, column_offset=0):
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name)) debug.info(1, "Creating {0}".format(self.name))
self.add_comment("columns: {0}".format(columns)) self.add_comment("columns: {0}".format(columns))
@ -27,6 +27,7 @@ class write_driver_array(design.design):
self.columns = columns self.columns = columns
self.word_size = word_size self.word_size = word_size
self.write_size = write_size self.write_size = write_size
self.column_offset = column_offset
self.words_per_row = int(columns / word_size) self.words_per_row = int(columns / word_size)
if self.write_size: if self.write_size:
@ -128,7 +129,7 @@ class write_driver_array(design.design):
index = int(i / self.words_per_row) index = int(i / self.words_per_row)
xoffset = i * self.driver_spacing xoffset = i * self.driver_spacing
if cell_properties.bitcell.mirror.y and i % 2: if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2:
mirror = "MY" mirror = "MY"
xoffset = xoffset + self.driver.width xoffset = xoffset + self.driver.width
else: 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. 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, port=0): def __init__(self, name, columns, word_size, write_size, column_offset=0):
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name)) debug.info(1, "Creating {0}".format(self.name))
self.add_comment("columns: {0}".format(columns)) self.add_comment("columns: {0}".format(columns))
@ -28,7 +28,7 @@ class write_mask_and_array(design.design):
self.columns = columns self.columns = columns
self.word_size = word_size self.word_size = word_size
self.write_size = write_size self.write_size = write_size
self.port = port self.column_offset = column_offset
self.words_per_row = int(columns / word_size) self.words_per_row = int(columns / word_size)
self.num_wmasks = int(word_size / write_size) self.num_wmasks = int(word_size / write_size)

View File

@ -124,26 +124,23 @@ class options(optparse.Values):
purge_temp = True purge_temp = True
# These are the default modules that can be over-riden # These are the default modules that can be over-riden
bitcell_suffix = ""
bank_select = "bank_select" bank_select = "bank_select"
bitcell_array = "bitcell_array" bitcell_array = "bitcell_array"
bitcell = "bitcell" bitcell = "bitcell"
col_cap_bitcell = "col_cap_bitcell"
column_mux_array = "single_level_column_mux_array" column_mux_array = "single_level_column_mux_array"
control_logic = "control_logic" control_logic = "control_logic"
decoder = "hierarchical_decoder" decoder = "hierarchical_decoder"
delay_chain = "delay_chain" delay_chain = "delay_chain"
dff_array = "dff_array" dff_array = "dff_array"
dff = "dff" dff = "dff"
dummy_bitcell = "dummy_bitcell"
inv_dec = "pinv" inv_dec = "pinv"
nand2_dec = "pnand2" nand2_dec = "pnand2"
nand3_dec = "pnand3" nand3_dec = "pnand3"
nand4_dec = "pnand4" # Not available right now nand4_dec = "pnand4" # Not available right now
precharge_array = "precharge_array" precharge_array = "precharge_array"
ptx = "ptx" ptx = "ptx"
replica_bitcell = "replica_bitcell"
replica_bitline = "replica_bitline" replica_bitline = "replica_bitline"
row_cap_bitcell = "row_cap_bitcell"
sense_amp_array = "sense_amp_array" sense_amp_array = "sense_amp_array"
sense_amp = "sense_amp" sense_amp = "sense_amp"
tri_gate_array = "tri_gate_array" tri_gate_array = "tri_gate_array"

View File

@ -77,8 +77,8 @@ class sram_factory:
""" """
tech_module_type, tm_overridden = self.get_techmodule_type(module_type) tech_module_type, tm_overridden = self.get_techmodule_type(module_type)
user_module_type, um_overridden = self.get_usermodule_type(module_type) user_module_type, um_overridden = self.get_usermodule_type(module_type)
#print(module_type, tech_module_type, tm_overridden) # print(module_type, tech_module_type, tm_overridden)
#print(module_type, user_module_type, um_overridden) # print(module_type, user_module_type, um_overridden)
# overridden user modules have priority # overridden user modules have priority
if um_overridden: if um_overridden:

View File

@ -22,10 +22,10 @@ class single_level_column_mux_1rw_1r_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file) globals.init_openram(config_file)
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(2, "Checking column mux port 0") debug.info(2, "Checking column mux port 0")
tx = factory.create(module_type="single_level_column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0") tx = factory.create(module_type="single_level_column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0")

View File

@ -23,12 +23,10 @@ class bitcell_1rw_1r_array_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file) globals.init_openram(config_file)
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
OPTS.dummy_bitcell="dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(2, "Testing 4x4 array for cell_1rw_1r") debug.info(2, "Testing 4x4 array for cell_1rw_1r")
a = factory.create(module_type="bitcell_array", cols=4, rows=4) a = factory.create(module_type="bitcell_array", cols=4, rows=4)

View File

@ -1,38 +0,0 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California
# 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 replica_bitcell_array_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
factory.reset()
debug.info(2, "Testing 4x4 array for bitcell")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=0, bitcell_ports=[0])
self.local_check(a)
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())

View File

@ -23,10 +23,10 @@ class hierarchical_decoder_1rw_1r_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
# Use the 2 port cell since it is usually bigger/easier # Use the 2 port cell since it is usually bigger/easier
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
globals.setup_bitcell()
# Checks 2x4 and 2-input NAND decoder # Checks 2x4 and 2-input NAND decoder
debug.info(1, "Testing 16 row sample for hierarchical_decoder") debug.info(1, "Testing 16 row sample for hierarchical_decoder")

View File

@ -21,10 +21,10 @@ class hierarchical_decoder_pbitcell_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file) globals.init_openram(config_file)
# check hierarchical decoder for multi-port # check hierarchical decoder for multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_ports = 0 OPTS.num_r_ports = 0
globals.setup_bitcell()
factory.reset() factory.reset()
debug.info(1, "Testing 16 row sample for hierarchical_decoder (multi-port case)") debug.info(1, "Testing 16 row sample for hierarchical_decoder (multi-port case)")

View File

@ -22,11 +22,10 @@ class hierarchical_predecode2x4_1rw_1r_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file) globals.init_openram(config_file)
# Use the 2 port cell since it is usually bigger/easier
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(1, "Testing sample for hierarchy_predecode2x4") debug.info(1, "Testing sample for hierarchy_predecode2x4")
a = factory.create(module_type="hierarchical_predecode2x4") a = factory.create(module_type="hierarchical_predecode2x4")

View File

@ -22,10 +22,10 @@ class hierarchical_predecode2x4_pbitcell_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
# checking hierarchical precode 2x4 for multi-port # checking hierarchical precode 2x4 for multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_ports = 0 OPTS.num_r_ports = 0
globals.setup_bitcell()
debug.info(1, "Testing sample for hierarchy_predecode2x4 (multi-port case)") debug.info(1, "Testing sample for hierarchy_predecode2x4 (multi-port case)")
a = factory.create(module_type="hierarchical_predecode2x4") a = factory.create(module_type="hierarchical_predecode2x4")

View File

@ -23,10 +23,10 @@ class hierarchical_predecode3x8_1rw_1r_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
# Use the 2 port cell since it is usually bigger/easier # Use the 2 port cell since it is usually bigger/easier
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(1, "Testing sample for hierarchy_predecode3x8") debug.info(1, "Testing sample for hierarchy_predecode3x8")
a = factory.create(module_type="hierarchical_predecode3x8") a = factory.create(module_type="hierarchical_predecode3x8")

View File

@ -22,10 +22,10 @@ class hierarchical_predecode3x8_pbitcell_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
# checking hierarchical precode 3x8 for multi-port # checking hierarchical precode 3x8 for multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_ports = 0 OPTS.num_r_ports = 0
globals.setup_bitcell()
debug.info(1, "Testing sample for hierarchy_predecode3x8 (multi-port case)") debug.info(1, "Testing sample for hierarchy_predecode3x8 (multi-port case)")
a = factory.create(module_type="hierarchical_predecode3x8") a = factory.create(module_type="hierarchical_predecode3x8")

View File

@ -20,17 +20,17 @@ class single_level_column_mux_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file) globals.init_openram(config_file)
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(1, "Testing sample for 4-way column_mux_array port 0") debug.info(1, "Testing sample for 4-way column_mux_array port 0")
a = factory.create(module_type="single_level_column_mux_array", columns=8, port=0, word_size=2, bitcell_bl="bl0", bitcell_br="br0") a = factory.create(module_type="single_level_column_mux_array", columns=8, word_size=2, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 4-way column_mux_array port 1") debug.info(1, "Testing sample for 4-way column_mux_array port 1")
a = factory.create(module_type="single_level_column_mux_array", columns=8, port=0, word_size=2, bitcell_bl="bl1", bitcell_br="br1") a = factory.create(module_type="single_level_column_mux_array", columns=8, word_size=2, bitcell_bl="bl1", bitcell_br="br1")
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -29,19 +29,19 @@ class single_level_column_mux_pbitcell_test(openram_test):
factory.reset() factory.reset()
debug.info(1, "Testing sample for 2-way column_mux_array in multi-port") debug.info(1, "Testing sample for 2-way column_mux_array in multi-port")
a = factory.create(module_type="single_level_column_mux_array", columns=16, port=0, word_size=8, bitcell_bl="bl0", bitcell_br="br0") a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 4-way column_mux_array in multi-port") debug.info(1, "Testing sample for 4-way column_mux_array in multi-port")
a = factory.create(module_type="single_level_column_mux_array", columns=16, port=0, word_size=4, bitcell_bl="bl0", bitcell_br="br0") a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (innermost connections)") debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (innermost connections)")
a = factory.create(module_type="single_level_column_mux_array", columns=32, port=0, word_size=4, bitcell_bl="bl0", bitcell_br="br0") a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (outermost connections)") debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (outermost connections)")
a = factory.create(module_type="single_level_column_mux_array", columns=32, port=3, word_size=4, bitcell_bl="bl2", bitcell_br="br2") a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2", column_offset=3)
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -21,15 +21,15 @@ class single_level_column_mux_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
debug.info(1, "Testing sample for 2-way column_mux_array") debug.info(1, "Testing sample for 2-way column_mux_array")
a = factory.create(module_type="single_level_column_mux_array", columns=16, port=0, word_size=8) a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=8)
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 4-way column_mux_array") debug.info(1, "Testing sample for 4-way column_mux_array")
a = factory.create(module_type="single_level_column_mux_array", columns=16, port=0, word_size=4) a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=4)
self.local_check(a) self.local_check(a)
debug.info(1, "Testing sample for 8-way column_mux_array") debug.info(1, "Testing sample for 8-way column_mux_array")
a = factory.create(module_type="single_level_column_mux_array", columns=32, port=0, word_size=4) a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4)
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -22,23 +22,19 @@ class precharge_1rw_1r_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
# check precharge array in multi-port # check precharge array in multi-port
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
globals.setup_bitcell()
factory.reset() factory.reset()
debug.info(2, "Checking 3 column precharge array for 1RW/1R bitcell") debug.info(2, "Checking 3 column precharge array for 1RW/1R bitcell (port 0)")
pc = factory.create(module_type="precharge_array", columns=3, port=0, bitcell_bl="bl0", bitcell_br="br0") pc = factory.create(module_type="precharge_array", columns=3, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(pc) self.local_check(pc)
# debug.info(2, "Checking 3 column precharge array for pbitcell (innermost connections)") debug.info(2, "Checking 3 column precharge array for 1RW/1R bitcell (port 1)")
# pc = precharge_array.precharge_array(name="pre3", columns=3, bitcell_bl="bl0", bitcell_br="br0") pc = factory.create(module_type="precharge_array", columns=3, bitcell_bl="bl0", bitcell_br="br0", column_offset=1)
# self.local_check(pc) self.local_check(pc)
# debug.info(2, "Checking 3 column precharge array for pbitcell (outermost connections)")
# pc = precharge_array.precharge_array(name="pre4", columns=3, bitcell_bl="bl2", bitcell_br="br2")
# self.local_check(pc)
globals.end_openram() globals.end_openram()

View File

@ -21,9 +21,8 @@ class precharge_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file) globals.init_openram(config_file)
# check precharge array in single port
debug.info(2, "Checking 3 column precharge") debug.info(2, "Checking 3 column precharge")
pc = factory.create(module_type="precharge_array", columns=3, port=0) pc = factory.create(module_type="precharge_array", columns=3)
self.local_check(pc) self.local_check(pc)
globals.end_openram() globals.end_openram()

View File

@ -23,10 +23,10 @@ class wordline_driver_array_1rw_1r_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
# Use the 2 port cell since it is usually bigger/easier # Use the 2 port cell since it is usually bigger/easier
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
globals.setup_bitcell()
# check wordline driver for single port # check wordline driver for single port
debug.info(2, "Checking driver") debug.info(2, "Checking driver")

View File

@ -21,7 +21,6 @@ class sense_amp_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file) globals.init_openram(config_file)
# check sense amp array for single port
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=1") debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=1")
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=1) a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=1)
self.local_check(a) self.local_check(a)

View File

@ -19,21 +19,17 @@ class replica_bitcell_array_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file) globals.init_openram(config_file)
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
OPTS.dummy_bitcell="dummy_bitcell_1rw_1r"
OPTS.col_cap_bitcell="col_cap_bitcell_1rw_1r"
OPTS.row_cap_bitcell="row_cap_bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(2, "Testing 4x4 array for cell_1rw_1r") debug.info(2, "Testing 4x4 array for cell_1rw_1r")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=2, right_rbl=0, bitcell_ports=[0,1]) a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=1, bitcell_ports=[0, 1])
self.local_check(a) self.local_check(a)
debug.info(2, "Testing 4x4 array for cell_1rw_1r") debug.info(2, "Testing 4x4 array for cell_1rw_1r")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=1, bitcell_ports=[0,1]) a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=2, right_rbl=0, bitcell_ports=[0, 1])
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -19,7 +19,12 @@ class replica_bitcell_array_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file) globals.init_openram(config_file)
debug.info(2, "Testing 4x4 array for 6t_cell") OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
factory.reset()
debug.info(2, "Testing 4x4 array for bitcell")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=0, bitcell_ports=[0]) a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=0, bitcell_ports=[0])
self.local_check(a) self.local_check(a)

View File

@ -21,15 +21,19 @@ class port_address_1rw_1r_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
# Use the 2 port cell since it is usually bigger/easier # Use the 2 port cell since it is usually bigger/easier
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(1, "Port address 16 rows") debug.info(1, "Port address 16 rows")
a = factory.create("port_address", cols=16, rows=16) a = factory.create("port_address", cols=16, rows=16)
self.local_check(a) self.local_check(a)
debug.info(1, "Port address 512 rows")
a = factory.create("port_address", cols=256, rows=512)
self.local_check(a)
globals.end_openram() globals.end_openram()
# run the test from the command line # run the test from the command line

View File

@ -24,6 +24,10 @@ class port_address_test(openram_test):
a = factory.create("port_address", cols=16, rows=16) a = factory.create("port_address", cols=16, rows=16)
self.local_check(a) self.local_check(a)
debug.info(1, "Port address 512 rows")
a = factory.create("port_address", cols=256, rows=512)
self.local_check(a)
globals.end_openram() globals.end_openram()
# run the test from the command line # run the test from the command line

View File

@ -13,6 +13,7 @@ from globals import OPTS
from sram_factory import factory from sram_factory import factory
import debug import debug
class port_data_1rw_1r_test(openram_test): class port_data_1rw_1r_test(openram_test):
def runTest(self): def runTest(self):
@ -20,10 +21,10 @@ class port_data_1rw_1r_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
globals.setup_bitcell()
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=16) num_words=16)

View File

@ -22,12 +22,10 @@ class single_bank_1rw_1r_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
OPTS.dummy_bitcell="dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
globals.setup_bitcell()
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=16) num_words=16)

View File

@ -22,13 +22,10 @@ class single_bank_1w_1r_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "bitcell_1w_1r"
OPTS.replica_bitcell = "replica_bitcell_1w_1r"
OPTS.dummy_bitcell="dummy_bitcell_1w_1r"
OPTS.num_rw_ports = 0 OPTS.num_rw_ports = 0
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 1 OPTS.num_w_ports = 1
globals.setup_bitcell()
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=16) num_words=16)

View File

@ -22,6 +22,10 @@ class single_bank_wmask_1rw_1r_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
from sram_config import sram_config from sram_config import sram_config
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
c = sram_config(word_size=8, c = sram_config(word_size=8,
write_size=4, write_size=4,

View File

@ -24,11 +24,10 @@ class psram_1bank_2mux_1rw_1w_test(openram_test):
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell"
OPTS.dummy_bitcell="dummy_pbitcell"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 1 OPTS.num_w_ports = 1
OPTS.num_r_ports = 0 OPTS.num_r_ports = 0
globals.setup_bitcell()
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=32, num_words=32,

View File

@ -24,11 +24,10 @@ class psram_1bank_2mux_1w_1r_test(openram_test):
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell"
OPTS.dummy_bitcell="dummy_pbitcell"
OPTS.num_rw_ports = 0 OPTS.num_rw_ports = 0
OPTS.num_w_ports = 1 OPTS.num_w_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
globals.setup_bitcell()
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=32, num_words=32,

View File

@ -22,14 +22,12 @@ class psram_1bank_2mux_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file) globals.init_openram(config_file)
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell"
OPTS.dummy_bitcell="dummy_pbitcell"
# testing layout of sram using pbitcell with 1 RW port (a 6T-cell equivalent) OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_ports = 0 OPTS.num_r_ports = 0
globals.setup_bitcell()
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=32, num_words=32,

View File

@ -24,11 +24,10 @@ class psram_1bank_4mux_1rw_1r_test(openram_test):
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell"
OPTS.dummy_bitcell="dummy_pbitcell"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
globals.setup_bitcell()
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=64, num_words=64,

View File

@ -22,12 +22,10 @@ class sram_1bank_2mux_1rw_1r_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
OPTS.dummy_bitcell="dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
globals.setup_bitcell()
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=32, num_words=32,

View File

@ -23,12 +23,10 @@ class psram_1bank_2mux_1w_1r_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "bitcell_1w_1r"
OPTS.replica_bitcell="replica_bitcell_1w_1r"
OPTS.dummy_bitcell="dummy_bitcell_1w_1r"
OPTS.num_rw_ports = 0 OPTS.num_rw_ports = 0
OPTS.num_w_ports = 1 OPTS.num_w_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
globals.setup_bitcell()
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=32, num_words=32,

View File

@ -22,12 +22,10 @@ class sram_1bank_8mux_1rw_1r_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
OPTS.dummy_bitcell="dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
globals.setup_bitcell()
c = sram_config(word_size=2, c = sram_config(word_size=2,
num_words=128, num_words=128,

View File

@ -22,12 +22,10 @@ class sram_1bank_nomux_1rw_1r_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
from sram_config import sram_config from sram_config import sram_config
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
OPTS.dummy_bitcell = "dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
globals.setup_bitcell()
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=16, num_words=16,

View File

@ -24,12 +24,10 @@ class psram_1bank_nomux_func_test(openram_test):
OPTS.analytical_delay = False OPTS.analytical_delay = False
OPTS.netlist_only = True OPTS.netlist_only = True
OPTS.trim_netlist = False OPTS.trim_netlist = False
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
OPTS.dummy_bitcell="dummy_bitcell_1rw_1r"
OPTS.num_rw_ports = 1 OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
globals.setup_bitcell()
# This is a hack to reload the characterizer __init__ with the spice version # This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload from importlib import reload

View File

@ -26,13 +26,10 @@ class sram_wmask_1w_1r_func_test(openram_test):
OPTS.analytical_delay = False OPTS.analytical_delay = False
OPTS.netlist_only = True OPTS.netlist_only = True
OPTS.trim_netlist = False OPTS.trim_netlist = False
OPTS.bitcell = "bitcell_1w_1r"
OPTS.replica_bitcell = "replica_bitcell_1w_1r"
OPTS.dummy_bitcell = "dummy_bitcell_1w_1r"
OPTS.num_rw_ports = 0 OPTS.num_rw_ports = 0
OPTS.num_w_ports = 1 OPTS.num_w_ports = 1
OPTS.num_r_ports = 1 OPTS.num_r_ports = 1
globals.setup_bitcell()
# This is a hack to reload the characterizer __init__ with the spice version # This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload from importlib import reload

View File

@ -5,23 +5,21 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import unittest,warnings import unittest
import pdb,traceback import sys, os, glob
import sys,os,glob,copy
import shutil
sys.path.append(os.getenv("OPENRAM_HOME")) sys.path.append(os.getenv("OPENRAM_HOME"))
from globals import OPTS from globals import OPTS
import debug import debug
class openram_test(unittest.TestCase): class openram_test(unittest.TestCase):
""" Base unit test that we have some shared classes in. """ """ Base unit test that we have some shared classes in. """
def local_drc_check(self, w): def local_drc_check(self, w):
self.reset() self.reset()
tempgds = "{0}{1}.gds".format(OPTS.openram_temp,w.name) tempgds = "{0}{1}.gds".format(OPTS.openram_temp, w.name)
w.gds_write(tempgds) w.gds_write(tempgds)
import verify import verify
@ -36,8 +34,8 @@ class openram_test(unittest.TestCase):
self.reset() self.reset()
tempspice = "{0}{1}.sp".format(OPTS.openram_temp,a.name) tempspice = "{0}{1}.sp".format(OPTS.openram_temp, a.name)
tempgds = "{0}{1}.gds".format(OPTS.openram_temp,a.name) tempgds = "{0}{1}.gds".format(OPTS.openram_temp, a.name)
a.lvs_write(tempspice) a.lvs_write(tempspice)
# cannot write gds in netlist_only mode # cannot write gds in netlist_only mode
@ -56,34 +54,36 @@ class openram_test(unittest.TestCase):
# Only allow DRC to fail and LVS to pass if we are using magic # Only allow DRC to fail and LVS to pass if we are using magic
if "magic" in OPTS.drc_exe and lvs_result == 0 and drc_result != 0: if "magic" in OPTS.drc_exe and lvs_result == 0 and drc_result != 0:
#zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid()) # import shutil
#debug.info(0,"Archiving failed files to {}.zip".format(zip_file)) # zip_file = "/tmp/{0}_{1}".format(a.name, os.getpid())
#shutil.make_archive(zip_file, 'zip', OPTS.openram_temp) # debug.info(0, "Archiving failed files to {}.zip".format(zip_file))
# shutil.make_archive(zip_file, 'zip', OPTS.openram_temp)
debug.warning("DRC failed but LVS passed: {}".format(a.name)) debug.warning("DRC failed but LVS passed: {}".format(a.name))
#self.fail("DRC failed but LVS passed: {}".format(a.name)) # self.fail("DRC failed but LVS passed: {}".format(a.name))
elif drc_result != 0: elif drc_result != 0:
#zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid()) # import shutil
#debug.info(0,"Archiving failed files to {}.zip".format(zip_file)) # zip_file = "/tmp/{0}_{1}".format(a.name, os.getpid())
#shutil.make_archive(zip_file, 'zip', OPTS.openram_temp) # debug.info(0,"Archiving failed files to {}.zip".format(zip_file))
# shutil.make_archive(zip_file, 'zip', OPTS.openram_temp)
self.fail("DRC failed: {}".format(a.name)) self.fail("DRC failed: {}".format(a.name))
if lvs_result != 0: if lvs_result != 0:
#zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid()) # import shutil
#debug.info(0,"Archiving failed files to {}.zip".format(zip_file)) # zip_file = "/tmp/{0}_{1}".format(a.name, os.getpid())
#shutil.make_archive(zip_file, 'zip', OPTS.openram_temp) # debug.info(0,"Archiving failed files to {}.zip".format(zip_file))
# shutil.make_archive(zip_file, 'zip', OPTS.openram_temp)
self.fail("LVS mismatch: {}".format(a.name)) self.fail("LVS mismatch: {}".format(a.name))
# For debug... # For debug...
#import pdb; pdb.set_trace() # import pdb; pdb.set_trace()
if OPTS.purge_temp: if OPTS.purge_temp:
self.cleanup() self.cleanup()
def run_pex(self, a, output=None): def run_pex(self, a, output=None):
if output == None: if output == None:
output = OPTS.openram_temp + a.name + ".pex.netlist" output = OPTS.openram_temp + a.name + ".pex.netlist"
tempspice = "{0}{1}.sp".format(OPTS.openram_temp,a.name) tempspice = "{0}{1}.sp".format(OPTS.openram_temp, a.name)
tempgds = "{0}{1}.gds".format(OPTS.openram_temp,a.name) tempgds = "{0}{1}.gds".format(OPTS.openram_temp, a.name)
import verify import verify
result=verify.run_pex(a.name, tempgds, tempspice, output=output, final_verification=False) result=verify.run_pex(a.name, tempgds, tempspice, output=output, final_verification=False)
@ -97,8 +97,8 @@ class openram_test(unittest.TestCase):
""" """
debug.info(1, "Finding feasible period for current test.") debug.info(1, "Finding feasible period for current test.")
delay_obj.set_load_slew(load, slew) delay_obj.set_load_slew(load, slew)
test_port = delay_obj.read_ports[0] #Only test one port, assumes other ports have similar period. test_port = delay_obj.read_ports[0] # Only test one port, assumes other ports have similar period.
delay_obj.analysis_init(probe_address="1"*sram.addr_size, probe_data=(sram.word_size-1)) delay_obj.analysis_init(probe_address="1" * sram.addr_size, probe_data=sram.word_size - 1)
delay_obj.find_feasible_period_one_port(test_port) delay_obj.find_feasible_period_one_port(test_port)
return delay_obj.period return delay_obj.period
@ -130,29 +130,27 @@ class openram_test(unittest.TestCase):
for k in data.keys(): for k in data.keys():
if type(data[k])==list: if type(data[k])==list:
for i in range(len(data[k])): for i in range(len(data[k])):
if not self.isclose(k,data[k][i],golden_data[k][i],error_tolerance): if not self.isclose(k, data[k][i], golden_data[k][i], error_tolerance):
data_matches = False data_matches = False
else: else:
if not self.isclose(k,data[k],golden_data[k],error_tolerance): if not self.isclose(k, data[k], golden_data[k], error_tolerance):
data_matches = False data_matches = False
if not data_matches: if not data_matches:
import pprint import pprint
data_string=pprint.pformat(data) data_string=pprint.pformat(data)
debug.error("Results exceeded {:.1f}% tolerance compared to golden results:\n".format(error_tolerance*100)+data_string) debug.error("Results exceeded {:.1f}% tolerance compared to golden results:\n".format(error_tolerance * 100) + data_string)
return data_matches return data_matches
def isclose(self, key, value, actual_value, error_tolerance=1e-2):
def isclose(self,key,value,actual_value,error_tolerance=1e-2):
""" This is used to compare relative values. """ """ This is used to compare relative values. """
import debug import debug
relative_diff = self.relative_diff(value,actual_value) relative_diff = self.relative_diff(value, actual_value)
check = relative_diff <= error_tolerance check = relative_diff <= error_tolerance
if check: if check:
debug.info(2,"CLOSE\t{0: <10}\t{1:.3f}\t{2:.3f}\tdiff={3:.1f}%".format(key,value,actual_value,relative_diff*100)) debug.info(2, "CLOSE\t{0: <10}\t{1:.3f}\t{2:.3f}\tdiff={3:.1f}%".format(key, value, actual_value, relative_diff * 100))
return True return True
else: else:
debug.error("NOT CLOSE\t{0: <10}\t{1:.3f}\t{2:.3f}\tdiff={3:.1f}%".format(key,value,actual_value,relative_diff*100)) debug.error("NOT CLOSE\t{0: <10}\t{1:.3f}\t{2:.3f}\tdiff={3:.1f}%".format(key, value, actual_value, relative_diff * 100))
return False return False
def relative_diff(self, value1, value2): def relative_diff(self, value1, value2):
@ -169,18 +167,14 @@ class openram_test(unittest.TestCase):
# Get normalization value # Get normalization value
norm_value = abs(max(value1, value2)) norm_value = abs(max(value1, value2))
# Edge case where greater is a zero
if norm_value == 0:
min_value = abs(min(value1, value2))
return abs(value1 - value2) / norm_value return abs(value1 - value2) / norm_value
def relative_compare(self, value, actual_value, error_tolerance):
def relative_compare(self, value,actual_value,error_tolerance):
""" This is used to compare relative values. """ """ This is used to compare relative values. """
if (value==actual_value): # if we don't need a relative comparison! if (value==actual_value): # if we don't need a relative comparison!
return True return True
return (abs(value - actual_value) / max(value,actual_value) <= error_tolerance) return (abs(value - actual_value) / max(value, actual_value) <= error_tolerance)
def isapproxdiff(self, filename1, filename2, error_tolerance=0.001): def isapproxdiff(self, filename1, filename2, error_tolerance=0.001):
"""Compare two files. """Compare two files.
@ -218,23 +212,22 @@ class openram_test(unittest.TestCase):
line_num+=1 line_num+=1
line1 = fp1.readline().decode('utf-8') line1 = fp1.readline().decode('utf-8')
line2 = fp2.readline().decode('utf-8') line2 = fp2.readline().decode('utf-8')
#print("line1:",line1) # print("line1:", line1)
#print("line2:",line2) # print("line2:", line2)
# 1. Find all of the floats using a regex # 1. Find all of the floats using a regex
line1_floats=rx.findall(line1) line1_floats=rx.findall(line1)
line2_floats=rx.findall(line2) line2_floats=rx.findall(line2)
debug.info(3,"line1_floats: "+str(line1_floats)) debug.info(3, "line1_floats: " + str(line1_floats))
debug.info(3,"line2_floats: "+str(line2_floats)) debug.info(3, "line2_floats: " + str(line2_floats))
# 2. Remove the floats from the string # 2. Remove the floats from the string
for f in line1_floats: for f in line1_floats:
line1=line1.replace(f,"",1) line1=line1.replace(f, "", 1)
for f in line2_floats: for f in line2_floats:
line2=line2.replace(f,"",1) line2=line2.replace(f, "", 1)
#print("line1:",line1) # print("line1:", line1)
#print("line2:",line2) # print("line2:", line2)
# 3. Convert to floats rather than strings # 3. Convert to floats rather than strings
line1_floats = [float(x) for x in line1_floats] line1_floats = [float(x) for x in line1_floats]
@ -242,29 +235,29 @@ class openram_test(unittest.TestCase):
# 4. Check if remaining string matches # 4. Check if remaining string matches
if line1 != line2: if line1 != line2:
#Uncomment if you want to see all the individual chars of the two lines # Uncomment if you want to see all the individual chars of the two lines
#print(str([i for i in line1])) # print(str([i for i in line1]))
#print(str([i for i in line2])) # print(str([i for i in line2]))
if mismatches==0: if mismatches==0:
debug.error("Mismatching files:\nfile1={0}\nfile2={1}".format(filename1,filename2)) debug.error("Mismatching files:\nfile1={0}\nfile2={1}".format(filename1, filename2))
mismatches += 1 mismatches += 1
debug.error("MISMATCH Line ({0}):\n{1}\n!=\n{2}".format(line_num,line1.rstrip('\n'),line2.rstrip('\n'))) debug.error("MISMATCH Line ({0}):\n{1}\n!=\n{2}".format(line_num, line1.rstrip('\n'), line2.rstrip('\n')))
# 5. Now compare that the floats match # 5. Now compare that the floats match
elif len(line1_floats)!=len(line2_floats): elif len(line1_floats)!=len(line2_floats):
if mismatches==0: if mismatches==0:
debug.error("Mismatching files:\nfile1={0}\nfile2={1}".format(filename1,filename2)) debug.error("Mismatching files:\nfile1={0}\nfile2={1}".format(filename1, filename2))
mismatches += 1 mismatches += 1
debug.error("MISMATCH Line ({0}) Length {1} != {2}".format(line_num,len(line1_floats),len(line2_floats))) debug.error("MISMATCH Line ({0}) Length {1} != {2}".format(line_num, len(line1_floats), len(line2_floats)))
else: else:
for (float1,float2) in zip(line1_floats,line2_floats): for (float1, float2) in zip(line1_floats, line2_floats):
relative_diff = self.relative_diff(float1,float2) relative_diff = self.relative_diff(float1, float2)
check = relative_diff <= error_tolerance check = relative_diff <= error_tolerance
if not check: if not check:
if mismatches==0: if mismatches==0:
debug.error("Mismatching files:\nfile1={0}\nfile2={1}".format(filename1,filename2)) debug.error("Mismatching files:\nfile1={0}\nfile2={1}".format(filename1, filename2))
mismatches += 1 mismatches += 1
debug.error("MISMATCH Line ({0}) Float {1} != {2} diff: {3:.1f}%".format(line_num,float1,float2,relative_diff*100)) debug.error("MISMATCH Line ({0}) Float {1} != {2} diff: {3:.1f}%".format(line_num, float1, float2, relative_diff * 100))
# Only show the first 10 mismatch lines # Only show the first 10 mismatch lines
if not line1 and not line2 or mismatches>10: if not line1 and not line2 or mismatches>10:
@ -275,19 +268,18 @@ class openram_test(unittest.TestCase):
# Never reached # Never reached
return False return False
def isdiff(self, filename1, filename2):
def isdiff(self,filename1,filename2):
""" This is used to compare two files and display the diff if they are different.. """ """ This is used to compare two files and display the diff if they are different.. """
import debug import debug
import filecmp import filecmp
import difflib import difflib
check = filecmp.cmp(filename1,filename2) check = filecmp.cmp(filename1, filename2)
if not check: if not check:
debug.error("MISMATCH file1={0} file2={1}".format(filename1,filename2)) debug.error("MISMATCH file1={0} file2={1}".format(filename1, filename2))
f1 = open(filename1,mode="r",encoding='utf-8') f1 = open(filename1, mode="r", encoding='utf-8')
s1 = f1.readlines() s1 = f1.readlines()
f1.close() f1.close()
f2 = open(filename2,mode="r",encoding='utf-8') f2 = open(filename2, mode="r", encoding='utf-8')
s2 = f2.readlines() s2 = f2.readlines()
f2.close() f2.close()
mismatches=0 mismatches=0
@ -302,9 +294,12 @@ class openram_test(unittest.TestCase):
return False return False
return False return False
else: else:
debug.info(2,"MATCH {0} {1}".format(filename1,filename2)) debug.info(2, "MATCH {0} {1}".format(filename1, filename2))
return True return True
def dbg():
import pdb; pdb.set_trace()
def header(filename, technology): def header(filename, technology):
# Skip the header for gitlab regression # Skip the header for gitlab regression
@ -323,10 +318,14 @@ def header(filename, technology):
print("|=========" + OPTS.openram_temp.center(60) + "=========|") print("|=========" + OPTS.openram_temp.center(60) + "=========|")
print("|==============================================================================|") print("|==============================================================================|")
def debugTestRunner(post_mortem=None): def debugTestRunner(post_mortem=None):
"""unittest runner doing post mortem debugging on failing tests""" """unittest runner doing post mortem debugging on failing tests"""
import pdb
import traceback
if post_mortem is None and not OPTS.purge_temp: if post_mortem is None and not OPTS.purge_temp:
post_mortem = pdb.post_mortem post_mortem = pdb.post_mortem
class DebugTestResult(unittest.TextTestResult): class DebugTestResult(unittest.TextTestResult):
def addError(self, test, err): def addError(self, test, err):
# called before tearDown() # called before tearDown()
@ -334,6 +333,7 @@ def debugTestRunner(post_mortem=None):
if post_mortem: if post_mortem:
post_mortem(err[2]) post_mortem(err[2])
super(DebugTestResult, self).addError(test, err) super(DebugTestResult, self).addError(test, err)
def addFailure(self, test, err): def addFailure(self, test, err):
traceback.print_exception(*err) traceback.print_exception(*err)
if post_mortem: if post_mortem: