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,
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.
If layer is a single value, it is a path.
If layer is a tuple, it is a wire with preferred directions.
"""
neg_offset = 1.0 - var_offset
# vertical first
if first_direction == "V":
if fixed_offset:
mid1 = vector(start.x, fixed_offset)
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)
# horizontal first
elif first_direction == "H":
if fixed_offset:
mid1 = vector(fixed_offset, start.y)
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)
else:
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:
ports += "{}r".format(OPTS.num_r_ports)
OPTS.bitcell = "bitcell_"+ports
OPTS.replica_bitcell = "replica_bitcell_"+ports
OPTS.dummy_bitcell = "dummy_bitcell_"+ports
else:
OPTS.replica_bitcell = "replica_" + OPTS.bitcell
OPTS.replica_bitcell = "dummy_" + OPTS.bitcell
if ports != "":
OPTS.bitcell_suffix = "_" + ports
OPTS.bitcell = "bitcell" + OPTS.bitcell_suffix
# See if bitcell exists
try:
__import__(OPTS.bitcell)
__import__(OPTS.replica_bitcell)
__import__(OPTS.dummy_bitcell)
except ImportError:
# Use the pbitcell if we couldn't find a custom bitcell
# or its custom replica bitcell
# Use the pbitcell (and give a warning if not in unit test mode)
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
OPTS.replica_bitcell = "dummy_pbitcell"
if not OPTS.is_unit_test:
debug.warning("Using the parameterized bitcell which may have suboptimal density.")
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):
# 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()
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port] + "_{}".format(row)).lc()
driver_wl_pin = self.port_address_inst[port].get_pin("wl_{}".format(row))
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)
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):
""" Connecting Wordline driver output to Bitcell WL connection """
for row in range(self.num_rows):
# 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()
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port] + "_{}".format(row)).rc()
driver_wl_pin = self.port_address_inst[port].get_pin("wl_{}".format(row))
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)
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):
""" 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 tech import cell_properties
class col_cap_array(bitcell_base_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):
""" 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_bitcell")
self.dummy_cell = factory.create(module_type="col_cap_{}".format(OPTS.bitcell))
self.add_mod(self.dummy_cell)
self.cell = factory.create(module_type="bitcell")

View File

@ -38,20 +38,19 @@ class dummy_array(bitcell_base_array):
def add_modules(self):
""" 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.cell = factory.create(module_type="bitcell")
def create_instances(self):
""" Create the module instances used in this design """
self.cell_inst = {}
for col in range(self.column_size):
for row in range(self.row_size):
name = "bit_r{0}_c{1}".format(row, col)
self.cell_inst[row,col]=self.add_inst(name=name,
mod=self.dummy_cell)
self.cell_inst[row, col]=self.add_inst(name=name,
mod=self.dummy_cell)
self.connect_inst(self.get_bitcell_pins(col, row))
def input_load(self):
@ -60,7 +59,7 @@ class dummy_array(bitcell_base_array):
def get_wordline_cin(self):
"""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()
total_cin = bitcell_wl_cin * self.column_size
return total_cin

View File

@ -48,11 +48,18 @@ class hierarchical_decoder(design.design):
self.setup_layout_constants()
self.place_pre_decoder()
self.place_row_decoder()
self.height = max(self.predecoder_height, self.row_decoder_height) + self.bus_space
self.route_inputs()
self.route_outputs()
self.route_decoder_bus()
self.route_vdd_gnd()
self.offset_all_coordinates()
self.width = self.and_inst[0].rx() + self.m1_space
self.add_boundary()
self.DRC_LVS()
@ -178,21 +185,6 @@ class hierarchical_decoder(design.design):
# Extra bus space for supply contacts
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):
""" Create input bus for the predecoders """
# Find the left-most predecoder

View File

@ -93,7 +93,7 @@ class port_address(design.design):
decoder_out_pos = decoder_out_pin.rc()
driver_in_pin = self.wordline_driver_inst.get_pin("in_{}".format(row))
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,
to_layer=self.route_layer,

View File

@ -178,14 +178,17 @@ class port_data(design.design):
# Extra column +1 is for RBL
# 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",
columns=self.num_cols + 1,
port=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)
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",
word_size=self.word_size,
words_per_row=self.words_per_row)
@ -194,9 +197,9 @@ class port_data(design.design):
self.sense_amp_array = None
if self.col_addr_size > 0:
# RBLs dont get a col mux
self.column_mux_array = factory.create(module_type="column_mux_array",
columns=self.num_cols,
port=self.port,
word_size=self.word_size,
bitcell_bl=self.bl_names[self.port],
bitcell_br=self.br_names[self.port])
@ -205,17 +208,18 @@ class port_data(design.design):
self.column_mux_array = None
if self.port in self.write_ports:
# RBLs dont get a write driver
self.write_driver_array = factory.create(module_type="write_driver_array",
columns=self.num_cols,
word_size=self.word_size,
write_size=self.write_size)
self.add_mod(self.write_driver_array)
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",
columns=self.num_cols,
word_size=self.word_size,
write_size=self.write_size,
port = self.port)
write_size=self.write_size)
self.add_mod(self.write_mask_and_array)
else:
self.write_mask_and_array = None
@ -248,13 +252,6 @@ class port_data(design.design):
self.precharge = factory.create(module_type="precharge",
bitcell_bl=self.bl_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):
""" Creating Precharge """
@ -732,8 +729,8 @@ class port_data(design.design):
top_bl, top_br = top_bl_pin.bc(), top_br_pin.bc()
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_br_pin.layer, bot_br, top_br, "V", top_bl_pin.by() - 2 * 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", fixed_offset=top_bl_pin.by() - 2 * layer_pitch)
def graph_exclude_precharge(self):
"""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.
"""
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)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("cols: {0} size: {1} bl: {2} br: {3}".format(columns, size, bitcell_bl, bitcell_br))
self.columns = columns
self.size = size
self.port = port
self.bitcell_bl = bitcell_bl
self.bitcell_br = bitcell_br
self.column_offset = column_offset
self.create_netlist()
if not OPTS.netlist_only:
@ -106,7 +106,7 @@ class precharge_array(design.design):
xoffset = 0
for i in range(self.columns):
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"
tempx = tempx + self.pc_cell.width
else:

View File

@ -32,8 +32,10 @@ class replica_bitcell_array(design.design):
self.right_rbl = right_rbl
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.bitcell_ports),"Bitcell ports must match total RBLs.")
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.bitcell_ports),
"Bitcell ports must match total RBLs.")
# Two dummy rows/cols plus replica for each port
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
# the replica bitcell in the control logic
#self.offset_all_coordinates()
# self.offset_all_coordinates()
def create_netlist(self):
""" Create and connect the netlist """
@ -90,15 +91,15 @@ class replica_bitcell_array(design.design):
# Replica bitlines
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
if bit<self.left_rbl:
replica_bit = bit+1
replica_bit = bit + 1
# dummy column
column_offset = self.left_rbl - bit
# Creating right_rbl
else:
replica_bit = bit+self.row_size+1
replica_bit = bit + self.row_size + 1
# dummy column + replica column + bitcell colums
column_offset = self.left_rbl - bit + self.row_size
self.replica_columns[bit] = factory.create(module_type="replica_column",
@ -118,7 +119,6 @@ class replica_bitcell_array(design.design):
mirror=0)
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.
try:
end_caps_enabled = cell_properties.bitcell.end_caps
@ -129,11 +129,11 @@ class replica_bitcell_array(design.design):
edge_row_module_type = ("col_cap_array" if end_caps_enabled else "dummy_array")
self.edge_row = factory.create(module_type=edge_row_module_type,
cols=self.column_size,
rows=1,
# dummy column + left replica column
column_offset=1 + self.left_rbl,
mirror=0)
cols=self.column_size,
rows=1,
# dummy column + left replica column(s)
column_offset=1 + self.left_rbl,
mirror=0)
self.add_mod(self.edge_row)
# Dummy Col or Row Cap, depending on bitcell array properties
@ -143,18 +143,18 @@ class replica_bitcell_array(design.design):
cols=1,
column_offset=0,
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.edge_col_right = factory.create(module_type=edge_col_module_type,
cols=1,
# dummy column
# + left replica column
# + left replica column(s)
# + bitcell columns
# + right replica column
column_offset=1 + self.left_rbl + self.column_size + self.right_rbl,
# + right replica column(s)
column_offset = 1 + self.left_rbl + self.column_size + self.right_rbl,
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)
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()
# 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_bl_names = ["dummy_"+x for x in self.cell.get_all_bitline_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_row_bl_names = self.bitcell_array_bl_names
# 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)
for port in range(self.left_rbl):
# 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
self.rbl_wl_names[port]=wl_names[self.bitcell_ports[port]]
self.replica_col_wl_names.extend(wl_names)
# Regular WLs
self.replica_col_wl_names.extend(self.bitcell_array_wl_names)
# 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
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
self.rbl_wl_names[port]=wl_names[self.bitcell_ports[port]]
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
self.dummy_col_wl_names = self.replica_col_wl_names
# Per port bitline names
self.replica_bl_names = {}
self.replica_wl_names = {}
# Array of all port bitline names
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))]
right_names=["rbl_{0}_{1}".format(self.cell.get_br_name(x),port) for x in range(len(self.all_ports))]
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))]
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
self.rbl_bl_names[port]=left_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]
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[port] = "rbl_wl{}".format(port)
wl_names = ["rbl_{0}_{1}".format(x, port) for x in self.cell.get_all_wl_names()]
self.replica_wl_names[port] = wl_names
# External pins
self.add_pin_list(self.bitcell_array_bl_names, "INOUT")
# 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())]
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):
self.add_pin(bl_name,"OUTPUT")
self.add_pin(br_name,"OUTPUT")
for (bl_name, br_name) in zip(bl_names, br_names):
self.add_pin(bl_name, "OUTPUT")
self.add_pin(br_name, "OUTPUT")
self.add_pin_list(self.bitcell_array_wl_names, "INPUT")
# 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())]
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("gnd", "GROUND")
def create_instances(self):
""" Create the module instances used in this design """
@ -247,77 +243,75 @@ class replica_bitcell_array(design.design):
# Replica columns
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),
mod=self.replica_columns[port])
mod=self.replica_columns[port])
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)
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),
mod=self.dummy_row)
self.connect_inst(self.dummy_row_bl_names + self.replica_wl_names[port] + supplies)
# Top/bottom dummy rows or col caps
self.dummy_row_bot_inst=self.add_inst(name="dummy_row_bot",
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",
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
self.dummy_col_left_inst=self.add_inst(name="dummy_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",
mod=self.edge_col_right)
self.connect_inst([x+"_right" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies)
mod=self.edge_col_right)
self.connect_inst([x + "_right" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies)
def create_layout(self):
self.height = (self.row_size+self.extra_rows)*self.dummy_row.height
self.width = (self.column_size+self.extra_cols)*self.cell.width
self.height = (self.row_size + self.extra_rows) * self.dummy_row.height
self.width = (self.column_size + self.extra_cols) * self.cell.width
# This is a bitcell x bitcell offset to scale
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
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
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)
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(),
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(),
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)
flip_dummy = (self.left_rbl+1)%2
self.dummy_row_bot_inst.place(offset=offset.scale(0,-self.left_rbl-1+flip_dummy),
flip_dummy = (self.left_rbl + 1) % 2
self.dummy_row_bot_inst.place(offset=offset.scale(0, -self.left_rbl - 1 + flip_dummy),
mirror="MX" if flip_dummy else "R0")
# 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
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
for bit in range(self.left_rbl):
self.dummy_row_replica_inst[bit].place(offset=offset.scale(0,-bit-bit%2),
mirror="R0" if bit%2 else "MX")
self.dummy_row_replica_inst[bit].place(offset=offset.scale(0, -bit - bit % 2),
mirror="R0" if bit % 2 else "MX")
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(),
mirror="MX" if bit%2 else "R0")
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")
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()
@ -325,7 +319,6 @@ class replica_bitcell_array(design.design):
self.DRC_LVS()
def add_layout_pins(self):
""" Add the layout pins """
@ -338,7 +331,7 @@ class replica_bitcell_array(design.design):
for pin in pin_list:
self.add_layout_pin(text=pin_name,
layer=pin.layer,
offset=pin.ll().scale(0,1),
offset=pin.ll().scale(0, 1),
width=self.width,
height=pin.height())
for bitline in self.bitcell_array_bl_names:
@ -347,17 +340,16 @@ class replica_bitcell_array(design.design):
for pin in pin_list:
self.add_layout_pin(text=pin_name,
layer=pin.layer,
offset=pin.ll().scale(1,0),
offset=pin.ll().scale(1, 0),
width=pin.width(),
height=self.height)
# 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]
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
pin_bit = port+1
pin_bit = port + 1
# +row_size if above the array
if port>=self.left_rbl:
pin_bit += self.row_size
@ -367,7 +359,7 @@ class replica_bitcell_array(design.design):
if wl_name in self.rbl_wl_names.values():
self.add_layout_pin(text=wl_name,
layer=pin.layer,
offset=pin.ll().scale(0,1),
offset=pin.ll().scale(0, 1),
width=self.width,
height=pin.height())
@ -416,8 +408,6 @@ class replica_bitcell_array(design.design):
def analytical_power(self, corner, load):
"""Power of Bitcell array and bitline in nW."""
from tech import drc, parameter
# Dynamic Power from Bitline
bl_wire = self.gen_bl_wire()
cell_load = 2 * bl_wire.return_input_cap()
@ -425,10 +415,10 @@ class replica_bitcell_array(design.design):
freq = spice["default_event_frequency"]
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)
#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,
cell_power.leakage * self.column_size * self.row_size)
return total_power
@ -439,13 +429,13 @@ class replica_bitcell_array(design.design):
else:
height = self.height
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
return bl_wire
def get_wordline_cin(self):
"""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()
total_cin = bitcell_wl_cin * self.column_size
return total_cin
@ -457,9 +447,9 @@ class replica_bitcell_array(design.design):
def graph_exclude_replica_col_bits(self):
"""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()
def get_cell_name(self, inst_name, row, col):
"""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 design
from tech import drc, cell_properties
import contact
from tech import cell_properties
from sram_factory import factory
from vector import vector
from globals import OPTS
class replica_column(design.design):
"""
Generate a replica bitline column for the replica array.
@ -29,11 +29,12 @@ class replica_column(design.design):
self.right_rbl = right_rbl
self.replica_bit = replica_bit
# 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
debug.check(replica_bit!=0 and replica_bit!=rows,"Replica bit cannot be the dummy row.")
debug.check(replica_bit<=left_rbl or replica_bit>=self.total_size-right_rbl-1,
debug.check(replica_bit != 0 and replica_bit != rows,
"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.")
self.create_netlist()
@ -46,7 +47,7 @@ class replica_column(design.design):
self.create_instances()
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.place_instances()
@ -58,25 +59,25 @@ class replica_column(design.design):
for bl_name in self.cell.get_all_bitline_names():
# 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 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("gnd", "GROUND")
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.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)
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:
edge_module_type = "dummy_bitcell"
self.edge_cell = factory.create(module_type=edge_module_type)
edge_module_type = "dummy"
self.edge_cell = factory.create(module_type=edge_module_type + "_" + OPTS.bitcell)
self.add_mod(self.edge_cell)
# Used for pin names only
self.cell = factory.create(module_type="bitcell")
@ -94,7 +95,7 @@ class replica_column(design.design):
# Top/bottom cell are always dummy cells.
# 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.
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,
mod=self.replica_cell)
self.connect_inst(self.get_bitcell_pins(0, row))
@ -118,7 +119,7 @@ class replica_column(design.design):
from tech import cell_properties
# 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
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
# column that needs to be flipped.
@ -129,12 +130,10 @@ class replica_column(design.design):
xoffset = self.replica_cell.width
for row in range(self.total_size):
dir_x = False
name = "bit_r{0}_{1}".format(row,"rbl")
if cell_properties.bitcell.mirror.x and (row+rbl_offset)%2:
dir_x = True
# name = "bit_r{0}_{1}".format(row, "rbl")
dir_x = cell_properties.bitcell.mirror.x and (row + rbl_offset) % 2
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:
dir_key = "XY"
@ -174,9 +173,9 @@ class replica_column(design.design):
for row in range(row_range_min, row_range_max):
for wl_name in self.cell.get_all_wl_names():
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,
offset=wl_pin.ll().scale(0,1),
offset=wl_pin.ll().scale(0, 1),
width=self.width,
height=wl_pin.height())
@ -194,10 +193,10 @@ class replica_column(design.design):
pin_names = self.cell.get_all_bitline_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()
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("gnd")
@ -211,12 +210,11 @@ class replica_column(design.design):
pin_names = self.cell.get_all_bitline_names()
for pin in pin_names:
bitcell_pins.append(pin+"_{0}".format(col))
bitcell_pins.append(pin + "_{0}".format(col))
bitcell_pins.append("vdd")
return bitcell_pins
def exclude_all_but_replica(self):
"""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):
""" 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.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.
"""
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)
debug.info(1, "Creating {0}".format(self.name))
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.words_per_row = words_per_row
self.column_offset = column_offset
self.row_size = self.word_size * self.words_per_row
self.create_netlist()
@ -102,25 +103,22 @@ class sense_amp_array(design.design):
def place_sense_amp_array(self):
from tech import cell_properties
if self.bitcell.width > self.amp.width:
amp_spacing = self.bitcell.width * self.words_per_row
amp_spacing = self.bitcell.width
else:
amp_spacing = self.amp.width * self.words_per_row
amp_spacing = self.amp.width
for i in range(0, self.word_size):
xoffset = amp_spacing * i
for i in range(0, self.row_size, self.words_per_row):
index = int(i / self.words_per_row)
xoffset = i * amp_spacing
# align the xoffset to the grid of bitcells. This way we
# know when to do the mirroring.
grid_x = int(xoffset / self.amp.width)
if cell_properties.bitcell.mirror.y and grid_x % 2:
if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2:
mirror = "MY"
xoffset = xoffset + self.amp.width
else:
mirror = ""
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):
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.
"""
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)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("cols: {0} word_size: {1} bl: {2} br: {3}".format(columns, word_size, bitcell_bl, bitcell_br))
self.columns = columns
self.port = port
self.word_size = word_size
self.words_per_row = int(self.columns / self.word_size)
self.bitcell_bl = bitcell_bl
self.bitcell_br = bitcell_br
self.column_offset = column_offset
if "li" in layer:
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 col_num in range(self.columns):
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"
xoffset = xoffset + self.mux.width
else:

View File

@ -18,7 +18,7 @@ class write_driver_array(design.design):
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)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("columns: {0}".format(columns))
@ -27,6 +27,7 @@ class write_driver_array(design.design):
self.columns = columns
self.word_size = word_size
self.write_size = write_size
self.column_offset = column_offset
self.words_per_row = int(columns / word_size)
if self.write_size:
@ -128,7 +129,7 @@ class write_driver_array(design.design):
index = int(i / self.words_per_row)
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"
xoffset = xoffset + self.driver.width
else:

View File

@ -18,7 +18,7 @@ class write_mask_and_array(design.design):
The write mask AND array goes between the write driver array and the sense amp array.
"""
def __init__(self, name, columns, word_size, write_size, port=0):
def __init__(self, name, columns, word_size, write_size, column_offset=0):
design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("columns: {0}".format(columns))
@ -28,7 +28,7 @@ class write_mask_and_array(design.design):
self.columns = columns
self.word_size = word_size
self.write_size = write_size
self.port = port
self.column_offset = column_offset
self.words_per_row = int(columns / word_size)
self.num_wmasks = int(word_size / write_size)

View File

@ -124,26 +124,23 @@ class options(optparse.Values):
purge_temp = True
# These are the default modules that can be over-riden
bitcell_suffix = ""
bank_select = "bank_select"
bitcell_array = "bitcell_array"
bitcell = "bitcell"
col_cap_bitcell = "col_cap_bitcell"
column_mux_array = "single_level_column_mux_array"
control_logic = "control_logic"
decoder = "hierarchical_decoder"
delay_chain = "delay_chain"
dff_array = "dff_array"
dff = "dff"
dummy_bitcell = "dummy_bitcell"
inv_dec = "pinv"
nand2_dec = "pnand2"
nand3_dec = "pnand3"
nand4_dec = "pnand4" # Not available right now
precharge_array = "precharge_array"
ptx = "ptx"
replica_bitcell = "replica_bitcell"
replica_bitline = "replica_bitline"
row_cap_bitcell = "row_cap_bitcell"
sense_amp_array = "sense_amp_array"
sense_amp = "sense_amp"
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)
user_module_type, um_overridden = self.get_usermodule_type(module_type)
#print(module_type, tech_module_type, tm_overridden)
#print(module_type, user_module_type, um_overridden)
# print(module_type, tech_module_type, tm_overridden)
# print(module_type, user_module_type, um_overridden)
# overridden user modules have priority
if um_overridden:

View File

@ -22,11 +22,11 @@ class single_level_column_mux_1rw_1r_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
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")
self.local_check(tx)

View File

@ -23,12 +23,10 @@ class bitcell_1rw_1r_array_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
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_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(2, "Testing 4x4 array for cell_1rw_1r")
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,11 +23,11 @@ class hierarchical_decoder_1rw_1r_test(openram_test):
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_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
# Checks 2x4 and 2-input NAND decoder
debug.info(1, "Testing 16 row sample for hierarchical_decoder")
a = factory.create(module_type="hierarchical_decoder", num_outputs=16)

View File

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

View File

@ -22,11 +22,10 @@ class hierarchical_predecode2x4_1rw_1r_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
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_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(1, "Testing sample for hierarchy_predecode2x4")
a = factory.create(module_type="hierarchical_predecode2x4")

View File

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

View File

@ -23,11 +23,11 @@ class hierarchical_predecode3x8_1rw_1r_test(openram_test):
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_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(1, "Testing sample for hierarchy_predecode3x8")
a = factory.create(module_type="hierarchical_predecode3x8")
self.local_check(a)

View File

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

View File

@ -20,17 +20,17 @@ class single_level_column_mux_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
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)
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)
globals.end_openram()

View File

@ -29,19 +29,19 @@ class single_level_column_mux_pbitcell_test(openram_test):
factory.reset()
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)
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)
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)
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)
globals.end_openram()

View File

@ -21,15 +21,15 @@ class single_level_column_mux_test(openram_test):
globals.init_openram(config_file)
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)
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)
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)
globals.end_openram()

View File

@ -22,24 +22,20 @@ class precharge_1rw_1r_test(openram_test):
globals.init_openram(config_file)
# check precharge array in multi-port
OPTS.bitcell = "bitcell_1rw_1r"
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
factory.reset()
debug.info(2, "Checking 3 column precharge array for 1RW/1R bitcell")
pc = factory.create(module_type="precharge_array", columns=3, port=0, bitcell_bl="bl0", bitcell_br="br0")
debug.info(2, "Checking 3 column precharge array for 1RW/1R bitcell (port 0)")
pc = factory.create(module_type="precharge_array", columns=3, bitcell_bl="bl0", bitcell_br="br0")
self.local_check(pc)
debug.info(2, "Checking 3 column precharge array for 1RW/1R bitcell (port 1)")
pc = factory.create(module_type="precharge_array", columns=3, bitcell_bl="bl0", bitcell_br="br0", column_offset=1)
self.local_check(pc)
# debug.info(2, "Checking 3 column precharge array for pbitcell (innermost connections)")
# pc = precharge_array.precharge_array(name="pre3", columns=3, bitcell_bl="bl0", bitcell_br="br0")
# 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()
# run the test from the command line

View File

@ -21,9 +21,8 @@ class precharge_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
# check precharge array in single port
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)
globals.end_openram()

View File

@ -23,10 +23,10 @@ class wordline_driver_array_1rw_1r_test(openram_test):
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_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
# check wordline driver for single port
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"))
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")
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=1)
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"))
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_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
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)
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)
globals.end_openram()

View File

@ -19,10 +19,15 @@ class replica_bitcell_array_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
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])
self.local_check(a)
globals.end_openram()
# run the test from the command line

View File

@ -21,14 +21,18 @@ class port_address_1rw_1r_test(openram_test):
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_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(1, "Port address 16 rows")
a = factory.create("port_address", cols=16, rows=16)
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()

View File

@ -24,6 +24,10 @@ class port_address_test(openram_test):
a = factory.create("port_address", cols=16, rows=16)
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()
# run the test from the command line

View File

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

View File

@ -22,12 +22,10 @@ class single_bank_1rw_1r_test(openram_test):
globals.init_openram(config_file)
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_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
c = sram_config(word_size=4,
num_words=16)

View File

@ -22,13 +22,10 @@ class single_bank_1w_1r_test(openram_test):
globals.init_openram(config_file)
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_r_ports = 1
OPTS.num_w_ports = 1
globals.setup_bitcell()
c = sram_config(word_size=4,
num_words=16)

View File

@ -22,6 +22,10 @@ class single_bank_wmask_1rw_1r_test(openram_test):
globals.init_openram(config_file)
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,
write_size=4,

View File

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

View File

@ -24,11 +24,10 @@ class psram_1bank_2mux_1w_1r_test(openram_test):
from sram_config import sram_config
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell"
OPTS.dummy_bitcell="dummy_pbitcell"
OPTS.num_rw_ports = 0
OPTS.num_w_ports = 1
OPTS.num_r_ports = 1
globals.setup_bitcell()
c = sram_config(word_size=4,
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"))
globals.init_openram(config_file)
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_w_ports = 0
OPTS.num_r_ports = 0
globals.setup_bitcell()
c = sram_config(word_size=4,
num_words=32,

View File

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

View File

@ -22,12 +22,10 @@ class sram_1bank_2mux_1rw_1r_test(openram_test):
globals.init_openram(config_file)
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_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
c = sram_config(word_size=4,
num_words=32,

View File

@ -23,12 +23,10 @@ class psram_1bank_2mux_1w_1r_test(openram_test):
globals.init_openram(config_file)
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_w_ports = 1
OPTS.num_r_ports = 1
globals.setup_bitcell()
c = sram_config(word_size=4,
num_words=32,

View File

@ -22,13 +22,11 @@ class sram_1bank_8mux_1rw_1r_test(openram_test):
globals.init_openram(config_file)
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_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
c = sram_config(word_size=2,
num_words=128,
num_banks=1)

View File

@ -22,12 +22,10 @@ class sram_1bank_nomux_1rw_1r_test(openram_test):
globals.init_openram(config_file)
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_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
c = sram_config(word_size=4,
num_words=16,

View File

@ -24,12 +24,10 @@ class psram_1bank_nomux_func_test(openram_test):
OPTS.analytical_delay = False
OPTS.netlist_only = True
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_w_ports = 0
OPTS.num_r_ports = 1
globals.setup_bitcell()
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload

View File

@ -26,14 +26,11 @@ class sram_wmask_1w_1r_func_test(openram_test):
OPTS.analytical_delay = False
OPTS.netlist_only = True
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_w_ports = 1
OPTS.num_r_ports = 1
globals.setup_bitcell()
# This is a hack to reload the characterizer __init__ with the spice version
from importlib import reload
import characterizer

View File

@ -5,23 +5,21 @@
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest,warnings
import pdb,traceback
import sys,os,glob,copy
import shutil
import unittest
import sys, os, glob
sys.path.append(os.getenv("OPENRAM_HOME"))
from globals import OPTS
import debug
class openram_test(unittest.TestCase):
""" Base unit test that we have some shared classes in. """
def local_drc_check(self, w):
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)
import verify
@ -36,8 +34,8 @@ class openram_test(unittest.TestCase):
self.reset()
tempspice = "{0}{1}.sp".format(OPTS.openram_temp,a.name)
tempgds = "{0}{1}.gds".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)
a.lvs_write(tempspice)
# 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
if "magic" in OPTS.drc_exe and lvs_result == 0 and drc_result != 0:
#zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid())
#debug.info(0,"Archiving failed files to {}.zip".format(zip_file))
#shutil.make_archive(zip_file, 'zip', OPTS.openram_temp)
# import shutil
# zip_file = "/tmp/{0}_{1}".format(a.name, os.getpid())
# 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))
#self.fail("DRC failed but LVS passed: {}".format(a.name))
# self.fail("DRC failed but LVS passed: {}".format(a.name))
elif drc_result != 0:
#zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid())
#debug.info(0,"Archiving failed files to {}.zip".format(zip_file))
#shutil.make_archive(zip_file, 'zip', OPTS.openram_temp)
# import shutil
# zip_file = "/tmp/{0}_{1}".format(a.name, os.getpid())
# 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))
if lvs_result != 0:
#zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid())
#debug.info(0,"Archiving failed files to {}.zip".format(zip_file))
#shutil.make_archive(zip_file, 'zip', OPTS.openram_temp)
# import shutil
# zip_file = "/tmp/{0}_{1}".format(a.name, os.getpid())
# 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))
# For debug...
#import pdb; pdb.set_trace()
# import pdb; pdb.set_trace()
if OPTS.purge_temp:
self.cleanup()
def run_pex(self, a, output=None):
if output == None:
output = OPTS.openram_temp + a.name + ".pex.netlist"
tempspice = "{0}{1}.sp".format(OPTS.openram_temp,a.name)
tempgds = "{0}{1}.gds".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)
import verify
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.")
delay_obj.set_load_slew(load, slew)
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))
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.find_feasible_period_one_port(test_port)
return delay_obj.period
@ -130,29 +130,27 @@ class openram_test(unittest.TestCase):
for k in data.keys():
if type(data[k])==list:
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
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
if not data_matches:
import pprint
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
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. """
import debug
relative_diff = self.relative_diff(value,actual_value)
relative_diff = self.relative_diff(value, actual_value)
check = relative_diff <= error_tolerance
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
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
def relative_diff(self, value1, value2):
@ -169,18 +167,14 @@ class openram_test(unittest.TestCase):
# Get normalization value
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
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. """
if (value==actual_value): # if we don't need a relative comparison!
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):
"""Compare two files.
@ -218,23 +212,22 @@ class openram_test(unittest.TestCase):
line_num+=1
line1 = fp1.readline().decode('utf-8')
line2 = fp2.readline().decode('utf-8')
#print("line1:",line1)
#print("line2:",line2)
# print("line1:", line1)
# print("line2:", line2)
# 1. Find all of the floats using a regex
line1_floats=rx.findall(line1)
line2_floats=rx.findall(line2)
debug.info(3,"line1_floats: "+str(line1_floats))
debug.info(3,"line2_floats: "+str(line2_floats))
debug.info(3, "line1_floats: " + str(line1_floats))
debug.info(3, "line2_floats: " + str(line2_floats))
# 2. Remove the floats from the string
for f in line1_floats:
line1=line1.replace(f,"",1)
line1=line1.replace(f, "", 1)
for f in line2_floats:
line2=line2.replace(f,"",1)
#print("line1:",line1)
#print("line2:",line2)
line2=line2.replace(f, "", 1)
# print("line1:", line1)
# print("line2:", line2)
# 3. Convert to floats rather than strings
line1_floats = [float(x) for x in line1_floats]
@ -242,29 +235,29 @@ class openram_test(unittest.TestCase):
# 4. Check if remaining string matches
if line1 != line2:
#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 line2]))
# 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 line2]))
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
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
elif len(line1_floats)!=len(line2_floats):
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
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:
for (float1,float2) in zip(line1_floats,line2_floats):
relative_diff = self.relative_diff(float1,float2)
for (float1, float2) in zip(line1_floats, line2_floats):
relative_diff = self.relative_diff(float1, float2)
check = relative_diff <= error_tolerance
if not check:
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
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
if not line1 and not line2 or mismatches>10:
@ -275,19 +268,18 @@ class openram_test(unittest.TestCase):
# Never reached
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.. """
import debug
import filecmp
import difflib
check = filecmp.cmp(filename1,filename2)
check = filecmp.cmp(filename1, filename2)
if not check:
debug.error("MISMATCH file1={0} file2={1}".format(filename1,filename2))
f1 = open(filename1,mode="r",encoding='utf-8')
debug.error("MISMATCH file1={0} file2={1}".format(filename1, filename2))
f1 = open(filename1, mode="r", encoding='utf-8')
s1 = f1.readlines()
f1.close()
f2 = open(filename2,mode="r",encoding='utf-8')
f2 = open(filename2, mode="r", encoding='utf-8')
s2 = f2.readlines()
f2.close()
mismatches=0
@ -302,10 +294,13 @@ class openram_test(unittest.TestCase):
return False
return False
else:
debug.info(2,"MATCH {0} {1}".format(filename1,filename2))
debug.info(2, "MATCH {0} {1}".format(filename1, filename2))
return True
def dbg():
import pdb; pdb.set_trace()
def header(filename, technology):
# Skip the header for gitlab regression
import getpass
@ -319,14 +314,18 @@ def header(filename, technology):
print("|=========" + tst.center(60) + "=========|")
print("|=========" + technology.center(60) + "=========|")
print("|=========" + filename.center(60) + "=========|")
from globals import OPTS
from globals import OPTS
print("|=========" + OPTS.openram_temp.center(60) + "=========|")
print("|==============================================================================|")
def debugTestRunner(post_mortem=None):
"""unittest runner doing post mortem debugging on failing tests"""
import pdb
import traceback
if post_mortem is None and not OPTS.purge_temp:
post_mortem = pdb.post_mortem
class DebugTestResult(unittest.TextTestResult):
def addError(self, test, err):
# called before tearDown()
@ -334,9 +333,10 @@ def debugTestRunner(post_mortem=None):
if post_mortem:
post_mortem(err[2])
super(DebugTestResult, self).addError(test, err)
def addFailure(self, test, err):
traceback.print_exception(*err)
if post_mortem:
if post_mortem:
post_mortem(err[2])
super(DebugTestResult, self).addFailure(test, err)
return unittest.TextTestRunner(resultclass=DebugTestResult)