mirror of https://github.com/VLSIDA/OpenRAM.git
Merging latest changes from multiport with changes made to pbitcell. Changing select code from other modules and tests to reflect changes made to pbitcell.
This commit is contained in:
commit
1a340c9c85
|
|
@ -116,6 +116,11 @@ def init_openram(config_file, is_unit_test=True):
|
|||
|
||||
import_tech()
|
||||
|
||||
init_paths()
|
||||
|
||||
# This depends on the tech, so do it after tech is loaded
|
||||
init_config()
|
||||
|
||||
# Reset the static duplicate name checker for unit tests.
|
||||
import hierarchy_design
|
||||
hierarchy_design.hierarchy_design.name_map=[]
|
||||
|
|
@ -229,15 +234,6 @@ def read_config(config_file, is_unit_test=True):
|
|||
OPTS.num_r_ports,
|
||||
OPTS.tech_name)
|
||||
|
||||
# Don't delete the output dir, it may have other files!
|
||||
# make the directory if it doesn't exist
|
||||
try:
|
||||
os.makedirs(OPTS.output_path, 0o750)
|
||||
except OSError as e:
|
||||
if e.errno == 17: # errno.EEXIST
|
||||
os.chmod(OPTS.output_path, 0o750)
|
||||
except:
|
||||
debug.error("Unable to make output directory.",-1)
|
||||
|
||||
|
||||
def end_openram():
|
||||
|
|
@ -299,12 +295,6 @@ def setup_paths():
|
|||
|
||||
cleanup_paths()
|
||||
|
||||
# make the directory if it doesn't exist
|
||||
try:
|
||||
os.makedirs(OPTS.openram_temp, 0o750)
|
||||
except OSError as e:
|
||||
if e.errno == 17: # errno.EEXIST
|
||||
os.chmod(OPTS.openram_temp, 0o750)
|
||||
|
||||
|
||||
def is_exe(fpath):
|
||||
|
|
@ -320,7 +310,37 @@ def find_exe(check_exe):
|
|||
if is_exe(exe):
|
||||
return exe
|
||||
return None
|
||||
|
||||
|
||||
def init_paths():
|
||||
""" Create the temp and output directory if it doesn't exist """
|
||||
|
||||
# make the directory if it doesn't exist
|
||||
try:
|
||||
os.makedirs(OPTS.openram_temp, 0o750)
|
||||
except OSError as e:
|
||||
if e.errno == 17: # errno.EEXIST
|
||||
os.chmod(OPTS.openram_temp, 0o750)
|
||||
|
||||
# Don't delete the output dir, it may have other files!
|
||||
# make the directory if it doesn't exist
|
||||
try:
|
||||
os.makedirs(OPTS.output_path, 0o750)
|
||||
except OSError as e:
|
||||
if e.errno == 17: # errno.EEXIST
|
||||
os.chmod(OPTS.output_path, 0o750)
|
||||
except:
|
||||
debug.error("Unable to make output directory.",-1)
|
||||
|
||||
def init_config():
|
||||
""" Initialize the SRAM configurations. """
|
||||
# Create the SRAM configuration
|
||||
from sram_config import sram_config
|
||||
OPTS.sram_config = sram_config(OPTS.word_size,
|
||||
OPTS.num_words,
|
||||
OPTS.num_banks)
|
||||
|
||||
|
||||
|
||||
# imports correct technology directories for testing
|
||||
def import_tech():
|
||||
global OPTS
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ class bank(design.design):
|
|||
design.design.__init__(self, name)
|
||||
debug.info(2, "create sram of size {0} with {1} words".format(self.word_size,self.num_words))
|
||||
|
||||
|
||||
self.total_write = OPTS.num_rw_ports + OPTS.num_w_ports
|
||||
self.total_read = OPTS.num_rw_ports + OPTS.num_r_ports
|
||||
self.total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
|
||||
|
||||
# The local control signals are gated when we have bank select logic,
|
||||
# so this prefix will be added to all of the input signals to create
|
||||
|
|
|
|||
|
|
@ -50,16 +50,6 @@ class bitcell(design.design):
|
|||
row_pins = ["wl"]
|
||||
return row_pins
|
||||
|
||||
def list_read_wl_names(self):
|
||||
""" Creates a list of wordline pin names associated with read ports """
|
||||
row_pins = ["wl"]
|
||||
return row_pins
|
||||
|
||||
def list_write_wl_names(self):
|
||||
""" Creates a list of wordline pin names associated with write ports """
|
||||
row_pins = ["wl"]
|
||||
return row_pins
|
||||
|
||||
def list_all_bitline_names(self):
|
||||
""" Creates a list of all bitline pin names (both bl and br) """
|
||||
column_pins = ["bl", "br"]
|
||||
|
|
|
|||
|
|
@ -53,11 +53,6 @@ class delay_chain(design.design):
|
|||
self.add_pin("gnd")
|
||||
|
||||
def add_modules(self):
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
|
||||
self.inv = pinv(route_output=False)
|
||||
self.add_mod(self.inv)
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@ class hierarchical_decoder(design.design):
|
|||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell_height = self.mod_bitcell.height
|
||||
b = self.mod_bitcell()
|
||||
self.bitcell_height = b.height
|
||||
|
||||
self.NAND_FORMAT = "DEC_NAND[{0}]"
|
||||
self.INV_FORMAT = "DEC_INV_[{0}]"
|
||||
|
|
@ -130,7 +131,7 @@ class hierarchical_decoder(design.design):
|
|||
self.total_number_of_predecoder_outputs = 4*self.no_of_pre2x4 + 8*self.no_of_pre3x8
|
||||
else:
|
||||
self.total_number_of_predecoder_outputs = 0
|
||||
debug.error("Not enough rows for a hierarchical decoder. Non-hierarchical not supported yet.",-1)
|
||||
debug.error("Not enough rows ({}) for a hierarchical decoder. Non-hierarchical not supported yet.".format(self.num_inputs),-1)
|
||||
|
||||
# Calculates height and width of pre-decoder,
|
||||
if self.no_of_pre3x8 > 0:
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ class replica_bitcell(design.design):
|
|||
is a hand-made cell, so the layout and netlist should be available in
|
||||
the technology library. """
|
||||
|
||||
pin_names = ["BL", "BR", "WL", "vdd", "gnd"]
|
||||
pin_names = ["bl", "br", "wl", "vdd", "gnd"]
|
||||
(width,height) = utils.get_libcell_size("replica_cell_6t", GDS["unit"], layer["boundary"])
|
||||
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_6t", GDS["unit"], layer["boundary"])
|
||||
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ class replica_bitline(design.design):
|
|||
|
||||
# 3. Route the contact of previous route to the bitcell WL
|
||||
# route bend of previous net to bitcell WL
|
||||
wl_offset = self.rbc_inst.get_pin("WL").lc()
|
||||
wl_offset = self.rbc_inst.get_pin("wl").lc()
|
||||
xmid_point= 0.5*(wl_offset.x+contact_offset.x)
|
||||
wl_mid1 = vector(xmid_point,contact_offset.y)
|
||||
wl_mid2 = vector(xmid_point,wl_offset.y)
|
||||
|
|
@ -247,7 +247,7 @@ class replica_bitline(design.design):
|
|||
|
||||
# Route the connection of the source route to the RBL bitline (left)
|
||||
# Via will go halfway down from the bitcell
|
||||
bl_offset = self.rbc_inst.get_pin("BL").bc()
|
||||
bl_offset = self.rbc_inst.get_pin("bl").bc()
|
||||
# Route down a pitch so we can use M2 routing
|
||||
bl_down_offset = bl_offset - vector(0, self.m2_pitch)
|
||||
self.add_path("metal2",[source_offset, bl_down_offset, bl_offset])
|
||||
|
|
|
|||
|
|
@ -57,10 +57,11 @@ class sense_amp_array(design.design):
|
|||
self.amp = self.mod_sense_amp("sense_amp")
|
||||
self.add_mod(self.amp)
|
||||
|
||||
# This is just used for measurements,
|
||||
# so don't add the module
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
self.add_mod(self.bitcell)
|
||||
|
||||
def create_sense_amp_array(self):
|
||||
self.local_insts = []
|
||||
|
|
|
|||
|
|
@ -50,6 +50,13 @@ class wordline_driver(design.design):
|
|||
|
||||
|
||||
def add_modules(self):
|
||||
# This is just used for measurements,
|
||||
# so don't add the module
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
|
||||
self.inv = pinv()
|
||||
self.add_mod(self.inv)
|
||||
|
||||
|
|
@ -59,11 +66,6 @@ class wordline_driver(design.design):
|
|||
self.nand2 = pnand2()
|
||||
self.add_mod(self.nand2)
|
||||
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
self.add_mod(self.bitcell)
|
||||
|
||||
def route_vdd_gnd(self):
|
||||
""" Add a pin for each row of vdd/gnd which are must-connects next level up. """
|
||||
|
|
|
|||
|
|
@ -58,11 +58,12 @@ class write_driver_array(design.design):
|
|||
self.mod_write_driver = getattr(c, OPTS.write_driver)
|
||||
self.driver = self.mod_write_driver("write_driver")
|
||||
self.add_mod(self.driver)
|
||||
|
||||
|
||||
# This is just used for measurements,
|
||||
# so don't add the module
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
self.add_mod(self.bitcell)
|
||||
|
||||
def create_write_array(self):
|
||||
self.driver_insts = {}
|
||||
|
|
|
|||
|
|
@ -52,14 +52,13 @@ print(*output_files,sep="\n")
|
|||
start_time = datetime.datetime.now()
|
||||
print_time("Start",start_time)
|
||||
|
||||
# Configure the SRAM organization
|
||||
c = sram_config(word_size=OPTS.word_size,
|
||||
num_words=OPTS.num_words,
|
||||
num_rw_ports=OPTS.num_rw_ports,
|
||||
num_w_ports=OPTS.num_w_ports,
|
||||
num_r_ports=OPTS.num_r_ports)
|
||||
num_words=OPTS.num_words)
|
||||
|
||||
# import SRAM test generation
|
||||
s = sram(c, OPTS.output_name)
|
||||
s = sram(sram_config=c,
|
||||
name=OPTS.output_name)
|
||||
|
||||
# Output the files for the resulting SRAM
|
||||
s.save()
|
||||
|
|
|
|||
|
|
@ -55,11 +55,17 @@ class options(optparse.Values):
|
|||
num_rw_ports = 1
|
||||
num_r_ports = 0
|
||||
num_w_ports = 0
|
||||
|
||||
# These will get initialized by the the file
|
||||
supply_voltages = ""
|
||||
temperatures = ""
|
||||
process_corners = ""
|
||||
|
||||
|
||||
# These are the main configuration parameters that should be over-ridden
|
||||
# in a configuration file.
|
||||
#num_words = 0
|
||||
#num_banks = 1
|
||||
#word_size = 0
|
||||
|
||||
# These are the default modules that can be over-riden
|
||||
decoder = "hierarchical_decoder"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import contact
|
||||
import pgate
|
||||
import design
|
||||
import debug
|
||||
from tech import drc, parameter, spice
|
||||
|
|
@ -7,47 +6,42 @@ from vector import vector
|
|||
from ptx import ptx
|
||||
from globals import OPTS
|
||||
|
||||
class pbitcell(pgate.pgate):
|
||||
class pbitcell(design.design):
|
||||
"""
|
||||
This module implements a parametrically sized multi-port bitcell,
|
||||
with a variable number of read/write, write, and read ports
|
||||
"""
|
||||
|
||||
width = None
|
||||
height = None
|
||||
|
||||
unique_id = 1
|
||||
|
||||
def __init__(self, num_readwrite=OPTS.num_rw_ports, num_write=OPTS.num_w_ports, num_read=OPTS.num_r_ports):
|
||||
name = "pbitcell_{0}RW_{1}W_{2}R_{3}".format(num_readwrite, num_write, num_read, pbitcell.unique_id)
|
||||
pbitcell.unique_id += 1
|
||||
pgate.pgate.__init__(self, name)
|
||||
debug.info(2, "create a multi-port bitcell with {0} write ports and {1} read ports".format(num_write, num_read))
|
||||
def __init__(self):
|
||||
|
||||
self.num_readwrite = num_readwrite
|
||||
self.num_write = num_write
|
||||
self.num_read = num_read
|
||||
self.total_ports = num_readwrite + num_write + num_read
|
||||
self.num_rw_ports = OPTS.num_rw_ports
|
||||
self.num_w_ports = OPTS.num_w_ports
|
||||
self.num_r_ports = OPTS.num_r_ports
|
||||
self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports
|
||||
|
||||
name = "pbitcell_{0}RW_{1}W_{2}R".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports)
|
||||
# This is not a pgate because pgates depend on the bitcell height!
|
||||
design.design.__init__(self, name)
|
||||
debug.info(2, "create a multi-port bitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports,
|
||||
self.num_w_ports,
|
||||
self.num_r_ports))
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.create_layout()
|
||||
# We must always create the bitcell layout because
|
||||
# some transistor sizes in the other netlists depend on it
|
||||
self.create_layout()
|
||||
|
||||
# Since since pbitcell's size is dependent on port choice, class width and height are set after layout creation
|
||||
# class width and height are necessary for modules that load bitcell attributes
|
||||
pbitcell.width = self.width
|
||||
pbitcell.height = self.height
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_modules()
|
||||
self.create_storage()
|
||||
|
||||
if(self.num_readwrite > 0):
|
||||
if(self.num_rw_ports > 0):
|
||||
self.create_readwrite_ports()
|
||||
if(self.num_write > 0):
|
||||
if(self.num_w_ports > 0):
|
||||
self.create_write_ports()
|
||||
if(self.num_read > 0):
|
||||
if(self.num_r_ports > 0):
|
||||
self.create_read_ports()
|
||||
|
||||
def create_layout(self):
|
||||
|
|
@ -58,18 +52,18 @@ class pbitcell(pgate.pgate):
|
|||
self.route_storage()
|
||||
self.route_rails()
|
||||
|
||||
if(self.num_readwrite > 0):
|
||||
if(self.num_rw_ports > 0):
|
||||
self.place_readwrite_ports()
|
||||
self.route_readwrite_wordlines()
|
||||
self.route_readwrite_bitlines()
|
||||
if(self.num_write == 0): # routing for write to storage is the same as read/write to storage
|
||||
if(self.num_w_ports == 0): # routing for write to storage is the same as read/write to storage
|
||||
self.route_readwrite_access()
|
||||
if(self.num_write > 0):
|
||||
if(self.num_w_ports > 0):
|
||||
self.place_write_ports()
|
||||
self.route_write_wordlines()
|
||||
self.route_write_bitlines()
|
||||
self.route_write_access()
|
||||
if(self.num_read > 0):
|
||||
if(self.num_r_ports > 0):
|
||||
self.place_read_ports()
|
||||
self.route_read_wordlines()
|
||||
self.route_read_bitlines()
|
||||
|
|
@ -86,22 +80,24 @@ class pbitcell(pgate.pgate):
|
|||
self.w_br_names = []
|
||||
self.r_bl_names = []
|
||||
self.r_br_names = []
|
||||
self.wl_names = []
|
||||
self.rw_wl_names = []
|
||||
self.w_wl_names = []
|
||||
self.r_wl_names = []
|
||||
port = 0
|
||||
|
||||
for k in range(self.num_readwrite):
|
||||
for k in range(self.num_rw_ports):
|
||||
self.add_pin("bl{}".format(port))
|
||||
self.add_pin("br{}".format(port))
|
||||
self.rw_bl_names.append("bl{}".format(port))
|
||||
self.rw_br_names.append("br{}".format(port))
|
||||
port += 1
|
||||
for k in range(self.num_write):
|
||||
for k in range(self.num_w_ports):
|
||||
self.add_pin("bl{}".format(port))
|
||||
self.add_pin("br{}".format(port))
|
||||
self.w_bl_names.append("bl{}".format(port))
|
||||
self.w_br_names.append("br{}".format(port))
|
||||
port += 1
|
||||
for k in range(self.num_read):
|
||||
for k in range(self.num_r_ports):
|
||||
self.add_pin("bl{}".format(port))
|
||||
self.add_pin("br{}".format(port))
|
||||
self.r_bl_names.append("bl{}".format(port))
|
||||
|
|
@ -109,20 +105,30 @@ class pbitcell(pgate.pgate):
|
|||
port += 1
|
||||
|
||||
port = 0
|
||||
for k in range(self.total_ports):
|
||||
for k in range(self.num_rw_ports):
|
||||
self.add_pin("wl{}".format(port))
|
||||
self.wl_names.append("wl{}".format(port))
|
||||
self.rw_wl_names.append("wl{}".format(port))
|
||||
port += 1
|
||||
for k in range(self.num_w_ports):
|
||||
self.add_pin("wl{}".format(port))
|
||||
self.w_wl_names.append("wl{}".format(port))
|
||||
port += 1
|
||||
for k in range(self.num_r_ports):
|
||||
self.add_pin("wl{}".format(port))
|
||||
self.r_wl_names.append("wl{}".format(port))
|
||||
port += 1
|
||||
|
||||
self.add_pin("vdd")
|
||||
self.add_pin("gnd")
|
||||
|
||||
|
||||
def add_modules(self):
|
||||
"""
|
||||
Determine size of transistors and add ptx modules
|
||||
"""
|
||||
# if there are any read/write ports, then the inverter nmos is sized based the number of read/write ports
|
||||
if(self.num_readwrite > 0):
|
||||
inverter_nmos_width = self.num_readwrite*3*parameter["min_tx_size"]
|
||||
if(self.num_rw_ports > 0):
|
||||
inverter_nmos_width = self.num_rw_ports*3*parameter["min_tx_size"]
|
||||
inverter_pmos_width = parameter["min_tx_size"]
|
||||
readwrite_nmos_width = 1.5*parameter["min_tx_size"]
|
||||
write_nmos_width = parameter["min_tx_size"]
|
||||
|
|
@ -197,7 +203,7 @@ class pbitcell(pgate.pgate):
|
|||
|
||||
# write to read transistor spacing (also acts as readwrite to read transistor spacing)
|
||||
# calculation is dependent on whether the read transistor is adjacent to a write transistor or a readwrite transistor
|
||||
if(self.num_write > 0):
|
||||
if(self.num_w_ports > 0):
|
||||
if(self.write_nmos_contact_extension > self.gate_contact_thres):
|
||||
write_portion = drc["minwidth_metal2"] + self.write_nmos_contact_extension
|
||||
else:
|
||||
|
|
@ -236,23 +242,23 @@ class pbitcell(pgate.pgate):
|
|||
Calculate positions that describe the edges and dimensions of the cell
|
||||
"""
|
||||
# create flags for excluding readwrite, write, or read port calculations if they are not included in the bitcell
|
||||
if(self.num_readwrite > 0):
|
||||
if(self.num_rw_ports > 0):
|
||||
self.readwrite_port_flag = True
|
||||
else:
|
||||
self.readwrite_port_flag = False
|
||||
|
||||
if(self.num_write > 0):
|
||||
if(self.num_w_ports > 0):
|
||||
self.write_port_flag = True
|
||||
else:
|
||||
self.write_port_flag = False
|
||||
|
||||
if(self.num_read > 0):
|
||||
if(self.num_r_ports > 0):
|
||||
self.read_port_flag = True
|
||||
else:
|
||||
self.read_port_flag = False
|
||||
|
||||
# determine the distance of the leftmost/rightmost transistor gate connection
|
||||
if (self.num_read > 0):
|
||||
if (self.num_r_ports > 0):
|
||||
if(self.read_nmos_contact_extension > self.gate_contact_thres):
|
||||
end_connection = drc["minwidth_metal2"] + self.read_nmos_contact_extension + contact.m1m2.height
|
||||
else:
|
||||
|
|
@ -266,11 +272,11 @@ class pbitcell(pgate.pgate):
|
|||
# leftmost position = storage width + read/write ports width + write ports width + read ports width + end transistor gate connections + metal spacing necessary for tiling the bitcell
|
||||
self.leftmost_xpos = -self.inverter_tile_width \
|
||||
- self.inverter_to_write_spacing \
|
||||
- self.readwrite_port_flag*(self.readwrite_nmos.active_height + (self.num_readwrite-1)*self.readwrite_tile_width) \
|
||||
- self.readwrite_port_flag*(self.readwrite_nmos.active_height + (self.num_rw_ports-1)*self.readwrite_tile_width) \
|
||||
- self.write_port_flag*self.readwrite_port_flag*self.write_to_write_spacing \
|
||||
- self.write_port_flag*(self.write_nmos.active_height + (self.num_write-1)*self.write_tile_width) \
|
||||
- self.write_port_flag*(self.write_nmos.active_height + (self.num_w_ports-1)*self.write_tile_width) \
|
||||
- self.read_port_flag*self.write_to_read_spacing \
|
||||
- self.read_port_flag*(self.read_nmos.active_height + (self.num_read-1)*self.read_tile_width) \
|
||||
- self.read_port_flag*(self.read_nmos.active_height + (self.num_r_ports-1)*self.read_tile_width) \
|
||||
- end_connection \
|
||||
- 0.5*drc["poly_to_polycontact"]
|
||||
|
||||
|
|
@ -279,9 +285,9 @@ class pbitcell(pgate.pgate):
|
|||
# bottommost position = gnd height + rwwl height + wwl height + rwl height + space needed between tiled bitcells
|
||||
array_tiling_offset = 0.5*drc["minwidth_metal2"]
|
||||
self.botmost_ypos = -self.rail_tile_height \
|
||||
- self.num_readwrite*self.rowline_tile_height \
|
||||
- self.num_write*self.rowline_tile_height \
|
||||
- self.num_read*self.rowline_tile_height \
|
||||
- self.num_rw_ports*self.rowline_tile_height \
|
||||
- self.num_w_ports*self.rowline_tile_height \
|
||||
- self.num_r_ports*self.rowline_tile_height \
|
||||
- array_tiling_offset
|
||||
|
||||
# topmost position = height of the inverter + height of vdd
|
||||
|
|
@ -420,19 +426,19 @@ class pbitcell(pgate.pgate):
|
|||
"""
|
||||
|
||||
# define write transistor variables as empty arrays based on the number of write ports
|
||||
self.readwrite_nmos_left = [None] * self.num_readwrite
|
||||
self.readwrite_nmos_right = [None] * self.num_readwrite
|
||||
self.readwrite_nmos_left = [None] * self.num_rw_ports
|
||||
self.readwrite_nmos_right = [None] * self.num_rw_ports
|
||||
|
||||
# iterate over the number of read/write ports
|
||||
for k in range(0,self.num_readwrite):
|
||||
for k in range(0,self.num_rw_ports):
|
||||
# add read/write transistors
|
||||
self.readwrite_nmos_left[k] = self.add_inst(name="readwrite_nmos_left{}".format(k),
|
||||
mod=self.readwrite_nmos)
|
||||
self.connect_inst(["Q", "rwwl{}".format(k), "rwbl{}".format(k), "gnd"])
|
||||
self.connect_inst(["Q", self.rw_wl_names[k], self.rw_bl_names[k], "gnd"])
|
||||
|
||||
self.readwrite_nmos_right[k] = self.add_inst(name="readwrite_nmos_right{}".format(k),
|
||||
mod=self.readwrite_nmos)
|
||||
self.connect_inst(["Q_bar", "rwwl{}".format(k), "rwbl_bar{}".format(k), "gnd"])
|
||||
self.connect_inst(["Q_bar", self.rw_wl_names[k], self.rw_br_names[k], "gnd"])
|
||||
|
||||
|
||||
def place_readwrite_ports(self):
|
||||
|
|
@ -441,15 +447,15 @@ class pbitcell(pgate.pgate):
|
|||
"""
|
||||
|
||||
# Define variables relevant to write transistors
|
||||
self.rwwl_positions = [None] * self.num_readwrite
|
||||
self.rwbl_positions = [None] * self.num_readwrite
|
||||
self.rwbl_bar_positions = [None] * self.num_readwrite
|
||||
self.rwwl_positions = [None] * self.num_rw_ports
|
||||
self.rwbl_positions = [None] * self.num_rw_ports
|
||||
self.rwbl_bar_positions = [None] * self.num_rw_ports
|
||||
|
||||
# define offset correction due to rotation of the ptx module
|
||||
readwrite_rotation_correct = self.readwrite_nmos.active_height
|
||||
|
||||
# iterate over the number of read/write ports
|
||||
for k in range(0,self.num_readwrite):
|
||||
for k in range(0,self.num_rw_ports):
|
||||
# Add transistors
|
||||
# calculate read/write transistor offsets
|
||||
left_readwrite_transistor_xpos = self.left_building_edge \
|
||||
|
|
@ -504,14 +510,14 @@ class pbitcell(pgate.pgate):
|
|||
"""
|
||||
Routes read/write trnasistors to their respective wordlines
|
||||
"""
|
||||
for k in range(0,self.num_readwrite):
|
||||
for k in range(0,self.num_rw_ports):
|
||||
# Gate/RWWL connections
|
||||
# add poly-to-meltal2 contacts to connect gate of read/write transistors to RWWL (contact next to gate)
|
||||
# contact must be placed a metal1 width below the source pin to avoid drc from source pin routings
|
||||
if(self.readwrite_nmos_contact_extension > self.gate_contact_thres):
|
||||
contact_xpos = self.readwrite_nmos_left[k].get_pin("S").lc().x - drc["minwidth_metal2"] - 0.5*contact.m1m2.width
|
||||
else:
|
||||
contact_xpos = left_readwrite_transistor_xpos - self.readwrite_nmos.active_height - drc["poly_to_active"] - 0.5*contact.poly.width
|
||||
contact_xpos = self.readwrite_nmos_left[k].offset.x - self.readwrite_nmos.active_height - drc["poly_to_active"] - 0.5*contact.poly.width
|
||||
contact_ypos = self.readwrite_nmos_left[k].get_pin("D").bc().y - drc["minwidth_metal1"] - 0.5*contact.m1m2.height
|
||||
left_gate_contact = vector(contact_xpos, contact_ypos)
|
||||
|
||||
|
|
@ -523,7 +529,7 @@ class pbitcell(pgate.pgate):
|
|||
if(self.readwrite_nmos_contact_extension > self.gate_contact_thres):
|
||||
contact_xpos = self.readwrite_nmos_right[k].get_pin("S").rc().x + drc["minwidth_metal2"] + 0.5*contact.m1m2.width
|
||||
else:
|
||||
contact_xpos = right_readwrite_transistor_xpos + drc["poly_to_active"] + 0.5*contact.poly.width
|
||||
contact_xpos = self.readwrite_nmos_right[k].offset.x + drc["poly_to_active"] + 0.5*contact.poly.width
|
||||
contact_ypos = self.readwrite_nmos_right[k].get_pin("D").bc().y - drc["minwidth_metal1"] - 0.5*contact.m1m2.height
|
||||
right_gate_contact = vector(contact_xpos, contact_ypos)
|
||||
|
||||
|
|
@ -559,7 +565,7 @@ class pbitcell(pgate.pgate):
|
|||
"""
|
||||
Routes read/write transistors to their respective bitlines
|
||||
"""
|
||||
for k in range(0,self.num_readwrite):
|
||||
for k in range(0,self.num_rw_ports):
|
||||
# Source/RWBL/RWBL_bar connections
|
||||
# add metal1-to-metal2 contacts on top of read/write transistor source pins for connection to WBL and WBL_bar
|
||||
offset_left = self.readwrite_nmos_left[k].get_pin("S").center()
|
||||
|
|
@ -577,7 +583,7 @@ class pbitcell(pgate.pgate):
|
|||
"""
|
||||
Routes read/write transistors to the storage component of the bitcell
|
||||
"""
|
||||
last_inst = self.num_readwrite - 1
|
||||
last_inst = self.num_rw_ports - 1
|
||||
|
||||
# Drain/Storage connections
|
||||
# this path only needs to be drawn once on the last iteration of the loop
|
||||
|
|
@ -624,19 +630,19 @@ class pbitcell(pgate.pgate):
|
|||
write_rotation_correct = self.write_nmos.active_height
|
||||
|
||||
# define write transistor variables as empty arrays based on the number of write ports
|
||||
self.write_nmos_left = [None] * self.num_write
|
||||
self.write_nmos_right = [None] * self.num_write
|
||||
self.write_nmos_left = [None] * self.num_w_ports
|
||||
self.write_nmos_right = [None] * self.num_w_ports
|
||||
|
||||
# iterate over the number of write ports
|
||||
for k in range(0,self.num_write):
|
||||
for k in range(0,self.num_w_ports):
|
||||
# add write transistors
|
||||
self.write_nmos_left[k] = self.add_inst(name="write_nmos_left{}".format(k),
|
||||
mod=self.write_nmos)
|
||||
self.connect_inst(["Q", "wwl{}".format(k), "wbl{}".format(k), "gnd"])
|
||||
self.connect_inst(["Q", self.w_wl_names[k], self.w_bl_names[k], "gnd"])
|
||||
|
||||
self.write_nmos_right[k] = self.add_inst(name="write_nmos_right{}".format(k),
|
||||
mod=self.write_nmos)
|
||||
self.connect_inst(["Q_bar", "wwl{}".format(k), "wbl_bar{}".format(k), "gnd"])
|
||||
self.connect_inst(["Q_bar", self.w_wl_names[k], self.w_br_names[k], "gnd"])
|
||||
|
||||
|
||||
def place_write_ports(self):
|
||||
|
|
@ -644,15 +650,15 @@ class pbitcell(pgate.pgate):
|
|||
Places write ports in the bit cell.
|
||||
"""
|
||||
# Define variables relevant to write transistors
|
||||
self.wwl_positions = [None] * self.num_write
|
||||
self.wbl_positions = [None] * self.num_write
|
||||
self.wbl_bar_positions = [None] * self.num_write
|
||||
self.wwl_positions = [None] * self.num_w_ports
|
||||
self.wbl_positions = [None] * self.num_w_ports
|
||||
self.wbl_bar_positions = [None] * self.num_w_ports
|
||||
|
||||
# define offset correction due to rotation of the ptx module
|
||||
write_rotation_correct = self.write_nmos.active_height
|
||||
|
||||
# iterate over the number of write ports
|
||||
for k in range(0,self.num_write):
|
||||
for k in range(0,self.num_w_ports):
|
||||
# Add transistors
|
||||
# calculate write transistor offsets
|
||||
left_write_transistor_xpos = self.left_building_edge \
|
||||
|
|
@ -677,7 +683,7 @@ class pbitcell(pgate.pgate):
|
|||
# Add WWL lines
|
||||
# calculate WWL position
|
||||
wwl_ypos = self.gnd_position.y \
|
||||
- self.num_readwrite*self.rowline_tile_height \
|
||||
- self.num_rw_ports*self.rowline_tile_height \
|
||||
- (k+1)*self.rowline_tile_height
|
||||
self.wwl_positions[k] = vector(self.leftmost_xpos, wwl_ypos)
|
||||
|
||||
|
|
@ -711,14 +717,14 @@ class pbitcell(pgate.pgate):
|
|||
"""
|
||||
Routes write transistors to their respective wordlines
|
||||
"""
|
||||
for k in range(0,self.num_write):
|
||||
for k in range(0,self.num_w_ports):
|
||||
# Gate/WWL connections
|
||||
# add poly-to-meltal2 contacts to connect gate of write transistors to WWL (contact next to gate)
|
||||
# contact must be placed a metal width below the source pin to avoid drc from source pin routings
|
||||
if(self.write_nmos_contact_extension > self.gate_contact_thres):
|
||||
contact_xpos = self.write_nmos_left[k].get_pin("S").lc().x - drc["minwidth_metal2"] - 0.5*contact.m1m2.width
|
||||
else:
|
||||
contact_xpos = left_write_transistor_xpos - self.write_nmos.active_height - drc["poly_to_active"] - 0.5*contact.poly.width
|
||||
contact_xpos = self.write_nmos_left[k].offset.x - self.write_nmos.active_height - drc["poly_to_active"] - 0.5*contact.poly.width
|
||||
contact_ypos = self.write_nmos_left[k].get_pin("D").bc().y - drc["minwidth_metal1"] - 0.5*contact.m1m2.height
|
||||
left_gate_contact = vector(contact_xpos, contact_ypos)
|
||||
|
||||
|
|
@ -730,7 +736,7 @@ class pbitcell(pgate.pgate):
|
|||
if(self.write_nmos_contact_extension > self.gate_contact_thres):
|
||||
contact_xpos = self.write_nmos_right[k].get_pin("S").rc().x + drc["minwidth_metal2"] + 0.5*contact.m1m2.width
|
||||
else:
|
||||
contact_xpos = right_write_transistor_xpos + drc["poly_to_active"] + 0.5*contact.poly.width
|
||||
contact_xpos = self.write_nmos_right[k].offset.x + drc["poly_to_active"] + 0.5*contact.poly.width
|
||||
contact_ypos = self.write_nmos_right[k].get_pin("D").bc().y - drc["minwidth_metal1"] - 0.5*contact.m1m2.height
|
||||
right_gate_contact = vector(contact_xpos, contact_ypos)
|
||||
|
||||
|
|
@ -765,7 +771,7 @@ class pbitcell(pgate.pgate):
|
|||
"""
|
||||
Routes write transistors to their respective bitlines
|
||||
"""
|
||||
for k in range(0,self.num_write):
|
||||
for k in range(0,self.num_w_ports):
|
||||
# Source/WBL/WBL_bar connections
|
||||
# add metal1-to-metal2 contacts on top of write transistor source pins for connection to WBL and WBL_bar
|
||||
offset_left = self.write_nmos_left[k].get_pin("S").center()
|
||||
|
|
@ -782,7 +788,7 @@ class pbitcell(pgate.pgate):
|
|||
"""
|
||||
Routes write transistors to the storage component of the bitcell
|
||||
"""
|
||||
last_inst = self.num_write - 1
|
||||
last_inst = self.num_w_ports - 1
|
||||
|
||||
# Drain/Storage connections
|
||||
# this path only needs to be drawn once on the last iteration of the loop
|
||||
|
|
@ -829,13 +835,13 @@ class pbitcell(pgate.pgate):
|
|||
"""
|
||||
|
||||
# define read transistor variables as empty arrays based on the number of read ports
|
||||
self.read_nmos_left = [None] * self.num_read
|
||||
self.read_nmos_right = [None] * self.num_read
|
||||
self.read_access_nmos_left = [None] * self.num_read
|
||||
self.read_access_nmos_right = [None] * self.num_read
|
||||
self.read_nmos_left = [None] * self.num_r_ports
|
||||
self.read_nmos_right = [None] * self.num_r_ports
|
||||
self.read_access_nmos_left = [None] * self.num_r_ports
|
||||
self.read_access_nmos_right = [None] * self.num_r_ports
|
||||
|
||||
# iterate over the number of read ports
|
||||
for k in range(0,self.num_read):
|
||||
for k in range(0,self.num_r_ports):
|
||||
# add read-access transistors
|
||||
self.read_access_nmos_left[k] = self.add_inst(name="read_access_nmos_left{}".format(k),
|
||||
mod=self.read_nmos)
|
||||
|
|
@ -848,20 +854,20 @@ class pbitcell(pgate.pgate):
|
|||
# add read transistors
|
||||
self.read_nmos_left[k] = self.add_inst(name="read_nmos_left{}".format(k),
|
||||
mod=self.read_nmos)
|
||||
self.connect_inst(["rbl{}".format(k), "rwl{}".format(k), "RA_to_R_left{}".format(k), "gnd"])
|
||||
self.connect_inst([self.r_bl_names[k], self.r_wl_names[k], "RA_to_R_left{}".format(k), "gnd"])
|
||||
|
||||
self.read_nmos_right[k] = self.add_inst(name="read_nmos_right{}".format(k),
|
||||
mod=self.read_nmos)
|
||||
self.connect_inst(["rbl_bar{}".format(k), "rwl{}".format(k), "RA_to_R_right{}".format(k), "gnd"])
|
||||
self.connect_inst([self.r_br_names[k], self.r_wl_names[k], "RA_to_R_right{}".format(k), "gnd"])
|
||||
|
||||
def place_read_ports(self):
|
||||
"""
|
||||
Places the read ports in the bit cell.
|
||||
"""
|
||||
# Define variables relevant to read transistors
|
||||
self.rwl_positions = [None] * self.num_read
|
||||
self.rbl_positions = [None] * self.num_read
|
||||
self.rbl_bar_positions = [None] * self.num_read
|
||||
self.rwl_positions = [None] * self.num_r_ports
|
||||
self.rbl_positions = [None] * self.num_r_ports
|
||||
self.rbl_bar_positions = [None] * self.num_r_ports
|
||||
|
||||
# define offset correction due to rotation of the ptx module
|
||||
read_rotation_correct = self.read_nmos.active_height
|
||||
|
|
@ -870,7 +876,7 @@ class pbitcell(pgate.pgate):
|
|||
overlap_offset = self.read_nmos.get_pin("D").ll() - self.read_nmos.get_pin("S").ll()
|
||||
|
||||
# iterate over the number of read ports
|
||||
for k in range(0,self.num_read):
|
||||
for k in range(0,self.num_r_ports):
|
||||
# Add transistors
|
||||
# calculate transistor offsets
|
||||
left_read_transistor_xpos = self.left_building_edge \
|
||||
|
|
@ -900,8 +906,8 @@ class pbitcell(pgate.pgate):
|
|||
# Add RWL lines
|
||||
# calculate RWL position
|
||||
rwl_ypos = self.gnd_position.y \
|
||||
- self.num_readwrite*self.rowline_tile_height \
|
||||
- self.num_write*self.rowline_tile_height \
|
||||
- self.num_rw_ports*self.rowline_tile_height \
|
||||
- self.num_w_ports*self.rowline_tile_height \
|
||||
- (k+1)*self.rowline_tile_height
|
||||
self.rwl_positions[k] = vector(self.leftmost_xpos, rwl_ypos)
|
||||
|
||||
|
|
@ -931,13 +937,13 @@ class pbitcell(pgate.pgate):
|
|||
"""
|
||||
Routes read transistors to their respective worlines
|
||||
"""
|
||||
for k in range(0,self.num_read):
|
||||
for k in range(0,self.num_r_ports):
|
||||
# Gate of read transistor / RWL connection
|
||||
# add poly-to-meltal2 contacts to connect gate of read transistors to RWL (contact next to gate)
|
||||
if(self.read_nmos_contact_extension > self.gate_contact_thres):
|
||||
contact_xpos = self.read_nmos_left[k].get_pin("S").lc().x - drc["minwidth_metal2"] - 0.5*contact.m1m2.width
|
||||
else:
|
||||
contact_xpos = left_read_transistor_xpos - self.read_nmos.active_height - drc["poly_to_active"] - 0.5*contact.poly.width
|
||||
contact_xpos = self.read_nmos_left[k].offset.x - self.read_nmos.active_height - drc["poly_to_active"] - 0.5*contact.poly.width
|
||||
contact_ypos = self.read_nmos_left[k].get_pin("G").lc().y
|
||||
left_gate_contact = vector(contact_xpos, contact_ypos)
|
||||
|
||||
|
|
@ -949,7 +955,7 @@ class pbitcell(pgate.pgate):
|
|||
if(self.read_nmos_contact_extension > self.gate_contact_thres):
|
||||
contact_xpos = self.read_nmos_right[k].get_pin("S").rc().x + drc["minwidth_metal2"] + 0.5*contact.m1m2.width
|
||||
else:
|
||||
contact_xpos = right_read_transistor_xpos + drc["poly_to_active"] + 0.5*contact.poly.width
|
||||
contact_xpos = self.read_nmos_right[k].offset.x + drc["poly_to_active"] + 0.5*contact.poly.width
|
||||
contact_ypos = self.read_nmos_right[k].get_pin("G").rc().y
|
||||
right_gate_contact = vector(contact_xpos, contact_ypos)
|
||||
|
||||
|
|
@ -989,7 +995,7 @@ class pbitcell(pgate.pgate):
|
|||
"""
|
||||
Routes read transistors to their respective bitlines
|
||||
"""
|
||||
for k in range(0,self.num_read):
|
||||
for k in range(0,self.num_r_ports):
|
||||
# Drain of read transistor / RBL & RBL_bar connection
|
||||
# add metal1-to-metal2 contacts on top of read transistor drain pins for connection to RBL and RBL_bar
|
||||
offset_left = self.read_nmos_left[k].get_pin("D").center()
|
||||
|
|
@ -1006,13 +1012,13 @@ class pbitcell(pgate.pgate):
|
|||
"""
|
||||
Routes read access transistors to the storage component of the bitcell
|
||||
"""
|
||||
for k in range(0,self.num_read):
|
||||
for k in range(0,self.num_r_ports):
|
||||
# Gate of read-access transistor / storage connection
|
||||
# add poly-to-metal1 contacts to connect gate of read-access transistors to output of inverters (contact next to gate)
|
||||
if(self.read_nmos_contact_extension > self.gate_contact_thres):
|
||||
contact_xpos = self.read_nmos_left[k].get_pin("S").rc().x + drc["minwidth_metal2"] + 0.5*contact.m1m2.width
|
||||
else:
|
||||
contact_xpos = left_read_transistor_xpos + drc["poly_to_active"] + 0.5*contact.poly.width
|
||||
contact_xpos = self.read_nmos_left[k].offset.x + drc["poly_to_active"] + 0.5*contact.poly.width
|
||||
contact_ypos = self.read_access_nmos_left[k].get_pin("G").rc().y
|
||||
left_gate_contact = vector(contact_xpos, contact_ypos)
|
||||
|
||||
|
|
@ -1022,7 +1028,7 @@ class pbitcell(pgate.pgate):
|
|||
if(self.read_nmos_contact_extension > self.gate_contact_thres):
|
||||
contact_xpos = self.read_nmos_right[k].get_pin("S").lc().x - drc["minwidth_metal2"] - 0.5*contact.m1m2.width
|
||||
else:
|
||||
contact_xpos = right_read_transistor_xpos - self.read_nmos.active_height - drc["poly_to_active"] - 0.5*contact.poly.width
|
||||
contact_xpos = self.read_nmos_right[k].offset.x - self.read_nmos.active_height - drc["poly_to_active"] - 0.5*contact.poly.width
|
||||
contact_ypos = self.read_access_nmos_right[k].get_pin("G").lc().y
|
||||
right_gate_contact = vector(contact_xpos, contact_ypos)
|
||||
|
||||
|
|
@ -1073,7 +1079,7 @@ class pbitcell(pgate.pgate):
|
|||
# extend pwell over read/write and write transistors to the
|
||||
# height of the write transistor well (read/write and write
|
||||
# transistors are the same height)
|
||||
if(self.num_write > 0):
|
||||
if(self.num_w_ports > 0):
|
||||
# calculate the edge of the write transistor well closest to the center
|
||||
left_write_well_xpos = self.write_nmos_left[0].offset.x + drc["well_enclosure_active"]
|
||||
right_write_well_xpos = self.write_nmos_right[0].offset.x - self.write_nmos.active_height - drc["well_enclosure_active"]
|
||||
|
|
@ -1099,7 +1105,7 @@ class pbitcell(pgate.pgate):
|
|||
height=write_well_height)
|
||||
|
||||
# extend pwell over the read transistors to the height of the bitcell
|
||||
if(self.num_read > 0):
|
||||
if(self.num_r_ports > 0):
|
||||
# calculate the edge of the read transistor well clostest to the center
|
||||
left_read_well_xpos = self.read_nmos_left[0].offset.x + drc["well_enclosure_active"]
|
||||
right_read_well_xpos = self.read_nmos_right[0].offset.x - self.read_nmos.active_height - drc["well_enclosure_active"]
|
||||
|
|
@ -1168,43 +1174,44 @@ class pbitcell(pgate.pgate):
|
|||
return bitcell_pins
|
||||
|
||||
def list_all_wl_names(self):
|
||||
""" Creates a list of all wordline pin names """
|
||||
return self.wl_names
|
||||
""" Creates a list of all wordline pin names """
|
||||
wordline_names = self.rw_wl_names + self.w_wl_names + self.r_wl_names
|
||||
return wordline_names
|
||||
|
||||
def list_all_bitline_names(self):
|
||||
""" Creates a list of all bitline pin names (both bl and br) """
|
||||
bitline_pins = []
|
||||
for port in range(self.total_ports):
|
||||
column_pins.append("bl{0}".format(port))
|
||||
column_pins.append("br{0}".format(port))
|
||||
bitline_pins.append("bl{0}".format(port))
|
||||
bitline_pins.append("br{0}".format(port))
|
||||
return bitline_pins
|
||||
|
||||
def list_all_bl_names(self):
|
||||
""" Creates a list of all bl pins names """
|
||||
bl_pins = [self.rw_bl_names, self.w_bl_names, self.r_bl_names]
|
||||
bl_pins = self.rw_bl_names + self.w_bl_names + self.r_bl_names
|
||||
return bl_pins
|
||||
|
||||
def list_all_br_names(self):
|
||||
""" Creates a list of all br pins names """
|
||||
br_pins = [self.rw_br_names, self.w_br_names, self.r_br_names]
|
||||
br_pins = self.rw_br_names + self.w_br_names + self.r_br_names
|
||||
return br_pins
|
||||
|
||||
def list_read_bl_names(self):
|
||||
""" Creates a list of bl pin names associated with read ports """
|
||||
bl_pins = [self.rw_bl_names, self.r_bl_names]
|
||||
bl_pins = self.rw_bl_names + self.r_bl_names
|
||||
return bl_pins
|
||||
|
||||
def list_read_br_names(self):
|
||||
""" Creates a list of br pin names associated with read ports """
|
||||
br_pins = [self.rw_br_names, self.r_br_names]
|
||||
br_pins = self.rw_br_names + self.r_br_names
|
||||
return br_pins
|
||||
|
||||
def list_write_bl_names(self):
|
||||
""" Creates a list of bl pin names associated with write ports """
|
||||
bl_pins = [self.rw_bl_names, self.w_bl_names]
|
||||
bl_pins = self.rw_bl_names + self.w_bl_names
|
||||
return bl_pins
|
||||
|
||||
def list_write_br_names(self):
|
||||
""" Creates a list of br pin names asscociated with write ports"""
|
||||
br_pins = [self.rw_br_names, self.w_br_names]
|
||||
br_pins = self.rw_br_names + self.w_br_names
|
||||
return br_pins
|
||||
|
|
|
|||
|
|
@ -11,10 +11,19 @@ class pgate(design.design):
|
|||
This is a module that implements some shared functions for parameterized gates.
|
||||
"""
|
||||
|
||||
def __init__(self, name):
|
||||
def __init__(self, name, height=None):
|
||||
""" Creates a generic cell """
|
||||
design.design.__init__(self, name)
|
||||
|
||||
if height:
|
||||
self.height = height
|
||||
elif not height:
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
bitcell = getattr(c, OPTS.bitcell)
|
||||
b = bitcell()
|
||||
self.height = b.height
|
||||
|
||||
|
||||
def connect_pin_to_rail(self,inst,pin,supply):
|
||||
""" Conencts a ptx pin to a supply rail. """
|
||||
|
|
|
|||
|
|
@ -17,26 +17,22 @@ class pinv(pgate.pgate):
|
|||
from center of rail to rail.. The route_output will route the
|
||||
output to the right side of the cell for easier access.
|
||||
"""
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
bitcell = getattr(c, OPTS.bitcell)
|
||||
|
||||
unique_id = 1
|
||||
|
||||
def __init__(self, size=1, beta=parameter["beta"], height=bitcell.height, route_output=True):
|
||||
def __init__(self, size=1, beta=parameter["beta"], height=None, route_output=True):
|
||||
# We need to keep unique names because outputting to GDSII
|
||||
# will use the last record with a given name. I.e., you will
|
||||
# over-write a design in GDS if one has and the other doesn't
|
||||
# have poly connected, for example.
|
||||
name = "pinv_{}".format(pinv.unique_id)
|
||||
pinv.unique_id += 1
|
||||
pgate.pgate.__init__(self, name)
|
||||
pgate.pgate.__init__(self, name, height)
|
||||
debug.info(2, "create pinv structure {0} with size of {1}".format(name, size))
|
||||
|
||||
self.nmos_size = size
|
||||
self.pmos_size = beta*size
|
||||
self.beta = beta
|
||||
self.height = height # Maybe minimize height if not defined in future?
|
||||
self.route_output = False
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -11,13 +11,9 @@ class pinvbuf(design.design):
|
|||
This is a simple inverter/buffer used for driving loads. It is
|
||||
used in the column decoder for 1:2 decoding and as the clock buffer.
|
||||
"""
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
bitcell = getattr(c, OPTS.bitcell)
|
||||
|
||||
unique_id = 1
|
||||
|
||||
def __init__(self, driver_size=4, height=bitcell.height, name=""):
|
||||
def __init__(self, driver_size=4, height=None, name=""):
|
||||
|
||||
self.stage_effort = 4
|
||||
self.row_height = height
|
||||
|
|
@ -32,7 +28,7 @@ class pinvbuf(design.design):
|
|||
name = "pinvbuf_{0}_{1}_{2}".format(self.predriver_size, self.driver_size, pinvbuf.unique_id)
|
||||
pinvbuf.unique_id += 1
|
||||
|
||||
design.design.__init__(self, name)
|
||||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {}".format(self.name))
|
||||
|
||||
self.create_netlist()
|
||||
|
|
|
|||
|
|
@ -12,24 +12,19 @@ class pnand2(pgate.pgate):
|
|||
This model use ptx to generate a 2-input nand within a cetrain height.
|
||||
"""
|
||||
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
bitcell = getattr(c, OPTS.bitcell)
|
||||
|
||||
unique_id = 1
|
||||
|
||||
def __init__(self, size=1, height=bitcell.height):
|
||||
def __init__(self, size=1, height=None):
|
||||
""" Creates a cell for a simple 2 input nand """
|
||||
name = "pnand2_{0}".format(pnand2.unique_id)
|
||||
pnand2.unique_id += 1
|
||||
pgate.pgate.__init__(self, name)
|
||||
pgate.pgate.__init__(self, name, height)
|
||||
debug.info(2, "create pnand2 structure {0} with size of {1}".format(name, size))
|
||||
|
||||
self.nmos_size = 2*size
|
||||
self.pmos_size = parameter["beta"]*size
|
||||
self.nmos_width = self.nmos_size*drc["minwidth_tx"]
|
||||
self.pmos_width = self.pmos_size*drc["minwidth_tx"]
|
||||
self.height = height
|
||||
|
||||
# FIXME: Allow these to be sized
|
||||
debug.check(size==1,"Size 1 pnand2 is only supported now.")
|
||||
|
|
|
|||
|
|
@ -12,18 +12,13 @@ class pnand3(pgate.pgate):
|
|||
This model use ptx to generate a 2-input nand within a cetrain height.
|
||||
"""
|
||||
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
bitcell = mod_bitcell()
|
||||
|
||||
unique_id = 1
|
||||
|
||||
def __init__(self, size=1, height=bitcell.height):
|
||||
def __init__(self, size=1, height=None):
|
||||
""" Creates a cell for a simple 3 input nand """
|
||||
name = "pnand3_{0}".format(pnand3.unique_id)
|
||||
pnand3.unique_id += 1
|
||||
pgate.pgate.__init__(self, name)
|
||||
pgate.pgate.__init__(self, name, height)
|
||||
debug.info(2, "create pnand3 structure {0} with size of {1}".format(name, size))
|
||||
|
||||
# We have trouble pitch matching a 3x sizes to the bitcell...
|
||||
|
|
@ -32,7 +27,6 @@ class pnand3(pgate.pgate):
|
|||
self.pmos_size = parameter["beta"]*size
|
||||
self.nmos_width = self.nmos_size*drc["minwidth_tx"]
|
||||
self.pmos_width = self.pmos_size*drc["minwidth_tx"]
|
||||
self.height = height
|
||||
|
||||
# FIXME: Allow these to be sized
|
||||
debug.check(size==1,"Size 1 pnand3 is only supported now.")
|
||||
|
|
|
|||
|
|
@ -12,17 +12,13 @@ class pnor2(pgate.pgate):
|
|||
This model use ptx to generate a 2-input nor within a cetrain height.
|
||||
"""
|
||||
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
bitcell = getattr(c, OPTS.bitcell)
|
||||
|
||||
unique_id = 1
|
||||
|
||||
def __init__(self, size=1, height=bitcell.height):
|
||||
def __init__(self, size=1, height=None):
|
||||
""" Creates a cell for a simple 2 input nor """
|
||||
name = "pnor2_{0}".format(pnor2.unique_id)
|
||||
pnor2.unique_id += 1
|
||||
pgate.pgate.__init__(self, name)
|
||||
pgate.pgate.__init__(self, name, height)
|
||||
debug.info(2, "create pnor2 structure {0} with size of {1}".format(name, size))
|
||||
|
||||
self.nmos_size = size
|
||||
|
|
@ -30,7 +26,6 @@ class pnor2(pgate.pgate):
|
|||
self.pmos_size = 1.5*parameter["beta"]*size
|
||||
self.nmos_width = self.nmos_size*drc["minwidth_tx"]
|
||||
self.pmos_width = self.pmos_size*drc["minwidth_tx"]
|
||||
self.height = height
|
||||
|
||||
# FIXME: Allow these to be sized
|
||||
debug.check(size==1,"Size 1 pnor2 is only supported now.")
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ class single_level_column_mux(design.design):
|
|||
self.add_wells()
|
||||
|
||||
def add_modules(self):
|
||||
# This is just used for measurements,
|
||||
# so don't add the module
|
||||
from importlib import reload
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
|
|
|
|||
|
|
@ -12,8 +12,9 @@ class sram():
|
|||
results.
|
||||
We can later add visualizer and other high-level functions as needed.
|
||||
"""
|
||||
def __init__(self, sram_config, name="sram"):
|
||||
def __init__(self, sram_config, name):
|
||||
|
||||
sram_config.compute_sizes()
|
||||
sram_config.set_local_config(self)
|
||||
|
||||
# reset the static duplicate name checker for unit tests
|
||||
|
|
@ -27,6 +28,8 @@ class sram():
|
|||
start_time = datetime.datetime.now()
|
||||
|
||||
self.name = name
|
||||
|
||||
|
||||
if self.num_banks == 1:
|
||||
from sram_1bank import sram_1bank as sram
|
||||
elif self.num_banks == 2:
|
||||
|
|
@ -35,8 +38,8 @@ class sram():
|
|||
from sram_4bank import sram_4bank as sram
|
||||
else:
|
||||
debug.error("Invalid number of banks.",-1)
|
||||
|
||||
self.s = sram(sram_config, name)
|
||||
|
||||
self.s = sram(name, sram_config)
|
||||
self.s.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
self.s.create_layout()
|
||||
|
|
|
|||
|
|
@ -18,12 +18,11 @@ class sram_1bank(sram_base):
|
|||
"""
|
||||
Procedures specific to a one bank SRAM.
|
||||
"""
|
||||
def __init__(self, sram_config, name):
|
||||
sram_base.__init__(self, sram_config, name)
|
||||
def __init__(self, name, sram_config):
|
||||
sram_base.__init__(self, name, sram_config)
|
||||
|
||||
|
||||
def create_netlist(self):
|
||||
self.compute_sizes()
|
||||
sram_base.create_netlist(self)
|
||||
self.create_modules()
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ class sram_2bank(sram_base):
|
|||
"""
|
||||
Procedures specific to a two bank SRAM.
|
||||
"""
|
||||
def __init__(self, sram_config, name):
|
||||
sram_base.__init__(self, sram_config, name)
|
||||
def __init__(self, name, sram_config):
|
||||
sram_base.__init__(self, name, sram_config)
|
||||
|
||||
def compute_bank_offsets(self):
|
||||
""" Compute the overall offsets for a two bank SRAM """
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ class sram_4bank(sram_base):
|
|||
"""
|
||||
Procedures specific to a four bank SRAM.
|
||||
"""
|
||||
def __init__(self, sram_config, name):
|
||||
sram_base.__init__(self, sram_config, name)
|
||||
def __init__(self, name, sram_config):
|
||||
sram_base.__init__(self, name, sram_config)
|
||||
|
||||
def compute_bank_offsets(self):
|
||||
""" Compute the overall offsets for a four bank SRAM """
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import datetime
|
|||
import getpass
|
||||
import debug
|
||||
from importlib import reload
|
||||
from math import log,sqrt,ceil
|
||||
from vector import vector
|
||||
from globals import OPTS, print_time
|
||||
|
||||
|
|
@ -14,85 +13,18 @@ class sram_base(design):
|
|||
Dynamically generated SRAM by connecting banks to control logic. The
|
||||
number of banks should be 1 , 2 or 4
|
||||
"""
|
||||
def __init__(self, sram_config, name):
|
||||
def __init__(self, name, sram_config):
|
||||
design.__init__(self, name)
|
||||
|
||||
# This is used to compute the sizes of the SRAM
|
||||
# and must be loaded before netlist creation
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
|
||||
self.sram_config = sram_config
|
||||
self.sram_config.set_local_config(self)
|
||||
|
||||
self.sram_config = sram_config
|
||||
sram_config.set_local_config(self)
|
||||
|
||||
self.total_write = OPTS.num_rw_ports + OPTS.num_w_ports
|
||||
self.total_read = OPTS.num_rw_ports + OPTS.num_r_ports
|
||||
self.total_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports
|
||||
|
||||
self.bank_insts = []
|
||||
|
||||
def compute_sizes(self):
|
||||
""" Computes the organization of the memory using bitcell size by trying to make it square."""
|
||||
|
||||
debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.")
|
||||
|
||||
self.num_words_per_bank = self.num_words/self.num_banks
|
||||
self.num_bits_per_bank = self.word_size*self.num_words_per_bank
|
||||
|
||||
# If this was hard coded, don't dynamically compute it!
|
||||
if self.sram_config.words_per_row:
|
||||
self.words_per_row = self.sram_config.words_per_row
|
||||
else:
|
||||
# Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry)
|
||||
self.bank_area = self.bitcell.width*self.bitcell.height*self.num_bits_per_bank
|
||||
self.bank_side_length = sqrt(self.bank_area)
|
||||
|
||||
# Estimate the words per row given the height of the bitcell and the square side length
|
||||
self.tentative_num_cols = int(self.bank_side_length/self.bitcell.width)
|
||||
self.words_per_row = self.estimate_words_per_row(self.tentative_num_cols, self.word_size)
|
||||
|
||||
# Estimate the number of rows given the tentative words per row
|
||||
self.tentative_num_rows = self.num_bits_per_bank / (self.words_per_row*self.word_size)
|
||||
self.words_per_row = self.amend_words_per_row(self.tentative_num_rows, self.words_per_row)
|
||||
|
||||
# Fix the number of columns and rows
|
||||
self.num_cols = int(self.words_per_row*self.word_size)
|
||||
self.num_rows = int(self.num_words_per_bank/self.words_per_row)
|
||||
|
||||
# Compute the address and bank sizes
|
||||
self.row_addr_size = int(log(self.num_rows, 2))
|
||||
self.col_addr_size = int(log(self.words_per_row, 2))
|
||||
self.bank_addr_size = self.col_addr_size + self.row_addr_size
|
||||
self.addr_size = self.bank_addr_size + int(log(self.num_banks, 2))
|
||||
|
||||
self.sram_config.words_per_row = self.words_per_row
|
||||
debug.info(1,"Words per row: {}".format(self.words_per_row))
|
||||
|
||||
def estimate_words_per_row(self,tentative_num_cols, word_size):
|
||||
"""
|
||||
This provides a heuristic rounded estimate for the number of words
|
||||
per row.
|
||||
"""
|
||||
|
||||
if tentative_num_cols < 1.5*word_size:
|
||||
return 1
|
||||
elif tentative_num_cols > 3*word_size:
|
||||
return 4
|
||||
else:
|
||||
return 2
|
||||
|
||||
def amend_words_per_row(self,tentative_num_rows, words_per_row):
|
||||
"""
|
||||
This picks the number of words per row more accurately by limiting
|
||||
it to a minimum and maximum.
|
||||
"""
|
||||
# Recompute the words per row given a hard max
|
||||
if(tentative_num_rows > 512):
|
||||
debug.check(tentative_num_rows*words_per_row <= 2048, "Number of words exceeds 2048")
|
||||
return int(words_per_row*tentative_num_rows/512)
|
||||
# Recompute the words per row given a hard min
|
||||
if(tentative_num_rows < 16):
|
||||
debug.check(tentative_num_rows*words_per_row >= 16, "Minimum number of rows is 16, but given {0}".format(tentative_num_rows))
|
||||
return int(words_per_row*tentative_num_rows/16)
|
||||
|
||||
return words_per_row
|
||||
|
||||
def add_pins(self):
|
||||
""" Add pins for entire SRAM. """
|
||||
|
|
@ -274,6 +206,9 @@ class sram_base(design):
|
|||
|
||||
def add_modules(self):
|
||||
""" Create all the modules that will be used """
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
|
||||
c = reload(__import__(OPTS.control_logic))
|
||||
self.mod_control_logic = getattr(c, OPTS.control_logic)
|
||||
|
|
|
|||
|
|
@ -1,36 +1,96 @@
|
|||
import debug
|
||||
from math import log,sqrt,ceil
|
||||
from importlib import reload
|
||||
from globals import OPTS
|
||||
|
||||
class sram_config:
|
||||
""" This is a structure that is used to hold the SRAM configuration options. """
|
||||
|
||||
def __init__(self, word_size, num_words, num_banks=1, num_rw_ports=OPTS.num_rw_ports, num_w_ports=OPTS.num_w_ports, num_r_ports=OPTS.num_r_ports):
|
||||
def __init__(self, word_size, num_words, num_banks=1):
|
||||
self.word_size = word_size
|
||||
self.num_words = num_words
|
||||
self.num_banks = num_banks
|
||||
self.num_rw_ports = num_rw_ports
|
||||
self.num_w_ports = num_w_ports
|
||||
self.num_r_ports = num_r_ports
|
||||
|
||||
# This will get over-written when we determine the organization
|
||||
self.num_banks = 1
|
||||
self.words_per_row = None
|
||||
|
||||
self.total_write = num_rw_ports + num_w_ports
|
||||
self.total_read = num_rw_ports + num_r_ports
|
||||
self.total_ports = num_rw_ports + num_w_ports + num_r_ports
|
||||
|
||||
# Move the module names to this?
|
||||
|
||||
|
||||
def set_local_config(self, module):
|
||||
module.word_size = self.word_size
|
||||
module.num_words = self.num_words
|
||||
module.num_banks = self.num_banks
|
||||
module.num_rw_ports = self.num_rw_ports
|
||||
module.num_w_ports = self.num_w_ports
|
||||
module.num_r_ports = self.num_r_ports
|
||||
""" Copy all of the member variables to the given module for convenience """
|
||||
|
||||
module.words_per_row = self.words_per_row
|
||||
|
||||
module.total_write = self.total_write
|
||||
module.total_read = self.total_read
|
||||
module.total_ports = self.total_ports
|
||||
members = [attr for attr in dir(self) if not callable(getattr(self, attr)) and not attr.startswith("__")]
|
||||
|
||||
# Copy all the variables to the local module
|
||||
for member in members:
|
||||
setattr(module,member,getattr(self,member))
|
||||
|
||||
def compute_sizes(self):
|
||||
""" Computes the organization of the memory using bitcell size by trying to make it square."""
|
||||
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
# pass a copy of myself for the port numbers
|
||||
self.bitcell = self.mod_bitcell()
|
||||
|
||||
|
||||
debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.")
|
||||
|
||||
self.num_words_per_bank = self.num_words/self.num_banks
|
||||
self.num_bits_per_bank = self.word_size*self.num_words_per_bank
|
||||
|
||||
# If this was hard coded, don't dynamically compute it!
|
||||
if not self.words_per_row:
|
||||
# Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry)
|
||||
self.bank_area = self.bitcell.width*self.bitcell.height*self.num_bits_per_bank
|
||||
self.bank_side_length = sqrt(self.bank_area)
|
||||
|
||||
# Estimate the words per row given the height of the bitcell and the square side length
|
||||
self.tentative_num_cols = int(self.bank_side_length/self.bitcell.width)
|
||||
self.words_per_row = self.estimate_words_per_row(self.tentative_num_cols, self.word_size)
|
||||
|
||||
# Estimate the number of rows given the tentative words per row
|
||||
self.tentative_num_rows = self.num_bits_per_bank / (self.words_per_row*self.word_size)
|
||||
self.words_per_row = self.amend_words_per_row(self.tentative_num_rows, self.words_per_row)
|
||||
|
||||
# Fix the number of columns and rows
|
||||
self.num_cols = int(self.words_per_row*self.word_size)
|
||||
self.num_rows = int(self.num_words_per_bank/self.words_per_row)
|
||||
|
||||
# Compute the address and bank sizes
|
||||
self.row_addr_size = int(log(self.num_rows, 2))
|
||||
self.col_addr_size = int(log(self.words_per_row, 2))
|
||||
self.bank_addr_size = self.col_addr_size + self.row_addr_size
|
||||
self.addr_size = self.bank_addr_size + int(log(self.num_banks, 2))
|
||||
|
||||
debug.info(1,"Words per row: {}".format(self.words_per_row))
|
||||
|
||||
def estimate_words_per_row(self,tentative_num_cols, word_size):
|
||||
"""
|
||||
This provides a heuristic rounded estimate for the number of words
|
||||
per row.
|
||||
"""
|
||||
|
||||
if tentative_num_cols < 1.5*word_size:
|
||||
return 1
|
||||
elif tentative_num_cols > 3*word_size:
|
||||
return 4
|
||||
else:
|
||||
return 2
|
||||
|
||||
def amend_words_per_row(self,tentative_num_rows, words_per_row):
|
||||
"""
|
||||
This picks the number of words per row more accurately by limiting
|
||||
it to a minimum and maximum.
|
||||
"""
|
||||
# Recompute the words per row given a hard max
|
||||
if(not OPTS.is_unit_test and tentative_num_rows > 512):
|
||||
debug.check(tentative_num_rows*words_per_row <= 2048, "Number of words exceeds 2048")
|
||||
return int(words_per_row*tentative_num_rows/512)
|
||||
# Recompute the words per row given a hard min
|
||||
if(not OPTS.is_unit_test and tentative_num_rows < 16):
|
||||
debug.check(tentative_num_rows*words_per_row >= 16, "Minimum number of rows is 16, but given {0}".format(tentative_num_rows))
|
||||
return int(words_per_row*tentative_num_rows/16)
|
||||
|
||||
return words_per_row
|
||||
|
|
|
|||
|
|
@ -18,47 +18,76 @@ class pbitcell_test(openram_test):
|
|||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
import pbitcell
|
||||
from pbitcell import pbitcell
|
||||
import tech
|
||||
|
||||
OPTS.num_rw_ports=1
|
||||
OPTS.num_w_ports=1
|
||||
OPTS.num_r_ports=1
|
||||
debug.info(2, "Bitcell with 1 of each port: read/write, write, and read")
|
||||
tx = pbitcell.pbitcell(num_rw_ports=1,num_w_ports=1,num_r_ports=1)
|
||||
tx = pbitcell()
|
||||
self.local_check(tx)
|
||||
|
||||
OPTS.num_rw_ports=0
|
||||
OPTS.num_w_ports=1
|
||||
OPTS.num_r_ports=1
|
||||
debug.info(2, "Bitcell with 0 read/write ports")
|
||||
tx = pbitcell.pbitcell(num_rw_ports=0,num_w_ports=1,num_r_ports=1)
|
||||
tx = pbitcell()
|
||||
self.local_check(tx)
|
||||
|
||||
OPTS.num_rw_ports=1
|
||||
OPTS.num_w_ports=0
|
||||
OPTS.num_r_ports=1
|
||||
debug.info(2, "Bitcell with 0 write ports")
|
||||
tx = pbitcell.pbitcell(num_rw_ports=1,num_w_ports=0,num_r_ports=1)
|
||||
tx = pbitcell()
|
||||
self.local_check(tx)
|
||||
|
||||
OPTS.num_rw_ports=1
|
||||
OPTS.num_w_ports=1
|
||||
OPTS.num_r_ports=0
|
||||
debug.info(2, "Bitcell with 0 read ports")
|
||||
tx = pbitcell.pbitcell(num_rw_ports=1,num_w_ports=1,num_r_ports=0)
|
||||
tx = pbitcell()
|
||||
self.local_check(tx)
|
||||
|
||||
OPTS.num_rw_ports=1
|
||||
OPTS.num_w_ports=0
|
||||
OPTS.num_r_ports=0
|
||||
debug.info(2, "Bitcell with 0 read ports and 0 write ports")
|
||||
tx = pbitcell.pbitcell(num_rw_ports=1,num_w_ports=0,num_r_ports=0)
|
||||
tx = pbitcell()
|
||||
self.local_check(tx)
|
||||
|
||||
OPTS.num_rw_ports=2
|
||||
OPTS.num_w_ports=2
|
||||
OPTS.num_r_ports=2
|
||||
debug.info(2, "Bitcell with 2 of each port: read/write, write, and read")
|
||||
tx = pbitcell.pbitcell(num_rw_ports=2,num_w_ports=2,num_r_ports=2)
|
||||
tx = pbitcell()
|
||||
self.local_check(tx)
|
||||
|
||||
OPTS.num_rw_ports=0
|
||||
OPTS.num_w_ports=2
|
||||
OPTS.num_r_ports=2
|
||||
debug.info(2, "Bitcell with 0 read/write ports")
|
||||
tx = pbitcell.pbitcell(num_rw_ports=0,num_w_ports=2,num_r_ports=2)
|
||||
tx = pbitcell()
|
||||
self.local_check(tx)
|
||||
|
||||
OPTS.num_rw_ports=2
|
||||
OPTS.num_w_ports=0
|
||||
OPTS.num_r_ports=2
|
||||
debug.info(2, "Bitcell with 0 write ports")
|
||||
tx = pbitcell.pbitcell(num_rw_ports=2,num_w_ports=0,num_r_ports=2)
|
||||
tx = pbitcell()
|
||||
self.local_check(tx)
|
||||
|
||||
OPTS.num_rw_ports=2
|
||||
OPTS.num_w_ports=2
|
||||
OPTS.num_r_ports=0
|
||||
debug.info(2, "Bitcell with 0 read ports")
|
||||
tx = pbitcell.pbitcell(num_rw_ports=2,num_w_ports=2,num_r_ports=0)
|
||||
tx = pbitcell()
|
||||
self.local_check(tx)
|
||||
|
||||
OPTS.num_rw_ports=2
|
||||
OPTS.num_w_ports=0
|
||||
OPTS.num_r_ports=0
|
||||
debug.info(2, "Bitcell with 0 read ports and 0 write ports")
|
||||
tx = pbitcell.pbitcell(num_rw_ports=2,num_w_ports=0,num_r_ports=0)
|
||||
tx = pbitcell()
|
||||
self.local_check(tx)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -27,13 +27,13 @@ class precharge_test(openram_test):
|
|||
OPTS.num_rw_ports = 2
|
||||
OPTS.num_r_ports = 2
|
||||
OPTS.num_w_ports = 2
|
||||
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="rwbl0", bitcell_br="rwbl_bar0")
|
||||
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl0", bitcell_br="br0")
|
||||
self.local_check(tx)
|
||||
|
||||
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="wbl0", bitcell_br="wbl_bar0")
|
||||
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl2", bitcell_br="br2")
|
||||
self.local_check(tx)
|
||||
|
||||
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="rbl0", bitcell_br="rbl_bar0")
|
||||
tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl4", bitcell_br="br4")
|
||||
self.local_check(tx)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -28,13 +28,13 @@ class precharge_test(openram_test):
|
|||
OPTS.num_r_ports = 2
|
||||
OPTS.num_w_ports = 2
|
||||
|
||||
pc = precharge_array.precharge_array(columns=3, bitcell_bl="rwbl0", bitcell_br="rwbl_bar0")
|
||||
pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl0", bitcell_br="br0")
|
||||
self.local_check(pc)
|
||||
|
||||
pc = precharge_array.precharge_array(columns=3, bitcell_bl="wbl0", bitcell_br="wbl_bar0")
|
||||
pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl2", bitcell_br="br2")
|
||||
self.local_check(pc)
|
||||
|
||||
pc = precharge_array.precharge_array(columns=3, bitcell_bl="rbl0", bitcell_br="rbl_bar0")
|
||||
pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl4", bitcell_br="br4")
|
||||
self.local_check(pc)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import globals
|
|||
from globals import OPTS
|
||||
import debug
|
||||
|
||||
@unittest.skip("SKIPPING 19_psingle_bank_test")
|
||||
#@unittest.skip("SKIPPING 19_psingle_bank_test")
|
||||
class psingle_bank_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
|
|
|
|||
|
|
@ -21,27 +21,28 @@ class sram_1bank_test(openram_test):
|
|||
num_words=16,
|
||||
num_banks=1)
|
||||
|
||||
c.words_per_row=1
|
||||
debug.info(1, "Single bank, no column mux with control logic")
|
||||
a = sram(c, name="sram1")
|
||||
a = sram(c, "sram1")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
c.num_words=32
|
||||
c.words_per_row=2
|
||||
debug.info(1, "Single bank two way column mux with control logic")
|
||||
a = sram(c, name="sram2")
|
||||
a = sram(c, "sram2")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
c.num_words=64
|
||||
c.words_per_row=4
|
||||
debug.info(1, "Single bank, four way column mux with control logic")
|
||||
a = sram(c, name="sram3")
|
||||
a = sram(c, "sram3")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
c.word_size=2
|
||||
c.num_words=128
|
||||
c.words_per_row=8
|
||||
debug.info(1, "Single bank, eight way column mux with control logic")
|
||||
a = sram(c, name="sram4")
|
||||
a = sram(c, "sram4")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -22,27 +22,28 @@ class sram_2bank_test(openram_test):
|
|||
num_words=32,
|
||||
num_banks=2)
|
||||
|
||||
c.words_per_row=1
|
||||
debug.info(1, "Two bank, no column mux with control logic")
|
||||
a = sram(c, name="sram1")
|
||||
a = sram(c, "sram1")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
c.num_words=64
|
||||
c.words_per_row=2
|
||||
debug.info(1, "Two bank two way column mux with control logic")
|
||||
a = sram(c, name="sram2")
|
||||
a = sram(c, "sram2")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
c.num_words=128
|
||||
c.words_per_row=4
|
||||
debug.info(1, "Two bank, four way column mux with control logic")
|
||||
a = sram(c, name="sram3")
|
||||
a = sram(c, "sram3")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
c.word_size=2
|
||||
c.num_words=256
|
||||
c.words_per_row=8
|
||||
debug.info(1, "Two bank, eight way column mux with control logic")
|
||||
a = sram(c, name="sram4")
|
||||
a = sram(c, "sram4")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -23,26 +23,26 @@ class sram_4bank_test(openram_test):
|
|||
num_banks=4)
|
||||
|
||||
debug.info(1, "Four bank, no column mux with control logic")
|
||||
a = sram(c, name="sram1")
|
||||
a = sram(c, "sram1")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
c.num_words=128
|
||||
c.words_per_row=2
|
||||
debug.info(1, "Four bank two way column mux with control logic")
|
||||
a = sram(c, name="sram2")
|
||||
a = sram(c, "sram2")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
c.num_words=256
|
||||
c.words_per_row=4
|
||||
debug.info(1, "Four bank, four way column mux with control logic")
|
||||
a = sram(word_size=16, num_words=256, num_banks=4, name="sram3")
|
||||
a = sram(c, "sram3")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
c.word_size=2
|
||||
c.num_words=256
|
||||
c.words_per_row=8
|
||||
debug.info(1, "Four bank, eight way column mux with control logic")
|
||||
a = sram.sram(word_size=2, num_words=256, num_banks=4, name="sram4")
|
||||
a = sram.sram(c, "sram4")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class timing_sram_test(openram_test):
|
|||
c = sram_config(word_size=1,
|
||||
num_words=16,
|
||||
num_banks=1)
|
||||
|
||||
c.words_per_row=1
|
||||
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
|
||||
s = sram(c, name="sram1")
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class timing_sram_test(openram_test):
|
|||
c = sram_config(word_size=1,
|
||||
num_words=16,
|
||||
num_banks=1)
|
||||
|
||||
c.words_per_row=1
|
||||
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
|
||||
s = sram(c, name="sram1")
|
||||
|
||||
|
|
|
|||
|
|
@ -22,10 +22,9 @@ class lib_test(openram_test):
|
|||
c = sram_config(word_size=2,
|
||||
num_words=16,
|
||||
num_banks=1)
|
||||
|
||||
c.words_per_row=1
|
||||
debug.info(1, "Testing analytical timing for sample 2 bit, 16 words SRAM with 1 bank")
|
||||
s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
s.sp_write(tempspice)
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class lib_test(openram_test):
|
|||
c = sram_config(word_size=2,
|
||||
num_words=16,
|
||||
num_banks=1)
|
||||
|
||||
c.words_per_row=1
|
||||
debug.info(1, "Testing pruned timing for sample 2 bit, 16 words SRAM with 1 bank")
|
||||
s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class lib_test(openram_test):
|
|||
c = sram_config(word_size=2,
|
||||
num_words=16,
|
||||
num_banks=1)
|
||||
|
||||
c.words_per_row=1
|
||||
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank")
|
||||
s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class lef_test(openram_test):
|
|||
c = sram_config(word_size=2,
|
||||
num_words=16,
|
||||
num_banks=1)
|
||||
|
||||
c.words_per_row=1
|
||||
debug.info(1, "Testing LEF for sample 2 bit, 16 words SRAM with 1 bank")
|
||||
s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class verilog_test(openram_test):
|
|||
c = sram_config(word_size=2,
|
||||
num_words=16,
|
||||
num_banks=1)
|
||||
|
||||
c.words_per_row=1
|
||||
debug.info(1, "Testing Verilog for sample 2 bit, 16 words SRAM with 1 bank")
|
||||
s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1521677056
|
||||
timestamp 1536091415
|
||||
<< nwell >>
|
||||
rect -8 29 42 51
|
||||
<< pwell >>
|
||||
|
|
@ -105,13 +105,13 @@ rect 6 2 10 48
|
|||
rect 24 -2 28 48
|
||||
rect 32 33 36 48
|
||||
rect 32 -2 36 29
|
||||
<< m3p >>
|
||||
<< bb >>
|
||||
rect 0 0 34 46
|
||||
<< labels >>
|
||||
rlabel metal2 0 0 0 0 1 gnd
|
||||
rlabel metal2 34 0 34 0 1 gnd
|
||||
rlabel m2contact 17 46 17 46 5 vdd
|
||||
rlabel metal1 4 7 4 7 1 WL
|
||||
rlabel metal2 8 43 8 43 1 BL
|
||||
rlabel metal2 26 43 26 43 1 BR
|
||||
rlabel metal2 8 43 8 43 1 bl
|
||||
rlabel metal2 26 43 26 43 1 br
|
||||
rlabel metal1 4 7 4 7 1 wl
|
||||
<< end >>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1518823399
|
||||
timestamp 1536089597
|
||||
<< nwell >>
|
||||
rect 0 48 109 103
|
||||
<< pwell >>
|
||||
|
|
@ -266,7 +266,7 @@ rect 6 30 10 50
|
|||
rect 22 20 26 57
|
||||
rect 70 44 74 70
|
||||
rect 70 20 74 40
|
||||
<< m3p >>
|
||||
<< bb >>
|
||||
rect 0 0 109 100
|
||||
<< labels >>
|
||||
rlabel m2contact 15 34 15 34 4 clk
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1523479368
|
||||
timestamp 1536089622
|
||||
<< nwell >>
|
||||
rect -2 0 18 200
|
||||
<< pwell >>
|
||||
|
|
@ -280,7 +280,7 @@ rect 14 8 20 9
|
|||
rect 14 4 15 8
|
||||
rect 19 4 20 8
|
||||
rect 14 3 20 4
|
||||
<< m3p >>
|
||||
<< bb >>
|
||||
rect 0 0 34 200
|
||||
<< labels >>
|
||||
rlabel metal1 0 8 0 8 2 clk
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1521677136
|
||||
timestamp 1536091380
|
||||
<< nwell >>
|
||||
rect -8 29 42 51
|
||||
<< pwell >>
|
||||
|
|
@ -106,13 +106,13 @@ rect 6 2 10 48
|
|||
rect 24 -2 28 48
|
||||
rect 32 33 36 48
|
||||
rect 32 -2 36 29
|
||||
<< m3p >>
|
||||
<< bb >>
|
||||
rect 0 0 34 46
|
||||
<< labels >>
|
||||
rlabel metal2 0 0 0 0 1 gnd
|
||||
rlabel metal2 34 0 34 0 1 gnd
|
||||
rlabel m2contact 17 46 17 46 5 vdd
|
||||
rlabel metal1 4 7 4 7 1 WL
|
||||
rlabel metal2 8 43 8 43 1 BL
|
||||
rlabel metal2 26 43 26 43 1 BR
|
||||
rlabel metal2 8 43 8 43 1 bl
|
||||
rlabel metal2 26 43 26 43 1 br
|
||||
rlabel metal1 4 7 4 7 1 wl
|
||||
<< end >>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1524065550
|
||||
timestamp 1536089670
|
||||
<< nwell >>
|
||||
rect 0 0 40 102
|
||||
<< pwell >>
|
||||
|
|
@ -122,7 +122,7 @@ rect 20 44 22 48
|
|||
rect 3 0 7 11
|
||||
rect 10 0 14 44
|
||||
rect 20 0 24 44
|
||||
<< m3p >>
|
||||
<< bb >>
|
||||
rect 0 0 34 163
|
||||
<< labels >>
|
||||
flabel metal1 0 149 0 149 4 FreeSans 26 0 0 0 en
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1524499924
|
||||
timestamp 1536089695
|
||||
<< nwell >>
|
||||
rect -2 45 38 73
|
||||
<< pwell >>
|
||||
|
|
@ -86,7 +86,7 @@ rect 24 19 28 23
|
|||
<< metal2 >>
|
||||
rect 15 34 25 38
|
||||
rect 15 0 19 34
|
||||
<< m3p >>
|
||||
<< bb >>
|
||||
rect 0 0 34 73
|
||||
<< labels >>
|
||||
rlabel metal1 0 12 0 12 3 en
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1524499497
|
||||
timestamp 1536089714
|
||||
<< nwell >>
|
||||
rect -3 101 37 138
|
||||
rect -3 0 37 51
|
||||
|
|
@ -209,7 +209,7 @@ rect 10 196 14 202
|
|||
rect 20 193 24 202
|
||||
rect 20 177 24 189
|
||||
rect 15 0 19 6
|
||||
<< m3p >>
|
||||
<< bb >>
|
||||
rect 0 0 34 202
|
||||
<< labels >>
|
||||
rlabel metal2 15 1 15 1 1 din
|
||||
|
|
|
|||
|
|
@ -276,6 +276,11 @@ cifoutput
|
|||
style lambda=0.30(p)
|
||||
scalefactor 30 15
|
||||
|
||||
# This is a custom section to add bounding boxes in OpenRAM
|
||||
layer BB bb
|
||||
labels bb
|
||||
calma 63 0
|
||||
|
||||
layer CWN nwell,rnw
|
||||
bloat-or pdiff,rpd,pdc/a,pfet * 180
|
||||
bloat-or nsd,nsc/a * 90
|
||||
|
|
@ -1506,7 +1511,12 @@ cifinput
|
|||
style lambda=0.30(p)
|
||||
scalefactor 30
|
||||
|
||||
layer nwell CWN
|
||||
# This is a custom section to add bounding boxes in OpenRAM
|
||||
layer bb BB
|
||||
labels BB
|
||||
calma 63 0
|
||||
|
||||
layer nwell CWN
|
||||
and-not CWNR
|
||||
and-not CTA
|
||||
labels CWN
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ layer["via1"] = 50
|
|||
layer["metal2"] = 51
|
||||
layer["via2"] = 61
|
||||
layer["metal3"] = 62
|
||||
layer["text"] = 83
|
||||
layer["boundary"] = 83
|
||||
layer["text"] = 63
|
||||
layer["boundary"] = 63
|
||||
|
||||
###################################################
|
||||
##END GDS Layer Map
|
||||
|
|
|
|||
|
|
@ -13,4 +13,4 @@ Metal2 drawing 51 0
|
|||
Via2 drawing 61 0
|
||||
Metal3 drawing 62 0
|
||||
Glass drawing 52 0
|
||||
text drawing 83 0
|
||||
comment drawing 63 0
|
||||
|
|
|
|||
Loading…
Reference in New Issue