Merge branch 'dev' into datasheet_gen

This commit is contained in:
Jesse Cirimelli-Low 2018-12-07 04:29:07 -08:00
commit 3d9203a7ea
43 changed files with 445 additions and 262 deletions

View File

@ -1,93 +1,45 @@
TECH = scn4m_subm
CUR_DIR = $(shell pwd) CUR_DIR = $(shell pwd)
TEST_DIR = ${CUR_DIR}/tests TEST_DIR = ${CUR_DIR}/tests
MAKEFLAGS += -j 2 MAKEFLAGS += -j 1
# Library test # Library test
LIBRARY_TESTS = \ LIBRARY_TESTS = $(shell find ${TEST_DIR} -name 0[1-2]*_test.py)
01_library_drc_test.py \
02_library_lvs_test.py
# Technology and DRC tests (along with ptx) # Technology and DRC tests (along with ptx)
TECH_TESTS = \ TECH_TESTS = $(shell find ${TEST_DIR} -name 03*_test.py)
03_contact_test.py \
03_ptx_1finger_pmos_test.py \
03_ptx_4finger_nmos_test.py \
03_path_test.py \
03_ptx_3finger_nmos_test.py \
03_ptx_4finger_pmos_test.py \
03_ptx_1finger_nmos_test.py \
03_ptx_3finger_pmos_test.py \
03_wire_test.py
# Parameterized cells # Parameterized cells
PCELLS_TESTS = \ CELL_TESTS = $(shell find ${TEST_DIR} -name 04*_test.py)
04_pinv_1x_test.py \
04_pinv_1x_beta_test.py \
04_pinv_2x_test.py \
04_pinv_10x_test.py \
04_pnand2_test.py \
04_pnor2_test.py \
04_pnand3_test.py\
04_wordline_driver_test.py \
04_precharge_test.py
# Dynamically generated modules and arrays # Dynamically generated modules and arrays
MODULE_TESTS = \ MODULE_TESTS = $(shell find ${TEST_DIR} -name 0[5-9]*_test.py)\
05_bitcell_array_test.py \ $(shell find ${TEST_DIR} -name 1*_test.py)
06_hierarchical_decoder_test.py \
06_hierarchical_predecode2x4_test.py \
06_hierarchical_predecode3x8_test.py \
07_single_level_column_mux_array_test.py \
08_precharge_array_test.py \
09_sense_amp_array_test.py \
10_write_driver_array_test.py \
11_ms_flop_array_test.py \
12_tri_gate_array_test.py \
13_delay_chain_test.py \
14_replica_bitline_test.py \
16_control_logic_test.py
# Top-level SRAM configurations # Top-level SRAM configurations
TOP_TESTS = \ TOP_TESTS = $(shell find ${TEST_DIR} -name 20*_test.py)
19_multi_bank_test.py \
19_single_bank_test.py \
20_sram_1bank_test.py \
20_sram_2bank_test.py \
20_sram_4bank_test.py
# All simulation tests. # All simulation tests.
CHAR_TESTS = \ CHAR_TESTS = $(shell find ${TEST_DIR} -name 2[1-2]*_test.py)
21_hspice_delay_test.py \
21_ngspice_delay_test.py \
21_ngspice_setuphold_test.py \
21_hspice_setuphold_test.py \
22_sram_func_test.py \
22_pex_func_test_with_pinv.py \
23_lib_sram_prune_test.py \
23_lib_sram_test.py
# Keep the model lib test here since it is fast # Keep the model lib test here since it is fast
# and doesn't need simulation. # and doesn't need simulation.
USAGE_TESTS = \ USAGE_TESTS = $(shell find ${TEST_DIR} -name 2[3-9]*_test.py)\
23_lib_sram_model_test.py \ $(shell find ${TEST_DIR} -name 30*_test.py)
24_lef_sram_test.py \
25_verilog_sram_test.py
ALL_FILES = \ ALL_TESTS = \
${LIBRARY_TESTS} \ ${LIBRARY_TESTS} \
${TECH_TESTS} \ ${TECH_TESTS} \
${PCELLS_TESTS} \ ${CELL_TESTS} \
${MODULES_TESTS} \ ${MODULE_TESTS} \
${TOP_TESTS} \ ${TOP_TESTS} \
${CHAR_TESTS} \ ${CHAR_TESTS} \
${USAGE_TESTS} ${USAGE_TESTS}
default all: .PHONY: ${ALL_TESTS}
$(ALL_FILES): all: ${ALL_TESTS}
python ${TEST_DIR}/$@ -t freepdk45
python ${TEST_DIR}/$@ -t scn3me_subm
# Library tests # Library tests
lib: ${LIBRARY_TESTS} lib: ${LIBRARY_TESTS}
@ -96,10 +48,10 @@ lib: ${LIBRARY_TESTS}
tech: ${TECH_TESTS} tech: ${TECH_TESTS}
# Dynamically generated cells # Dynamically generated cells
pcells: ${PCELLS_TESTS} cell: ${CELL_TESTS}
# Dynamically generated modules # Dynamically generated modules
modules: ${MODULES_TESTS} module: ${MODULE_TESTS}
# Top level SRAM tests # Top level SRAM tests
top: ${TOP_TESTS} top: ${TOP_TESTS}
@ -110,6 +62,9 @@ char: ${CHAR_TESTS}
# Usage and file generation # Usage and file generation
usage: ${USAGE_TESTS} usage: ${USAGE_TESTS}
$(ALL_TESTS):
python3 $@ -t ${TECH}
clean: clean:
find . -name \*.pyc -exec rm {} \; find . -name \*.pyc -exec rm {} \;
find . -name \*~ -exec rm {} \; find . -name \*~ -exec rm {} \;

View File

@ -59,7 +59,7 @@ def parse_args():
# This may be overridden when we read a config file though... # This may be overridden when we read a config file though...
if OPTS.tech_name == "": if OPTS.tech_name == "":
OPTS.tech_name = "scmos" OPTS.tech_name = "scmos"
# Alias SCMOS to AMI 0.5um # Alias SCMOS to 180nm
if OPTS.tech_name == "scmos": if OPTS.tech_name == "scmos":
OPTS.tech_name = "scn4m_subm" OPTS.tech_name = "scn4m_subm"
@ -89,6 +89,7 @@ def print_banner():
print("|=========" + dev_info.center(60) + "=========|") print("|=========" + dev_info.center(60) + "=========|")
temp_info = "Temp dir: {}".format(OPTS.openram_temp) temp_info = "Temp dir: {}".format(OPTS.openram_temp)
print("|=========" + temp_info.center(60) + "=========|") print("|=========" + temp_info.center(60) + "=========|")
print("|=========" + "See LICENSE for license info".center(60) + "=========|")
print("|==============================================================================|") print("|==============================================================================|")
@ -418,6 +419,9 @@ def report_status():
print("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size, print("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size,
OPTS.num_words, OPTS.num_words,
OPTS.num_banks)) OPTS.num_banks))
print("RW ports: {0}\nR-only ports: {1}\nW-only ports: {2}".format(OPTS.num_rw_ports,
OPTS.num_r_ports,
OPTS.num_w_ports))
if OPTS.netlist_only: if OPTS.netlist_only:
print("Netlist only mode (no physical design is being done).") print("Netlist only mode (no physical design is being done).")

View File

@ -26,6 +26,10 @@ if len(args) != 1:
# These depend on arguments, so don't load them until now. # These depend on arguments, so don't load them until now.
import debug import debug
# Keep track of running stats
start_time = datetime.datetime.now()
print_time("Start",start_time)
init_openram(config_file=args[0], is_unit_test=False) init_openram(config_file=args[0], is_unit_test=False)
# Only print banner here so it's not in unit tests # Only print banner here so it's not in unit tests
@ -34,10 +38,14 @@ print_banner()
# Output info about this run # Output info about this run
report_status() report_status()
# Start importing design modules after we have the config file
import verify
from sram import sram
from sram_config import sram_config from sram_config import sram_config
# Configure the SRAM organization
c = sram_config(word_size=OPTS.word_size,
num_words=OPTS.num_words)
print("Words per row: {}".format(c.words_per_row))
#from parser import * #from parser import *
output_extensions = ["sp","v","lib","py"] output_extensions = ["sp","v","lib","py"]
if OPTS.datasheet_gen: if OPTS.datasheet_gen:
@ -48,15 +56,8 @@ output_files = ["{0}.{1}".format(OPTS.output_name,x) for x in output_extensions]
print("Output files are: ") print("Output files are: ")
print(*output_files,sep="\n") print(*output_files,sep="\n")
# Keep track of running stats
start_time = datetime.datetime.now()
print_time("Start",start_time)
# Configure the SRAM organization from sram import sram
c = sram_config(word_size=OPTS.word_size,
num_words=OPTS.num_words)
# import SRAM test generation
s = sram(sram_config=c, s = sram(sram_config=c,
name=OPTS.output_name) name=OPTS.output_name)

227
compiler/pgates/pdriver.py Normal file
View File

@ -0,0 +1,227 @@
import debug
import pgate
import math
from tech import drc
from math import log
from vector import vector
from globals import OPTS
from pinv import pinv
class pdriver(pgate.pgate):
"""
This instantiates an even or odd number of inverters sized for driving a load.
"""
unique_id = 1
inv_list = []
inv_inst_list = []
calc_size_list = []
def __init__(self, height=None, name="", neg_polarity=False, c_load=8, size_list = []):
self.stage_effort = 4
self.row_height = height
self.neg_polarity = neg_polarity
self.size_list = size_list
self.c_load = c_load
if len(self.size_list) > 0 and (self.c_load != 8 or self.neg_polarity):
raise Exception("Cannot specify both size_list and neg_polarity or c_load.")
self.compute_sizes()
if name=="":
name = "pdriver_{0}_{1}_".format(self.num_inv, pdriver.unique_id)
pdriver.unique_id += 1
pgate.pgate.__init__(self, name)
debug.info(1, "Creating {}".format(self.name))
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
def compute_sizes(self):
# size_list specified
if len(self.size_list) > 0:
if not len(self.size_list) % 2:
neg_polarity = True
self.num_inv = len(self.size_list)
else:
# find the number of stages
c_prev = int(round(self.c_load/self.stage_effort))
num_stages = 1
while c_prev > 1: #stop when the first stage is 1
c_prev = int(round(c_prev/self.stage_effort))
num_stages+=1
# find inv_num and compute sizes
if self.neg_polarity:
if (num_stages % 2 == 0): # if num_stages is even
self.diff_polarity(num_stages=num_stages)
else: # if num_stages is odd
self.same_polarity(num_stages=num_stages)
else: # positive polarity
if (num_stages % 2 == 0):
self.same_polarity(num_stages=num_stages)
else:
self.diff_polarity(num_stages=num_stages)
def same_polarity(self, num_stages):
self.num_inv = num_stages
# compute sizes
c_prev = self.c_load
for x in range(self.num_inv-1,-1,-1):
c_prev = int(round(c_prev/self.stage_effort))
self.calc_size_list.append(c_prev)
def diff_polarity(self, num_stages):
# find which delay is smaller
delay_below = ((num_stages-1)*(self.c_load**(1/num_stages-1))) + num_stages-1
delay_above = ((num_stages+1)*(self.c_load**(1/num_stages+1))) + num_stages+1
if (delay_above < delay_below):
# recompute stage_effort for this delay
self.num_inv = num_stages+1
polarity_stage_effort = self.c_load**(1/self.num_inv)
else:
self.num_inv = num_stages-1
polarity_stage_effort = self.c_load**(1/self.num_inv)
# compute sizes
c_prev = self.c_load
for x in range(self.num_inv-1,-1,-1):
c_prev = int(round(c_prev/polarity_stage_effort))
self.calc_size_list.append(c_prev)
def create_netlist(self):
self.add_pins()
self.add_modules()
self.create_insts()
def create_layout(self):
self.width = self.num_inv * self.inv_list[0].width
self.height = self.inv_list[0].height
self.place_modules()
self.route_wires()
self.add_layout_pins()
self.DRC_LVS()
def add_pins(self):
self.add_pin("A")
self.add_pin("Z")
self.add_pin("vdd")
self.add_pin("gnd")
def add_modules(self):
if len(self.size_list) > 0: # size list specified
for x in range(len(self.size_list)):
self.inv_list.append(pinv(size=self.size_list[x], height=self.row_height))
self.add_mod(self.inv_list[x])
else: # find inv sizes
for x in range(len(self.calc_size_list)):
self.inv_list.append(pinv(size=self.calc_size_list[x], height=self.row_height))
self.add_mod(self.inv_list[x])
def create_insts(self):
for x in range(1,self.num_inv+1):
# Create first inverter
if x == 1:
zbx_int = "Zb{}_int".format(x);
self.inv_inst_list.append(self.add_inst(name="buf_inv{}".format(x),
mod=self.inv_list[x-1]))
if self.num_inv == 1:
self.connect_inst(["A", "Z", "vdd", "gnd"])
else:
self.connect_inst(["A", zbx_int, "vdd", "gnd"])
# Create last inverter
elif x == self.num_inv:
zbn_int = "Zb{}_int".format(x-1);
self.inv_inst_list.append(self.add_inst(name="buf_inv{}".format(x),
mod=self.inv_list[x-1]))
self.connect_inst([zbn_int, "Z", "vdd", "gnd"])
# Create middle inverters
else:
zbx_int = "Zb{}_int".format(x-1);
zbn_int = "Zb{}_int".format(x);
self.inv_inst_list.append(self.add_inst(name="buf_inv{}".format(x),
mod=self.inv_list[x-1]))
self.connect_inst([zbx_int, zbn_int, "vdd", "gnd"])
def place_modules(self):
# Add INV1 to the left
self.inv_inst_list[0].place(vector(0,0))
# Add inverters to the right of INV1
for x in range(1,len(self.inv_inst_list)):
self.inv_inst_list[x].place(vector(self.inv_inst_list[x-1].rx(),0))
def route_wires(self):
z_inst_list = []
a_inst_list = []
# inv_current Z to inv_next A
for x in range(0,len(self.inv_inst_list)-1):
z_inst_list.append(self.inv_inst_list[x].get_pin("Z"))
a_inst_list.append(self.inv_inst_list[x+1].get_pin("A"))
mid_point = vector(z_inst_list[x].cx(), a_inst_list[x].cy())
self.add_path("metal1", [z_inst_list[x].center(), mid_point, a_inst_list[x].center()])
def add_layout_pins(self):
# Continous vdd rail along with label.
vdd_pin=self.inv_inst_list[0].get_pin("vdd")
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vdd_pin.ll().scale(0,1),
width=self.width,
height=vdd_pin.height())
# Continous gnd rail along with label.
gnd_pin=self.inv_inst_list[0].get_pin("gnd")
self.add_layout_pin(text="gnd",
layer="metal1",
offset=gnd_pin.ll().scale(0,1),
width=self.width,
height=vdd_pin.height())
z_pin = self.inv_inst_list[len(self.inv_inst_list)-1].get_pin("Z")
self.add_layout_pin_rect_center(text="Z",
layer=z_pin.layer,
offset=z_pin.center(),
width = z_pin.width(),
height = z_pin.height())
a_pin = self.inv_inst_list[0].get_pin("A")
self.add_layout_pin_rect_center(text="A",
layer=a_pin.layer,
offset=a_pin.center(),
width = a_pin.width(),
height = a_pin.height())
def analytical_delay(self, slew, load=0.0):
"""Calculate the analytical delay of INV1 -> ... -> INVn"""
delay = 0;
if len(self.inv_inst_list) == 1:
delay = self.inv_inst_list[x].analytical_delay(slew=slew);
else:
for x in range(len(self.inv_inst_list-1)):
load_next = 0.0
for n in range(x,len(self.inv_inst_list+1)):
load_next += self.inv_inst_list[x+1]
if x == 1:
delay += self.inv_inst_list[x].analytical_delay(slew=slew,
load=load_next)
else:
delay += self.inv_inst_list[x+1].analytical_delay(slew=delay.slew,
load=load_next)
return delay

View File

@ -70,8 +70,7 @@ class router(router_tech):
self.boundary = self.layout.measureBoundary(self.top_name) self.boundary = self.layout.measureBoundary(self.top_name)
# These must be un-indexed to get rid of the matrix type # These must be un-indexed to get rid of the matrix type
self.ll = vector(self.boundary[0][0], self.boundary[0][1]) self.ll = vector(self.boundary[0][0], self.boundary[0][1])
# Pad the UR by a few tracks to add an extra rail possibly self.ur = vector(self.boundary[1][0], self.boundary[1][1])
self.ur = vector(self.boundary[1][0], self.boundary[1][1]) + self.track_widths.scale(5,5)
def clear_pins(self): def clear_pins(self):
""" """
@ -130,12 +129,8 @@ class router(router_tech):
Pin can either be a label or a location,layer pair: [[x,y],layer]. Pin can either be a label or a location,layer pair: [[x,y],layer].
""" """
debug.info(1,"Finding pins for {}.".format(pin_name)) debug.info(1,"Finding pins for {}.".format(pin_name))
#start_time = datetime.now()
self.retrieve_pins(pin_name) self.retrieve_pins(pin_name)
#print_time("Retrieved pins",datetime.now(), start_time)
#start_time = datetime.now()
self.analyze_pins(pin_name) self.analyze_pins(pin_name)
#print_time("Analyzed pins",datetime.now(), start_time)
def find_blockages(self): def find_blockages(self):
""" """
@ -160,41 +155,26 @@ class router(router_tech):
# This will get all shapes as blockages and convert to grid units # This will get all shapes as blockages and convert to grid units
# This ignores shapes that were pins # This ignores shapes that were pins
#start_time = datetime.now()
self.find_blockages() self.find_blockages()
#print_time("Find blockags",datetime.now(), start_time)
# Convert the blockages to grid units # Convert the blockages to grid units
#start_time = datetime.now()
self.convert_blockages() self.convert_blockages()
#print_time("Find blockags",datetime.now(), start_time)
# This will convert the pins to grid units # This will convert the pins to grid units
# It must be done after blockages to ensure no DRCs between expanded pins and blocked grids # It must be done after blockages to ensure no DRCs between expanded pins and blocked grids
#start_time = datetime.now()
for pin in pin_list: for pin in pin_list:
self.convert_pins(pin) self.convert_pins(pin)
#print_time("Convert pins",datetime.now(), start_time)
#start_time = datetime.now() # Combine adjacent pins into pin groups to reduce run-time
#for pin in pin_list: for pin in pin_list:
# self.combine_adjacent_pins(pin) self.combine_adjacent_pins(pin)
#print_time("Combine pins",datetime.now(), start_time)
#self.write_debug_gds("debug_combine_pins.gds",stop_program=True)
# Separate any adjacent grids of differing net names that overlap # Separate any adjacent grids of differing net names that overlap
# Must be done before enclosing pins # Must be done before enclosing pins
#start_time = datetime.now()
self.separate_adjacent_pins(0) self.separate_adjacent_pins(0)
#print_time("Separate pins",datetime.now(), start_time)
# For debug
#self.separate_adjacent_pins(1)
# Enclose the continguous grid units in a metal rectangle to fix some DRCs # Enclose the continguous grid units in a metal rectangle to fix some DRCs
#start_time = datetime.now()
self.enclose_pins() self.enclose_pins()
#print_time("Enclose pins",datetime.now(), start_time)
#self.write_debug_gds("debug_enclose_pins.gds",stop_program=True)
def combine_adjacent_pins(self, pin_name): def combine_adjacent_pins(self, pin_name):
@ -257,16 +237,17 @@ class router(router_tech):
This will try to separate all grid pins by the supplied number of separation This will try to separate all grid pins by the supplied number of separation
tracks (default is to prevent adjacency). tracks (default is to prevent adjacency).
""" """
debug.info(1,"Separating adjacent pins.")
# Commented out to debug with SCMOS # Commented out to debug with SCMOS
#if separation==0: #if separation==0:
# return # return
pin_names = self.pin_groups.keys() pin_names = self.pin_groups.keys()
for pin_name1 in pin_names: for i,pin_name1 in enumerate(pin_names):
for pin_name2 in pin_names: for j,pin_name2 in enumerate(pin_names):
if pin_name1==pin_name2: if i==j:
continue continue
if i>j:
return
self.separate_adjacent_pin(pin_name1, pin_name2, separation) self.separate_adjacent_pin(pin_name1, pin_name2, separation)
def separate_adjacent_pin(self, pin_name1, pin_name2, separation): def separate_adjacent_pin(self, pin_name1, pin_name2, separation):
@ -277,14 +258,19 @@ class router(router_tech):
Try to do this intelligently to keep th pins enclosed. Try to do this intelligently to keep th pins enclosed.
""" """
debug.info(1,"Comparing {0} and {1} adjacency".format(pin_name1, pin_name2)) debug.info(1,"Comparing {0} and {1} adjacency".format(pin_name1, pin_name2))
removed_grids = 0
for index1,pg1 in enumerate(self.pin_groups[pin_name1]): for index1,pg1 in enumerate(self.pin_groups[pin_name1]):
for index2,pg2 in enumerate(self.pin_groups[pin_name2]): for index2,pg2 in enumerate(self.pin_groups[pin_name2]):
adj_grids = pg1.adjacent_grids(pg2, separation) adj_grids = pg1.adjacent_grids(pg2, separation)
removed_grids += len(adj_grids)
# These should have the same length, so... # These should have the same length, so...
if len(adj_grids)>0: if len(adj_grids)>0:
debug.info(2,"Adjacent grids {0} {1} adj={2}".format(index1,index2,adj_grids)) debug.info(3,"Adjacent grids {0} {1} adj={2}".format(index1,index2,adj_grids))
self.remove_adjacent_grid(pg1, pg2, adj_grids) self.remove_adjacent_grid(pg1, pg2, adj_grids)
debug.info(1,"Removed {} adjacent grids.".format(removed_grids))
def remove_adjacent_grid(self, pg1, pg2, adj_grids): def remove_adjacent_grid(self, pg1, pg2, adj_grids):
""" """
Remove one of the adjacent grids in a heuristic manner. Remove one of the adjacent grids in a heuristic manner.
@ -304,12 +290,12 @@ class router(router_tech):
# If the adjacent grids are a subset of the secondary grids (i.e. not necessary) # If the adjacent grids are a subset of the secondary grids (i.e. not necessary)
# remove them from each # remove them from each
if adj in bigger.secondary_grids: if adj in bigger.secondary_grids:
debug.info(2,"Removing {} from bigger secondary {}".format(adj, bigger)) debug.info(3,"Removing {} from bigger secondary {}".format(adj, bigger))
bigger.grids.remove(adj) bigger.grids.remove(adj)
bigger.secondary_grids.remove(adj) bigger.secondary_grids.remove(adj)
self.blocked_grids.add(adj) self.blocked_grids.add(adj)
elif adj in smaller.secondary_grids: elif adj in smaller.secondary_grids:
debug.info(2,"Removing {} from smaller secondary {}".format(adj, smaller)) debug.info(3,"Removing {} from smaller secondary {}".format(adj, smaller))
smaller.grids.remove(adj) smaller.grids.remove(adj)
smaller.secondary_grids.remove(adj) smaller.secondary_grids.remove(adj)
self.blocked_grids.add(adj) self.blocked_grids.add(adj)
@ -317,10 +303,10 @@ class router(router_tech):
# If we couldn't remove from a secondary grid, we must remove from the primary # If we couldn't remove from a secondary grid, we must remove from the primary
# grid of at least one pin # grid of at least one pin
if adj in bigger.grids: if adj in bigger.grids:
debug.info(2,"Removing {} from bigger primary {}".format(adj, bigger)) debug.info(3,"Removing {} from bigger primary {}".format(adj, bigger))
bigger.grids.remove(adj) bigger.grids.remove(adj)
elif adj in smaller.grids: elif adj in smaller.grids:
debug.info(2,"Removing {} from smaller primary {}".format(adj, smaller)) debug.info(3,"Removing {} from smaller primary {}".format(adj, smaller))
smaller.grids.remove(adj) smaller.grids.remove(adj)
@ -361,17 +347,6 @@ class router(router_tech):
self.set_blockages(blockage_grids,False) self.set_blockages(blockage_grids,False)
# def translate_coordinates(self, coord, mirr, angle, xyShift):
# """
# Calculate coordinates after flip, rotate, and shift
# """
# coordinate = []
# for item in coord:
# x = (item[0]*math.cos(angle)-item[1]*mirr*math.sin(angle)+xyShift[0])
# y = (item[0]*math.sin(angle)+item[1]*mirr*math.cos(angle)+xyShift[1])
# coordinate += [(x, y)]
# return coordinate
def convert_shape_to_units(self, shape): def convert_shape_to_units(self, shape):
""" """
Scale a shape (two vector list) to user units Scale a shape (two vector list) to user units
@ -498,11 +473,6 @@ class router(router_tech):
# and the track points are at the center # and the track points are at the center
ll = ll.round() ll = ll.round()
ur = ur.round() ur = ur.round()
# if ll[0]<45 and ll[0]>35 and ll[1]<5 and ll[1]>-5:
# debug.info(0,"Converting [ {0} , {1} ]".format(old_ll,old_ur))
# debug.info(0,"Converted [ {0} , {1} ]".format(ll,ur))
# pin=self.convert_track_to_shape(ll)
# debug.info(0,"Pin {}".format(pin))
return [ll,ur] return [ll,ur]
def convert_pin_to_tracks(self, pin_name, pin, expansion=0): def convert_pin_to_tracks(self, pin_name, pin, expansion=0):
@ -558,7 +528,6 @@ class router(router_tech):
""" """
Find a list of the single pin with the most overlap. Find a list of the single pin with the most overlap.
""" """
#print("INSUFFICIENT LIST",insufficient_list)
# Find the coordinate with the most overlap # Find the coordinate with the most overlap
best_coord = None best_coord = None
best_overlap = -math.inf best_overlap = -math.inf
@ -579,7 +548,6 @@ class router(router_tech):
Get a grid cell that is the furthest from the blocked grids. Get a grid cell that is the furthest from the blocked grids.
""" """
#print("INSUFFICIENT LIST",insufficient_list)
# Find the coordinate with the most overlap # Find the coordinate with the most overlap
best_coord = None best_coord = None
best_dist = math.inf best_dist = math.inf
@ -596,7 +564,6 @@ class router(router_tech):
Given a pin and a list of grid cells (probably non-overlapping), Given a pin and a list of grid cells (probably non-overlapping),
return the nearest grid cell (center to center). return the nearest grid cell (center to center).
""" """
#print("INSUFFICIENT LIST",insufficient_list)
# Find the coordinate with the most overlap # Find the coordinate with the most overlap
best_coord = None best_coord = None
best_dist = math.inf best_dist = math.inf
@ -640,10 +607,6 @@ class router(router_tech):
return (None,None) return (None,None)
def convert_track_to_pin(self, track): def convert_track_to_pin(self, track):
""" """
Convert a grid point into a rectangle shape that is centered Convert a grid point into a rectangle shape that is centered
@ -764,8 +727,6 @@ class router(router_tech):
pg.enclose_pin() pg.enclose_pin()
pg.add_enclosure(self.cell) pg.add_enclosure(self.cell)
#self.write_debug_gds("pin_debug.gds", False)
def add_source(self, pin_name): def add_source(self, pin_name):
""" """
This will mark the grids for all pin components as a source. This will mark the grids for all pin components as a source.
@ -835,9 +796,6 @@ class router(router_tech):
""" """
debug.info(4,"Set path: " + str(path)) debug.info(4,"Set path: " + str(path))
# Keep track of path for future blockages
#path.set_blocked()
# This is marked for debug # This is marked for debug
path.set_path() path.set_path()
@ -906,45 +864,11 @@ class router(router_tech):
(abs_ll,unused) = pin.rect (abs_ll,unused) = pin.rect
pin = self.convert_track_to_pin(ur) pin = self.convert_track_to_pin(ur)
(unused,abs_ur) = pin.rect (unused,abs_ur) = pin.rect
#print("enclose ll={0} ur={1}".format(ll,ur))
#print("enclose ll={0} ur={1}".format(abs_ll,abs_ur))
pin = pin_layout(name, [abs_ll, abs_ur], layer) pin = pin_layout(name, [abs_ll, abs_ur], layer)
return pin return pin
# def compute_wide_enclosure(self, ll, ur, zindex, name=""):
# """
# Enclose the tracks from ll to ur in a single rectangle that meets the track DRC rules.
# """
# # Find the pin enclosure of the whole track shape (ignoring DRCs)
# (abs_ll,unused) = self.convert_track_to_shape(ll)
# (unused,abs_ur) = self.convert_track_to_shape(ur)
# # Get the layer information
# x_distance = abs(abs_ll.x-abs_ur.x)
# y_distance = abs(abs_ll.y-abs_ur.y)
# shape_width = min(x_distance, y_distance)
# shape_length = max(x_distance, y_distance)
# # Get the DRC rule for the grid dimensions
# (width, space) = self.get_supply_layer_width_space(zindex)
# layer = self.get_layer(zindex)
# if zindex==0:
# spacing = vector(0.5*self.track_width, 0.5*space)
# else:
# spacing = vector(0.5*space, 0.5*self.track_width)
# # Compute the shape offsets with correct spacing
# new_ll = abs_ll + spacing
# new_ur = abs_ur - spacing
# pin = pin_layout(name, [new_ll, new_ur], layer)
# return pin
def contract_path(self,path): def contract_path(self,path):
""" """
Remove intermediate points in a rectilinear path or a wave. Remove intermediate points in a rectilinear path or a wave.

View File

@ -48,9 +48,9 @@ class router_tech:
self.track_width = max(self.horiz_track_width,self.vert_track_width) self.track_width = max(self.horiz_track_width,self.vert_track_width)
debug.info(1,"Track width: {:.3f}".format(self.track_width)) debug.info(1,"Track width: {:.3f}".format(self.track_width))
self.track_space = max(self.horiz_layer_spacing,self.vert_layer_spacing) self.track_space = max(self.horiz_layer_spacing,self.vert_layer_spacing)
debug.info(1,"Track spacing: {:.3f}".format(self.track_space)) debug.info(1,"Track space: {:.3f}".format(self.track_space))
self.track_wire = self.track_width - self.track_space self.track_wire = self.track_width - self.track_space
debug.info(1,"Wire width: {:.3f}".format(self.track_wire)) debug.info(1,"Track wire width: {:.3f}".format(self.track_wire))
self.track_widths = vector([self.track_width] * 2) self.track_widths = vector([self.track_width] * 2)
self.track_factor = vector([1/self.track_width] * 2) self.track_factor = vector([1/self.track_width] * 2)

View File

@ -64,17 +64,10 @@ class supply_router(router):
# but this is simplest for now. # but this is simplest for now.
self.create_routing_grid() self.create_routing_grid()
# Compute the grid dimensions
self.compute_supply_rail_dimensions()
# Get the pin shapes # Get the pin shapes
#start_time = datetime.now()
self.find_pins_and_blockages([self.vdd_name, self.gnd_name]) self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
#print_time("Pins and blockages",datetime.now(), start_time)
#self.write_debug_gds("pin_enclosures.gds",stop_program=True)
# Add the supply rails in a mesh network and connect H/V with vias # Add the supply rails in a mesh network and connect H/V with vias
#start_time = datetime.now()
# Block everything # Block everything
self.prepare_blockages(self.gnd_name) self.prepare_blockages(self.gnd_name)
# Determine the rail locations # Determine the rail locations
@ -84,22 +77,14 @@ class supply_router(router):
self.prepare_blockages(self.vdd_name) self.prepare_blockages(self.vdd_name)
# Determine the rail locations # Determine the rail locations
self.route_supply_rails(self.vdd_name,1) self.route_supply_rails(self.vdd_name,1)
#self.write_debug_gds("debug_rails.gds",stop_program=True)
#print_time("Supply rails",datetime.now(), start_time)
#start_time = datetime.now()
self.route_simple_overlaps(vdd_name) self.route_simple_overlaps(vdd_name)
self.route_simple_overlaps(gnd_name) self.route_simple_overlaps(gnd_name)
#print_time("Simple overlaps",datetime.now(), start_time)
#self.write_debug_gds("debug_simple_route.gds",stop_program=False)
# Route the supply pins to the supply rails # Route the supply pins to the supply rails
# Route vdd first since we want it to be shorter # Route vdd first since we want it to be shorter
#start_time = datetime.now()
self.route_pins_to_rails(vdd_name) self.route_pins_to_rails(vdd_name)
self.route_pins_to_rails(gnd_name) self.route_pins_to_rails(gnd_name)
#print_time("Routing",datetime.now(), start_time)
#self.write_debug_gds("debug_pin_routes.gds",stop_program=True)
#self.write_debug_gds("final.gds",False) #self.write_debug_gds("final.gds",False)
@ -116,7 +101,7 @@ class supply_router(router):
# These are the wire tracks # These are the wire tracks
wire_tracks = self.supply_rail_tracks[pin_name] wire_tracks = self.supply_rail_tracks[pin_name]
routed_count=0
for pg in self.pin_groups[pin_name]: for pg in self.pin_groups[pin_name]:
if pg.is_routed(): if pg.is_routed():
continue continue
@ -124,6 +109,7 @@ class supply_router(router):
# First, check if we just overlap, if so, we are done. # First, check if we just overlap, if so, we are done.
overlap_grids = wire_tracks & pg.grids overlap_grids = wire_tracks & pg.grids
if len(overlap_grids)>0: if len(overlap_grids)>0:
routed_count += 1
pg.set_routed() pg.set_routed()
continue continue
@ -131,7 +117,7 @@ class supply_router(router):
#pg.create_simple_overlap_enclosure(pg.grids) #pg.create_simple_overlap_enclosure(pg.grids)
#pg.add_enclosure(self.cell) #pg.add_enclosure(self.cell)
debug.info(1,"Routed {} simple overlap pins".format(routed_count))
def finalize_supply_rails(self, name): def finalize_supply_rails(self, name):
""" """
@ -227,40 +213,6 @@ class supply_router(router):
width=pin.width(), width=pin.width(),
height=pin.height()) height=pin.height())
def compute_supply_rail_dimensions(self):
"""
Compute the supply rail dimensions including wide metal spacing rules.
"""
self.max_yoffset = self.rg.ur.y
self.max_xoffset = self.rg.ur.x
# # Longest length is conservative
# rail_length = max(self.max_yoffset,self.max_xoffset)
# # Convert the number of tracks to dimensions to get the design rule spacing
# rail_width = self.track_width*self.rail_track_width
# # Get the conservative width and spacing of the top rails
# (horizontal_width, horizontal_space) = self.get_supply_layer_width_space(0)
# (vertical_width, vertical_space) = self.get_supply_layer_width_space(1)
# width = max(horizontal_width, vertical_width)
# space = max(horizontal_space, vertical_space)
# track_pitch = width + space
# # Determine the pitch (in tracks) of the rail wire + spacing
# self.supply_rail_width = math.ceil(track_pitch/self.track_width)
# debug.info(1,"Rail step: {}".format(self.supply_rail_width))
# # Conservatively determine the number of tracks that the rail actually occupies
# space_tracks = math.ceil(space/self.track_width)
# self.supply_rail_wire_width = self.supply_rail_width - space_tracks
# debug.info(1,"Rail wire tracks: {}".format(self.supply_rail_wire_width))
# total_space = self.supply_rail_width - self.supply_rail_wire_width
# self.supply_rail_space_width = math.floor(0.5*total_space)
# debug.info(1,"Rail space tracks: {} (on both sides)".format(self.supply_rail_space_width))
def compute_supply_rails(self, name, supply_number): def compute_supply_rails(self, name, supply_number):
""" """
Compute the unblocked locations for the horizontal and vertical supply rails. Compute the unblocked locations for the horizontal and vertical supply rails.
@ -270,14 +222,19 @@ class supply_router(router):
self.supply_rails[name]=[] self.supply_rails[name]=[]
start_offset = supply_number max_yoffset = self.rg.ur.y
max_xoffset = self.rg.ur.x
min_yoffset = self.rg.ll.y
min_xoffset = self.rg.ll.x
# Horizontal supply rails # Horizontal supply rails
for offset in range(start_offset, self.max_yoffset, 2): start_offset = min_yoffset + supply_number
for offset in range(start_offset, max_yoffset, 2):
# Seed the function at the location with the given width # Seed the function at the location with the given width
wave = [vector3d(0,offset,0)] wave = [vector3d(min_xoffset,offset,0)]
# While we can keep expanding east in this horizontal track # While we can keep expanding east in this horizontal track
while wave and wave[0].x < self.max_xoffset: while wave and wave[0].x < max_xoffset:
added_rail = self.find_supply_rail(name, wave, direction.EAST) added_rail = self.find_supply_rail(name, wave, direction.EAST)
if not added_rail: if not added_rail:
# Just seed with the next one # Just seed with the next one
@ -287,12 +244,12 @@ class supply_router(router):
wave = added_rail.neighbor(direction.EAST) wave = added_rail.neighbor(direction.EAST)
# Vertical supply rails # Vertical supply rails
max_offset = self.rg.ur.x start_offset = min_xoffset + supply_number
for offset in range(start_offset, self.max_xoffset, 2): for offset in range(start_offset, max_xoffset, 2):
# Seed the function at the location with the given width # Seed the function at the location with the given width
wave = [vector3d(offset,0,1)] wave = [vector3d(offset,min_yoffset,1)]
# While we can keep expanding north in this vertical track # While we can keep expanding north in this vertical track
while wave and wave[0].y < self.max_yoffset: while wave and wave[0].y < max_yoffset:
added_rail = self.find_supply_rail(name, wave, direction.NORTH) added_rail = self.find_supply_rail(name, wave, direction.NORTH)
if not added_rail: if not added_rail:
# Just seed with the next one # Just seed with the next one
@ -410,8 +367,8 @@ class supply_router(router):
""" """
remaining_components = sum(not x.is_routed() for x in self.pin_groups[pin_name]) remaining_components = sum(not x.is_routed() for x in self.pin_groups[pin_name])
debug.info(1,"Routing {0} with {1} pin components to route.".format(pin_name, debug.info(1,"Maze routing {0} with {1} pin components to connect.".format(pin_name,
remaining_components)) remaining_components))
for index,pg in enumerate(self.pin_groups[pin_name]): for index,pg in enumerate(self.pin_groups[pin_name]):
if pg.is_routed(): if pg.is_routed():

View File

@ -14,7 +14,6 @@ class sram():
""" """
def __init__(self, sram_config, name): def __init__(self, sram_config, name):
sram_config.compute_sizes()
sram_config.set_local_config(self) sram_config.set_local_config(self)
# reset the static duplicate name checker for unit tests # reset the static duplicate name checker for unit tests

View File

@ -10,6 +10,7 @@ from globals import OPTS, print_time
from sram_base import sram_base from sram_base import sram_base
from bank import bank from bank import bank
from contact import m2m3
from dff_buf_array import dff_buf_array from dff_buf_array import dff_buf_array
from dff_array import dff_array from dff_array import dff_array
@ -21,11 +22,6 @@ class sram_1bank(sram_base):
def __init__(self, name, sram_config): def __init__(self, name, sram_config):
sram_base.__init__(self, name, sram_config) sram_base.__init__(self, name, sram_config)
def create_netlist(self):
sram_base.create_netlist(self)
self.create_modules()
def create_modules(self): def create_modules(self):
""" """
This adds the modules for a single bank SRAM with control This adds the modules for a single bank SRAM with control
@ -207,9 +203,8 @@ class sram_1bank(sram_base):
offset=clk_steiner_pos, offset=clk_steiner_pos,
rotate=90) rotate=90)
# Note, the via to the control logic is taken care of when we route # Note, the via to the control logic is taken care of above
# the control logic to the bank self.add_wire(("metal3","via2","metal2"),[row_addr_clk_pos, mid1_pos, clk_steiner_pos])
self.add_wire(("metal3","via2","metal2"),[row_addr_clk_pos, mid1_pos, clk_steiner_pos, control_clk_buf_pos])
if self.col_addr_dff: if self.col_addr_dff:
dff_clk_pin = self.col_addr_dff_insts[port].get_pin("clk") dff_clk_pin = self.col_addr_dff_insts[port].get_pin("clk")
@ -221,6 +216,9 @@ class sram_1bank(sram_base):
data_dff_clk_pin = self.data_dff_insts[port].get_pin("clk") data_dff_clk_pin = self.data_dff_insts[port].get_pin("clk")
data_dff_clk_pos = data_dff_clk_pin.center() data_dff_clk_pos = data_dff_clk_pin.center()
mid_pos = vector(clk_steiner_pos.x, data_dff_clk_pos.y) mid_pos = vector(clk_steiner_pos.x, data_dff_clk_pos.y)
# In some designs, the steiner via will be too close to the mid_pos via
# so make the wire as wide as the contacts
self.add_path("metal2",[mid_pos, clk_steiner_pos], width=max(m2m3.width,m2m3.height))
self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, clk_steiner_pos]) self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, clk_steiner_pos])

View File

@ -2,6 +2,7 @@ import sys
import datetime import datetime
import getpass import getpass
import debug import debug
from datetime import datetime
from importlib import reload from importlib import reload
from vector import vector from vector import vector
from globals import OPTS, print_time from globals import OPTS, print_time
@ -64,35 +65,50 @@ class sram_base(design):
def create_netlist(self): def create_netlist(self):
""" Netlist creation """ """ Netlist creation """
start_time = datetime.now()
# Must create the control logic before pins to get the pins # Must create the control logic before pins to get the pins
self.add_modules() self.add_modules()
self.add_pins() self.add_pins()
self.create_modules()
# This is for the lib file if we don't create layout # This is for the lib file if we don't create layout
self.width=0 self.width=0
self.height=0 self.height=0
if not OPTS.is_unit_test:
print_time("Submodules",datetime.now(), start_time)
def create_layout(self): def create_layout(self):
""" Layout creation """ """ Layout creation """
start_time = datetime.now()
self.place_instances() self.place_instances()
if not OPTS.is_unit_test:
print_time("Placement",datetime.now(), start_time)
start_time = datetime.now()
self.route_layout() self.route_layout()
self.route_supplies()
if not OPTS.is_unit_test:
print_time("Routing",datetime.now(), start_time)
self.add_lvs_correspondence_points() self.add_lvs_correspondence_points()
self.offset_all_coordinates() self.offset_all_coordinates()
# Must be done after offsetting lower-left
self.route_supplies()
highest_coord = self.find_highest_coords() highest_coord = self.find_highest_coords()
self.width = highest_coord[0] self.width = highest_coord[0]
self.height = highest_coord[1] self.height = highest_coord[1]
start_time = datetime.now()
self.DRC_LVS(final_verification=True) self.DRC_LVS(final_verification=True)
if not OPTS.is_unit_test:
print_time("Verification",datetime.now(), start_time)
def create_modules(self):
debug.error("Must override pure virtual function.",-1)
def route_supplies(self): def route_supplies(self):
""" Route the supply grid and connect the pins to them. """ """ Route the supply grid and connect the pins to them. """

View File

@ -14,7 +14,7 @@ class sram_config:
# This will get over-written when we determine the organization # This will get over-written when we determine the organization
self.words_per_row = None self.words_per_row = None
# Move the module names to this? self.compute_sizes()
def set_local_config(self, module): def set_local_config(self, module):
@ -54,6 +54,20 @@ class sram_config:
self.tentative_num_rows = self.num_bits_per_bank / (self.words_per_row*self.word_size) 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) self.words_per_row = self.amend_words_per_row(self.tentative_num_rows, self.words_per_row)
debug.info(1,"Words per row: {}".format(self.words_per_row))
self.recompute_sizes()
def recompute_sizes(self):
"""
Calculate the auxiliary values assuming fixed number of words per row.
This can be called multiple times from the unit test when we reconfigure an
SRAM for testing.
"""
# If the banks changed
self.num_words_per_bank = self.num_words/self.num_banks
self.num_bits_per_bank = self.word_size*self.num_words_per_bank
# Fix the number of columns and rows # Fix the number of columns and rows
self.num_cols = int(self.words_per_row*self.word_size) self.num_cols = int(self.words_per_row*self.word_size)
self.num_rows = int(self.num_words_per_bank/self.words_per_row) self.num_rows = int(self.num_words_per_bank/self.words_per_row)
@ -64,7 +78,6 @@ class sram_config:
self.bank_addr_size = self.col_addr_size + self.row_addr_size 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.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): def estimate_words_per_row(self,tentative_num_cols, word_size):
""" """
@ -74,10 +87,14 @@ class sram_config:
if tentative_num_cols < 1.5*word_size: if tentative_num_cols < 1.5*word_size:
return 1 return 1
elif tentative_num_cols > 3*word_size: elif tentative_num_cols < 3*word_size:
return 2
elif tentative_num_cols < 6*word_size:
return 4 return 4
else: else:
return 2 if tentative_num_cols > 16*word_size:
debug.warning("Reaching column mux size limit. Consider increasing above 8-way.")
return 8
def amend_words_per_row(self,tentative_num_rows, words_per_row): def amend_words_per_row(self,tentative_num_rows, words_per_row):
""" """

View File

@ -0,0 +1,46 @@
#!/usr/bin/env python3
"""
Run a regression test on a 2-row buffer cell
"""
import unittest
from testutils import header,openram_test
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
@unittest.skip("SKIPPING 04_pdriver_test, LVS error in FreePDK45")
class pdriver_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import pdriver
debug.info(2, "Testing inverter/buffer 4x 8x")
# a tests the error message for specifying conflicting conditions
#a = pdriver.pdriver(c_load = 4,size_list = [1,2,4,8])
b = pdriver.pdriver(size_list = [1,2,4,8])
c = pdriver.pdriver(c_load = 50)
d = pdriver.pdriver(c_load = 50, neg_polarity = True)
e = pdriver.pdriver(c_load = 64)
f = pdriver.pdriver(c_load = 64, neg_polarity = True)
#self.local_check(a)
self.local_check(b)
self.local_check(c)
self.local_check(d)
self.local_check(e)
self.local_check(f)
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

View File

@ -24,18 +24,21 @@ class multi_bank_test(openram_test):
c.num_banks=2 c.num_banks=2
c.words_per_row=1 c.words_per_row=1
c.recompute_sizes()
debug.info(1, "No column mux") debug.info(1, "No column mux")
a = bank(c, name="bank1_multi") a = bank(c, name="bank1_multi")
self.local_check(a) self.local_check(a)
c.num_words=32 c.num_words=32
c.words_per_row=2 c.words_per_row=2
c.recompute_sizes()
debug.info(1, "Two way column mux") debug.info(1, "Two way column mux")
a = bank(c, name="bank2_multi") a = bank(c, name="bank2_multi")
self.local_check(a) self.local_check(a)
c.num_words=64 c.num_words=64
c.words_per_row=4 c.words_per_row=4
c.recompute_sizes()
debug.info(1, "Four way column mux") debug.info(1, "Four way column mux")
a = bank(c, name="bank3_multi") a = bank(c, name="bank3_multi")
self.local_check(a) self.local_check(a)
@ -43,6 +46,7 @@ class multi_bank_test(openram_test):
c.word_size=2 c.word_size=2
c.num_words=128 c.num_words=128
c.words_per_row=8 c.words_per_row=8
c.recompute_sizes()
debug.info(1, "Eight way column mux") debug.info(1, "Eight way column mux")
a = bank(c, name="bank4_multi") a = bank(c, name="bank4_multi")
self.local_check(a) self.local_check(a)

View File

@ -31,6 +31,7 @@ class psingle_bank_test(openram_test):
num_words=16) num_words=16)
c.words_per_row=1 c.words_per_row=1
c.recompute_sizes()
debug.info(1, "No column mux") debug.info(1, "No column mux")
name = "bank1_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) name = "bank1_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports)
a = bank(c, name=name) a = bank(c, name=name)
@ -38,6 +39,7 @@ class psingle_bank_test(openram_test):
c.num_words=32 c.num_words=32
c.words_per_row=2 c.words_per_row=2
c.recompute_sizes()
debug.info(1, "Two way column mux") debug.info(1, "Two way column mux")
name = "bank2_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) name = "bank2_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports)
a = bank(c, name=name) a = bank(c, name=name)
@ -45,6 +47,7 @@ class psingle_bank_test(openram_test):
c.num_words=64 c.num_words=64
c.words_per_row=4 c.words_per_row=4
c.recompute_sizes()
debug.info(1, "Four way column mux") debug.info(1, "Four way column mux")
name = "bank3_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) name = "bank3_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports)
a = bank(c, name=name) a = bank(c, name=name)
@ -53,6 +56,7 @@ class psingle_bank_test(openram_test):
c.word_size=2 c.word_size=2
c.num_words=128 c.num_words=128
c.words_per_row=8 c.words_per_row=8
c.recompute_sizes()
debug.info(1, "Four way column mux") debug.info(1, "Four way column mux")
name = "bank4_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) name = "bank4_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports)
a = bank(c, name=name) a = bank(c, name=name)

View File

@ -30,6 +30,7 @@ class psram_1bank_2mux_1rw_1w_test(openram_test):
num_banks=1) num_banks=1)
c.num_words=32 c.num_words=32
c.words_per_row=2 c.words_per_row=2
c.recompute_sizes()
debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports, OPTS.num_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,

View File

@ -30,6 +30,7 @@ class psram_1bank_2mux_1w_1r_test(openram_test):
num_banks=1) num_banks=1)
c.num_words=32 c.num_words=32
c.words_per_row=2 c.words_per_row=2
c.recompute_sizes()
debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports, OPTS.num_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,

View File

@ -31,6 +31,7 @@ class psram_1bank_2mux_test(openram_test):
num_banks=1) num_banks=1)
c.num_words=32 c.num_words=32
c.words_per_row=2 c.words_per_row=2
c.recompute_sizes()
debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports, OPTS.num_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,

View File

@ -29,6 +29,7 @@ class psram_1bank_4mux_1rw_1r_test(openram_test):
num_banks=1) num_banks=1)
c.num_words=64 c.num_words=64
c.words_per_row=4 c.words_per_row=4
c.recompute_sizes()
debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Layout test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports, OPTS.num_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,

View File

@ -29,6 +29,7 @@ class sram_1bank_2mux_1rw_1r_test(openram_test):
num_banks=1) num_banks=1)
c.words_per_row=2 c.words_per_row=2
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, 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_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,

View File

@ -23,6 +23,7 @@ class sram_1bank_2mux_test(openram_test):
num_banks=1) num_banks=1)
c.words_per_row=2 c.words_per_row=2
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, 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_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,

View File

@ -23,6 +23,7 @@ class sram_1bank_4mux_test(openram_test):
num_banks=1) num_banks=1)
c.words_per_row=4 c.words_per_row=4
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, 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_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,

View File

@ -29,6 +29,7 @@ class sram_1bank_8mux_1rw_1r_test(openram_test):
num_banks=1) num_banks=1)
c.words_per_row=8 c.words_per_row=8
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, 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_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,

View File

@ -23,6 +23,7 @@ class sram_1bank_8mux_test(openram_test):
num_banks=1) num_banks=1)
c.words_per_row=8 c.words_per_row=8
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, 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_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,

View File

@ -29,6 +29,7 @@ class sram_1bank_nomux_1rw_1r_test(openram_test):
num_banks=1) num_banks=1)
c.words_per_row=1 c.words_per_row=1
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, 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_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,

View File

@ -23,6 +23,7 @@ class sram_1bank_nomux_test(openram_test):
num_banks=1) num_banks=1)
c.words_per_row=1 c.words_per_row=1
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, 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_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,

View File

@ -23,18 +23,21 @@ class sram_2bank_test(openram_test):
num_banks=2) num_banks=2)
c.words_per_row=1 c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Two bank, no column mux with control logic") debug.info(1, "Two bank, no column mux with control logic")
a = sram(c, "sram1") a = sram(c, "sram1")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)
c.num_words=64 c.num_words=64
c.words_per_row=2 c.words_per_row=2
c.recompute_sizes()
debug.info(1, "Two bank two way column mux with control logic") debug.info(1, "Two bank two way column mux with control logic")
a = sram(c, "sram2") a = sram(c, "sram2")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)
c.num_words=128 c.num_words=128
c.words_per_row=4 c.words_per_row=4
c.recompute_sizes()
debug.info(1, "Two bank, four way column mux with control logic") debug.info(1, "Two bank, four way column mux with control logic")
a = sram(c, "sram3") a = sram(c, "sram3")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)
@ -42,6 +45,7 @@ class sram_2bank_test(openram_test):
c.word_size=2 c.word_size=2
c.num_words=256 c.num_words=256
c.words_per_row=8 c.words_per_row=8
c.recompute_sizes()
debug.info(1, "Two bank, eight way column mux with control logic") debug.info(1, "Two bank, eight way column mux with control logic")
a = sram(c, "sram4") a = sram(c, "sram4")
self.local_check(a, final_verification=True) self.local_check(a, final_verification=True)

View File

@ -30,6 +30,7 @@ class timing_sram_test(openram_test):
num_words=16, num_words=16,
num_banks=1) num_banks=1)
c.words_per_row=1 c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
s = sram(c, name="sram1") s = sram(c, name="sram1")

View File

@ -30,6 +30,7 @@ class timing_sram_test(openram_test):
num_words=16, num_words=16,
num_banks=1) num_banks=1)
c.words_per_row=1 c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
s = sram(c, name="sram1") s = sram(c, name="sram1")

View File

@ -35,6 +35,7 @@ class psram_1bank_2mux_1rw_1r_1w_func_test(openram_test):
num_words=64, num_words=64,
num_banks=1) num_banks=1)
c.words_per_row=2 c.words_per_row=2
c.recompute_sizes()
debug.info(1, "Functional test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Functional test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports, OPTS.num_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,

View File

@ -35,6 +35,7 @@ class psram_1bank_4mux_func_test(openram_test):
num_words=256, num_words=256,
num_banks=1) num_banks=1)
c.words_per_row=4 c.words_per_row=4
c.recompute_sizes()
debug.info(1, "Functional test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Functional test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports, OPTS.num_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,

View File

@ -35,6 +35,7 @@ class psram_1bank_8mux_func_test(openram_test):
num_words=256, num_words=256,
num_banks=1) num_banks=1)
c.words_per_row=8 c.words_per_row=8
c.recompute_sizes()
debug.info(1, "Functional test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Functional test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports, OPTS.num_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,

View File

@ -35,6 +35,7 @@ class psram_1bank_nomux_func_test(openram_test):
num_words=32, num_words=32,
num_banks=1) num_banks=1)
c.words_per_row=1 c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Functional test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports, debug.info(1, "Functional test for {}rw,{}r,{}w psram with {} bit words, {} words, {} words per row, {} banks".format(OPTS.num_rw_ports,
OPTS.num_r_ports, OPTS.num_r_ports,
OPTS.num_w_ports, OPTS.num_w_ports,

View File

@ -30,6 +30,7 @@ class sram_1bank_2mux_func_test(openram_test):
num_words=64, num_words=64,
num_banks=1) num_banks=1)
c.words_per_row=2 c.words_per_row=2
c.recompute_sizes()
debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size, debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.num_words, c.num_words,
c.words_per_row, c.words_per_row,

View File

@ -30,6 +30,7 @@ class sram_1bank_4mux_func_test(openram_test):
num_words=256, num_words=256,
num_banks=1) num_banks=1)
c.words_per_row=4 c.words_per_row=4
c.recompute_sizes()
debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size, debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.num_words, c.num_words,
c.words_per_row, c.words_per_row,

View File

@ -33,6 +33,7 @@ class sram_1bank_8mux_func_test(openram_test):
num_words=256, num_words=256,
num_banks=1) num_banks=1)
c.words_per_row=8 c.words_per_row=8
c.recompute_sizes()
debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size, debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.num_words, c.num_words,
c.words_per_row, c.words_per_row,

View File

@ -30,6 +30,7 @@ class sram_1bank_nomux_func_test(openram_test):
num_words=32, num_words=32,
num_banks=1) num_banks=1)
c.words_per_row=1 c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size, debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.num_words, c.num_words,
c.words_per_row, c.words_per_row,

View File

@ -35,6 +35,7 @@ class psram_1bank_nomux_func_test(openram_test):
num_words=32, num_words=32,
num_banks=1) num_banks=1)
c.words_per_row=1 c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Functional test for sram 1rw,1r with {} bit words, {} words, {} words per row, {} banks".format(c.word_size, debug.info(1, "Functional test for sram 1rw,1r with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
c.num_words, c.num_words,
c.words_per_row, c.words_per_row,

View File

@ -23,6 +23,7 @@ class lib_test(openram_test):
num_words=16, num_words=16,
num_banks=1) num_banks=1)
c.words_per_row=1 c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Testing analytical timing for sample 2 bit, 16 words SRAM with 1 bank") 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)) s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "temp.sp"

View File

@ -32,6 +32,7 @@ class lib_test(openram_test):
num_words=16, num_words=16,
num_banks=1) num_banks=1)
c.words_per_row=1 c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Testing pruned timing for sample 2 bit, 16 words SRAM with 1 bank") 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)) s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))

View File

@ -32,6 +32,7 @@ class lib_test(openram_test):
num_words=16, num_words=16,
num_banks=1) num_banks=1)
c.words_per_row=1 c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank") 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)) s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))

View File

@ -23,6 +23,7 @@ class lef_test(openram_test):
num_words=16, num_words=16,
num_banks=1) num_banks=1)
c.words_per_row=1 c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Testing LEF for sample 2 bit, 16 words SRAM with 1 bank") 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)) s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))

View File

@ -22,6 +22,7 @@ class verilog_test(openram_test):
num_words=16, num_words=16,
num_banks=1) num_banks=1)
c.words_per_row=1 c.words_per_row=1
c.recompute_sizes()
debug.info(1, "Testing Verilog for sample 2 bit, 16 words SRAM with 1 bank") 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)) s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))

View File

@ -39,7 +39,7 @@ class worst_case_timing_sram_test(openram_test):
num_words=num_words, num_words=num_words,
num_banks=num_banks) num_banks=num_banks)
c.words_per_row=1 c.words_per_row=1
#c.compute_sizes() c.recompute_sizes()
debug.info(1, "Testing the timing different bitecells inside a {}bit, {} words SRAM with {} bank".format( debug.info(1, "Testing the timing different bitecells inside a {}bit, {} words SRAM with {} bank".format(
word_size, num_words, num_banks)) word_size, num_words, num_banks))
s = sram(c, name="sram1") s = sram(c, name="sram1")