Merge branch 'dev' into gridless_router

This commit is contained in:
Eren Dogan 2023-07-18 10:00:00 -07:00
commit 53d00f5b34
76 changed files with 2077 additions and 504 deletions

View File

@ -13,7 +13,7 @@ SRAM_LIB_GIT_REPO ?= https://github.com/vlsida/sky130_fd_bd_sram.git
# Use this for development
#SRAM_LIB_GIT_REPO ?= git@github.com:VLSIDA/sky130_fd_bd_sram.git
#SRAM_LIB_GIT_REPO ?= https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git
SRAM_LIB_GIT_COMMIT ?= a83b6468c48434d927b90058b22047843c58027b
SRAM_LIB_GIT_COMMIT ?= 060f3638be6269dd9aa82cfbbdfd9525943c1582
# Open PDKs
OPEN_PDKS_DIR ?= $(PDK_ROOT)/open_pdks

View File

@ -1 +1 @@
1.2.16
1.2.20

View File

@ -68,7 +68,7 @@ class spice():
self.trim_insts = set()
# Keep track of any comments to add the the spice
try:
self.commments
self.comments
except AttributeError:
self.comments = []
@ -82,7 +82,7 @@ class spice():
""" Add a comment to the spice file """
try:
self.commments
self.comments
except AttributeError:
self.comments = []

View File

@ -18,6 +18,7 @@ class wire_spice_model():
def cal_wire_c(self, wire_length, wire_width):
from openram.tech import spice
# Convert the F/um^2 to fF/um^2 then multiple by width and length
# FIXME: shouldn't it be 1e15?
total_c = (spice["wire_unit_c"]*1e12) * wire_length * wire_width
wire_c = total_c / self.lump_num
return wire_c

View File

@ -594,7 +594,7 @@ class simulation():
for path in paths:
aliases = self.sram.find_aliases(self.sram_instance_name, self.pins, path, internal_net, mod, exclusion_set)
if net_found and len(aliases) >= 1:
debug.error('Found multiple paths with {} net.'.format(internal_net), 1)
pass #debug.error('Found multiple paths with {} net.'.format(internal_net), 1)
elif len(aliases) > 1:
debug.error('Found multiple {} nets in single path.'.format(internal_net), 1)
elif not net_found and len(aliases) == 1:

View File

@ -85,7 +85,8 @@ class bank(design):
for bit in range(self.word_size + self.num_spare_cols):
self.add_pin("dout{0}_{1}".format(port, bit), "OUTPUT")
for port in self.all_ports:
self.add_pin("rbl_bl_{0}_{0}".format(port), "OUTPUT")
if self.has_rbl:
self.add_pin("rbl_bl_{0}_{0}".format(port), "OUTPUT")
for port in self.write_ports:
for bit in range(self.word_size + self.num_spare_cols):
self.add_pin("din{0}_{1}".format(port, bit), "INPUT")
@ -114,11 +115,10 @@ class bank(design):
""" Create routing amoung the modules """
self.route_central_bus()
self.route_unused_wordlines()
for port in self.all_ports:
self.route_bitlines(port)
self.route_rbl(port)
if self.has_rbl:
self.route_rbl(port)
self.route_port_address(port)
self.route_column_address_lines(port)
self.route_control_lines(port)
@ -360,6 +360,18 @@ class bank(design):
def add_modules(self):
""" Add all the modules using the class loader """
# delay control logic does not have RBLs
if OPTS.control_logic != "control_logic_delay":
self.has_rbl = True
rbl = [1, 1 if len(self.all_ports)>1 else 0]
left_rbl = [0]
right_rbl = [1] if len(self.all_ports)>1 else []
else:
self.has_rbl = False
rbl = [0, 0]
left_rbl = []
right_rbl = []
local_array_size = OPTS.local_array_size
if local_array_size > 0:
@ -372,21 +384,25 @@ class bank(design):
cols.append(local_array_size + final_size)
self.bitcell_array = factory.create(module_type="global_bitcell_array",
cols=cols,
rows=self.num_rows)
rows=self.num_rows,
rbl=rbl,
left_rbl=left_rbl,
right_rbl=right_rbl)
else:
self.bitcell_array = factory.create(module_type="capped_replica_bitcell_array",
cols=self.num_cols + self.num_spare_cols,
rows=self.num_rows,
rbl=[1, 1 if len(self.all_ports)>1 else 0],
left_rbl=[0],
right_rbl=[1] if len(self.all_ports)>1 else [])
rbl=rbl,
left_rbl=left_rbl,
right_rbl=right_rbl)
self.port_address = []
for port in self.all_ports:
self.port_address.append(factory.create(module_type="port_address",
cols=self.num_cols + self.num_spare_cols,
rows=self.num_rows,
port=port))
port=port,
has_rbl=self.has_rbl))
self.port_data = []
self.bit_offsets = self.get_column_offsets()
@ -394,6 +410,7 @@ class bank(design):
self.port_data.append(factory.create(module_type="port_data",
sram_config=self.sram_config,
port=port,
has_rbl=self.has_rbl,
bit_offsets=self.bit_offsets))
def create_bitcell_array(self):
@ -407,9 +424,10 @@ class bank(design):
# gnd
temp = self.bitcell_array.get_inouts()
temp.append("rbl_wl0")
if self.has_rbl:
temp.append("rbl_wl0")
temp.extend(self.bitcell_array.get_wordline_names())
if len(self.all_ports) > 1:
if len(self.all_ports) > 1 and self.has_rbl:
temp.append("rbl_wl1")
temp.append("vdd")
@ -432,7 +450,8 @@ class bank(design):
mod=self.port_data[port])
temp = []
temp.extend(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)])
if self.has_rbl:
temp.extend(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)])
temp.extend(self.bitcell_array.get_bitline_names(port))
if port in self.read_ports:
for bit in range(self.word_size + self.num_spare_cols):
@ -480,7 +499,8 @@ class bank(design):
temp.append("wl_en{}".format(port))
wordline_names = self.bitcell_array.get_wordline_names(port)
temp.extend(wordline_names)
temp.append("rbl_wl{}".format(port))
if self.has_rbl:
temp.append("rbl_wl{}".format(port))
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
@ -719,8 +739,9 @@ class bank(design):
inst2_br_name=inst2_br_name)
# Connect the replica bitlines
for (array_name, data_name) in zip(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)], ["rbl_bl", "rbl_br"]):
self.connect_bitline(inst1, inst2, array_name, data_name)
if self.has_rbl:
for (array_name, data_name) in zip(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)], ["rbl_bl", "rbl_br"]):
self.connect_bitline(inst1, inst2, array_name, data_name)
def route_port_data_out(self, port):
""" Add pins for the port data out """
@ -841,8 +862,13 @@ class bank(design):
def route_port_address_out(self, port, side="left"):
""" Connecting Wordline driver output to Bitcell WL connection """
driver_names = ["wl_{}".format(x) for x in range(self.num_rows)] + ["rbl_wl"]
rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port)[port]
driver_names = ["wl_{}".format(x) for x in range(self.num_rows)]
if self.has_rbl:
driver_names = driver_names + ["rbl_wl"]
rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port)[port]
else:
rbl_wl_name = None
# rbl_wl in next line will be ignored by zip once driver_names is exhausted in the no rbl case
for (driver_name, array_name) in zip(driver_names, self.bitcell_array.get_wordline_names(port) + [rbl_wl_name]):
# The mid guarantees we exit the input cell to the right.
driver_wl_pin = self.port_address_inst[port].get_pin(driver_name)
@ -875,7 +901,10 @@ class bank(design):
def route_port_address_right(self, port):
""" Connecting Wordline driver output to Bitcell WL connection """
driver_names = ["wl_{}".format(x) for x in range(self.num_rows)] + ["rbl_wl"]
driver_names = ["wl_{}".format(x) for x in range(self.num_rows)]
if self.has_rbl:
driver_names = driver_names + ["rbl_wl"]
# rbl_wl in next two lines will be ignored by zip once driver_names is exhausted in the no rbl case
rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port)[port]
for (driver_name, array_name) in zip(driver_names, self.bitcell_array.get_wordline_names(port) + [rbl_wl_name]):
# The mid guarantees we exit the input cell to the right.
@ -971,36 +1000,6 @@ class bank(design):
# layer="m1",
# offset=data_pin.center())
def route_unused_wordlines(self):
""" Connect the unused RBL and dummy wordlines to gnd """
gnd_wl_names = []
return
# Connect unused RBL WL to gnd
# All RBL WL names
array_rbl_names = set(self.bitcell_array.get_rbl_wordline_names())
# List of used RBL WL names
rbl_wl_names = set()
for port in self.all_ports:
rbl_wl_names.add(self.bitcell_array.get_rbl_wordline_names(port)[port])
gnd_wl_names = list((array_rbl_names - rbl_wl_names))
for wl_name in gnd_wl_names:
pin = self.bitcell_array_inst.get_pin(wl_name)
pin_layer = pin.layer
layer_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer))
left_pin_loc = pin.lc()
right_pin_loc = pin.rc()
# Place the pins a track outside of the array
left_loc = left_pin_loc - vector(layer_pitch, 0)
right_loc = right_pin_loc + vector(layer_pitch, 0)
self.add_power_pin("gnd", left_loc, directions=("H", "H"))
self.add_power_pin("gnd", right_loc, directions=("H", "H"))
# Add a path to connect to the array
self.add_path(pin_layer, [left_loc, left_pin_loc])
self.add_path(pin_layer, [right_loc, right_pin_loc])
def route_control_lines(self, port):
""" Route the control lines of the entire bank """

View File

@ -33,7 +33,10 @@ class capped_replica_bitcell_array(bitcell_base_array):
self.column_size = cols
self.row_size = rows
# This is how many RBLs are in all the arrays
self.rbl = rbl
if rbl is not None:
self.rbl = rbl
else:
self.rbl = [0] * len(self.all_ports)
# This specifies which RBL to put on the left or right by port number
# This could be an empty list
if left_rbl is not None:
@ -64,28 +67,7 @@ class capped_replica_bitcell_array(bitcell_base_array):
self.create_instances()
def add_modules(self):
""" Array and dummy/replica columns
d or D = dummy cell (caps to distinguish grouping)
r or R = replica cell (caps to distinguish grouping)
b or B = bitcell
replica columns 1
v v
bdDDDDDDDDDDDDDDdb <- Dummy row
bdDDDDDDDDDDDDDDrb <- Dummy row
br--------------rb
br| Array |rb
br| row x col |rb
br--------------rb
brDDDDDDDDDDDDDDdb <- Dummy row
bdDDDDDDDDDDDDDDdb <- Dummy row
^^^^^^^^^^^^^^^
dummy rows cols x 1
^ dummy columns ^
1 x (rows + 4)
"""
""" Array and cap rows/columns """
self.replica_bitcell_array = factory.create(module_type="replica_bitcell_array",
cols=self.column_size,
@ -132,7 +114,7 @@ class capped_replica_bitcell_array(bitcell_base_array):
# + right replica column(s)
column_offset=1 + len(self.left_rbl) + self.column_size + self.rbl[0],
rows=self.row_size + self.extra_rows,
mirror=(self.rbl[0] + 1) %2)
mirror=(self.rbl[0] + 1) % 2)
def add_pins(self):
@ -219,6 +201,7 @@ class capped_replica_bitcell_array(bitcell_base_array):
# row-based or column based power and ground lines.
self.vertical_pitch = 1.1 * getattr(self, "{}_pitch".format(self.supply_stack[0]))
self.horizontal_pitch = 1.1 * getattr(self, "{}_pitch".format(self.supply_stack[2]))
# FIXME: custom sky130 replica module has a better version of this offset
self.unused_offset = vector(0.25, 0.25)
# This is a bitcell x bitcell offset to scale

View File

@ -118,8 +118,6 @@ class control_logic(control_logic_base):
# list of output control signals (for making a vertical bus)
if self.port_type == "rw":
self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "gated_clk_bar", "gated_clk_buf", "we", "we_bar", "clk_buf", "cs"]
elif self.port_type == "r":
self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "gated_clk_bar", "gated_clk_buf", "clk_buf", "cs_bar", "cs"]
else:
self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "gated_clk_bar", "gated_clk_buf", "clk_buf", "cs"]
# leave space for the bus plus one extra space

View File

@ -328,8 +328,6 @@ class control_logic_base(design):
def route_dffs(self):
if self.port_type == "rw":
dff_out_map = zip(["dout_bar_0", "dout_bar_1", "dout_1"], ["cs", "we", "we_bar"])
elif self.port_type == "r":
dff_out_map = zip(["dout_bar_0", "dout_0"], ["cs", "cs_bar"])
else:
dff_out_map = zip(["dout_bar_0"], ["cs"])
self.connect_vertical_bus(dff_out_map, self.ctrl_dff_inst, self.input_bus, self.m2_stack[::-1])

View File

@ -0,0 +1,469 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import math
from openram import debug
from openram import OPTS
from openram.base import design
from openram.base import vector
from openram.base import logical_effort, convert_farad_to_relative_c
from openram.tech import drc, spice
from openram.sram_factory import factory
from .control_logic_base import control_logic_base
class control_logic_delay(control_logic_base):
"""
Dynamically generated Control logic for the total SRAM circuit.
Variant: delay-based
"""
def __init__(self, num_rows, words_per_row, word_size, spare_columns=None, sram=None, port_type="rw", name=""):
""" Constructor """
super().__init__(num_rows, words_per_row, word_size, spare_columns, sram, port_type, name)
def add_pins(self):
""" Add the pins to the control logic module. """
self.add_pin_list(self.input_list + ["clk"], "INPUT")
self.add_pin_list(self.output_list, "OUTPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def add_modules(self):
""" Add all the required modules """
self.dff = factory.create(module_type="dff_buf")
dff_height = self.dff.height
self.ctrl_dff_array = factory.create(module_type="dff_buf_array",
rows=self.num_control_signals,
columns=1)
self.and2 = factory.create(module_type="pand2",
size=12,
height=dff_height)
# clk_buf drives a flop for every address
addr_flops = math.log(self.num_words, 2) + math.log(self.words_per_row, 2)
# plus data flops and control flops
num_flops = addr_flops + self.word_size + self.num_spare_cols + self.num_control_signals
# each flop internally has a FO 5 approximately
# plus about 5 fanouts for the control logic
clock_fanout = 5 * num_flops + 5
self.clk_buf_driver = factory.create(module_type="pdriver",
fanout=clock_fanout,
height=dff_height)
# We will use the maximum since this same value is used to size the wl_en
# and the p_en_bar drivers
# max_fanout = max(self.num_rows, self.num_cols)
# wl_en drives every row in the bank
# this calculation is from the rbl control logic, it may not be optimal in this circuit
size_list = [max(int(self.num_rows / 9), 1), max(int(self.num_rows / 3), 1)]
self.wl_en_driver = factory.create(module_type="pdriver",
size_list=size_list,
height=dff_height)
# this is the weak timing signal that feeds wl_en_driver
self.wl_en_and = factory.create(module_type="pand2",
size=1,
height=dff_height)
# w_en drives every write driver
self.wen_and = factory.create(module_type="pand3",
size=self.word_size + 8,
height=dff_height)
# s_en drives every sense amp
self.sen_and3 = factory.create(module_type="pand3",
size=self.word_size + self.num_spare_cols,
height=dff_height)
# used to generate inverted signals with low fanout
self.inv = factory.create(module_type="pinv",
size=1,
height=dff_height)
# p_en_bar drives every column in the bitcell array
# but it is sized the same as the wl_en driver with
# prepended 3 inverter stages to guarantee it is slower and odd polarity
self.p_en_bar_driver = factory.create(module_type="pdriver",
fanout=self.num_cols,
height=dff_height)
self.nand2 = factory.create(module_type="pnand2",
height=dff_height)
self.compute_delay_chain_size()
self.delay_chain = factory.create(module_type="multi_delay_chain",
fanout_list=self.delay_chain_fanout_list,
pinout_list=self.delay_chain_pinout_list)
def compute_delay_chain_size(self):
"""
calculate the pinouts needed for the delay chain based on
wordline, bitline, and precharge delays
delays 0 & 1 need to be even for polarity
delays 2 - 4 need to be odd for polarity
"""
bitcell = factory.create(module_type=OPTS.bitcell)
# TODO: check that these spice values are up to date in tech files and if not figure out how to update them
# 2 access tx gate per cell
wordline_area = bitcell.width * drc("minwidth_m1")
wordline_cap_ff = self.num_cols * (2 * spice["min_tx_gate_c"] + spice["wire_unit_c"] * 1e15 * wordline_area)
wordline_cap = convert_farad_to_relative_c(wordline_cap_ff)
# 1 access tx drain per cell
bitline_area = bitcell.height * drc("minwidth_m2")
bitline_cap_ff = self.num_rows * (spice["min_tx_drain_c"] + spice["wire_unit_c"] * 1e15 * bitline_area)
bitline_cap = convert_farad_to_relative_c(bitline_cap_ff)
# 3 pmos gate per cell
pen_cap_ff = self.num_cols * (3 * spice["min_tx_gate_c"] + spice["wire_unit_c"] * 1e15 * wordline_area)
pen_cap = convert_farad_to_relative_c(pen_cap_ff)
# number of stages in the p_en driver
pen_stages = self.p_en_bar_driver.num_stages
inverter_stage_delay = logical_effort("inv", 1, 1, OPTS.delay_chain_fanout_per_stage, 1, True).get_absolute_delay()
# model precharge as a minimum sized inverter with the bitline as its load
precharge_delay = logical_effort("precharge", 1, 1, bitline_cap, 1, True).get_absolute_delay()
# exponential horn delay from logical effort paper (converted to absolute delay)
pen_signal_delay = logical_effort.tau * (pen_stages * (pen_cap ** (1 / pen_stages) + 1))
# size is a pessimistic version of wordline_driver module's FO4 sizing
wordline_driver_size = int(self.num_cols / 4) + 1
wordline_delay = logical_effort("wordline", wordline_driver_size, 1, wordline_cap, 1, True).get_absolute_delay()
# wl_en driver is always two stages so add each independently?
wlen_signal_delay = logical_effort("wlen_driver", self.wl_en_driver.size_list[0], 1, self.wl_en_driver.size_list[1], 1, True).get_absolute_delay()
wlen_signal_delay += logical_effort("wlen_driver", self.wl_en_driver.size_list[1], 1, wordline_driver_size * self.num_rows, 1, True).get_absolute_delay()
# time for bitline to drop from vdd by threshold voltage once wordline enabled
bitline_vth_swing = (spice["nom_supply_voltage"] - spice["nom_threshold"]) / spice["nom_supply_voltage"]
bitline_vth_delay = abs(math.log(1 - bitline_vth_swing)) * spice["wire_unit_r"] * bitline_area * bitline_cap_ff
# print("delays: delay_stage {} precharge {} pen {} wl {} wlen {} vth {}".format(inverter_stage_delay, precharge_delay, pen_signal_delay, wordline_delay, wlen_signal_delay, bitline_vth_delay))
delays = [None] * 5
# keepout between p_en rising and wl_en falling
delays[0] = (wlen_signal_delay + wordline_delay) / inverter_stage_delay # could possibly subtract pen_signal_delay?
delays[0] = int(delays[0] * OPTS.delay_control_scaling_factor)
# round up to nearest even integer
delays[0] += delays[0] % 2
delays[2] = delays[0] + (pen_signal_delay + precharge_delay) / inverter_stage_delay
delays[2] *= OPTS.delay_control_scaling_factor
# round up to nearest odd integer
delays[2] = int(1 - (2 * ((1 - delays[2]) // 2)))
# delays[1] can be any even value less than delays[2]
delays[1] = delays[2] - 1
# keepout between p_en falling and wl_en rising
delays[3] = delays[2] + pen_signal_delay / inverter_stage_delay
delays[3] *= OPTS.delay_control_scaling_factor
delays[3] = int(1 - (2 * ((1 - delays[3]) // 2)))
delays[4] = delays[3] + (wlen_signal_delay + wordline_delay + bitline_vth_delay) / inverter_stage_delay
delays[4] *= OPTS.delay_control_scaling_factor
delays[4] = int(1 - (2 * ((1 - delays[4]) // 2)))
self.delay_chain_pinout_list = delays
# FIXME: fanout should be used to control delay chain height
# for now, use default/user-defined fanout constant
self.delay_chain_fanout_list = self.delay_chain_pinout_list[-1] * [OPTS.delay_chain_fanout_per_stage]
def setup_signal_busses(self):
""" Setup bus names, determine the size of the busses etc """
# List of input control signals
if self.port_type == "rw":
self.input_list = ["csb", "web"]
else:
self.input_list = ["csb"]
if self.port_type == "rw":
self.dff_output_list = ["cs_bar", "cs", "we_bar", "we"]
else:
self.dff_output_list = ["cs_bar", "cs"]
# list of output control signals (for making a vertical bus)
if self.port_type == "rw":
self.internal_bus_list = ["glitch1", "glitch2", "delay0", "delay1", "delay2", "delay3", "delay4", "gated_clk_bar", "gated_clk_buf", "we", "we_bar", "clk_buf", "cs"]
else:
self.internal_bus_list = ["glitch1", "glitch2", "delay0", "delay1", "delay2", "delay3", "delay4", "gated_clk_bar", "gated_clk_buf", "clk_buf", "cs"]
# leave space for the bus plus one extra space
self.internal_bus_width = (len(self.internal_bus_list) + 1) * self.m2_pitch
# Outputs to the bank
if self.port_type == "rw":
self.output_list = ["s_en", "w_en"]
elif self.port_type == "r":
self.output_list = ["s_en"]
else:
self.output_list = ["w_en"]
self.output_list.append("p_en_bar")
self.output_list.append("wl_en")
self.output_list.append("clk_buf")
self.supply_list = ["vdd", "gnd"]
def create_instances(self):
""" Create all the instances """
self.create_dffs()
self.create_clk_buf_row()
self.create_gated_clk_bar_row()
self.create_gated_clk_buf_row()
self.create_delay()
self.create_glitches()
self.create_wlen_row()
if (self.port_type == "rw") or (self.port_type == "w"):
self.create_wen_row()
if (self.port_type == "rw") or (self.port_type == "r"):
self.create_sen_row()
self.create_pen_row()
def place_logic_rows(self):
row = 0
self.place_clk_buf_row(row)
row += 1
self.place_gated_clk_bar_row(row)
row += 1
self.place_gated_clk_buf_row(row)
row += 1
if (self.port_type == "rw") or (self.port_type == "r"):
self.place_sen_row(row)
row += 1
if (self.port_type == "rw") or (self.port_type == "w"):
self.place_wen_row(row)
row += 1
self.place_pen_row(row)
row += 1
self.place_wlen_row(row)
row += 1
self.place_glitch1_row(row)
row += 1
self.place_glitch2_row(row)
self.control_center_y = self.glitch2_nand_inst.uy() + self.m3_pitch
def route_all(self):
""" Routing between modules """
self.route_rails()
self.route_dffs()
self.route_wlen()
if (self.port_type == "rw") or (self.port_type == "w"):
self.route_wen()
if (self.port_type == "rw") or (self.port_type == "r"):
self.route_sen()
self.route_delay()
self.route_pen()
self.route_glitches()
self.route_clk_buf()
self.route_gated_clk_bar()
self.route_gated_clk_buf()
self.route_supplies()
def create_delay(self):
""" Create the delay chain """
self.delay_inst=self.add_inst(name="multi_delay_chain",
mod=self.delay_chain)
self.connect_inst(["gated_clk_buf", "delay0", "delay1", "delay2", "delay3", "delay4", "vdd", "gnd"])
def route_delay(self):
# this is a bit of a hack because I would prefer to just name these pins delay in the layout
# instead I have this which duplicates the out_pin naming logic from multi_delay_chain.py
out_pins = ["out{}".format(str(pin)) for pin in self.delay_chain.pinout_list]
delay_map = zip(["in", out_pins[0], out_pins[1], out_pins[2], out_pins[3], out_pins[4]], \
["gated_clk_buf", "delay0", "delay1", "delay2", "delay3", "delay4"])
self.connect_vertical_bus(delay_map,
self.delay_inst,
self.input_bus,
self.m2_stack[::-1])
# glitch{0-2} are internal timing signals based on different in/out
# points on the delay chain for adjustable start time and duration
def create_glitches(self):
self.glitch0_nand_inst = self.add_inst(name="nand2_glitch0",
mod=self.nand2)
self.connect_inst(["delay0", "delay2", "glitch0", "vdd", "gnd"])
self.glitch1_nand_inst = self.add_inst(name="nand2_glitch1",
mod=self.nand2)
self.connect_inst(["gated_clk_buf", "delay3", "glitch1", "vdd", "gnd"])
self.glitch2_nand_inst = self.add_inst(name="nand2_glitch2",
mod=self.nand2)
self.connect_inst(["delay1", "delay4", "glitch2", "vdd", "gnd"])
# glitch0 is placed in place_pen_row()
def place_glitch1_row(self, row):
x_offset = self.control_x_offset
x_offset = self.place_util(self.glitch1_nand_inst, x_offset, row)
self.row_end_inst.append(self.glitch1_nand_inst)
def place_glitch2_row(self, row):
x_offset = self.control_x_offset
x_offset = self.place_util(self.glitch2_nand_inst, x_offset, row)
self.row_end_inst.append(self.glitch2_nand_inst)
def route_glitches(self):
glitch1_map = zip(["A", "B", "Z"], ["gated_clk_buf", "delay3", "glitch1"])
self.connect_vertical_bus(glitch1_map, self.glitch1_nand_inst, self.input_bus)
glitch2_map = zip(["A", "B", "Z"], ["delay1", "delay4", "glitch2"])
self.connect_vertical_bus(glitch2_map, self.glitch2_nand_inst, self.input_bus)
def create_wlen_row(self):
self.wl_en_unbuf_and_inst = self.add_inst(name="and_wl_en_unbuf",
mod=self.wl_en_and)
self.connect_inst(["cs", "glitch1", "wl_en_unbuf", "vdd", "gnd"])
self.wl_en_driver_inst=self.add_inst(name="buf_wl_en",
mod=self.wl_en_driver)
self.connect_inst(["wl_en_unbuf", "wl_en", "vdd", "gnd"])
def place_wlen_row(self, row):
x_offset = self.control_x_offset
x_offset = self.place_util(self.wl_en_unbuf_and_inst, x_offset, row)
x_offset = self.place_util(self.wl_en_driver_inst, x_offset, row)
self.row_end_inst.append(self.wl_en_driver_inst)
def route_wlen(self):
in_map = zip(["A", "B"], ["cs", "glitch1"])
self.connect_vertical_bus(in_map, self.wl_en_unbuf_and_inst, self.input_bus)
out_pin = self.wl_en_unbuf_and_inst.get_pin("Z")
out_pos = out_pin.center()
in_pin = self.wl_en_driver_inst.get_pin("A")
in_pos = in_pin.center()
mid1 = vector(out_pos.x, in_pos.y)
self.add_path(out_pin.layer, [out_pos, mid1, in_pos])
self.add_via_stack_center(from_layer=out_pin.layer,
to_layer=in_pin.layer,
offset=in_pin.center())
self.connect_output(self.wl_en_driver_inst, "Z", "wl_en")
def create_pen_row(self):
self.p_en_bar_driver_inst=self.add_inst(name="buf_p_en_bar",
mod=self.p_en_bar_driver)
self.connect_inst(["glitch0", "p_en_bar", "vdd", "gnd"])
def place_pen_row(self, row):
x_offset = self.control_x_offset
x_offset = self.place_util(self.glitch0_nand_inst, x_offset, row)
x_offset = self.place_util(self.p_en_bar_driver_inst, x_offset, row)
self.row_end_inst.append(self.p_en_bar_driver_inst)
def route_pen(self):
in_map = zip(["A", "B"], ["delay0", "delay2"])
self.connect_vertical_bus(in_map, self.glitch0_nand_inst, self.input_bus)
out_pin = self.glitch0_nand_inst.get_pin("Z") # same code here as wl_en, refactor?
out_pos = out_pin.center()
in_pin = self.p_en_bar_driver_inst.get_pin("A")
in_pos = in_pin.center()
mid1 = vector(in_pos.x, out_pos.y)
self.add_path(out_pin.layer, [out_pos, mid1, in_pos])
self.add_via_stack_center(from_layer=out_pin.layer,
to_layer=in_pin.layer,
offset=in_pin.center())
self.connect_output(self.p_en_bar_driver_inst, "Z", "p_en_bar")
def create_sen_row(self):
if self.port_type=="rw":
input_name = "we_bar"
else:
input_name = "cs"
self.s_en_gate_inst = self.add_inst(name="and_s_en",
mod=self.sen_and3)
self.connect_inst(["glitch2", "gated_clk_bar", input_name, "s_en", "vdd", "gnd"])
def place_sen_row(self, row):
x_offset = self.control_x_offset
x_offset = self.place_util(self.s_en_gate_inst, x_offset, row)
self.row_end_inst.append(self.s_en_gate_inst)
def route_sen(self):
if self.port_type=="rw": # this is repeated many times in here, refactor?
input_name = "we_bar"
else:
input_name = "cs"
sen_map = zip(["A", "B", "C"], ["glitch2", "gated_clk_bar", input_name])
self.connect_vertical_bus(sen_map, self.s_en_gate_inst, self.input_bus)
self.connect_output(self.s_en_gate_inst, "Z", "s_en")
def create_wen_row(self):
self.glitch2_bar_inv_inst = self.add_inst(name="inv_glitch2_bar",
mod=self.inv)
self.connect_inst(["glitch2", "glitch2_bar", "vdd", "gnd"])
if self.port_type == "rw":
input_name = "we"
else:
input_name = "cs"
self.w_en_gate_inst = self.add_inst(name="and_w_en",
mod=self.wen_and)
self.connect_inst([input_name, "glitch1", "glitch2_bar", "w_en", "vdd", "gnd"])
def place_wen_row(self, row):
x_offset = self.control_x_offset
x_offset = self.place_util(self.glitch2_bar_inv_inst, x_offset, row)
x_offset = self.place_util(self.w_en_gate_inst, x_offset, row)
self.row_end_inst.append(self.w_en_gate_inst)
def route_wen(self): # w_en comes from a 3and but one of the inputs needs to be inverted
glitch2_map = zip(["A"], ["glitch2"])
self.connect_vertical_bus(glitch2_map, self.glitch2_bar_inv_inst, self.input_bus)
out_pin = self.glitch2_bar_inv_inst.get_pin("Z")
out_pos = out_pin.center()
in_pin = self.w_en_gate_inst.get_pin("C")
in_pos = in_pin.center()
mid1 = vector(in_pos.x, out_pos.y)
self.add_path(out_pin.layer, [out_pos, mid1, in_pos])
self.add_via_stack_center(from_layer=out_pin.layer,
to_layer=in_pin.layer,
offset=in_pos)
if self.port_type == "rw":
input_name = "we"
else:
input_name = "cs"
# This is the second gate over, so it needs to be on M3
wen_map = zip(["A", "B"], [input_name, "glitch1"])
self.connect_vertical_bus(wen_map,
self.w_en_gate_inst,
self.input_bus,
self.m2_stack[::-1])
# The pins are on M1, so we need more vias as well
a_pin = self.w_en_gate_inst.get_pin("A")
self.add_via_stack_center(from_layer=a_pin.layer,
to_layer="m3",
offset=a_pin.center())
b_pin = self.w_en_gate_inst.get_pin("B")
self.add_via_stack_center(from_layer=b_pin.layer,
to_layer="m3",
offset=b_pin.center())
self.connect_output(self.w_en_gate_inst, "Z", "w_en")

View File

@ -20,14 +20,31 @@ class global_bitcell_array(bitcell_base_array):
Rows is an integer number for all local arrays.
Cols is a list of the array widths.
"""
def __init__(self, rows, cols, name=""):
def __init__(self, rows, cols, rbl=None, left_rbl=None, right_rbl=None, name=""):
# The total of all columns will be the number of columns
super().__init__(name=name, rows=rows, cols=sum(cols), column_offset=0)
self.column_sizes = cols
self.col_offsets = [0] + list(cumsum(cols)[:-1])
debug.check(len(self.all_ports)<=2, "Only support dual port or less in global bitcell array.")
self.rbl = [1, 1 if len(self.all_ports)>1 else 0]
debug.check(len(self.all_ports) < 3, "Only support dual port or less in global bitcell array.")
# This is how many RBLs are in all the arrays
if rbl is not None:
self.rbl = rbl
else:
self.rbl = [0] * len(self.all_ports)
# This specifies which RBL to put on the left or right by port number
# This could be an empty list
if left_rbl is not None:
self.left_rbl = left_rbl
else:
self.left_rbl = []
# This could be an empty list
if right_rbl is not None:
self.right_rbl = right_rbl
else:
self.right_rbl=[]
self.rbls = self.left_rbl + self.right_rbl
self.create_netlist()
if not OPTS.netlist_only:
@ -56,14 +73,13 @@ class global_bitcell_array(bitcell_base_array):
self.local_mods = []
# Special case of a single local array
# so it should contain the left and possibly right RBL
if len(self.column_sizes) == 1:
la = factory.create(module_type="local_bitcell_array",
rows=self.row_size,
cols=self.column_sizes[0],
rbl=self.rbl,
left_rbl=[0],
right_rbl=[1] if len(self.all_ports) > 1 else [])
left_rbl=self.left_rbl,
right_rbl=self.right_rbl)
self.local_mods.append(la)
return
@ -74,14 +90,14 @@ class global_bitcell_array(bitcell_base_array):
rows=self.row_size,
cols=cols,
rbl=self.rbl,
left_rbl=[0])
# Add the right RBL to the last subarray
elif i == len(self.column_sizes) - 1 and len(self.all_ports) > 1:
left_rbl=self.left_rbl)
# Add the right RBLs to the last subarray
elif i == len(self.column_sizes) - 1:
la = factory.create(module_type="local_bitcell_array",
rows=self.row_size,
cols=cols,
rbl=self.rbl,
right_rbl=[1])
right_rbl=self.right_rbl)
# Middle subarrays do not have any RBLs
else:
la = factory.create(module_type="local_bitcell_array",
@ -100,13 +116,16 @@ class global_bitcell_array(bitcell_base_array):
self.add_pin("gnd", "GROUND")
def add_bitline_pins(self):
# FIXME: aren't these already defined via inheritence by bitcell base array?
self.bitline_names = [[] for x in self.all_ports]
self.rbl_bitline_names = [[] for x in self.all_ports]
for port in self.all_ports:
self.rbl_bitline_names[0].append("rbl_bl_{}_0".format(port))
for port in self.all_ports:
self.rbl_bitline_names[0].append("rbl_br_{}_0".format(port))
# The bit is which port the RBL is for
for bit in self.rbls:
for port in self.all_ports:
self.rbl_bitline_names[bit].append("rbl_bl_{0}_{1}".format(port, bit))
for port in self.all_ports:
self.rbl_bitline_names[bit].append("rbl_br_{0}_{1}".format(port, bit))
for col in range(self.column_size):
for port in self.all_ports:
@ -114,21 +133,16 @@ class global_bitcell_array(bitcell_base_array):
for port in self.all_ports:
self.bitline_names[port].append("br_{0}_{1}".format(port, col))
if len(self.all_ports) > 1:
for port in self.all_ports:
self.rbl_bitline_names[1].append("rbl_bl_{}_1".format(port))
for port in self.all_ports:
self.rbl_bitline_names[1].append("rbl_br_{}_1".format(port))
# Make a flat list too
self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl]
# Make a flat list too
self.all_rbl_bitline_names = [x for sl in zip(*self.rbl_bitline_names) for x in sl]
self.add_pin_list(self.rbl_bitline_names[0], "INOUT")
for port in self.left_rbl:
self.add_pin_list(self.rbl_bitline_names[port], "INOUT")
self.add_pin_list(self.all_bitline_names, "INOUT")
if len(self.all_ports) > 1:
self.add_pin_list(self.rbl_bitline_names[1], "INOUT")
for port in self.right_rbl:
self.add_pin_list(self.rbl_bitline_names[port], "INOUT")
def add_wordline_pins(self):
@ -137,6 +151,8 @@ class global_bitcell_array(bitcell_base_array):
self.wordline_names = [[] for x in self.all_ports]
for bit in self.all_ports:
if self.rbl[bit] == 0:
continue
for port in self.all_ports:
self.rbl_wordline_names[port].append("rbl_wl_{0}_{1}".format(port, bit))
@ -239,17 +255,18 @@ class global_bitcell_array(bitcell_base_array):
start=left_pin.lc(),
end=right_pin.rc())
# Replica bitlines
self.copy_layout_pin(self.local_insts[0], "rbl_bl_0_0")
self.copy_layout_pin(self.local_insts[0], "rbl_br_0_0")
if len(self.rbls) > 0:
# Replica bitlines
self.copy_layout_pin(self.local_insts[0], "rbl_bl_0_0")
self.copy_layout_pin(self.local_insts[0], "rbl_br_0_0")
if len(self.all_ports) > 1:
self.copy_layout_pin(self.local_insts[0], "rbl_bl_1_0")
self.copy_layout_pin(self.local_insts[0], "rbl_br_1_0")
self.copy_layout_pin(self.local_insts[-1], "rbl_bl_0_1")
self.copy_layout_pin(self.local_insts[-1], "rbl_br_0_1")
self.copy_layout_pin(self.local_insts[-1], "rbl_bl_1_1")
self.copy_layout_pin(self.local_insts[-1], "rbl_br_1_1")
if len(self.all_ports) > 1:
self.copy_layout_pin(self.local_insts[0], "rbl_bl_1_0")
self.copy_layout_pin(self.local_insts[0], "rbl_br_1_0")
self.copy_layout_pin(self.local_insts[-1], "rbl_bl_0_1")
self.copy_layout_pin(self.local_insts[-1], "rbl_br_0_1")
self.copy_layout_pin(self.local_insts[-1], "rbl_bl_1_1")
self.copy_layout_pin(self.local_insts[-1], "rbl_br_1_1")
for inst in self.insts:
self.copy_power_pins(inst, "vdd")

View File

@ -31,7 +31,10 @@ class local_bitcell_array(bitcell_base_array):
self.rows = rows
self.cols = cols
# This is how many RBLs are in all the arrays
self.rbl = rbl
if rbl is not None:
self.rbl = rbl
else:
self.rbl = [0] * len(self.all_ports)
# This specifies which RBL to put on the left or right by port number
# This could be an empty list
if left_rbl is not None:
@ -84,8 +87,11 @@ class local_bitcell_array(bitcell_base_array):
left_rbl=self.left_rbl,
right_rbl=self.right_rbl)
# FIXME: this won't allow asymetric configurations such as rbl=[0, 1]
# but neither does a lot of this code...
rows = self.rows + (sum(self.rbl) != 0)
self.wl_array = factory.create(module_type="wordline_buffer_array",
rows=self.rows + 1,
rows=rows,
cols=self.cols)
def add_pins(self):
@ -136,7 +142,8 @@ class local_bitcell_array(bitcell_base_array):
self.wl_insts.append(self.add_inst(name="wl_driver{}".format(port),
mod=self.wl_array))
temp = []
temp += [self.get_rbl_wordline_names(port)[port]]
if self.rbl[port] != 0:
temp += [self.get_rbl_wordline_names(port)[port]]
if port == 0:
temp += self.get_wordline_names(port)
else:
@ -180,8 +187,9 @@ class local_bitcell_array(bitcell_base_array):
self.bitcell_array_inst.place(bitcell_array_offset)
if len(self.all_ports) > 1:
rbl_wl_adder = self.cell.height * (self.rbl[1] != 0)
wl_offset = vector(self.bitcell_array_inst.rx() + self.wl_array.width + driver_to_array_spacing,
self.bitcell_array.get_replica_bottom() + self.wl_array.height + self.cell.height)
self.bitcell_array.get_replica_bottom() + self.wl_array.height + rbl_wl_adder)
self.wl_insts[1].place(wl_offset,
mirror="XY")
@ -209,10 +217,16 @@ class local_bitcell_array(bitcell_base_array):
# Route the global wordlines
for port in self.all_ports:
if port == 0:
wordline_names = [self.get_rbl_wordline_names(port)[port]] + self.get_wordline_names(port)
if self.rbl[port] != 0:
if port == 0:
wordline_names = [self.get_rbl_wordline_names(port)[port]] + self.get_wordline_names(port)
else:
wordline_names = [self.get_rbl_wordline_names(port)[port]] + self.get_wordline_names(port)[::-1]
else:
wordline_names = [self.get_rbl_wordline_names(port)[port]] + self.get_wordline_names(port)[::-1]
if port == 0:
wordline_names = self.get_wordline_names(port)
else:
wordline_names = self.get_wordline_names(port)[::-1]
wordline_pins = self.wl_array.get_inputs()

View File

@ -0,0 +1,229 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
from openram import debug
from openram.base import design
from openram.base import vector
from openram.sram_factory import factory
from openram import OPTS
class multi_delay_chain(design):
"""
Generate a delay chain with the given number of stages, fanout, and output pins.
Fanout list contains the electrical effort (fanout) of each stage.
Usually, this will be constant, but it could have varied fanout.
Pinout list contains the inverter stages which have an output pin attached.
Supplying an empty pinout list will result in an output only on the last stage.
"""
def __init__(self, name, fanout_list, pinout_list=None):
"""init function"""
super().__init__(name)
debug.info(1, "creating delay chain with {0}".format("fanouts: " + str(fanout_list) + " pinouts: " + str(pinout_list)))
self.add_comment("fanouts: {0}".format(str(fanout_list)))
self.add_comment("pinouts: {0}".format(str(pinout_list)))
# Two fanouts are needed so that we can route the vdd/gnd connections
for f in fanout_list:
debug.check(f>=2, "Must have >=2 fanouts for each stage.")
# number of inverters including any fanout loads.
self.fanout_list = fanout_list
self.rows = len(self.fanout_list)
# defaults to signle output at end of delay chain
if not pinout_list:
self.pinout_list = [self.rows] # TODO: check for off-by-one here
else:
self.pinout_list = pinout_list
# TODO: would like to sort and check pinout list for valid format but don't have time now
# Check pinout bounds
# debug.check(self.pinout_list[-1] <= self.rows,
# "Ouput pin cannot exceed delay chain length.")
# debug.check(self.pinout_list[0] > 0,
# "Delay chain output pin numbers must be positive")
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
def create_netlist(self):
self.add_modules()
self.add_pins()
self.create_inverters()
def create_layout(self):
# Each stage is a row
self.height = self.rows * self.inv.height
# The width is determined by the largest fanout plus the driver
self.width = (max(self.fanout_list) + 1) * self.inv.width
self.place_inverters()
self.route_inverters()
self.route_supplies()
self.add_layout_pins()
self.add_boundary()
self.DRC_LVS()
def add_pins(self):
""" Add the pins of the delay chain"""
self.add_pin("in", "INPUT")
for pin_stage in self.pinout_list:
self.add_pin("out{}".format(pin_stage), "OUTPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def add_modules(self):
self.dff = factory.create(module_type="dff_buf")
dff_height = self.dff.height
self.inv = factory.create(module_type="pinv",
height=dff_height)
def create_inverters(self):
""" Create the inverters and connect them based on the stage list """
self.driver_inst_list = []
self.load_inst_map = {}
for stage_num, fanout_size in zip(range(self.rows), self.fanout_list):
# Add the inverter
cur_driver=self.add_inst(name="dinv{}".format(stage_num),
mod=self.inv)
# keep track of the inverter instances so we can use them to get the pins
self.driver_inst_list.append(cur_driver)
# Hook up the driver
stageout_name = "out{}".format(stage_num + 1) # TODO: check for off-by-one here
if stage_num == 0:
stagein_name = "in"
else:
stagein_name = "out{}".format(stage_num)
self.connect_inst([stagein_name, stageout_name, "vdd", "gnd"])
# Now add the dummy loads to the right
self.load_inst_map[cur_driver]=[]
for i in range(fanout_size):
cur_load=self.add_inst(name="dload_{0}_{1}".format(stage_num, i),
mod=self.inv)
# Fanout stage is always driven by driver and output is disconnected
disconnect_name = "n_{0}_{1}".format(stage_num, i)
self.connect_inst([stageout_name, disconnect_name, "vdd", "gnd"])
# Keep track of all the loads to connect their inputs as a load
self.load_inst_map[cur_driver].append(cur_load)
def place_inverters(self):
""" Place the inverters and connect them based on the stage list """
for stage_num, fanout_size in zip(range(self.rows), self.fanout_list):
if stage_num % 2:
inv_mirror = "MX"
inv_offset = vector(0, (stage_num + 1) * self.inv.height)
else:
inv_mirror = "R0"
inv_offset = vector(0, stage_num * self.inv.height)
# Add the inverter
cur_driver=self.driver_inst_list[stage_num]
cur_driver.place(offset=inv_offset,
mirror=inv_mirror)
# Now add the dummy loads to the right
load_list = self.load_inst_map[cur_driver]
for i in range(fanout_size):
inv_offset += vector(self.inv.width, 0)
load_list[i].place(offset=inv_offset,
mirror=inv_mirror)
def add_route(self, pin1, pin2):
""" This guarantees that we route from the top to bottom row correctly. """
pin1_pos = pin1.center()
pin2_pos = pin2.center()
if pin1_pos.y == pin2_pos.y:
self.add_path("m2", [pin1_pos, pin2_pos])
else:
mid_point = vector(pin2_pos.x, 0.5 * (pin1_pos.y + pin2_pos.y))
# Written this way to guarantee it goes right first if we are switching rows
self.add_path("m2", [pin1_pos, vector(pin1_pos.x, mid_point.y), mid_point, vector(mid_point.x, pin2_pos.y), pin2_pos])
def route_inverters(self):
""" Add metal routing for each of the fanout stages """
for i in range(len(self.driver_inst_list)):
inv = self.driver_inst_list[i]
for load in self.load_inst_map[inv]:
# Drop a via on each A pin
a_pin = load.get_pin("A")
self.add_via_stack_center(from_layer=a_pin.layer,
to_layer="m3",
offset=a_pin.center())
# Route an M3 horizontal wire to the furthest
z_pin = inv.get_pin("Z")
a_pin = inv.get_pin("A")
a_max = self.load_inst_map[inv][-1].get_pin("A")
self.add_via_stack_center(from_layer=a_pin.layer,
to_layer="m2",
offset=a_pin.center())
self.add_via_stack_center(from_layer=z_pin.layer,
to_layer="m3",
offset=z_pin.center())
self.add_path("m3", [z_pin.center(), a_max.center()])
# Route Z to the A of the next stage
if i + 1 < len(self.driver_inst_list):
z_pin = inv.get_pin("Z")
next_inv = self.driver_inst_list[i + 1]
next_a_pin = next_inv.get_pin("A")
y_mid = (z_pin.cy() + next_a_pin.cy()) / 2
mid1_point = vector(z_pin.cx(), y_mid)
mid2_point = vector(next_a_pin.cx(), y_mid)
self.add_path("m2", [z_pin.center(), mid1_point, mid2_point, next_a_pin.center()])
def route_supplies(self):
# Add power and ground to all the cells except:
# the fanout driver, the right-most load
# The routing to connect the loads is over the first and last cells
# We have an even number of drivers and must only do every other
# supply rail
for inst in self.driver_inst_list:
load_list = self.load_inst_map[inst]
for pin_name in ["vdd", "gnd"]:
pin = load_list[0].get_pin(pin_name)
self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0))
pin = load_list[-2].get_pin(pin_name)
self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0))
def add_layout_pins(self):
# input is A pin of first inverter
# It gets routed down a bit to prevent overlapping adjacent
# M3 when connecting to vertical bus
a_pin = self.driver_inst_list[0].get_pin("A")
mid_loc = vector(a_pin.cx(), a_pin.cy() - self.m3_pitch)
self.add_via_stack_center(from_layer=a_pin.layer,
to_layer="m3",
offset=mid_loc)
self.add_path("m2", [a_pin.center(), mid_loc])
self.add_layout_pin_rect_center(text="in",
layer="m3",
offset=mid_loc)
for pin_number in self.pinout_list:
# pin is A pin of right-most load/fanout inverter
output_driver_inst = self.driver_inst_list[pin_number - 1]
a_pin = self.load_inst_map[output_driver_inst][-1].get_pin("A")
self.add_via_stack_center(from_layer=a_pin.layer,
to_layer="m3",
offset=a_pin.center())
self.add_layout_pin_rect_center(text="out{}".format(str(pin_number)),
layer="m3",
offset=a_pin.center())

View File

@ -18,11 +18,12 @@ class port_address(design):
Create the address port (row decoder and wordline driver)..
"""
def __init__(self, cols, rows, port, name=""):
def __init__(self, cols, rows, port, has_rbl, name=""):
self.num_cols = cols
self.num_rows = rows
self.port = port
self.has_rbl = has_rbl
self.addr_size = ceil(log(self.num_rows, 2))
if name == "":
@ -41,7 +42,8 @@ class port_address(design):
self.add_modules()
self.create_row_decoder()
self.create_wordline_driver()
self.create_rbl_driver()
if self.has_rbl:
self.create_rbl_driver()
def create_layout(self):
if "li" in layer:
@ -63,7 +65,8 @@ class port_address(design):
for bit in range(self.num_rows):
self.add_pin("wl_{0}".format(bit), "OUTPUT")
self.add_pin("rbl_wl", "OUTPUT")
if self.has_rbl:
self.add_pin("rbl_wl", "OUTPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
@ -76,12 +79,13 @@ class port_address(design):
def route_supplies(self):
""" Propagate all vdd/gnd pins up to this level for all modules """
if layer_props.wordline_driver.vertical_supply:
self.copy_layout_pin(self.rbl_driver_inst, "vdd")
else:
rbl_pos = self.rbl_driver_inst.get_pin("vdd").rc()
self.add_power_pin("vdd", rbl_pos)
self.add_path("m4", [rbl_pos, self.wordline_driver_array_inst.get_pins("vdd")[0].rc()])
if self.has_rbl:
if layer_props.wordline_driver.vertical_supply:
self.copy_layout_pin(self.rbl_driver_inst, "vdd")
else:
rbl_pos = self.rbl_driver_inst.get_pin("vdd").rc()
self.add_power_pin("vdd", rbl_pos)
self.add_path("m4", [rbl_pos, self.wordline_driver_array_inst.get_pins("vdd")[0].rc()])
self.copy_layout_pin(self.wordline_driver_array_inst, "vdd")
self.copy_layout_pin(self.wordline_driver_array_inst, "gnd")
@ -90,11 +94,12 @@ class port_address(design):
self.copy_layout_pin(self.row_decoder_inst, "gnd")
# Also connect the B input of the RBL and_dec to vdd
if OPTS.local_array_size == 0:
rbl_b_pin = self.rbl_driver_inst.get_pin("B")
rbl_loc = rbl_b_pin.center() - vector(3 * self.m1_pitch, 0)
self.add_path(rbl_b_pin.layer, [rbl_b_pin.center(), rbl_loc])
self.add_power_pin("vdd", rbl_loc, start_layer=rbl_b_pin.layer)
if self.has_rbl:
if OPTS.local_array_size == 0:
rbl_b_pin = self.rbl_driver_inst.get_pin("B")
rbl_loc = rbl_b_pin.center() - vector(3 * self.m1_pitch, 0)
self.add_path(rbl_b_pin.layer, [rbl_b_pin.center(), rbl_loc])
self.add_power_pin("vdd", rbl_loc, start_layer=rbl_b_pin.layer)
def route_pins(self):
for row in range(self.addr_size):
@ -105,7 +110,8 @@ class port_address(design):
driver_name = "wl_{}".format(row)
self.copy_layout_pin(self.wordline_driver_array_inst, driver_name)
self.copy_layout_pin(self.rbl_driver_inst, "Z", "rbl_wl")
if self.has_rbl:
self.copy_layout_pin(self.rbl_driver_inst, "Z", "rbl_wl")
def route_internal(self):
for row in range(self.num_rows):
@ -130,19 +136,25 @@ class port_address(design):
en_pos = en_pin.bc()
else:
en_pos = en_pin.uc()
rbl_in_pin = self.rbl_driver_inst.get_pin("A")
rbl_in_pos = rbl_in_pin.center()
self.add_via_stack_center(from_layer=rbl_in_pin.layer,
to_layer=en_pin.layer,
offset=rbl_in_pos)
self.add_zjog(layer=en_pin.layer,
start=rbl_in_pos,
end=en_pos,
first_direction="V")
if self.has_rbl:
rbl_in_pin = self.rbl_driver_inst.get_pin("A")
rbl_in_pos = rbl_in_pin.center()
wl_en_offset = rbl_in_pos
self.add_via_stack_center(from_layer=rbl_in_pin.layer,
to_layer=en_pin.layer,
offset=rbl_in_pos)
self.add_zjog(layer=en_pin.layer,
start=rbl_in_pos,
end=en_pos,
first_direction="V")
else:
wl_en_offset = en_pos
self.add_layout_pin_rect_center(text="wl_en",
layer=en_pin.layer,
offset=rbl_in_pos)
offset=wl_en_offset)
def add_modules(self):
@ -164,16 +176,17 @@ class port_address(design):
# to compensate for the local array inverters
b = factory.create(module_type=OPTS.bitcell)
if local_array_size > 0:
# The local wordline driver will change the polarity
self.rbl_driver = factory.create(module_type="inv_dec",
size=driver_size,
height=b.height)
else:
# There is no local wordline driver
self.rbl_driver = factory.create(module_type="and2_dec",
size=driver_size,
height=b.height)
if self.has_rbl:
if local_array_size > 0:
# The local wordline driver will change the polarity
self.rbl_driver = factory.create(module_type="inv_dec",
size=driver_size,
height=b.height)
else:
# There is no local wordline driver
self.rbl_driver = factory.create(module_type="and2_dec",
size=driver_size,
height=b.height)
def create_row_decoder(self):
""" Create the hierarchical row decoder """
@ -231,16 +244,17 @@ class port_address(design):
wordline_driver_array_offset = vector(self.row_decoder_inst.rx(), 0)
self.wordline_driver_array_inst.place(wordline_driver_array_offset)
# This m4_pitch corresponds to the offset space for jog routing in the
# wordline_driver_array
rbl_driver_offset = wordline_driver_array_offset + vector(2 * self.m4_pitch, 0)
if self.has_rbl:
# This m4_pitch corresponds to the offset space for jog routing in the
# wordline_driver_array
rbl_driver_offset = wordline_driver_array_offset + vector(2 * self.m4_pitch, 0)
if self.port == 0:
self.rbl_driver_inst.place(rbl_driver_offset, "MX")
else:
rbl_driver_offset += vector(0,
self.wordline_driver_array.height)
self.rbl_driver_inst.place(rbl_driver_offset)
if self.port == 0:
self.rbl_driver_inst.place(rbl_driver_offset, "MX")
else:
rbl_driver_offset += vector(0,
self.wordline_driver_array.height)
self.rbl_driver_inst.place(rbl_driver_offset)
# Pass this up
self.predecoder_height = self.row_decoder.predecoder_height

View File

@ -18,13 +18,14 @@ from openram import OPTS
class port_data(design):
"""
Create the data port (column mux, sense amps, write driver, etc.) for the given port number.
Port 0 always has the RBL on the left while port 1 is on the right.
When RBLs present: port 0 always has the RBL on the left while port 1 is on the right.
"""
def __init__(self, sram_config, port, num_spare_cols=None, bit_offsets=None, name="",):
def __init__(self, sram_config, port, has_rbl, num_spare_cols=None, bit_offsets=None, name="",):
sram_config.set_local_config(self)
self.port = port
self.has_rbl = has_rbl
if self.write_size != self.word_size:
self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
else:
@ -115,8 +116,9 @@ class port_data(design):
def add_pins(self):
""" Adding pins for port data module"""
self.add_pin("rbl_bl", "INOUT")
self.add_pin("rbl_br", "INOUT")
if self.has_rbl:
self.add_pin("rbl_bl", "INOUT")
self.add_pin("rbl_br", "INOUT")
for bit in range(self.num_cols):
self.add_pin("bl_{0}".format(bit), "INOUT")
self.add_pin("br_{0}".format(bit), "INOUT")
@ -202,15 +204,19 @@ class port_data(design):
precharge_width = cell.width + strap.width
else:
precharge_width = cell.width
if self.port == 0:
# Append an offset on the left
precharge_bit_offsets = [self.bit_offsets[0] - precharge_width] + self.bit_offsets
if self.has_rbl:
if self.port == 0:
# Append an offset on the left
precharge_bit_offsets = [self.bit_offsets[0] - precharge_width] + self.bit_offsets
else:
# Append an offset on the right
precharge_bit_offsets = self.bit_offsets + [self.bit_offsets[-1] + precharge_width]
else:
# Append an offset on the right
precharge_bit_offsets = self.bit_offsets + [self.bit_offsets[-1] + precharge_width]
precharge_bit_offsets = self.bit_offsets
# has_rbl is a boolean treated as 1 if true 0 if false typical python
self.precharge_array = factory.create(module_type="precharge_array",
columns=self.num_cols + self.num_spare_cols + 1,
columns=self.num_cols + self.num_spare_cols + self.has_rbl,
offsets=precharge_bit_offsets,
bitcell_bl=self.bl_names[self.port],
bitcell_br=self.br_names[self.port],
@ -294,7 +300,7 @@ class port_data(design):
mod=self.precharge_array)
temp = []
# Use left BLs for RBL
if self.port==0:
if self.port==0 and self.has_rbl:
temp.append("rbl_bl")
temp.append("rbl_br")
for bit in range(self.num_cols):
@ -306,7 +312,7 @@ class port_data(design):
temp.append("sparebr_{0}".format(bit))
# Use right BLs for RBL
if self.port==1:
if self.port==1 and self.has_rbl:
temp.append("rbl_bl")
temp.append("rbl_br")
temp.extend(["p_en_bar", "vdd"])
@ -537,7 +543,7 @@ class port_data(design):
if self.col_addr_size==0:
return
start_bit = 1 if self.port == 0 else 0
start_bit = 1 if self.port == 0 and self.has_rbl else 0
self.connect_bitlines(inst1=self.column_mux_array_inst,
inst2=self.precharge_array_inst,
@ -558,7 +564,7 @@ class port_data(design):
inst1 = self.precharge_array_inst
inst1_bls_templ="{inst}_{bit}"
if self.port==0:
if self.port==0 and self.has_rbl:
start_bit=1
else:
start_bit=0
@ -683,11 +689,11 @@ class port_data(design):
""" Add the bitline pins for the given port """
# Connect one bitline to the RBL and offset the indices for the other BLs
if self.port==0:
if self.port==0 and self.has_rbl:
self.copy_layout_pin(self.precharge_array_inst, "bl_0", "rbl_bl")
self.copy_layout_pin(self.precharge_array_inst, "br_0", "rbl_br")
bit_offset=1
elif self.port==1:
elif self.port==1 and self.has_rbl:
self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(self.num_cols + self.num_spare_cols), "rbl_bl")
self.copy_layout_pin(self.precharge_array_inst, "br_{}".format(self.num_cols + self.num_spare_cols), "rbl_br")
bit_offset=0

View File

@ -16,11 +16,11 @@ from .bitcell_base_array import bitcell_base_array
class replica_bitcell_array(bitcell_base_array):
"""
Creates a bitcell array of cols x rows and then adds the replica
and dummy columns and rows. Replica columns are on the left and
columns and dummy rows. Replica columns are on the left and
right, respectively and connected to the given bitcell ports.
Dummy are the outside columns/rows with WL and BL tied to gnd.
Requires a regular bitcell array, replica bitcell, and dummy
bitcell (BL/BR disconnected).
Dummy rows are on the top and bottom passing through the RBL WLs.
Requires a regular bitcell array and (if using replica topology)
replica bitcell and dummy bitcell (BL/BR disconnected).
"""
def __init__(self, rows, cols, rbl=None, left_rbl=None, right_rbl=None, name=""):
super().__init__(name=name, rows=rows, cols=cols, column_offset=0)
@ -36,22 +36,29 @@ class replica_bitcell_array(bitcell_base_array):
self.column_size = cols
self.row_size = rows
# This is how many RBLs are in all the arrays
self.rbl = rbl
# This specifies which RBL to put on the left or right by port number
# This could be an empty list
# Even if the RBL is not placed in this array, the module still needs
# to place dummy rows with rbl wordlines so that they will have the same
# load as the regular wordlines (and so the arrays are the same size)
if rbl is not None:
self.rbl = rbl
else:
self.rbl = [0] * len(self.all_ports)
# This specifies how many RBLs to put on the left by port number.
# For example, left_rbl = [0, 1] means there will be two
# RBLs on the left, one for port 0 and another for port 1.
if left_rbl is not None:
self.left_rbl = left_rbl
else:
self.left_rbl = []
# This could be an empty list
# Similar to left_rbl but on the right side of the array
if right_rbl is not None:
self.right_rbl = right_rbl
else:
self.right_rbl=[]
self.right_rbl = []
self.rbls = self.left_rbl + self.right_rbl
debug.check(sum(self.rbl) >= len(self.left_rbl) + len(self.right_rbl),
"Invalid number of RBLs for port configuration.")
"Cannot have more left + right RBLs than total RBLs")
self.create_netlist()
if not OPTS.netlist_only:
@ -64,28 +71,7 @@ class replica_bitcell_array(bitcell_base_array):
self.create_instances()
def add_modules(self):
""" Array and dummy/replica columns
d or D = dummy cell (caps to distinguish grouping)
r or R = replica cell (caps to distinguish grouping)
b or B = bitcell
replica columns 1
v v
bdDDDDDDDDDDDDDDdb <- Dummy row
bdDDDDDDDDDDDDDDrb <- Dummy row
br--------------rb
br| Array |rb
br| row x col |rb
br--------------rb
brDDDDDDDDDDDDDDdb <- Dummy row
bdDDDDDDDDDDDDDDdb <- Dummy row
^^^^^^^^^^^^^^^
dummy rows cols x 1
^ dummy columns ^
1 x (rows + 4)
"""
""" Array and dummy/replica columns """
# Bitcell array
self.bitcell_array = factory.create(module_type="bitcell_array",
column_offset=1 + len(self.left_rbl),
@ -96,18 +82,14 @@ class replica_bitcell_array(bitcell_base_array):
self.replica_columns = {}
for port in self.all_ports:
# We will always have self.rbl[0] dummy rows below the array
# for the replica wordlines.
if port in self.left_rbl:
# We will always have self.rbl[0] rows of replica wordlines below
# the array.
# These go from the top (where the bitcell array starts ) down
# These go top down starting from the bottom of the bitcell array.
replica_bit = self.rbl[0] - port - 1
column_offset = len(self.left_rbl)
elif port in self.right_rbl:
# We will always have self.rbl[0] rows of replica wordlines below
# the array.
# These go from the bottom up
# These go bottom up starting from the top of the bitcell array.
replica_bit = self.rbl[0] + self.row_size + port - 1
column_offset = len(self.left_rbl) + self.column_size + 1
else:
@ -119,11 +101,13 @@ class replica_bitcell_array(bitcell_base_array):
column_offset=column_offset,
replica_bit=replica_bit)
# Dummy row
# Dummy row (for replica wordlines)
self.dummy_row = factory.create(module_type="dummy_array",
cols=self.column_size,
rows=1,
# dummy column + left replica column
# cap column + left replica column
# FIXME: these col offsets should really start at 0 because
# this is the left edge of the array... but changing them all is work
column_offset=1 + len(self.left_rbl),
mirror=0)
@ -148,7 +132,7 @@ class replica_bitcell_array(bitcell_base_array):
self.add_pin("gnd", "GROUND")
def add_bitline_pins(self):
# The bit is which port the RBL is for
# The bit represents which port the RBL is for
for bit in self.rbls:
for port in self.all_ports:
self.rbl_bitline_names[bit].append("rbl_bl_{0}_{1}".format(port, bit))
@ -175,6 +159,8 @@ class replica_bitcell_array(bitcell_base_array):
self.unused_wordline_names = []
for port in self.all_ports:
if self.rbl[port] == 0:
continue # TODO: there's probably a better way to do this check
for bit in self.all_ports:
self.rbl_wordline_names[port].append("rbl_wl_{0}_{1}".format(port, bit))
if bit != port:
@ -225,9 +211,12 @@ class replica_bitcell_array(bitcell_base_array):
self.dummy_row_replica_insts = []
# Note, this is the number of left and right even if we aren't adding the columns to this bitcell array!
for port in self.all_ports: # TODO: tie to self.rbl or whatever
self.dummy_row_replica_insts.append(self.add_inst(name="dummy_row_{}".format(port),
mod=self.dummy_row))
self.connect_inst(self.all_bitline_names + self.rbl_wordline_names[port] + self.supplies)
if self.rbl[port] != 0:
self.dummy_row_replica_insts.append(self.add_inst(name="dummy_row_{}".format(port),
mod=self.dummy_row))
self.connect_inst(self.all_bitline_names + self.rbl_wordline_names[port] + self.supplies)
else:
self.dummy_row_replica_insts.append(None)
def create_layout(self):
@ -249,8 +238,8 @@ class replica_bitcell_array(bitcell_base_array):
# Array was at (0, 0) but move everything so it is at the lower left
# We move DOWN the number of left RBL even if we didn't add the column to this bitcell array
# Note that this doesn't include the row/col cap
array_offset = self.bitcell_offset.scale(len(self.left_rbl), self.rbl[0])
self.translate_all(array_offset.scale(-1, -1))
array_offset = self.bitcell_offset.scale(-len(self.left_rbl), -self.rbl[0])
self.translate_all(array_offset)
self.add_layout_pins()
@ -359,7 +348,7 @@ class replica_bitcell_array(bitcell_base_array):
height=self.height)
def route_supplies(self):
""" just copy supply pins from all instances """
for inst in self.insts:
for pin_name in ["vdd", "gnd"]:
self.copy_layout_pin(inst, pin_name)

View File

@ -49,6 +49,9 @@ class sram_1bank(design, verilog, lef):
# Route a M3/M4 grid
self.supply_stack = self.m3_stack
# delay control logic does not have RBLs
self.has_rbl = OPTS.control_logic != "control_logic_delay"
def add_pins(self):
""" Add pins for entire SRAM. """
@ -518,8 +521,9 @@ class sram_1bank(design, verilog, lef):
for port in self.read_ports:
for bit in range(self.word_size + self.num_spare_cols):
temp.append("dout{0}[{1}]".format(port, bit))
for port in self.all_ports:
temp.append("rbl_bl{0}".format(port))
if self.has_rbl:
for port in self.all_ports:
temp.append("rbl_bl{0}".format(port))
for port in self.write_ports:
for bit in range(self.word_size + self.num_spare_cols):
temp.append("bank_din{0}_{1}".format(port, bit))
@ -694,7 +698,8 @@ class sram_1bank(design, verilog, lef):
if port in self.readwrite_ports:
temp.append("web{}".format(port))
temp.append("clk{}".format(port))
temp.append("rbl_bl{}".format(port))
if self.has_rbl:
temp.append("rbl_bl{}".format(port))
# Outputs
if port in self.read_ports:
@ -1293,18 +1298,19 @@ class sram_1bank(design, verilog, lef):
dest_pin = self.bank_inst.get_pin(signal + "{}".format(port))
self.connect_vbus(src_pin, dest_pin)
for port in self.all_ports:
# Only input (besides pins) is the replica bitline
src_pin = self.control_logic_insts[port].get_pin("rbl_bl")
dest_pin = self.bank_inst.get_pin("rbl_bl_{0}_{0}".format(port))
self.add_wire(self.m3_stack,
[src_pin.center(), vector(src_pin.cx(), dest_pin.cy()), dest_pin.rc()])
self.add_via_stack_center(from_layer=src_pin.layer,
to_layer="m4",
offset=src_pin.center())
self.add_via_stack_center(from_layer=dest_pin.layer,
to_layer="m3",
offset=dest_pin.center())
if self.has_rbl:
for port in self.all_ports:
# Only input (besides pins) is the replica bitline
src_pin = self.control_logic_insts[port].get_pin("rbl_bl")
dest_pin = self.bank_inst.get_pin("rbl_bl_{0}_{0}".format(port))
self.add_wire(self.m3_stack,
[src_pin.center(), vector(src_pin.cx(), dest_pin.cy()), dest_pin.rc()])
self.add_via_stack_center(from_layer=src_pin.layer,
to_layer="m4",
offset=src_pin.center())
self.add_via_stack_center(from_layer=dest_pin.layer,
to_layer="m3",
offset=dest_pin.center())
def route_row_addr_dff(self):
"""

View File

@ -68,9 +68,13 @@ class options(optparse.Values):
# Approximate percentage of delay compared to bitlines
rbl_delay_percentage = 0.5
# Allow manual adjustment of the delay chain over automatic
auto_delay_chain_sizing = False
# delay chain is automatically sized in delay based control logic
# this multiplier can be used to add a guard band to the standard timing
# lowering it can improve performance but may cause sram to fail
delay_control_scaling_factor = 1.0
# stages for delay chain in rbl control logic only
delay_chain_stages = 9
# fanout per stage for any control logic
delay_chain_fanout_per_stage = 4
accuracy_requirement = 0.75

View File

@ -14,7 +14,7 @@ from openram.sram_factory import factory
from openram import OPTS
class capped_replica_bitcell_array_1rw_1r_test(openram_test):
class capped_replica_bitcell_array_bothrbl_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
@ -25,13 +25,8 @@ class capped_replica_bitcell_array_1rw_1r_test(openram_test):
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 array left and right replica for dp cell")
a = factory.create(module_type="capped_replica_bitcell_array",
cols=4,
rows=4,
rbl=[1, 1],
left_rbl=[0],
right_rbl=[1])
debug.info(2, "Testing 4x4 capped replica array for 1rw1r cell with both replica columns")
a = factory.create(module_type="capped_replica_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0], right_rbl=[1])
self.local_check(a)
openram.end_openram()

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class capped_replica_bitcell_array_dummies_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 capped replica array for 1rw1r cell with dummy rows only")
a = factory.create(module_type="capped_replica_bitcell_array", cols=4, rows=4, rbl=[1, 1])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class capped_replica_bitcell_array_dummies_1rw_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 7x5 capped replica array for 1rw cell with dummy row only")
a = factory.create(module_type="capped_replica_bitcell_array", cols=7, rows=5, rbl=[1, 0])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -14,7 +14,7 @@ from openram.sram_factory import factory
from openram import OPTS
class capped_replica_bitcell_array_1rw_1r_test(openram_test):
class capped_replica_bitcell_array_leftrbl_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
@ -25,16 +25,13 @@ class capped_replica_bitcell_array_1rw_1r_test(openram_test):
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 left replica array for dp cell")
a = factory.create(module_type="capped_replica_bitcell_array",
cols=4,
rows=4,
rbl=[1, 1],
left_rbl=[0])
debug.info(2, "Testing 4x4 capped replica array for 1rw1r cell with left replica column")
a = factory.create(module_type="capped_replica_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()

View File

@ -14,7 +14,7 @@ from openram.sram_factory import factory
from openram import OPTS
class capped_replica_bitcell_array_test(openram_test):
class capped_replica_bitcell_array_leftrbl_1rw_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
@ -23,8 +23,9 @@ class capped_replica_bitcell_array_test(openram_test):
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 array for bitcell")
debug.info(2, "Testing 7x5 capped replica array for 1rw cell with left replica column")
a = factory.create(module_type="capped_replica_bitcell_array", cols=7, rows=5, rbl=[1, 0], left_rbl=[0])
self.local_check(a)

View File

@ -14,7 +14,7 @@ from openram.sram_factory import factory
from openram import OPTS
class capped_replica_bitcell_array_1rw_1r_test(openram_test):
class capped_replica_bitcell_array_norbl_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
@ -25,11 +25,8 @@ class capped_replica_bitcell_array_1rw_1r_test(openram_test):
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 non-replica array for dp cell")
a = factory.create(module_type="capped_replica_bitcell_array",
cols=4,
rows=4,
rbl=[1, 1])
debug.info(2, "Testing 4x4 capped replica array for 1rw1r cell without replica columns or dummy rows")
a = factory.create(module_type="capped_replica_bitcell_array", cols=4, rows=4, rbl=[0, 0])
self.local_check(a)
openram.end_openram()

View File

@ -14,7 +14,7 @@ from openram.sram_factory import factory
from openram import OPTS
class capped_replica_bitcell_array_test(openram_test):
class capped_replica_bitcell_array_norbl_1rw_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
@ -23,9 +23,10 @@ class capped_replica_bitcell_array_test(openram_test):
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 array for bitcell")
a = factory.create(module_type="capped_replica_bitcell_array", cols=7, rows=5, rbl=[1, 0])
debug.info(2, "Testing 7x5 capped replica array for 1rw cell without replica column or dummy row")
a = factory.create(module_type="capped_replica_bitcell_array", cols=7, rows=5, rbl=[0, 0])
self.local_check(a)
openram.end_openram()

View File

@ -14,7 +14,7 @@ from openram.sram_factory import factory
from openram import OPTS
class capped_replica_bitcell_array_1rw_1r_test(openram_test):
class capped_replica_bitcell_array_rightrbl_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
@ -25,16 +25,13 @@ class capped_replica_bitcell_array_1rw_1r_test(openram_test):
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 left replica array for dp cell")
a = factory.create(module_type="capped_replica_bitcell_array",
cols=4,
rows=4,
rbl=[1, 1],
right_rbl=[1])
debug.info(2, "Testing 4x4 capped replica array for 1rw1r cell with right replica column")
a = factory.create(module_type="capped_replica_bitcell_array", cols=4, rows=4, rbl=[1, 1], right_rbl=[1])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()

View File

@ -14,7 +14,7 @@ from openram.sram_factory import factory
from openram import OPTS
class replica_bitcell_array_1rw_1r_test(openram_test):
class replica_bitcell_array_bothrbl_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
@ -25,13 +25,8 @@ class replica_bitcell_array_1rw_1r_test(openram_test):
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 array left and right replica for dp cell")
a = factory.create(module_type="replica_bitcell_array",
cols=4,
rows=4,
rbl=[1, 1],
left_rbl=[0],
right_rbl=[1])
debug.info(2, "Testing 4x4 replica array for 1rw1r cell with both replica columns")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0], right_rbl=[1])
self.local_check(a)
openram.end_openram()

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class replica_bitcell_array_dummies_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 replica array for 1rw1r cell with dummy rows only")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 1])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class replica_bitcell_array_dummies_1rw_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 7x5 replica array for 1rw cell with dummy row only")
a = factory.create(module_type="replica_bitcell_array", cols=7, rows=5, rbl=[1, 0])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -14,7 +14,7 @@ from openram.sram_factory import factory
from openram import OPTS
class replica_bitcell_array_1rw_1r_test(openram_test):
class replica_bitcell_array_leftrbl_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
@ -25,16 +25,13 @@ class replica_bitcell_array_1rw_1r_test(openram_test):
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 left replica array for dp cell")
a = factory.create(module_type="replica_bitcell_array",
cols=4,
rows=4,
rbl=[1, 1],
left_rbl=[0])
debug.info(2, "Testing 4x4 replica array for 1rw1r cell with left replica column")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()

View File

@ -14,7 +14,7 @@ from openram.sram_factory import factory
from openram import OPTS
class replica_bitcell_array_test(openram_test):
class replica_bitcell_array_leftrbl_1rw_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
@ -23,8 +23,9 @@ class replica_bitcell_array_test(openram_test):
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 array for bitcell")
debug.info(2, "Testing 7x5 replica array for 1rw cell with left replica column")
a = factory.create(module_type="replica_bitcell_array", cols=7, rows=5, rbl=[1, 0], left_rbl=[0])
self.local_check(a)

View File

@ -14,7 +14,7 @@ from openram.sram_factory import factory
from openram import OPTS
class replica_bitcell_array_1rw_1r_test(openram_test):
class replica_bitcell_array_norbl_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
@ -25,11 +25,8 @@ class replica_bitcell_array_1rw_1r_test(openram_test):
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 non-replica array for dp cell")
a = factory.create(module_type="replica_bitcell_array",
cols=4,
rows=4,
rbl=[1, 1])
debug.info(2, "Testing 4x4 replica array for 1rw1r cell without replica columns or dummy rows")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[0, 0])
self.local_check(a)
openram.end_openram()

View File

@ -14,7 +14,7 @@ from openram.sram_factory import factory
from openram import OPTS
class replica_bitcell_array_test(openram_test):
class replica_bitcell_array_norbl_1rw_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
@ -23,9 +23,10 @@ class replica_bitcell_array_test(openram_test):
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 array for bitcell")
a = factory.create(module_type="replica_bitcell_array", cols=7, rows=5, rbl=[1, 0])
debug.info(2, "Testing 7x5 replica array for 1rw cell without replica column or dummy row")
a = factory.create(module_type="replica_bitcell_array", cols=7, rows=5, rbl=[0, 0])
self.local_check(a)
openram.end_openram()

View File

@ -14,7 +14,7 @@ from openram.sram_factory import factory
from openram import OPTS
class replica_bitcell_array_1rw_1r_test(openram_test):
class replica_bitcell_array_rightrbl_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
@ -25,16 +25,13 @@ class replica_bitcell_array_1rw_1r_test(openram_test):
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 left replica array for dp cell")
a = factory.create(module_type="replica_bitcell_array",
cols=4,
rows=4,
rbl=[1, 1],
right_rbl=[1])
debug.info(2, "Testing 4x4 replica array for 1rw1r cell with right replica column")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 1], right_rbl=[1])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class global_bitcell_array_norbl_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 2 x 4x4 global bitcell array for 1rw1r cell without replica columns")
a = factory.create(module_type="global_bitcell_array", cols=[4, 4, 4], rows=4, rbl=[0, 0], left_rbl=[], right_rbl=[])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class global_bitcell_array_norbl_1rw_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 2 x 4x4 global bitcell array for 1rw cell without replica column")
a = factory.create(module_type="global_bitcell_array", cols=[4, 4], rows=4, rbl=[0, 0], left_rbl=[])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class global_bitcell_array_rbl_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 2 x 4x4 global bitcell array for 1rw1r cell with replica columns")
a = factory.create(module_type="global_bitcell_array", cols=[4, 4, 4], rows=4, rbl=[1, 1], left_rbl=[0], right_rbl=[1])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class global_bitcell_array_rbl_1rw_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 2 x 4x4 global bitcell array for 1rw cell with left replica column")
a = factory.create(module_type="global_bitcell_array", cols=[4, 4], rows=4, rbl=[1, 0], left_rbl=[0])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -1,55 +0,0 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
# @unittest.skip("SKIPPING 05_local_bitcell_array_test")
class local_bitcell_array_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 local bitcell array for cell_1rw_1r without replica")
a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1])
self.local_check(a)
debug.info(2, "Testing 4x4 local bitcell array for cell_1rw_1r with replica column")
a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], right_rbl=[1])
self.local_check(a)
debug.info(2, "Testing 4x4 local bitcell array for cell_1rw_1r with replica column")
a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0])
self.local_check(a)
debug.info(2, "Testing 4x4 local bitcell array for cell_1rw_1r with replica column")
a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0], right_rbl=[1])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class local_bitcell_array_bothrbl_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 local bitcell array for 1rw1r cell with both replica columns")
a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0], right_rbl=[1])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class local_bitcell_array_dummies_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 local bitcell array for 1rw1r cell with dummy rows only")
a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class local_bitcell_array_dummies_1rw_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 7x5 local bitcell array for 1rw cell with dummy row only")
a = factory.create(module_type="local_bitcell_array", cols=7, rows=5, rbl=[1, 0])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class local_bitcell_array_leftrbl_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 local bitcell array for 1rw1r cell with left replica column")
a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class local_bitcell_array_leftrbl_1rw_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 7x5 local bitcell array for 1rw cell with left replica column")
a = factory.create(module_type="local_bitcell_array", cols=7, rows=5, rbl=[1, 0], left_rbl=[0])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class local_bitcell_array_norbl_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 local bitcell array for 1rw1r cell without replica columns or dummy rows")
a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[0, 0])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class local_bitcell_array_norbl_1rw_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 7x5 local bitcell array for 1rw cell without replica column or dummy row")
a = factory.create(module_type="local_bitcell_array", cols=7, rows=5, rbl=[0, 0])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class local_bitcell_array_rightrbl_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 4x4 local bitcell array for 1rw1r cell with right replica column")
a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], right_rbl=[1])
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,60 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
"""
Run a regression test on a control_logic_delay
"""
import sys, os
import unittest
from testutils import header,openram_test
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class control_logic_delay_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
# check control logic for multi-port
OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell = "replica_pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 1
OPTS.num_r_ports = 1
debug.info(1, "Testing sample for control_logic_delay for multiport, combined read-write control logic")
a = factory.create(module_type="control_logic_delay", num_rows=128, words_per_row=1, word_size=8, port_type="rw")
self.local_check(a)
# OPTS.num_rw_ports = 0
# OPTS.num_w_ports = 1
debug.info(1, "Testing sample for control_logic_delay for multiport, only write control logic")
a = factory.create(module_type="control_logic_delay", num_rows=128, words_per_row=1, word_size=8, port_type="w")
self.local_check(a)
# OPTS.num_w_ports = 0
# OPTS.num_r_ports = 1
debug.info(1, "Testing sample for control_logic_delay for multiport, only read control logic")
a = factory.create(module_type="control_logic_delay", num_rows=128, words_per_row=1, word_size=8, port_type="r")
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

View File

@ -11,29 +11,23 @@ import unittest
from testutils import *
import openram
from openram.sram_factory import factory
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
# @unittest.skip("SKIPPING 05_global_bitcell_array_test")
class global_bitcell_array_test(openram_test):
class control_logic_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
# debug.info(2, "Testing 2 x 4x4 global bitcell array for 6t_cell")
# a = factory.create(module_type="global_bitcell_array", cols=[4, 4], rows=4)
# self.local_check(a)
debug.info(2, "Testing 2 x 4x4 global bitcell array for 6t_cell")
a = factory.create(module_type="global_bitcell_array", cols=[10, 6], rows=4)
debug.info(1, "Testing sample for control_logic_r")
a = factory.create(module_type="control_logic_delay", num_rows=128, words_per_row=1, word_size=32, port_type="r")
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()

View File

@ -16,24 +16,18 @@ from openram.sram_factory import factory
from openram import OPTS
# @unittest.skip("SKIPPING 05_local_bitcell_array_test")
class local_bitcell_array_test(openram_test):
class control_logic_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
debug.info(2, "Testing 4x4 local bitcell array for 6t_cell without replica")
a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 0])
self.local_check(a)
debug.info(2, "Testing 4x4 local bitcell array for 6t_cell with replica column")
a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 0], left_rbl=[0])
debug.info(1, "Testing sample for control_logic_rw")
a = factory.create(module_type="control_logic_delay", num_rows=128, words_per_row=1, word_size=32)
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()

View File

@ -0,0 +1,36 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class control_logic_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
debug.info(1, "Testing sample for control_logic_w")
a = factory.create(module_type="control_logic_delay", num_rows=128, words_per_row=1, word_size=32, port_type="w")
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -33,7 +33,7 @@ class control_logic_test(openram_test):
OPTS.num_w_ports = 1
OPTS.num_r_ports = 1
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
debug.info(1, "Testing sample for control_logic for multiport, combined read-write control logic")
a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, port_type="rw")
self.local_check(a)

View File

@ -27,7 +27,7 @@ class port_address_1rw_1r_test(openram_test):
openram.setup_bitcell()
debug.info(1, "Port address 16 rows")
a = factory.create("port_address", cols=16, rows=16, port=0)
a = factory.create("port_address", cols=16, rows=16, port=0, has_rbl=True)
self.local_check(a)
openram.end_openram()

View File

@ -21,7 +21,7 @@ class port_address_test(openram_test):
openram.init_openram(config_file, is_unit_test=True)
debug.info(1, "Port address 16 rows")
a = factory.create("port_address", cols=16, rows=16, port=0)
a = factory.create("port_address", cols=16, rows=16, port=0, has_rbl=True)
self.local_check(a)
openram.end_openram()

View File

@ -27,7 +27,7 @@ class port_address_1rw_1r_test(openram_test):
openram.setup_bitcell()
debug.info(1, "Port address 256 rows")
a = factory.create("port_address", cols=256, rows=256, port=1)
a = factory.create("port_address", cols=256, rows=256, port=1, has_rbl=True)
self.local_check(a)
openram.end_openram()

View File

@ -21,7 +21,7 @@ class port_address_test(openram_test):
openram.init_openram(config_file, is_unit_test=True)
debug.info(1, "Port address 512 rows")
a = factory.create("port_address", cols=256, rows=512, port=0)
a = factory.create("port_address", cols=256, rows=512, port=0, has_rbl=True)
self.local_check(a)
openram.end_openram()

View File

@ -34,9 +34,9 @@ class port_data_1rw_1r_test(openram_test):
c.words_per_row=16
c.recompute_sizes()
debug.info(1, "Sixteen way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
a = factory.create("port_data", sram_config=c, port=1, has_rbl=True)
self.local_check(a)
openram.end_openram()

View File

@ -38,7 +38,7 @@ class port_data_test(openram_test):
c.words_per_row=16
c.recompute_sizes()
debug.info(1, "Sixteen way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
openram.end_openram()

View File

@ -33,9 +33,9 @@ class port_data_1rw_1r_test(openram_test):
c.words_per_row=2
c.recompute_sizes()
debug.info(1, "Two way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
a = factory.create("port_data", sram_config=c, port=1, has_rbl=True)
self.local_check(a)
openram.end_openram()

View File

@ -37,7 +37,7 @@ class port_data_test(openram_test):
c.words_per_row=2
c.recompute_sizes()
debug.info(1, "Two way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
openram.end_openram()

View File

@ -33,9 +33,9 @@ class port_data_1rw_1r_test(openram_test):
c.words_per_row=4
c.recompute_sizes()
debug.info(1, "Four way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
a = factory.create("port_data", sram_config=c, port=1, has_rbl=True)
self.local_check(a)
openram.end_openram()

View File

@ -37,7 +37,7 @@ class port_data_test(openram_test):
c.words_per_row=4
c.recompute_sizes()
debug.info(1, "Four way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
openram.end_openram()

View File

@ -34,9 +34,9 @@ class port_data_1rw_1r_test(openram_test):
c.words_per_row=8
c.recompute_sizes()
debug.info(1, "Eight way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
a = factory.create("port_data", sram_config=c, port=1, has_rbl=True)
self.local_check(a)
openram.end_openram()

View File

@ -38,7 +38,7 @@ class port_data_test(openram_test):
c.words_per_row=8
c.recompute_sizes()
debug.info(1, "Eight way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
openram.end_openram()

View File

@ -32,9 +32,9 @@ class port_data_1rw_1r_test(openram_test):
c.words_per_row=1
c.recompute_sizes()
debug.info(1, "No column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
a = factory.create("port_data", sram_config=c, port=1, has_rbl=True)
self.local_check(a)
openram.end_openram()

View File

@ -36,7 +36,7 @@ class port_data_test(openram_test):
c.words_per_row=1
c.recompute_sizes()
debug.info(1, "No column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
openram.end_openram()

View File

@ -28,14 +28,14 @@ class port_data_spare_cols_test(openram_test):
c.words_per_row=1
c.recompute_sizes()
debug.info(1, "No column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
c.num_words=32
c.words_per_row=2
c.recompute_sizes()
debug.info(1, "Two way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
c.num_words=64
@ -43,7 +43,7 @@ class port_data_spare_cols_test(openram_test):
c.num_spare_cols=3
c.recompute_sizes()
debug.info(1, "Four way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
c.word_size=2
@ -52,7 +52,7 @@ class port_data_spare_cols_test(openram_test):
c.num_spare_cols=4
c.recompute_sizes()
debug.info(1, "Eight way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
OPTS.num_rw_ports = 0
@ -64,27 +64,27 @@ class port_data_spare_cols_test(openram_test):
c.words_per_row=1
c.recompute_sizes()
debug.info(1, "No column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
a = factory.create("port_data", sram_config=c, port=1, has_rbl=True)
self.local_check(a)
c.num_words=32
c.words_per_row=2
c.recompute_sizes()
debug.info(1, "Two way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
a = factory.create("port_data", sram_config=c, port=1, has_rbl=True)
self.local_check(a)
c.num_words=64
c.words_per_row=4
c.recompute_sizes()
debug.info(1, "Four way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
a = factory.create("port_data", sram_config=c, port=1, has_rbl=True)
self.local_check(a)
c.word_size=2
@ -92,9 +92,9 @@ class port_data_spare_cols_test(openram_test):
c.words_per_row=8
c.recompute_sizes()
debug.info(1, "Eight way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
a = factory.create("port_data", sram_config=c, port=1, has_rbl=True)
self.local_check(a)
openram.end_openram()

View File

@ -33,28 +33,28 @@ class port_data_wmask_1rw_1r_test(openram_test):
c.words_per_row = 1
c.recompute_sizes()
debug.info(1, "No column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
c.num_words = 32
c.words_per_row = 2
c.recompute_sizes()
debug.info(1, "Two way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
c.num_words = 64
c.words_per_row = 4
c.recompute_sizes()
debug.info(1, "Four way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
c.num_words = 128
c.words_per_row = 8
c.recompute_sizes()
debug.info(1, "Eight way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
OPTS.num_rw_ports = 0
@ -66,27 +66,27 @@ class port_data_wmask_1rw_1r_test(openram_test):
c.words_per_row = 1
c.recompute_sizes()
debug.info(1, "No column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
a = factory.create("port_data", sram_config=c, port=1, has_rbl=True)
self.local_check(a)
#
c.num_words = 32
c.words_per_row = 2
c.recompute_sizes()
debug.info(1, "Two way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
a = factory.create("port_data", sram_config=c, port=1, has_rbl=True)
self.local_check(a)
c.num_words = 64
c.words_per_row = 4
c.recompute_sizes()
debug.info(1, "Four way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
a = factory.create("port_data", sram_config=c, port=1, has_rbl=True)
self.local_check(a)
c.word_size = 8
@ -94,9 +94,9 @@ class port_data_wmask_1rw_1r_test(openram_test):
c.words_per_row = 8
c.recompute_sizes()
debug.info(1, "Eight way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
a = factory.create("port_data", sram_config=c, port=1, has_rbl=True)
self.local_check(a)
openram.end_openram()

View File

@ -37,28 +37,28 @@ class port_data_wmask_test(openram_test):
c.words_per_row = 1
c.recompute_sizes()
debug.info(1, "No column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
c.num_words = 32
c.words_per_row = 2
c.recompute_sizes()
debug.info(1, "Two way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
c.num_words = 64
c.words_per_row = 4
c.recompute_sizes()
debug.info(1, "Four way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
c.num_words = 128
c.words_per_row = 8
c.recompute_sizes()
debug.info(1, "Eight way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
OPTS.num_rw_ports = 0
@ -70,27 +70,27 @@ class port_data_wmask_test(openram_test):
c.words_per_row = 1
c.recompute_sizes()
debug.info(1, "No column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
a = factory.create("port_data", sram_config=c, port=1, has_rbl=True)
self.local_check(a)
#
c.num_words = 32
c.words_per_row = 2
c.recompute_sizes()
debug.info(1, "Two way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
a = factory.create("port_data", sram_config=c, port=1, has_rbl=True)
self.local_check(a)
c.num_words = 64
c.words_per_row = 4
c.recompute_sizes()
debug.info(1, "Four way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
a = factory.create("port_data", sram_config=c, port=1, has_rbl=True)
self.local_check(a)
c.word_size = 8
@ -98,9 +98,9 @@ class port_data_wmask_test(openram_test):
c.words_per_row = 8
c.recompute_sizes()
debug.info(1, "Eight way column mux")
a = factory.create("port_data", sram_config=c, port=0)
a = factory.create("port_data", sram_config=c, port=0, has_rbl=True)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
a = factory.create("port_data", sram_config=c, port=1, has_rbl=True)
self.local_check(a)
openram.end_openram()

View File

@ -16,25 +16,27 @@ from openram.sram_factory import factory
from openram import OPTS
# @unittest.skip("SKIPPING 05_global_bitcell_array_test")
class global_bitcell_array_test(openram_test):
class single_bank_nomux_norbl_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
from openram import sram_config
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
openram.setup_bitcell()
debug.info(2, "Testing 2 x 4x4 global bitcell array for cell_1rw_1r")
a = factory.create(module_type="global_bitcell_array", cols=[4, 4], rows=4)
self.local_check(a)
c = sram_config(word_size=4,
num_words=16)
# debug.info(2, "Testing 4x4 local bitcell array for 6t_cell with replica column")
# a = factory.create(module_type="local_bitcell_array", cols=4, left_rbl=1, rows=4, ports=[0])
# self.local_check(a)
c.words_per_row=1
OPTS.control_logic = "control_logic_delay"
c.recompute_sizes()
debug.info(1, "No column mux")
a = factory.create(module_type="bank", sram_config=c)
self.local_check(a)
openram.end_openram()

View File

@ -0,0 +1,54 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class single_bank_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
from openram import sram_config
if OPTS.tech_name == "sky130":
num_spare_rows = 1
num_spare_cols = 1
else:
num_spare_rows = 0
num_spare_cols = 0
c = sram_config(word_size=4,
num_words=16,
num_spare_cols=num_spare_cols,
num_spare_rows=num_spare_rows)
c.words_per_row=1
OPTS.control_logic = "control_logic_delay"
factory.reset()
c.recompute_sizes()
debug.info(1, "No column mux")
a = factory.create("bank", sram_config=c)
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,58 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class sram_1bank_nomux_norbl_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
from openram import sram_config
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
openram.setup_bitcell()
c = sram_config(word_size=4,
num_words=16,
num_banks=1)
c.words_per_row=1
OPTS.control_logic = "control_logic_delay"
c.recompute_sizes()
debug.info(1, "Layout test for {}rw,{}r,{}w sram "
"with {} bit words, {} words, {} words per "
"row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports,
OPTS.num_w_ports,
c.word_size,
c.num_words,
c.words_per_row,
c.num_banks))
a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -0,0 +1,58 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class sram_1bank_nomux_norbl_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
from openram import sram_config
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 0
OPTS.num_w_ports = 0
openram.setup_bitcell()
c = sram_config(word_size=4,
num_words=16,
num_banks=1)
c.words_per_row=1
OPTS.control_logic = "control_logic_delay"
c.recompute_sizes()
debug.info(1, "Layout test for {}rw,{}r,{}w sram "
"with {} bit words, {} words, {} words per "
"row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports,
OPTS.num_w_ports,
c.word_size,
c.num_words,
c.words_per_row,
c.num_banks))
a = factory.create(module_type="sram", sram_config=c)
self.local_check(a, final_verification=True)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -32,6 +32,7 @@ BROKEN_STAMPS = \
%/20_psram_1bank_2mux_test.ok \
%/21_hspice_delay_test.ok \
%/21_hspice_setuphold_test.ok \
%/21_xyce_delay_test.ok \
%/22_psram_1bank_2mux_func_test.ok \
%/22_psram_1bank_4mux_func_test.ok \
%/22_psram_1bank_8mux_func_test.ok \
@ -69,8 +70,11 @@ BROKEN_STAMPS = \
freepdk45/10_rom_wordline_driver_array_test.ok \
freepdk45/14_rom_array_test.ok \
freepdk45/16_rom_control_logic_test.ok \
freepdk45/16_control_logic_delay_multiport_test.ok \
freepdk45/16_control_logic_delay_rw_test.ok \
freepdk45/16_control_logic_delay_r_test.ok \
freepdk45/16_control_logic_delay_w_test.ok \
freepdk45/19_rom_bank_test.ok \
freepdk45/21_xyce_delay_test.ok \
scn4m_subm/06_rom_decoder_test.ok \
scn4m_subm/07_rom_column_mux_array_test.ok \
scn4m_subm/08_rom_decoder_buffer_array_test.ok \
@ -80,8 +84,8 @@ BROKEN_STAMPS = \
scn4m_subm/16_rom_control_logic_test.ok \
scn4m_subm/19_rom_bank_test.ok \
scn4m_subm/19_single_bank_global_bitline_test.ok \
scn4m_subm/21_xyce_delay_test.ok \
sky130/01_library_test.ok \
sky130/03_wire_test.ok \
sky130/04_column_mux_pbitcell_test.ok \
sky130/04_dummy_pbitcell_test.ok \
sky130/04_pbitcell_test.ok \
@ -89,15 +93,78 @@ BROKEN_STAMPS = \
sky130/04_pand4_test.ok \
sky130/04_precharge_pbitcell_test.ok \
sky130/04_replica_pbitcell_test.ok \
sky130/04_dummy_pbitcell_1rw1r1w_test.ok \
sky130/04_dummy_pbitcell_1rw_test.ok \
sky130/04_replica_pbitcell_1rw1r1w_test.ok \
sky130/04_replica_pbitcell_1rw_test.ok \
sky130/05_pbitcell_array_test.ok \
sky130/05_bitcell_array_test.ok \
sky130/05_bitcell_array_1rw_1r_test.ok \
sky130/05_dummy_array_test.ok \
sky130/06_hierarchical_decoder_132row_test.ok \
sky130/06_hierarchical_decoder_512row_test.ok \
sky130/06_hierarchical_decoder_64row_test.ok \
sky130/06_hierarchical_decoder_pbitcell_test.ok \
sky130/07_column_mux_array_pbitcell_test.ok \
sky130/10_write_driver_array_spare_cols_test.ok \
sky130/10_write_driver_array_wmask_spare_cols_test.ok \
sky130/14_capped_replica_bitcell_array_dummies_1rw_test.ok \
sky130/14_capped_replica_bitcell_array_leftrbl_1rw_test.ok \
sky130/14_capped_replica_bitcell_array_norbl_1rw_1r_test.ok \
sky130/14_capped_replica_bitcell_array_norbl_1rw_test.ok \
sky130/14_replica_bitcell_array_dummies_1rw_test.ok \
sky130/14_replica_bitcell_array_leftrbl_1rw_test.ok \
sky130/14_replica_bitcell_array_norbl_1rw_1r_test.ok \
sky130/14_replica_bitcell_array_norbl_1rw_test.ok \
sky130/14_replica_column_1rw_1r_test.ok \
sky130/14_replica_column_1rw_test.ok \
sky130/14_replica_pbitcell_1rw1r_array_test.ok \
sky130/14_replica_pbitcell_1rw_array_test.ok \
sky130/15_global_bitcell_array_norbl_1rw_1r_test.ok \
sky130/15_global_bitcell_array_norbl_1rw_test.ok \
sky130/15_global_bitcell_array_rbl_1rw_1r_test.ok \
sky130/15_global_bitcell_array_rbl_1rw_test.ok \
sky130/15_local_bitcell_array_dummies_1rw_test.ok \
sky130/15_local_bitcell_array_leftrbl_1rw_test.ok \
sky130/15_local_bitcell_array_norbl_1rw_1r_test.ok \
sky130/15_local_bitcell_array_norbl_1rw_test.ok \
sky130/16_control_logic_delay_multiport_test.ok \
sky130/16_control_logic_delay_rw_test.ok \
sky130/16_control_logic_delay_r_test.ok \
sky130/16_control_logic_delay_w_test.ok \
sky130/18_port_address_512rows_test.ok \
sky130/18_port_data_spare_cols_test.ok \
sky130/19_single_bank_2mux_test.ok \
sky130/19_single_bank_4mux_test.ok \
sky130/19_single_bank_8mux_test.ok \
sky130/19_single_bank_global_bitline_test.ok \
sky130/19_single_bank_nomux_test.ok \
sky130/19_single_bank_nomux_norbl_1rw_1r_test.ok \
sky130/19_single_bank_nomux_norbl_test.ok \
sky130/19_single_bank_spare_cols_test.ok \
sky130/19_single_bank_wmask_test.ok \
sky130/19_pmulti_bank_test.ok \
sky130/19_psingle_bank_test.ok \
sky130/19_bank_select_pbitcell_test.ok \
sky130/20_psram_1bank_4mux_1rw_1r_test.ok \
sky130/20_sram_1bank_2mux_1rw_1r_spare_cols_test.ok \
sky130/20_sram_1bank_2mux_1w_1r_spare_cols_test.ok \
sky130/20_sram_1bank_2mux_global_test.ok \
sky130/20_sram_1bank_2mux_test.ok \
sky130/20_sram_1bank_2mux_wmask_spare_cols_test.ok \
sky130/20_sram_1bank_2mux_wmask_test.ok \
sky130/20_sram_1bank_4mux_test.ok \
sky130/20_sram_1bank_8mux_test.ok \
sky130/20_sram_1bank_nomux_norbl_1rw_1r_test.ok \
sky130/20_sram_1bank_nomux_norbl_test.ok \
sky130/20_sram_1bank_nomux_spare_cols_test.ok \
sky130/20_sram_1bank_nomux_test.ok \
sky130/20_sram_1bank_nomux_wmask_test.ok \
sky130/20_sram_1bank_ring_test.ok \
sky130/21_model_delay_test.ok \
sky130/21_ngspice_delay_extra_rows_test.ok \
sky130/21_ngspice_delay_test.ok \
sky130/21_regression_delay_test.ok \
sky130/22_psram_1bank_2mux_func_test.ok \
sky130/22_psram_1bank_4mux_func_test.ok \
sky130/22_psram_1bank_8mux_func_test.ok \
@ -107,54 +174,6 @@ BROKEN_STAMPS = \
sky130/23_lib_sram_model_test.ok \
sky130/23_lib_sram_prune_test.ok \
sky130/23_lib_sram_test.ok \
sky130/03_wire_test.ok \
sky130/04_dummy_pbitcell_1rw1r1w_test.ok \
sky130/04_dummy_pbitcell_1rw_test.ok \
sky130/04_replica_pbitcell_1rw1r1w_test.ok \
sky130/04_replica_pbitcell_1rw_test.ok \
sky130/06_hierarchical_decoder_132row_test.ok \
sky130/06_hierarchical_decoder_512row_test.ok \
sky130/06_hierarchical_decoder_64row_test.ok \
sky130/06_hierarchical_decoder_pbitcell_test.ok \
sky130/10_write_driver_array_spare_cols_test.ok \
sky130/10_write_driver_array_wmask_spare_cols_test.ok \
sky130/14_capped_replica_bitcell_array_leftrbl_1rw_test.ok \
sky130/14_capped_replica_bitcell_array_norbl_1rw_test.ok \
sky130/14_replica_bitcell_array_leftrbl_1rw_test.ok \
sky130/14_replica_bitcell_array_norbl_1rw_test.ok \
sky130/14_replica_column_1rw_1r_test.ok \
sky130/14_replica_column_1rw_test.ok \
sky130/14_replica_pbitcell_1rw1r_array_test.ok \
sky130/14_replica_pbitcell_1rw_array_test.ok \
sky130/15_global_bitcell_array_1rw_1r_test.ok \
sky130/15_global_bitcell_array_test.ok \
sky130/15_local_bitcell_array_test.ok \
sky130/18_port_address_512rows_test.ok \
sky130/18_port_data_spare_cols_test.ok \
sky130/19_single_bank_2mux_test.ok \
sky130/19_single_bank_4mux_test.ok \
sky130/19_single_bank_8mux_test.ok \
sky130/19_single_bank_global_bitline_test.ok \
sky130/19_single_bank_nomux_test.ok \
sky130/19_single_bank_spare_cols_test.ok \
sky130/19_single_bank_wmask_test.ok \
sky130/20_sram_1bank_2mux_1rw_1r_spare_cols_test.ok \
sky130/20_sram_1bank_2mux_1w_1r_spare_cols_test.ok \
sky130/20_sram_1bank_2mux_global_test.ok \
sky130/20_sram_1bank_2mux_test.ok \
sky130/20_sram_1bank_2mux_wmask_spare_cols_test.ok \
sky130/20_sram_1bank_2mux_wmask_test.ok \
sky130/20_sram_1bank_4mux_test.ok \
sky130/20_sram_1bank_8mux_test.ok \
sky130/20_sram_1bank_nomux_spare_cols_test.ok \
sky130/20_sram_1bank_nomux_test.ok \
sky130/20_sram_1bank_nomux_wmask_test.ok \
sky130/20_sram_1bank_ring_test.ok \
sky130/21_model_delay_test.ok \
sky130/21_ngspice_delay_extra_rows_test.ok \
sky130/21_ngspice_delay_test.ok \
sky130/21_regression_delay_test.ok \
sky130/21_xyce_delay_test.ok \
sky130/25_verilog_multibank_test.ok \
sky130/25_verilog_sram_test.ok \
sky130/30_openram_back_end_library_test.ok \

View File

@ -110,7 +110,7 @@ Commercial tools (optional):
* Michael Grimes
* Jennifer Sowash
* Jesse Cirimelli-Low
<img align="right" height="100" src="../assets/images/logos/vlsida.png">https://www.youtube.com/watch?v=rd5j8mG24H4&t=0s
<img align="right" height="100" src="../assets/images/logos/vlsida.png">
* Many other past students:
* Jeff Butera
* Tom Golubev

View File

@ -30,9 +30,19 @@ class sky130_capped_replica_bitcell_array(sky130_bitcell_base_array):
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
self.add_comment("rbl: {0} left_rbl: {1} right_rbl: {2}".format(rbl, left_rbl, right_rbl))
# This is how many RBLs are in all the arrays
self.rbl = rbl
self.left_rbl = left_rbl
self.right_rbl = right_rbl
# This specifies which RBL to put on the left or right by port number
# This could be an empty list
if left_rbl is not None:
self.left_rbl = left_rbl
else:
self.left_rbl = []
# This could be an empty list
if right_rbl is not None:
self.right_rbl = right_rbl
else:
self.right_rbl = []
self.create_netlist()
if not OPTS.netlist_only: