mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev' into datasheet_gen
This commit is contained in:
commit
3d9203a7ea
|
|
@ -1,93 +1,45 @@
|
|||
TECH = scn4m_subm
|
||||
CUR_DIR = $(shell pwd)
|
||||
TEST_DIR = ${CUR_DIR}/tests
|
||||
|
||||
MAKEFLAGS += -j 2
|
||||
MAKEFLAGS += -j 1
|
||||
|
||||
# Library test
|
||||
LIBRARY_TESTS = \
|
||||
01_library_drc_test.py \
|
||||
02_library_lvs_test.py
|
||||
LIBRARY_TESTS = $(shell find ${TEST_DIR} -name 0[1-2]*_test.py)
|
||||
|
||||
# Technology and DRC tests (along with ptx)
|
||||
TECH_TESTS = \
|
||||
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
|
||||
TECH_TESTS = $(shell find ${TEST_DIR} -name 03*_test.py)
|
||||
|
||||
# Parameterized cells
|
||||
PCELLS_TESTS = \
|
||||
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
|
||||
CELL_TESTS = $(shell find ${TEST_DIR} -name 04*_test.py)
|
||||
|
||||
# Dynamically generated modules and arrays
|
||||
MODULE_TESTS = \
|
||||
05_bitcell_array_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
|
||||
MODULE_TESTS = $(shell find ${TEST_DIR} -name 0[5-9]*_test.py)\
|
||||
$(shell find ${TEST_DIR} -name 1*_test.py)
|
||||
|
||||
# Top-level SRAM configurations
|
||||
TOP_TESTS = \
|
||||
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
|
||||
TOP_TESTS = $(shell find ${TEST_DIR} -name 20*_test.py)
|
||||
|
||||
# All simulation tests.
|
||||
CHAR_TESTS = \
|
||||
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
|
||||
CHAR_TESTS = $(shell find ${TEST_DIR} -name 2[1-2]*_test.py)
|
||||
|
||||
# Keep the model lib test here since it is fast
|
||||
# and doesn't need simulation.
|
||||
USAGE_TESTS = \
|
||||
23_lib_sram_model_test.py \
|
||||
24_lef_sram_test.py \
|
||||
25_verilog_sram_test.py
|
||||
USAGE_TESTS = $(shell find ${TEST_DIR} -name 2[3-9]*_test.py)\
|
||||
$(shell find ${TEST_DIR} -name 30*_test.py)
|
||||
|
||||
ALL_FILES = \
|
||||
ALL_TESTS = \
|
||||
${LIBRARY_TESTS} \
|
||||
${TECH_TESTS} \
|
||||
${PCELLS_TESTS} \
|
||||
${MODULES_TESTS} \
|
||||
${CELL_TESTS} \
|
||||
${MODULE_TESTS} \
|
||||
${TOP_TESTS} \
|
||||
${CHAR_TESTS} \
|
||||
${USAGE_TESTS}
|
||||
|
||||
default all:
|
||||
.PHONY: ${ALL_TESTS}
|
||||
|
||||
$(ALL_FILES):
|
||||
python ${TEST_DIR}/$@ -t freepdk45
|
||||
python ${TEST_DIR}/$@ -t scn3me_subm
|
||||
all: ${ALL_TESTS}
|
||||
|
||||
# Library tests
|
||||
lib: ${LIBRARY_TESTS}
|
||||
|
|
@ -96,10 +48,10 @@ lib: ${LIBRARY_TESTS}
|
|||
tech: ${TECH_TESTS}
|
||||
|
||||
# Dynamically generated cells
|
||||
pcells: ${PCELLS_TESTS}
|
||||
cell: ${CELL_TESTS}
|
||||
|
||||
# Dynamically generated modules
|
||||
modules: ${MODULES_TESTS}
|
||||
module: ${MODULE_TESTS}
|
||||
|
||||
# Top level SRAM tests
|
||||
top: ${TOP_TESTS}
|
||||
|
|
@ -110,6 +62,9 @@ char: ${CHAR_TESTS}
|
|||
# Usage and file generation
|
||||
usage: ${USAGE_TESTS}
|
||||
|
||||
$(ALL_TESTS):
|
||||
python3 $@ -t ${TECH}
|
||||
|
||||
clean:
|
||||
find . -name \*.pyc -exec rm {} \;
|
||||
find . -name \*~ -exec rm {} \;
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ def parse_args():
|
|||
# This may be overridden when we read a config file though...
|
||||
if OPTS.tech_name == "":
|
||||
OPTS.tech_name = "scmos"
|
||||
# Alias SCMOS to AMI 0.5um
|
||||
# Alias SCMOS to 180nm
|
||||
if OPTS.tech_name == "scmos":
|
||||
OPTS.tech_name = "scn4m_subm"
|
||||
|
||||
|
|
@ -89,6 +89,7 @@ def print_banner():
|
|||
print("|=========" + dev_info.center(60) + "=========|")
|
||||
temp_info = "Temp dir: {}".format(OPTS.openram_temp)
|
||||
print("|=========" + temp_info.center(60) + "=========|")
|
||||
print("|=========" + "See LICENSE for license info".center(60) + "=========|")
|
||||
print("|==============================================================================|")
|
||||
|
||||
|
||||
|
|
@ -418,6 +419,9 @@ def report_status():
|
|||
print("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size,
|
||||
OPTS.num_words,
|
||||
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:
|
||||
print("Netlist only mode (no physical design is being done).")
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@ if len(args) != 1:
|
|||
# These depend on arguments, so don't load them until now.
|
||||
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)
|
||||
|
||||
# Only print banner here so it's not in unit tests
|
||||
|
|
@ -34,10 +38,14 @@ print_banner()
|
|||
# Output info about this run
|
||||
report_status()
|
||||
|
||||
# Start importing design modules after we have the config file
|
||||
import verify
|
||||
from sram import sram
|
||||
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 *
|
||||
output_extensions = ["sp","v","lib","py"]
|
||||
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,sep="\n")
|
||||
|
||||
# Keep track of running stats
|
||||
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)
|
||||
|
||||
# import SRAM test generation
|
||||
from sram import sram
|
||||
s = sram(sram_config=c,
|
||||
name=OPTS.output_name)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -70,8 +70,7 @@ class router(router_tech):
|
|||
self.boundary = self.layout.measureBoundary(self.top_name)
|
||||
# These must be un-indexed to get rid of the matrix type
|
||||
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.track_widths.scale(5,5)
|
||||
self.ur = vector(self.boundary[1][0], self.boundary[1][1])
|
||||
|
||||
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].
|
||||
"""
|
||||
debug.info(1,"Finding pins for {}.".format(pin_name))
|
||||
#start_time = datetime.now()
|
||||
self.retrieve_pins(pin_name)
|
||||
#print_time("Retrieved pins",datetime.now(), start_time)
|
||||
#start_time = datetime.now()
|
||||
self.analyze_pins(pin_name)
|
||||
#print_time("Analyzed pins",datetime.now(), start_time)
|
||||
|
||||
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 ignores shapes that were pins
|
||||
#start_time = datetime.now()
|
||||
self.find_blockages()
|
||||
#print_time("Find blockags",datetime.now(), start_time)
|
||||
|
||||
# Convert the blockages to grid units
|
||||
#start_time = datetime.now()
|
||||
self.convert_blockages()
|
||||
#print_time("Find blockags",datetime.now(), start_time)
|
||||
|
||||
# This will convert the pins to grid units
|
||||
# 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:
|
||||
self.convert_pins(pin)
|
||||
#print_time("Convert pins",datetime.now(), start_time)
|
||||
|
||||
#start_time = datetime.now()
|
||||
#for pin in pin_list:
|
||||
# self.combine_adjacent_pins(pin)
|
||||
#print_time("Combine pins",datetime.now(), start_time)
|
||||
#self.write_debug_gds("debug_combine_pins.gds",stop_program=True)
|
||||
|
||||
# Combine adjacent pins into pin groups to reduce run-time
|
||||
for pin in pin_list:
|
||||
self.combine_adjacent_pins(pin)
|
||||
|
||||
# Separate any adjacent grids of differing net names that overlap
|
||||
# Must be done before enclosing pins
|
||||
#start_time = datetime.now()
|
||||
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
|
||||
#start_time = datetime.now()
|
||||
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):
|
||||
|
|
@ -257,18 +237,19 @@ class router(router_tech):
|
|||
This will try to separate all grid pins by the supplied number of separation
|
||||
tracks (default is to prevent adjacency).
|
||||
"""
|
||||
debug.info(1,"Separating adjacent pins.")
|
||||
# Commented out to debug with SCMOS
|
||||
#if separation==0:
|
||||
# return
|
||||
|
||||
pin_names = self.pin_groups.keys()
|
||||
for pin_name1 in pin_names:
|
||||
for pin_name2 in pin_names:
|
||||
if pin_name1==pin_name2:
|
||||
continue
|
||||
self.separate_adjacent_pin(pin_name1, pin_name2, separation)
|
||||
|
||||
pin_names = self.pin_groups.keys()
|
||||
for i,pin_name1 in enumerate(pin_names):
|
||||
for j,pin_name2 in enumerate(pin_names):
|
||||
if i==j:
|
||||
continue
|
||||
if i>j:
|
||||
return
|
||||
self.separate_adjacent_pin(pin_name1, pin_name2, separation)
|
||||
|
||||
def separate_adjacent_pin(self, pin_name1, pin_name2, separation):
|
||||
"""
|
||||
Go through all of the pin groups and check if any other pin group is
|
||||
|
|
@ -277,13 +258,18 @@ class router(router_tech):
|
|||
Try to do this intelligently to keep th pins enclosed.
|
||||
"""
|
||||
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 index2,pg2 in enumerate(self.pin_groups[pin_name2]):
|
||||
adj_grids = pg1.adjacent_grids(pg2, separation)
|
||||
removed_grids += len(adj_grids)
|
||||
# These should have the same length, so...
|
||||
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)
|
||||
|
||||
|
||||
debug.info(1,"Removed {} adjacent grids.".format(removed_grids))
|
||||
|
||||
def remove_adjacent_grid(self, pg1, pg2, adj_grids):
|
||||
"""
|
||||
|
|
@ -304,12 +290,12 @@ class router(router_tech):
|
|||
# If the adjacent grids are a subset of the secondary grids (i.e. not necessary)
|
||||
# remove them from each
|
||||
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.secondary_grids.remove(adj)
|
||||
self.blocked_grids.add(adj)
|
||||
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.secondary_grids.remove(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
|
||||
# grid of at least one pin
|
||||
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)
|
||||
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)
|
||||
|
||||
|
||||
|
|
@ -361,17 +347,6 @@ class router(router_tech):
|
|||
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):
|
||||
"""
|
||||
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
|
||||
ll = ll.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]
|
||||
|
||||
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.
|
||||
"""
|
||||
#print("INSUFFICIENT LIST",insufficient_list)
|
||||
# Find the coordinate with the most overlap
|
||||
best_coord = None
|
||||
best_overlap = -math.inf
|
||||
|
|
@ -579,7 +548,6 @@ class router(router_tech):
|
|||
Get a grid cell that is the furthest from the blocked grids.
|
||||
"""
|
||||
|
||||
#print("INSUFFICIENT LIST",insufficient_list)
|
||||
# Find the coordinate with the most overlap
|
||||
best_coord = None
|
||||
best_dist = math.inf
|
||||
|
|
@ -596,7 +564,6 @@ class router(router_tech):
|
|||
Given a pin and a list of grid cells (probably non-overlapping),
|
||||
return the nearest grid cell (center to center).
|
||||
"""
|
||||
#print("INSUFFICIENT LIST",insufficient_list)
|
||||
# Find the coordinate with the most overlap
|
||||
best_coord = None
|
||||
best_dist = math.inf
|
||||
|
|
@ -638,10 +605,6 @@ class router(router_tech):
|
|||
else:
|
||||
debug.info(2," No overlap: {0} {1}".format(overlap_length,0))
|
||||
return (None,None)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def convert_track_to_pin(self, track):
|
||||
|
|
@ -764,8 +727,6 @@ class router(router_tech):
|
|||
pg.enclose_pin()
|
||||
pg.add_enclosure(self.cell)
|
||||
|
||||
#self.write_debug_gds("pin_debug.gds", False)
|
||||
|
||||
def add_source(self, pin_name):
|
||||
"""
|
||||
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))
|
||||
|
||||
# Keep track of path for future blockages
|
||||
#path.set_blocked()
|
||||
|
||||
# This is marked for debug
|
||||
path.set_path()
|
||||
|
||||
|
|
@ -906,44 +864,10 @@ class router(router_tech):
|
|||
(abs_ll,unused) = pin.rect
|
||||
pin = self.convert_track_to_pin(ur)
|
||||
(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)
|
||||
|
||||
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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -48,9 +48,9 @@ class router_tech:
|
|||
self.track_width = max(self.horiz_track_width,self.vert_track_width)
|
||||
debug.info(1,"Track width: {:.3f}".format(self.track_width))
|
||||
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
|
||||
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_factor = vector([1/self.track_width] * 2)
|
||||
|
|
|
|||
|
|
@ -64,17 +64,10 @@ class supply_router(router):
|
|||
# but this is simplest for now.
|
||||
self.create_routing_grid()
|
||||
|
||||
# Compute the grid dimensions
|
||||
self.compute_supply_rail_dimensions()
|
||||
|
||||
# Get the pin shapes
|
||||
#start_time = datetime.now()
|
||||
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
|
||||
#start_time = datetime.now()
|
||||
# Block everything
|
||||
self.prepare_blockages(self.gnd_name)
|
||||
# Determine the rail locations
|
||||
|
|
@ -84,23 +77,15 @@ class supply_router(router):
|
|||
self.prepare_blockages(self.vdd_name)
|
||||
# Determine the rail locations
|
||||
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(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 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(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)
|
||||
|
||||
return True
|
||||
|
|
@ -116,7 +101,7 @@ class supply_router(router):
|
|||
|
||||
# These are the wire tracks
|
||||
wire_tracks = self.supply_rail_tracks[pin_name]
|
||||
|
||||
routed_count=0
|
||||
for pg in self.pin_groups[pin_name]:
|
||||
if pg.is_routed():
|
||||
continue
|
||||
|
|
@ -124,6 +109,7 @@ class supply_router(router):
|
|||
# First, check if we just overlap, if so, we are done.
|
||||
overlap_grids = wire_tracks & pg.grids
|
||||
if len(overlap_grids)>0:
|
||||
routed_count += 1
|
||||
pg.set_routed()
|
||||
continue
|
||||
|
||||
|
|
@ -131,7 +117,7 @@ class supply_router(router):
|
|||
#pg.create_simple_overlap_enclosure(pg.grids)
|
||||
#pg.add_enclosure(self.cell)
|
||||
|
||||
|
||||
debug.info(1,"Routed {} simple overlap pins".format(routed_count))
|
||||
|
||||
def finalize_supply_rails(self, name):
|
||||
"""
|
||||
|
|
@ -227,40 +213,6 @@ class supply_router(router):
|
|||
width=pin.width(),
|
||||
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):
|
||||
"""
|
||||
Compute the unblocked locations for the horizontal and vertical supply rails.
|
||||
|
|
@ -270,14 +222,19 @@ class supply_router(router):
|
|||
|
||||
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
|
||||
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
|
||||
wave = [vector3d(0,offset,0)]
|
||||
wave = [vector3d(min_xoffset,offset,0)]
|
||||
# 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)
|
||||
if not added_rail:
|
||||
# Just seed with the next one
|
||||
|
|
@ -287,12 +244,12 @@ class supply_router(router):
|
|||
wave = added_rail.neighbor(direction.EAST)
|
||||
|
||||
# Vertical supply rails
|
||||
max_offset = self.rg.ur.x
|
||||
for offset in range(start_offset, self.max_xoffset, 2):
|
||||
start_offset = min_xoffset + supply_number
|
||||
for offset in range(start_offset, max_xoffset, 2):
|
||||
# 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 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)
|
||||
if not added_rail:
|
||||
# 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])
|
||||
debug.info(1,"Routing {0} with {1} pin components to route.".format(pin_name,
|
||||
remaining_components))
|
||||
debug.info(1,"Maze routing {0} with {1} pin components to connect.".format(pin_name,
|
||||
remaining_components))
|
||||
|
||||
for index,pg in enumerate(self.pin_groups[pin_name]):
|
||||
if pg.is_routed():
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ class 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
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ from globals import OPTS, print_time
|
|||
|
||||
from sram_base import sram_base
|
||||
from bank import bank
|
||||
from contact import m2m3
|
||||
from dff_buf_array import dff_buf_array
|
||||
from dff_array import dff_array
|
||||
|
||||
|
|
@ -21,11 +22,6 @@ class sram_1bank(sram_base):
|
|||
def __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):
|
||||
"""
|
||||
This adds the modules for a single bank SRAM with control
|
||||
|
|
@ -207,9 +203,8 @@ class sram_1bank(sram_base):
|
|||
offset=clk_steiner_pos,
|
||||
rotate=90)
|
||||
|
||||
# Note, the via to the control logic is taken care of when we route
|
||||
# the control logic to the bank
|
||||
self.add_wire(("metal3","via2","metal2"),[row_addr_clk_pos, mid1_pos, clk_steiner_pos, control_clk_buf_pos])
|
||||
# Note, the via to the control logic is taken care of above
|
||||
self.add_wire(("metal3","via2","metal2"),[row_addr_clk_pos, mid1_pos, clk_steiner_pos])
|
||||
|
||||
if self.col_addr_dff:
|
||||
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_pos = data_dff_clk_pin.center()
|
||||
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])
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import sys
|
|||
import datetime
|
||||
import getpass
|
||||
import debug
|
||||
from datetime import datetime
|
||||
from importlib import reload
|
||||
from vector import vector
|
||||
from globals import OPTS, print_time
|
||||
|
|
@ -63,37 +64,52 @@ class sram_base(design):
|
|||
|
||||
def create_netlist(self):
|
||||
""" Netlist creation """
|
||||
|
||||
|
||||
start_time = datetime.now()
|
||||
|
||||
# Must create the control logic before pins to get the pins
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
self.create_modules()
|
||||
|
||||
# This is for the lib file if we don't create layout
|
||||
self.width=0
|
||||
self.height=0
|
||||
|
||||
|
||||
if not OPTS.is_unit_test:
|
||||
print_time("Submodules",datetime.now(), start_time)
|
||||
|
||||
|
||||
def create_layout(self):
|
||||
""" Layout creation """
|
||||
start_time = datetime.now()
|
||||
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_supplies()
|
||||
if not OPTS.is_unit_test:
|
||||
print_time("Routing",datetime.now(), start_time)
|
||||
|
||||
self.add_lvs_correspondence_points()
|
||||
|
||||
self.offset_all_coordinates()
|
||||
|
||||
# Must be done after offsetting lower-left
|
||||
self.route_supplies()
|
||||
|
||||
highest_coord = self.find_highest_coords()
|
||||
self.width = highest_coord[0]
|
||||
self.height = highest_coord[1]
|
||||
|
||||
|
||||
start_time = datetime.now()
|
||||
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):
|
||||
""" Route the supply grid and connect the pins to them. """
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class sram_config:
|
|||
# This will get over-written when we determine the organization
|
||||
self.words_per_row = None
|
||||
|
||||
# Move the module names to this?
|
||||
self.compute_sizes()
|
||||
|
||||
|
||||
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.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
|
||||
self.num_cols = int(self.words_per_row*self.word_size)
|
||||
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.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):
|
||||
"""
|
||||
|
|
@ -74,10 +87,14 @@ class sram_config:
|
|||
|
||||
if tentative_num_cols < 1.5*word_size:
|
||||
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
|
||||
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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -24,18 +24,21 @@ class multi_bank_test(openram_test):
|
|||
c.num_banks=2
|
||||
|
||||
c.words_per_row=1
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "No column mux")
|
||||
a = bank(c, name="bank1_multi")
|
||||
self.local_check(a)
|
||||
|
||||
c.num_words=32
|
||||
c.words_per_row=2
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "Two way column mux")
|
||||
a = bank(c, name="bank2_multi")
|
||||
self.local_check(a)
|
||||
|
||||
c.num_words=64
|
||||
c.words_per_row=4
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "Four way column mux")
|
||||
a = bank(c, name="bank3_multi")
|
||||
self.local_check(a)
|
||||
|
|
@ -43,6 +46,7 @@ class multi_bank_test(openram_test):
|
|||
c.word_size=2
|
||||
c.num_words=128
|
||||
c.words_per_row=8
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "Eight way column mux")
|
||||
a = bank(c, name="bank4_multi")
|
||||
self.local_check(a)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ class psingle_bank_test(openram_test):
|
|||
num_words=16)
|
||||
|
||||
c.words_per_row=1
|
||||
c.recompute_sizes()
|
||||
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)
|
||||
a = bank(c, name=name)
|
||||
|
|
@ -38,6 +39,7 @@ class psingle_bank_test(openram_test):
|
|||
|
||||
c.num_words=32
|
||||
c.words_per_row=2
|
||||
c.recompute_sizes()
|
||||
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)
|
||||
a = bank(c, name=name)
|
||||
|
|
@ -45,6 +47,7 @@ class psingle_bank_test(openram_test):
|
|||
|
||||
c.num_words=64
|
||||
c.words_per_row=4
|
||||
c.recompute_sizes()
|
||||
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)
|
||||
a = bank(c, name=name)
|
||||
|
|
@ -53,6 +56,7 @@ class psingle_bank_test(openram_test):
|
|||
c.word_size=2
|
||||
c.num_words=128
|
||||
c.words_per_row=8
|
||||
c.recompute_sizes()
|
||||
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)
|
||||
a = bank(c, name=name)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class psram_1bank_2mux_1rw_1w_test(openram_test):
|
|||
num_banks=1)
|
||||
c.num_words=32
|
||||
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,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.num_w_ports,
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class psram_1bank_2mux_1w_1r_test(openram_test):
|
|||
num_banks=1)
|
||||
c.num_words=32
|
||||
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,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.num_w_ports,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ class psram_1bank_2mux_test(openram_test):
|
|||
num_banks=1)
|
||||
c.num_words=32
|
||||
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,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.num_w_ports,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ class psram_1bank_4mux_1rw_1r_test(openram_test):
|
|||
num_banks=1)
|
||||
c.num_words=64
|
||||
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,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.num_w_ports,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ class sram_1bank_2mux_1rw_1r_test(openram_test):
|
|||
num_banks=1)
|
||||
|
||||
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,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.num_w_ports,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ class sram_1bank_2mux_test(openram_test):
|
|||
num_banks=1)
|
||||
|
||||
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,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.num_w_ports,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ class sram_1bank_4mux_test(openram_test):
|
|||
num_banks=1)
|
||||
|
||||
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,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.num_w_ports,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ class sram_1bank_8mux_1rw_1r_test(openram_test):
|
|||
num_banks=1)
|
||||
|
||||
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,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.num_w_ports,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ class sram_1bank_8mux_test(openram_test):
|
|||
num_banks=1)
|
||||
|
||||
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,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.num_w_ports,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ class sram_1bank_nomux_1rw_1r_test(openram_test):
|
|||
num_banks=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,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.num_w_ports,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ class sram_1bank_nomux_test(openram_test):
|
|||
num_banks=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,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.num_w_ports,
|
||||
|
|
|
|||
|
|
@ -23,18 +23,21 @@ class sram_2bank_test(openram_test):
|
|||
num_banks=2)
|
||||
|
||||
c.words_per_row=1
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "Two bank, no column mux with control logic")
|
||||
a = sram(c, "sram1")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
c.num_words=64
|
||||
c.words_per_row=2
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "Two bank two way column mux with control logic")
|
||||
a = sram(c, "sram2")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
c.num_words=128
|
||||
c.words_per_row=4
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "Two bank, four way column mux with control logic")
|
||||
a = sram(c, "sram3")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
|
@ -42,6 +45,7 @@ class sram_2bank_test(openram_test):
|
|||
c.word_size=2
|
||||
c.num_words=256
|
||||
c.words_per_row=8
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "Two bank, eight way column mux with control logic")
|
||||
a = sram(c, "sram4")
|
||||
self.local_check(a, final_verification=True)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class timing_sram_test(openram_test):
|
|||
num_words=16,
|
||||
num_banks=1)
|
||||
c.words_per_row=1
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
|
||||
s = sram(c, name="sram1")
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class timing_sram_test(openram_test):
|
|||
num_words=16,
|
||||
num_banks=1)
|
||||
c.words_per_row=1
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
|
||||
s = sram(c, name="sram1")
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class psram_1bank_2mux_1rw_1r_1w_func_test(openram_test):
|
|||
num_words=64,
|
||||
num_banks=1)
|
||||
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,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.num_w_ports,
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class psram_1bank_4mux_func_test(openram_test):
|
|||
num_words=256,
|
||||
num_banks=1)
|
||||
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,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.num_w_ports,
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class psram_1bank_8mux_func_test(openram_test):
|
|||
num_words=256,
|
||||
num_banks=1)
|
||||
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,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.num_w_ports,
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class psram_1bank_nomux_func_test(openram_test):
|
|||
num_words=32,
|
||||
num_banks=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,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.num_w_ports,
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class sram_1bank_2mux_func_test(openram_test):
|
|||
num_words=64,
|
||||
num_banks=1)
|
||||
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,
|
||||
c.num_words,
|
||||
c.words_per_row,
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class sram_1bank_4mux_func_test(openram_test):
|
|||
num_words=256,
|
||||
num_banks=1)
|
||||
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,
|
||||
c.num_words,
|
||||
c.words_per_row,
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ class sram_1bank_8mux_func_test(openram_test):
|
|||
num_words=256,
|
||||
num_banks=1)
|
||||
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,
|
||||
c.num_words,
|
||||
c.words_per_row,
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class sram_1bank_nomux_func_test(openram_test):
|
|||
num_words=32,
|
||||
num_banks=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,
|
||||
c.num_words,
|
||||
c.words_per_row,
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class psram_1bank_nomux_func_test(openram_test):
|
|||
num_words=32,
|
||||
num_banks=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,
|
||||
c.num_words,
|
||||
c.words_per_row,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ class lib_test(openram_test):
|
|||
num_words=16,
|
||||
num_banks=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")
|
||||
s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ class lib_test(openram_test):
|
|||
num_words=16,
|
||||
num_banks=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")
|
||||
s = sram(c, "sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ class lib_test(openram_test):
|
|||
num_words=16,
|
||||
num_banks=1)
|
||||
c.words_per_row=1
|
||||
c.recompute_sizes()
|
||||
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))
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ class lef_test(openram_test):
|
|||
num_words=16,
|
||||
num_banks=1)
|
||||
c.words_per_row=1
|
||||
c.recompute_sizes()
|
||||
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))
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ class verilog_test(openram_test):
|
|||
num_words=16,
|
||||
num_banks=1)
|
||||
c.words_per_row=1
|
||||
c.recompute_sizes()
|
||||
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))
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class worst_case_timing_sram_test(openram_test):
|
|||
num_words=num_words,
|
||||
num_banks=num_banks)
|
||||
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(
|
||||
word_size, num_words, num_banks))
|
||||
s = sram(c, name="sram1")
|
||||
|
|
|
|||
Loading…
Reference in New Issue