Merge branch 'dev'

Add Magic+Netgen support. General improvements to designs
to make them DRC portable.
This commit is contained in:
Matt Guthaus 2018-02-06 16:07:41 -08:00
commit bae83fc686
214 changed files with 34608 additions and 9824 deletions

View File

@ -1,4 +1,4 @@
Copyright 2017 Regents of the University of California and The Board
Copyright 2018 Regents of the University of California and The Board
of Regents for the Oklahoma Agricultural and Mechanical College
(acting for and on behalf of Oklahoma State University)

View File

@ -7,9 +7,14 @@ https://github.com/mguthaus/OpenRAM/blob/master/OpenRAM_ICCAD_2016_presentation.
The OpenRAM compiler has very few dependencies:
* ngspice-26 (or later) or HSpice I-2013.12-1 (or later) or CustomSim 2017 (or later)
* Python 2.7 and higher (currently excludes Python 3 and up)
* Python numpy
* a setup script for each technology
* a technology directory for each technology with the base cells
If you want to perform DRC and LVS, you will need either:
* Calibre (for FreePDK45 or SCMOS)
* Magic + Netgen (for SCMOS only)
You must set two environment variables: OPENRAM_HOME should point to
the compiler source directory. OPENERAM_TECH should point to a root
technology directory that contains subdirs of all other technologies.
@ -36,6 +41,12 @@ For example, in csh/tcsh, add to your .tcshrc:
We do not distribute the PDK, but you may get it from:
https://www.eda.ncsu.edu/wiki/FreePDK45:Contents
If you are using SCMOS, you should install Magic and netgen from:
http://opencircuitdesign.com/magic/
http://opencircuitdesign.com/netgen/
In addition, you will need to install the MOSIS SCMOS rules for scn3me_subm
that are part of QFlow:
http://opencircuitdesign.com/qflow/
# DIRECTORY STRUCTURE

116
compiler/Makefile Normal file
View File

@ -0,0 +1,116 @@
CUR_DIR = $(shell pwd)
TEST_DIR = ${CUR_DIR}/tests
MAKEFLAGS += -j 2
# Library test
LIBRARY_TESTS = \
01_library_drc_test.py \
02_library_lvs_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
# 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
# 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
# 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
# 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
# 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
ALL_FILES = \
${LIBRARY_TESTS} \
${TECH_TESTS} \
${PCELLS_TESTS} \
${MODULES_TESTS} \
${TOP_TESTS} \
${CHAR_TESTS} \
${USAGE_TESTS}
default all:
$(ALL_FILES):
python ${TEST_DIR}/$@ -t freepdk45
python ${TEST_DIR}/$@ -t scn3me_subm
# Library tests
lib: ${LIBRARY_TESTS}
# Transistor and wire tests
tech: ${TECH_TESTS}
# Dynamically generated cells
pcells: ${PCELLS_TESTS}
# Dynamically generated modules
modules: ${MODULES_TESTS}
# Top level SRAM tests
top: ${TOP_TESTS}
# Timing and characterization tests
char: ${CHAR_TESTS}
# Usage and file generation
usage: ${USAGE_TESTS}
clean:
find . -name \*.pyc -exec rm {} \;
find . -name \*~ -exec rm {} \;

View File

@ -23,7 +23,7 @@ class bank(design.design):
"bitcell_array", "sense_amp_array", "precharge_array",
"column_mux_array", "write_driver_array", "tri_gate_array"]
for mod_name in mod_list:
config_mod_name = getattr(OPTS.config, mod_name)
config_mod_name = getattr(OPTS, mod_name)
class_file = reload(__import__(config_mod_name))
mod_class = getattr(class_file , config_mod_name)
setattr (self, "mod_"+mod_name, mod_class)
@ -99,8 +99,10 @@ class bank(design.design):
self.add_precharge_array()
if self.col_addr_size > 0:
# The m2 width is because the 6T cell may have vias on the boundary edge for
# overlapping when making the array
self.column_mux_height = self.column_mux_array.height + 0.5*self.m2_width
self.add_column_mux_array()
self.column_mux_height = self.column_mux_array.height
else:
self.column_mux_height = 0
if self.col_addr_size > 1: # size 1 is from addr FF
@ -234,8 +236,8 @@ class bank(design.design):
""" Adding Precharge """
# The wells must be far enough apart
# We use two well spacings because the bitcells tend to have a shared rail in the height
y_offset = self.bitcell_array.height + 2*drc["pwell_to_nwell"]
# The enclosure is for the well and the spacig is to the bitcell wells
y_offset = self.bitcell_array.height + 2*drc["pwell_to_nwell"] + drc["well_enclosure_active"]
self.precharge_array_inst=self.add_inst(name="precharge_array",
mod=self.precharge_array,
offset=vector(0,y_offset))
@ -249,7 +251,7 @@ class bank(design.design):
def add_column_mux_array(self):
""" Adding Column Mux when words_per_row > 1 . """
y_offset = self.column_mux_array.height
y_offset = self.column_mux_height
self.col_mux_array_inst=self.add_inst(name="column_mux_array",
mod=self.column_mux_array,
offset=vector(0,y_offset).scale(-1,-1))
@ -434,7 +436,8 @@ class bank(design.design):
# Place the col decoder just to the left of the control bus
x_off = self.m2_pitch + self.overall_central_bus_width + self.col_decoder.width
gap = max(drc["pwell_to_nwell"], 2*self.m2_pitch)
x_off = gap + self.overall_central_bus_width + self.col_decoder.width
# Place the col decoder below the the address flops which are below the row decoder (lave some space for wells)
vertical_gap = max(drc["pwell_to_nwell"], 2*self.m2_pitch)
y_off = self.decoder.predecoder_height + self.msf_address.width + self.col_decoder.height + 2*vertical_gap

View File

@ -21,12 +21,13 @@ class bitcell_array(design.design):
self.column_size = cols
self.row_size = rows
c = reload(__import__(OPTS.config.bitcell))
self.mod_bitcell = getattr(c, OPTS.config.bitcell)
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.cell = self.mod_bitcell()
self.add_mod(self.cell)
self.height = self.row_size*self.cell.height
# We increase it by a well enclosure so the precharges don't overlap our wells
self.height = self.row_size*self.cell.height + drc["well_enclosure_active"]
self.width = self.column_size*self.cell.width
self.add_pins()
@ -115,8 +116,8 @@ class bitcell_array(design.design):
gnd_pins = self.cell_inst[0,col].get_pins("gnd")
for gnd_pin in gnd_pins:
# avoid duplicates by only doing even rows
# also skip if it is not the full height (a through rail)
if gnd_pin.layer=="metal2" and col%2 == 0 and gnd_pin.height()>=self.cell.height:
# also skip if it isn't the pin that spans the entire cell down to the bottom
if gnd_pin.layer=="metal2" and gnd_pin.by()==lower_y:
self.add_layout_pin(text="gnd",
layer="metal2",
offset=gnd_pin.ll(),

View File

@ -8,22 +8,22 @@ import setup_hold
debug.info(2,"Initializing characterizer...")
spice_exe = ""
OPTS.spice_exe = ""
if not OPTS.analytical_delay:
if OPTS.spice_name != "":
spice_exe=find_exe(OPTS.spice_name)
if spice_exe=="":
OPTS.spice_exe=find_exe(OPTS.spice_name)
if OPTS.spice_exe=="":
debug.error("{0} not found. Unable to perform characterization.".format(OPTS.spice_name),1)
else:
(choice,spice_exe) = get_tool("spice",["xa", "hspice", "ngspice", "ngspice.exe"])
OPTS.spice_name = choice
(OPTS.spice_name,OPTS.spice_exe) = get_tool("spice",["xa", "hspice", "ngspice", "ngspice.exe"])
# set the input dir for spice files if using ngspice
if OPTS.spice_name == "ngspice":
os.environ["NGSPICE_INPUT_DIR"] = "{0}".format(OPTS.openram_temp)
if spice_exe == "":
if OPTS.spice_exe == "":
debug.error("No recognizable spice version found. Unable to perform characterization.",1)

View File

@ -40,9 +40,9 @@ class delay():
def write_stimulus(self, period, load, slew):
"""Creates a stimulus file for simulations to probe a certain bitcell, given an address and data-position of the data-word
(probe-address form: '111010000' LSB=0, MSB=1)
(probe_data form: number corresponding to the bit position of data-bus, begins with position 0)
""" Creates a stimulus file for simulations to probe a bitcell at a given clock period.
Address and bit were previously set with set_probe().
Input slew (in ns) and output capacitive load (in fF) are required for charaterization.
"""
self.check_arguments()
@ -52,7 +52,7 @@ class delay():
# creates and opens stimulus file for writing
temp_stim = "{0}/stim.sp".format(OPTS.openram_temp)
self.sf = open(temp_stim, "w")
self.sf.write("* Stimulus for period of {0}n load={1} slew={2}\n\n".format(period,load,slew))
self.sf.write("* Stimulus for period of {0}n load={1}fF slew={2}ns\n\n".format(period,load,slew))
# include files in stimulus file
model_list = tech.spice["fet_models"] + [self.sram_sp_file]
@ -116,8 +116,8 @@ class delay():
self.write_measures(period)
# run until the last cycle time
stimuli.write_control(self.sf,self.cycle_times[-1])
# run until the end of the cycle time
stimuli.write_control(self.sf,self.cycle_times[-1] + period)
self.sf.close()
@ -125,11 +125,14 @@ class delay():
# meas statement for delay and power measurements
self.sf.write("* Measure statements for delay and power\n")
for comment in self.cycle_comments:
self.sf.write("* {}\n".format(comment))
trig_name = "clk"
targ_name = "{0}".format("d[{0}]".format(self.probe_data))
trig_val = targ_val = 0.5 * self.vdd
# add measure statments for delay0
# delay the target to measure after the negetive edge
# delay the target to measure after the negative edge
stimuli.gen_meas_delay(stim_file=self.sf,
meas_name="DELAY0",
trig_name=trig_name,
@ -138,7 +141,8 @@ class delay():
targ_val=targ_val,
trig_dir="FALL",
targ_dir="FALL",
td=self.cycle_times[self.read0_cycle]+0.5*period)
trig_td=self.cycle_times[self.read0_cycle],
targ_td=self.cycle_times[self.read0_cycle]+0.5*period)
stimuli.gen_meas_delay(stim_file=self.sf,
meas_name="DELAY1",
@ -148,7 +152,8 @@ class delay():
targ_val=targ_val,
trig_dir="FALL",
targ_dir="RISE",
td=self.cycle_times[self.read1_cycle]+0.5*period)
trig_td=self.cycle_times[self.read1_cycle],
targ_td=self.cycle_times[self.read1_cycle]+0.5*period)
stimuli.gen_meas_delay(stim_file=self.sf,
meas_name="SLEW0",
@ -158,7 +163,8 @@ class delay():
targ_val=0.1*self.vdd,
trig_dir="FALL",
targ_dir="FALL",
td=self.cycle_times[self.read0_cycle]+0.5*period)
trig_td=self.cycle_times[self.read0_cycle],
targ_td=self.cycle_times[self.read0_cycle]+0.5*period)
stimuli.gen_meas_delay(stim_file=self.sf,
meas_name="SLEW1",
@ -168,7 +174,8 @@ class delay():
targ_val=0.9*self.vdd,
trig_dir="RISE",
targ_dir="RISE",
td=self.cycle_times[self.read1_cycle]+0.5*period)
trig_td=self.cycle_times[self.read1_cycle],
targ_td=self.cycle_times[self.read1_cycle]+0.5*period)
# add measure statements for power
t_initial = self.cycle_times[self.write0_cycle]
@ -238,12 +245,14 @@ class delay():
# if it failed or the read was longer than a period
if type(delay0)!=float or type(delay1)!=float or type(slew1)!=float or type(slew0)!=float:
debug.info(2,"Failed simulation: period {0} load {1} slew {2}, delay0={3}n delay1={4}ns slew0={5}n slew1={6}n".format(period,load,slew,delay0,delay1,slew0,slew1))
return (False,0,0,0,0)
delay0 *= 1e9
delay1 *= 1e9
slew0 *= 1e9
slew1 *= 1e9
if delay0>period or delay1>period or slew0>period or slew1>period:
debug.info(2,"UNsuccessful simulation: period {0} load {1} slew {2}, delay0={3}n delay1={4}ns slew0={5}n slew1={6}n".format(period,load,slew,delay0,delay1,slew0,slew1))
return (False,0,0,0,0)
else:
debug.info(2,"Successful simulation: period {0} load {1} slew {2}, delay0={3}n delay1={4}ns slew0={5}n slew1={6}n".format(period,load,slew,delay0,delay1,slew0,slew1))
@ -364,7 +373,7 @@ class delay():
for slew in slews:
for load in loads:
(success, delay1, slew1, delay0, slew0) = self.run_simulation(feasible_period, load, slew)
debug.check(success,"Couldn't run a simulation properly.\n")
debug.check(success,"Couldn't run a simulation. slew={0} load={1}\n".format(slew,load))
LH_delay.append(delay1)
HL_delay.append(delay0)
LH_slew.append(slew1)
@ -394,44 +403,52 @@ class delay():
of the cycles to do a timing evaluation. The last time is the end of the simulation
and does not need a rising edge."""
self.cycle_comments = []
# idle cycle, no operation
t_current = period
self.cycle_times = []
# cycle0: W data 1 address 1111 to initialize cell to a value
self.cycle_times.append(t_current)
self.cycle_comments.append("Cycle0 {}ns: W data 1 address 11..11 to initialize cell".format(t_current))
t_current += period
# cycle1: W data 0 address 1111 (to ensure a write of value works)
self.cycle_times.append(t_current)
self.write0_cycle=1
self.cycle_comments.append("Cycle1 {}ns: W data 0 address 11..11 (to ensure a write of value works)".format(t_current))
t_current += period
# cycle2: W data 1 address 0000 (to clear the data bus cap)
self.cycle_times.append(t_current)
self.cycle_comments.append("Cycle2 {}ns: W data 1 address 00..00 (to clear bus caps)".format(t_current))
t_current += period
# cycle3: R data 0 address 1111 to check W0 works
self.cycle_times.append(t_current)
self.read0_cycle=3
self.cycle_comments.append("Cycle3 {}ns: R data 0 address 11..11 to check W0 worked".format(t_current))
t_current += period
# cycle4: W data 1 address 1111 (to ensure a write of value works)
self.cycle_times.append(t_current)
self.write1_cycle=4
self.cycle_comments.append("Cycle4 {}ns: W data 1 address 11..11 (to ensure a write of value worked)".format(t_current))
t_current += period
# cycle5: W data 0 address 0000 (to clear the data bus cap)
self.cycle_times.append(t_current)
self.cycle_comments.append("Cycle5 {}ns: W data 0 address 00..00 (to clear bus caps)".format(t_current))
t_current += period
# cycle6: R data 1 address 1111 to check W1 works
self.cycle_times.append(t_current)
self.read1_cycle=6
self.cycle_comments.append("Cycle6 {}ns: R data 1 address 11..11 to check W1 worked".format(t_current))
t_current += period
# cycle7: wait a clock period to end the simulation
self.cycle_times.append(t_current)
self.cycle_comments.append("Cycle7 {}ns: Idle period to end simulation".format(t_current))
t_current += period

View File

@ -145,7 +145,8 @@ class setup_hold():
targ_val=targ_val,
trig_dir="RISE",
targ_dir=dout_rise_or_fall,
td=1.9*self.period)
trig_td=1.9*self.period,
targ_td=1.9*self.period)
targ_name = "data"
# Start triggers right after initialize value is returned to normal
@ -158,7 +159,8 @@ class setup_hold():
targ_val=targ_val,
trig_dir="RISE",
targ_dir=din_rise_or_fall,
td=1.2*self.period)
trig_td=1.2*self.period,
targ_td=1.2*self.period)

View File

@ -218,17 +218,18 @@ def get_inverse_value(value):
debug.error("Invalid value to get an inverse of: {0}".format(value))
def gen_meas_delay(stim_file, meas_name, trig_name, targ_name, trig_val, targ_val, trig_dir, targ_dir, td):
def gen_meas_delay(stim_file, meas_name, trig_name, targ_name, trig_val, targ_val, trig_dir, targ_dir, trig_td, targ_td):
"""Creates the .meas statement for the measurement of delay"""
measure_string=".meas tran {0} TRIG v({1}) VAL={2} {3}=1 TD={7}n TARG v({4}) VAL={5} {6}=1 TD={7}n\n\n"
measure_string=".meas tran {0} TRIG v({1}) VAL={2} {3}=1 TD={4}n TARG v({5}) VAL={6} {7}=1 TD={8}n\n\n"
stim_file.write(measure_string.format(meas_name,
trig_name,
trig_val,
trig_dir,
trig_td,
targ_name,
targ_val,
targ_dir,
td))
targ_td))
def gen_meas_power(stim_file, meas_name, t_initial, t_final):
"""Creates the .meas statement for the measurement of avg power"""
@ -246,7 +247,13 @@ def gen_meas_power(stim_file, meas_name, t_initial, t_final):
def write_control(stim_file, end_time):
# UIC is needed for ngspice to converge
stim_file.write(".TRAN 5p {0}n UIC\n".format(end_time))
stim_file.write(".OPTIONS POST=1 RUNLVL=4 PROBE\n")
if OPTS.spice_name == "ngspice":
# ngspice sometimes has convergence problems if not using gear method
# which is more accurate, but slower than the default trapezoid method
stim_file.write(".OPTIONS POST=1 RUNLVL=4 PROBE method=gear\n")
else:
stim_file.write(".OPTIONS POST=1 RUNLVL=4 PROBE\n")
# create plots for all signals
stim_file.write("* probe is used for hspice/xa, while plot is used in ngspice\n")
if OPTS.debug_level>0:
@ -265,7 +272,10 @@ def write_control(stim_file, end_time):
def write_include(stim_file, models):
"""Writes include statements, inputs are lists of model files"""
for item in list(models):
stim_file.write(".include \"{0}\"\n\n".format(item))
if os.path.isfile(item):
stim_file.write(".include \"{0}\"\n\n".format(item))
else:
debug.error("Could not find spice model: {0}\nSet SPICE_MODEL_DIR to over-ride path.\n".format(item))
def write_supply(stim_file):
@ -282,26 +292,26 @@ def run_sim():
temp_stim = "{0}stim.sp".format(OPTS.openram_temp)
import datetime
start_time = datetime.datetime.now()
debug.check(OPTS.spice_exe!="","No spice simulator has been found.")
from characterizer import spice_exe
if OPTS.spice_name == "xa":
# Output the xa configurations here. FIXME: Move this to write it once.
xa_cfg = open("{}xa.cfg".format(OPTS.openram_temp), "w")
xa_cfg.write("set_sim_level -level 7\n")
xa_cfg.write("set_powernet_level 7 -node vdd\n")
xa_cfg.close()
cmd = "{0} {1} -c {2}xa.cfg -o {2}xa -mt 20".format(spice_exe,
cmd = "{0} {1} -c {2}xa.cfg -o {2}xa -mt 2".format(OPTS.spice_exe,
temp_stim,
OPTS.openram_temp)
valid_retcode=0
elif OPTS.spice_name == "hspice":
# TODO: Should make multithreading parameter a configuration option
cmd = "{0} -mt 2 -i {1} -o {2}timing".format(spice_exe,
cmd = "{0} -mt 2 -i {1} -o {2}timing".format(OPTS.spice_exe,
temp_stim,
OPTS.openram_temp)
valid_retcode=0
else:
cmd = "{0} -b -o {2}timing.lis {1}".format(spice_exe,
cmd = "{0} -b -o {2}timing.lis {1}".format(OPTS.spice_exe,
temp_stim,
OPTS.openram_temp)
# for some reason, ngspice-25 returns 1 when it only has acceptable warnings

View File

@ -45,23 +45,33 @@ class trim_spice():
# Always start fresh if we do multiple reductions
self.sp_buffer = self.spice
# Find the row and column indices for the removals
# Convert address froms tring to int
address = int(address,2)
array_row = address >> self.col_addr_size
# Which word in the array (0 if only one word)
if self.col_addr_size>0:
lower_mask = int(self.col_addr_size-1)
lower_address = address & lower_mask
else:
lower_address=0
# Which bit in the array
array_bit = lower_address*self.word_size + data_bit
# Split up the address and convert to an int
wl_address = int(address[self.col_addr_size:],2)
if self.col_addr_size>1:
col_address = int(address[0:self.col_addr_size],2)
else:
col_address = 0
# 1. Keep cells in the bitcell array based on WL and BL
wl_name = "wl[{}]".format(array_row)
bl_name = "bl[{}]".format(array_bit)
wl_name = "wl[{}]".format(wl_address)
bl_name = "bl[{}]".format(self.words_per_row*data_bit + col_address)
# Prepend info about the trimming
addr_msg = "Keeping {} address".format(address)
self.sp_buffer.insert(0, "* "+addr_msg)
debug.info(1,addr_msg)
data_msg = "Keeping {} data bit".format(data_bit)
self.sp_buffer.insert(0, "* "+data_msg)
debug.info(1,data_msg)
bl_msg = "Keeping {} (trimming other BLs)".format(bl_name)
wl_msg = "Keeping {} (trimming other WLs)".format(wl_name)
self.sp_buffer.insert(0, "* "+bl_msg)
debug.info(1,bl_msg)
self.sp_buffer.insert(0, "* "+wl_msg)
debug.info(1,wl_msg)
self.sp_buffer.insert(0, "* It should NOT be used for LVS!!")
self.sp_buffer.insert(0, "* WARNING: This is a TRIMMED NETLIST.")
self.remove_insts("bitcell_array",[wl_name,bl_name])
# 2. Keep sense amps basd on BL

View File

@ -11,19 +11,34 @@ class contact(design.design):
Creates a contact array minimum active or poly enclosure and metal1 enclosure.
This class has enclosure on multiple sides of the contact whereas a via may
have extension on two or four sides.
The well/implant_type is an option to add a select/implant layer enclosing the contact. This is
necessary to import layouts into Magic which requires the select to be in the same GDS
hierarchy as the contact.
"""
def __init__(self, layer_stack, dimensions=[1,1]):
name = "{0}_{1}_{2}_{3}x{4}".format(layer_stack[0],
layer_stack[1],
layer_stack[2],
dimensions[0],
dimensions[1])
def __init__(self, layer_stack, dimensions=[1,1], implant_type=None, well_type=None):
if implant_type or well_type:
name = "{0}_{1}_{2}_{3}x{4}_{5}{6}".format(layer_stack[0],
layer_stack[1],
layer_stack[2],
dimensions[0],
dimensions[1],
implant_type,
well_type)
else:
name = "{0}_{1}_{2}_{3}x{4}".format(layer_stack[0],
layer_stack[1],
layer_stack[2],
dimensions[0],
dimensions[1])
design.design.__init__(self, name)
debug.info(4, "create contact object {0}".format(name))
self.layer_stack = layer_stack
self.dimensions = dimensions
self.offset = vector(0,0)
self.implant_type = implant_type
self.well_type = well_type
self.pins = [] # used for matching parm lengths
self.create_layout()
@ -37,74 +52,112 @@ class contact(design.design):
self.height = max(obj.offset.y + obj.height for obj in self.objs)
self.width = max(obj.offset.x + obj.width for obj in self.objs)
# Do not include the select layer in the height/width
if self.implant_type and self.well_type:
self.create_implant_well_enclosures()
elif self.implant_type or self.well_type:
debug.error(-1,"Must define both implant and well type or none at all.")
def setup_layers(self):
(first_layer, via_layer, second_layer) = self.layer_stack
self.first_layer_name = first_layer
self.via_layer_name = via_layer
# Some technologies have a separate active contact from the poly contact
# We will use contact for DRC, but active_contact for output
if first_layer=="active" or second_layer=="active":
self.via_layer_name_expanded = "active_"+via_layer
else:
self.via_layer_name_expanded = via_layer
self.second_layer_name = second_layer
def setup_layout_constants(self):
self.contact_width = drc["minwidth_{0}". format(self.via_layer_name)]
self.contact_to_contact = drc["{0}_to_{0}".format(self.via_layer_name)]
self.contact_pitch = self.contact_width + self.contact_to_contact
contact_to_contact = drc["{0}_to_{0}".format(self.via_layer_name)]
self.contact_pitch = self.contact_width + contact_to_contact
self.contact_array_width = self.contact_width + (self.dimensions[0] - 1) * self.contact_pitch
self.contact_array_height = self.contact_width + (self.dimensions[1] - 1) * self.contact_pitch
# FIME break this up
self.first_layer_horizontal_enclosure = max((drc["minwidth_{0}".format(self.first_layer_name)] - self.contact_array_width) / 2,
drc["{0}_enclosure_{1}".format(self.first_layer_name, self.via_layer_name)])
self.first_layer_vertical_enclosure = max(utils.ceil((drc["minarea_{0}".format(self.first_layer_name)]
/ (self.contact_array_width + 2 * self.first_layer_horizontal_enclosure) - self.contact_array_height) / 2),
(drc["minheight_{0}".format(self.first_layer_name)] - self.contact_array_height) / 2,
drc["{0}_extend_{1}".format(self.first_layer_name, self.via_layer_name)])
# DRC rules
first_layer_minwidth = drc["minwidth_{0}".format(self.first_layer_name)]
first_layer_minarea = drc["minarea_{0}".format(self.first_layer_name)]
first_layer_enclosure = drc["{0}_enclosure_{1}".format(self.first_layer_name, self.via_layer_name)]
first_layer_extend = drc["{0}_extend_{1}".format(self.first_layer_name, self.via_layer_name)]
second_layer_minwidth = drc["minwidth_{0}".format(self.second_layer_name)]
second_layer_minarea = drc["minarea_{0}".format(self.second_layer_name)]
second_layer_enclosure = drc["{0}_enclosure_{1}".format(self.second_layer_name, self.via_layer_name)]
second_layer_extend = drc["{0}_extend_{1}".format(self.second_layer_name, self.via_layer_name)]
self.second_layer_horizontal_enclosure = max((drc["minwidth_{0}".format(self.second_layer_name)] - self.contact_array_width) / 2,
drc["{0}_enclosure_{1}".format(self.second_layer_name, self.via_layer_name)])
self.second_layer_vertical_enclosure = max(utils.ceil((drc["minarea_{0}".format(self.second_layer_name)]
/ (self.contact_array_width + 2 * self.second_layer_horizontal_enclosure) - self.contact_array_height) / 2),
(drc["minheight_{0}".format(self.second_layer_name)] - self.contact_array_height) / 2,
drc["{0}_extend_{1}".format(self.second_layer_name, self.via_layer_name)])
self.first_layer_horizontal_enclosure = max((first_layer_minwidth - self.contact_array_width) / 2,
first_layer_enclosure)
self.first_layer_vertical_enclosure = max(utils.ceil((first_layer_minarea
/ (self.contact_array_width + 2*self.first_layer_horizontal_enclosure)
- self.contact_array_height)/2),
(first_layer_minwidth - self.contact_array_height)/2,
first_layer_extend)
self.second_layer_horizontal_enclosure = max((second_layer_minwidth - self.contact_array_width)/2,
second_layer_enclosure)
self.second_layer_vertical_enclosure = max(utils.ceil((second_layer_minarea
/ (self.contact_array_width + 2*self.second_layer_horizontal_enclosure)
- self.contact_array_height)/2),
(second_layer_minwidth - self.contact_array_height)/2,
second_layer_extend)
def create_contact_array(self):
""" Create the contact array at the origin"""
# offset for the via array
self.via_layer_position =vector(max(self.first_layer_horizontal_enclosure,self.second_layer_horizontal_enclosure),
max(self.first_layer_vertical_enclosure,self.second_layer_vertical_enclosure))
# this is if the first and second layers are different
self.first_layer_position = vector(max(self.second_layer_horizontal_enclosure - self.first_layer_horizontal_enclosure,0),
max(self.second_layer_vertical_enclosure - self.first_layer_vertical_enclosure,0))
self.second_layer_position = vector(max(self.first_layer_horizontal_enclosure - self.second_layer_horizontal_enclosure,0),
max(self.first_layer_vertical_enclosure - self.second_layer_vertical_enclosure,0))
def create_contact_array(self):
""" Create the contact array at the origin"""
for i in range(self.dimensions[1]):
offset = self.via_layer_position + vector(0, self.contact_pitch * i)
for j in range(self.dimensions[0]):
self.add_rect(layer=self.via_layer_name,
self.add_rect(layer=self.via_layer_name_expanded,
offset=offset,
width=self.contact_width,
height=self.contact_width)
offset = offset + vector(self.contact_pitch,0)
def create_first_layer_enclosure(self):
width = self.first_layer_width = self.contact_array_width \
+ 2 * self.first_layer_horizontal_enclosure
height = self.first_layer_height = self.contact_array_height \
+ 2 * self.first_layer_vertical_enclosure
# this is if the first and second layers are different
self.first_layer_position = vector(max(self.second_layer_horizontal_enclosure - self.first_layer_horizontal_enclosure,0),
max(self.second_layer_vertical_enclosure - self.first_layer_vertical_enclosure,0))
self.first_layer_width = self.contact_array_width + 2*self.first_layer_horizontal_enclosure
self.first_layer_height = self.contact_array_height + 2*self.first_layer_vertical_enclosure
self.add_rect(layer=self.first_layer_name,
offset=self.first_layer_position,
width=width,
height=height)
width=self.first_layer_width,
height=self.first_layer_height)
def create_second_layer_enclosure(self):
width = self.second_layer_width = self.contact_array_width \
+ 2 * self.second_layer_horizontal_enclosure
height = self.second_layer_height = self.contact_array_height \
+ 2 * self.second_layer_vertical_enclosure
# this is if the first and second layers are different
self.second_layer_position = vector(max(self.first_layer_horizontal_enclosure - self.second_layer_horizontal_enclosure,0),
max(self.first_layer_vertical_enclosure - self.second_layer_vertical_enclosure,0))
self.second_layer_width = self.contact_array_width + 2*self.second_layer_horizontal_enclosure
self.second_layer_height = self.contact_array_height + 2*self.second_layer_vertical_enclosure
self.add_rect(layer=self.second_layer_name,
offset=self.second_layer_position,
width=width,
height=height)
width=self.second_layer_width,
height=self.second_layer_height)
def create_implant_well_enclosures(self):
implant_position = self.first_layer_position - [drc["implant_enclosure_active"]]*2
implant_width = self.first_layer_width + 2*drc["implant_enclosure_active"]
implant_height = self.first_layer_height + 2*drc["implant_enclosure_active"]
self.add_rect(layer="{}implant".format(self.implant_type),
offset=implant_position,
width=implant_width,
height=implant_height)
well_position = self.first_layer_position - [drc["well_enclosure_active"]]*2
well_width = self.first_layer_width + 2*drc["well_enclosure_active"]
well_height = self.first_layer_height + 2*drc["well_enclosure_active"]
self.add_rect(layer="{}well".format(self.well_type),
offset=well_position,
width=well_width,
height=well_height)
# This is not instantiated and used for calculations only.

View File

@ -59,15 +59,15 @@ class control_logic(design.design):
self.inv16 = pinv(16)
self.add_mod(self.inv16)
c = reload(__import__(OPTS.config.ms_flop_array))
ms_flop_array = getattr(c, OPTS.config.ms_flop_array)
c = reload(__import__(OPTS.ms_flop_array))
ms_flop_array = getattr(c, OPTS.ms_flop_array)
self.msf_control = ms_flop_array(name="msf_control",
columns=3,
word_size=3)
self.add_mod(self.msf_control)
c = reload(__import__(OPTS.config.replica_bitline))
replica_bitline = getattr(c, OPTS.config.replica_bitline)
c = reload(__import__(OPTS.replica_bitline))
replica_bitline = getattr(c, OPTS.replica_bitline)
self.replica_bitline = replica_bitline(rows=int(math.ceil(self.num_rows / 10.0)))
self.add_mod(self.replica_bitline)
@ -77,8 +77,6 @@ class control_logic(design.design):
# These aren't for instantiating, but we use them to get the dimensions
self.poly_contact_offset = vector(0.5*contact.poly.width,0.5*contact.poly.height)
# For different layer width vias
self.m1m2_offset_fix = vector(0,0.5*(drc["minwidth_metal2"]-drc["minwidth_metal1"]))
# M1/M2 routing pitch is based on contacted pitch
self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(drc["metal1_to_metal1"],drc["metal2_to_metal2"])
self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(drc["metal2_to_metal2"],drc["metal3_to_metal3"])
@ -87,10 +85,6 @@ class control_logic(design.design):
# Some cells may have pwell/nwell spacing problems too when the wells are different heights.
self.cell_gap = max(self.m2_pitch,drc["pwell_to_nwell"])
# Amount to shift a 90 degree rotated via from center-line path routing to it's offset
self.m1m2_via_offset = vector(contact.m1m2.first_layer_height,-0.5*drc["minwidth_metal2"])
self.m2m3_via_offset = vector(contact.m2m3.first_layer_height,-0.5*drc["minwidth_metal3"])
# First RAIL Parameters: gnd, oe, oebar, cs, we, clk_buf, clk_bar
self.rail_1_start_x = 0
self.num_rails_1 = 8
@ -275,7 +269,7 @@ class control_logic(design.design):
mod=self.nand2,
offset=self.tri_en_bar_offset,
mirror="MX")
self.connect_inst(["oe", "clk_bar", "tri_en_bar", "vdd", "gnd"])
self.connect_inst(["clk_bar", "oe", "tri_en_bar", "vdd", "gnd"])
x_off += self.nand2.width
x_off += self.inv1.width + self.cell_gap
@ -326,6 +320,7 @@ class control_logic(design.design):
x_off += self.inv1.width
# BUFFER INVERTERS FOR W_EN
# FIXME: Can we remove these two invs and size the previous one?
self.pre_w_en_bar_offset = vector(x_off, y_off)
self.pre_w_en_bar=self.add_inst(name="inv_pre_w_en_bar",
mod=self.inv1,
@ -512,11 +507,25 @@ class control_logic(design.design):
offset=clk_buf_rail_position,
rotate=90)
# clk_bar
self.connect_rail_from_left_m2m3(self.clk_bar,"Z","clk_bar")
# clk_bar, routes over the clock buffer vdd rail
clk_pin = self.clk_bar.get_pin("Z")
vdd_pin = self.clk_bar.get_pin("vdd")
# move the output pin up to metal2
self.add_via_center(layers=("metal1","via1","metal2"),
offset=self.clk_bar.get_pin("Z").rc(),
offset=clk_pin.rc(),
rotate=90)
# route to a position over the supply rail
in_pos = vector(clk_pin.rx(), vdd_pin.cy())
self.add_path("metal2",[clk_pin.rc(), in_pos])
# connect that position to the control bus
rail_pos = vector(self.rail_1_x_offsets["clk_bar"], in_pos.y)
self.add_wire(("metal3","via2","metal2"),[in_pos, rail_pos])
self.add_via_center(layers=("metal2","via2","metal3"),
offset=in_pos,
rotate=90)
self.add_via_center(layers=("metal2","via2","metal3"),
offset=rail_pos,
rotate=90)
# clk_buf to msf control flops
msf_clk_pos = self.msf_inst.get_pin("clk").bc()

View File

@ -14,14 +14,13 @@ def check(check,str):
index) = inspect.getouterframes(inspect.currentframe())[1]
if not check:
print("ERROR: file {0}: line {1}: {2}".format(os.path.basename(filename),line_number,str))
sys.exit(-1)
assert 0
def error(str,return_value=None):
def error(str,return_value=0):
(frame, filename, line_number, function_name, lines,
index) = inspect.getouterframes(inspect.currentframe())[1]
print("ERROR: file {0}: line {1}: {2}".format(os.path.basename(filename),line_number,str))
if return_value:
sys.exit(return_value)
assert return_value==0
def warning(str):
(frame, filename, line_number, function_name, lines,

View File

@ -24,8 +24,8 @@ class delay_chain(design.design):
self.num_inverters = 1 + sum(fanout_list)
self.num_top_half = round(self.num_inverters / 2.0)
c = reload(__import__(OPTS.config.bitcell))
self.mod_bitcell = getattr(c, OPTS.config.bitcell)
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
self.add_pins()

View File

@ -27,8 +27,13 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
# Check if the name already exists, if so, give an error
# because each reference must be a unique name.
ok_list = ['ms_flop.ms_flop', 'bitcell.bitcell', 'contact.contact',
'ptx.ptx', 'sram.sram',
# These modules ensure unique names or have no changes if they
# aren't unique
ok_list = ['ms_flop.ms_flop',
'bitcell.bitcell',
'contact.contact',
'ptx.ptx',
'sram.sram',
'hierarchical_predecode2x4.hierarchical_predecode2x4',
'hierarchical_predecode3x8.hierarchical_predecode3x8']
if name not in design.name_map:
@ -41,6 +46,7 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
def setup_drc_constants(self):
""" These are some DRC constants used in many places in the compiler."""
from tech import drc
self.well_width = drc["minwidth_well"]
self.poly_width = drc["minwidth_poly"]
self.poly_space = drc["poly_to_poly"]
self.m1_width = drc["minwidth_metal1"]
@ -49,7 +55,16 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
self.m2_space = drc["metal2_to_metal2"]
self.m3_width = drc["minwidth_metal3"]
self.m3_space = drc["metal3_to_metal3"]
self.active_width = drc["minwidth_active"]
self.contact_width = drc["minwidth_contact"]
self.poly_to_active = drc["poly_to_active"]
self.poly_extend_active = drc["poly_extend_active"]
self.contact_to_gate = drc["contact_to_gate"]
self.well_enclose_active = drc["well_enclosure_active"]
self.implant_enclose_active = drc["implant_enclosure_active"]
self.implant_space = drc["implant_to_implant"]
def get_layout_pins(self,inst):
""" Return a map of pin locations of the instance offset """
# find the instance
@ -62,7 +77,7 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
return inst_map
def DRC_LVS(self):
def DRC_LVS(self, final_verification=False):
"""Checks both DRC and LVS for a module"""
if OPTS.check_lvsdrc:
tempspice = OPTS.openram_temp + "/temp.sp"
@ -70,7 +85,7 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
self.sp_write(tempspice)
self.gds_write(tempgds)
debug.check(verify.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name))
debug.check(verify.run_lvs(self.name, tempgds, tempspice) == 0,"LVS failed for {0}".format(self.name))
debug.check(verify.run_lvs(self.name, tempgds, tempspice, final_verification) == 0,"LVS failed for {0}".format(self.name))
os.remove(tempspice)
os.remove(tempgds)
@ -82,14 +97,14 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
debug.check(verify.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name))
os.remove(tempgds)
def LVS(self):
def LVS(self, final_verification=False):
"""Checks LVS for a module"""
if OPTS.check_lvsdrc:
tempspice = OPTS.openram_temp + "/temp.sp"
tempgds = OPTS.openram_temp + "/temp.gds"
self.sp_write(tempspice)
self.gds_write(tempgds)
debug.check(verify.run_lvs(self.name, tempgds, tempspice) == 0,"LVS failed for {0}".format(self.name))
debug.check(verify.run_lvs(self.name, tempgds, tempspice, final_verification) == 0,"LVS failed for {0}".format(self.name))
os.remove(tempspice)
os.remove(tempgds)

View File

@ -4,24 +4,6 @@ num_banks = 1
tech_name = "freepdk45"
output_path = "/tmp/mysram"
output_path = "temp"
output_name = "sram_2_16_1_freepdk45"
decoder = "hierarchical_decoder"
ms_flop = "ms_flop"
ms_flop_array = "ms_flop_array"
control_logic = "control_logic"
bitcell_array = "bitcell_array"
sense_amp = "sense_amp"
sense_amp_array = "sense_amp_array"
precharge_array = "precharge_array"
column_mux_array = "single_level_column_mux_array"
write_driver = "write_driver"
write_driver_array = "write_driver_array"
tri_gate = "tri_gate"
tri_gate_array = "tri_gate_array"
wordline_driver = "wordline_driver"
replica_bitline = "replica_bitline"
replica_bitcell = "replica_bitcell"
bitcell = "bitcell"
delay_chain = "delay_chain"

View File

@ -1,27 +1,9 @@
word_size = 1
word_size = 2
num_words = 16
num_banks = 1
tech_name = "scn3me_subm"
output_path = "/tmp/mysram"
output_path = "temp"
output_name = "sram_2_16_1_scn3me_subm"
decoder = "hierarchical_decoder"
ms_flop = "ms_flop"
ms_flop_array = "ms_flop_array"
control_logic = "control_logic"
bitcell_array = "bitcell_array"
sense_amp = "sense_amp"
sense_amp_array = "sense_amp_array"
precharge_array = "precharge_array"
column_mux_array = "single_level_column_mux_array"
write_driver = "write_driver"
write_driver_array = "write_driver_array"
tri_gate = "tri_gate"
tri_gate_array = "tri_gate_array"
wordline_driver = "wordline_driver"
replica_bitline = "replica_bitline"
replica_bitcell = "replica_bitcell"
bitcell = "bitcell"
delay_chain = "delay_chain"

View File

@ -11,9 +11,6 @@ import sys
import re
import importlib
# Current version of OpenRAM.
VERSION = "1.01"
USAGE = "Usage: openram.py [options] <config file>\nUse -h for help.\n"
# Anonymous object that will be the options
@ -50,22 +47,26 @@ def parse_args():
optparse.make_option("-r", "--remove_netlist_trimming", action="store_false", dest="trim_netlist",
help="Disable removal of noncritical memory cells during characterization"),
optparse.make_option("-c", "--characterize", action="store_false", dest="analytical_delay",
help="Perform characterization to calculate delays (default is analytical models)")
help="Perform characterization to calculate delays (default is analytical models)"),
optparse.make_option("-d", "--dontpurge", action="store_false", dest="purge_temp",
help="Don't purge the contents of the temp directory after a successful run")
# -h --help is implicit.
}
parser = optparse.OptionParser(option_list=option_list,
description="Compile and/or characterize an SRAM.",
usage=USAGE,
version="OpenRAM v" + VERSION)
version="OpenRAM")
(options, args) = parser.parse_args(values=OPTS)
# If we don't specify a tech, assume freepdk45.
# This may be overridden when we read a config file though...
if OPTS.tech_name == "":
OPTS.tech_name = "freepdk45"
# Alias SCMOS to AMI 0.5um
if OPTS.tech_name == "scmos":
OPTS.tech_name = "scn3me_subm"
return (options, args)
def print_banner():
@ -75,7 +76,7 @@ def print_banner():
return
print("|==============================================================================|")
name = "OpenRAM Compiler v"+VERSION
name = "OpenRAM Compiler"
print("|=========" + name.center(60) + "=========|")
print("|=========" + " ".center(60) + "=========|")
print("|=========" + "VLSI Design and Automation Lab".center(60) + "=========|")
@ -99,13 +100,13 @@ def init_openram(config_file):
import_tech()
def get_tool(tool_type, preferences):
"""
Find which tool we have from a list of preferences and return the
one selected and its full path.
"""
debug.info(2,"Finding {} tool...".format(tool_type))
global OPTS
for name in preferences:
exe_name = find_exe(name)
@ -125,6 +126,8 @@ def read_config(config_file):
config file is just a Python file that defines some config
options.
"""
global OPTS
# Create a full path relative to current dir unless it is already an abs path
if not os.path.isabs(config_file):
config_file = os.getcwd() + "/" + config_file
@ -140,18 +143,17 @@ def read_config(config_file):
# Import the configuration file of which modules to use
debug.info(1, "Configuration file is " + config_file + ".py")
try:
OPTS.config = importlib.import_module(file_name)
config = importlib.import_module(file_name)
except:
debug.error("Unable to read configuration file: {0}".format(config_file),2)
# This path must be setup after the config file.
try:
# If path not set on command line, try config file.
if OPTS.output_path=="":
OPTS.output_path=OPTS.config.output_path
except:
# Default to current directory.
OPTS.output_path="."
for k,v in config.__dict__.items():
# The command line will over-ride the config file
# except in the case of the tech name! This is because the tech name
# is sometimes used to specify the config file itself (e.g. unit tests)
if not k in OPTS.__dict__ or k=="tech_name":
OPTS.__dict__[k]=v
if not OPTS.output_path.endswith('/'):
OPTS.output_path += "/"
debug.info(1, "Output saved in " + OPTS.output_path)
@ -172,16 +174,15 @@ def end_openram():
""" Clean up openram for a proper exit """
cleanup_paths()
# Reset the static duplicate name checker for unit tests.
# This is needed for running unit tests.
import design
design.design.name_map=[]
def cleanup_paths():
"""
We should clean up the temp directory after execution.
"""
if not OPTS.purge_temp:
debug.info(0,"Preserving temp directory: {}".format(OPTS.openram_temp))
return
if os.path.exists(OPTS.openram_temp):
shutil.rmtree(OPTS.openram_temp, ignore_errors=True)
@ -242,7 +243,7 @@ def import_tech():
debug.info(2,"Importing technology: " + OPTS.tech_name)
# Set the tech to the config file we read in instead of the command line value.
OPTS.tech_name = OPTS.config.tech_name
OPTS.tech_name = OPTS.tech_name
# environment variable should point to the technology dir

View File

@ -21,8 +21,8 @@ class hierarchical_decoder(design.design):
def __init__(self, rows):
design.design.__init__(self, "hierarchical_decoder_{0}rows".format(rows))
c = reload(__import__(OPTS.config.bitcell))
self.mod_bitcell = getattr(c, OPTS.config.bitcell)
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell_height = self.mod_bitcell.height
self.pre2x4_inst = []

View File

@ -19,8 +19,8 @@ class hierarchical_predecode(design.design):
self.number_of_outputs = int(math.pow(2, self.number_of_inputs))
design.design.__init__(self, name="pre{0}x{1}".format(self.number_of_inputs,self.number_of_outputs))
c = reload(__import__(OPTS.config.bitcell))
self.mod_bitcell = getattr(c, OPTS.config.bitcell)
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell_height = self.mod_bitcell.height
@ -252,7 +252,7 @@ class hierarchical_predecode(design.design):
if self.number_of_inputs == 2:
gate_lst = ["A","B"]
else:
gate_lst = ["A","B","C"]
gate_lst = ["A","B","C"]
# this will connect pins A,B or A,B,C
for rail_pin,gate_pin in zip(index_lst,gate_lst):

View File

@ -27,10 +27,10 @@ class hierarchical_predecode2x4(hierarchical_predecode):
self.create_rails()
self.add_input_inverters()
self.add_output_inverters()
connections =[["in[0]", "in[1]", "Z[3]", "vdd", "gnd"],
["inbar[0]", "in[1]", "Z[2]", "vdd", "gnd"],
connections =[["inbar[0]", "inbar[1]", "Z[0]", "vdd", "gnd"],
["in[0]", "inbar[1]", "Z[1]", "vdd", "gnd"],
["inbar[0]", "inbar[1]", "Z[0]", "vdd", "gnd"]]
["inbar[0]", "in[1]", "Z[2]", "vdd", "gnd"],
["in[0]", "in[1]", "Z[3]", "vdd", "gnd"]]
self.add_nand(connections)
self.route()

View File

@ -27,26 +27,26 @@ class hierarchical_predecode3x8(hierarchical_predecode):
self.create_rails()
self.add_input_inverters()
self.add_output_inverters()
connections=[["in[0]", "in[1]", "in[2]", "Z[7]", "vdd", "gnd"],
["in[0]", "in[1]", "inbar[2]", "Z[6]", "vdd", "gnd"],
["in[0]", "inbar[1]", "in[2]", "Z[5]", "vdd", "gnd"],
["in[0]", "inbar[1]", "inbar[2]", "Z[4]", "vdd", "gnd"],
["inbar[0]", "in[1]", "in[2]", "Z[3]", "vdd", "gnd"],
connections=[["inbar[0]", "inbar[1]", "inbar[2]", "Z[0]", "vdd", "gnd"],
["in[0]", "inbar[1]", "inbar[2]", "Z[1]", "vdd", "gnd"],
["inbar[0]", "in[1]", "inbar[2]", "Z[2]", "vdd", "gnd"],
["inbar[0]", "inbar[1]", "in[2]", "Z[1]", "vdd", "gnd"],
["inbar[0]", "inbar[1]", "inbar[2]", "Z[0]", "vdd", "gnd"]]
["in[0]", "in[1]", "inbar[2]", "Z[3]", "vdd", "gnd"],
["inbar[0]", "inbar[1]", "in[2]", "Z[4]", "vdd", "gnd"],
["in[0]", "inbar[1]", "in[2]", "Z[5]", "vdd", "gnd"],
["inbar[0]", "in[1]", "in[2]", "Z[6]", "vdd", "gnd"],
["in[0]", "in[1]", "in[2]", "Z[7]", "vdd", "gnd"]]
self.add_nand(connections)
self.route()
def get_nand_input_line_combination(self):
""" These are the decoder connections of the NAND gates to the A,B,C pins """
combination = [["Abar[0]", "Abar[1]", "Abar[2]"],
["Abar[0]", "Abar[1]", "A[2]"],
["Abar[0]", "A[1]", "Abar[2]"],
["Abar[0]", "A[1]", "A[2]"],
["A[0]", "Abar[1]", "Abar[2]"],
["A[0]", "Abar[1]", "A[2]"],
["Abar[0]", "A[1]", "Abar[2]"],
["A[0]", "A[1]", "Abar[2]"],
["Abar[0]", "Abar[1]", "A[2]"],
["A[0]", "Abar[1]", "A[2]"],
["Abar[0]", "A[1]", "A[2]"],
["A[0]", "A[1]", "A[2]"]]
return combination

View File

@ -60,21 +60,44 @@ class layout(lef.lef):
def find_lowest_coords(self):
"""Finds the lowest set of 2d cartesian coordinates within
this layout"""
lowestx1 = min(obj.lx() for obj in self.objs if obj.name!="label")
lowesty1 = min(obj.by() for obj in self.objs if obj.name!="label")
lowestx2 = min(inst.lx() for inst in self.insts)
lowesty2 = min(inst.by() for inst in self.insts)
return vector(min(lowestx1, lowestx2), min(lowesty1, lowesty2))
if len(self.objs)>0:
lowestx1 = min(obj.lx() for obj in self.objs if obj.name!="label")
lowesty1 = min(obj.by() for obj in self.objs if obj.name!="label")
else:
lowestx1=lowesty1=None
if len(self.insts)>0:
lowestx2 = min(inst.lx() for inst in self.insts)
lowesty2 = min(inst.by() for inst in self.insts)
else:
lowestx2=lowesty2=None
if lowestx1==None:
return vector(lowestx2,lowesty2)
elif lowestx2==None:
return vector(lowestx1,lowesty1)
else:
return vector(min(lowestx1, lowestx2), min(lowesty1, lowesty2))
def find_highest_coords(self):
"""Finds the highest set of 2d cartesian coordinates within
this layout"""
highestx1 = min(obj.rx() for obj in self.objs if obj.name!="label")
highesty1 = min(obj.uy() for obj in self.objs if obj.name!="label")
highestx2 = min(inst.rx() for inst in self.insts)
highesty2 = min(inst.uy() for inst in self.insts)
return vector(min(highestx1, highestx2), min(highesty1, highesty2))
if len(self.objs)>0:
highestx1 = max(obj.rx() for obj in self.objs if obj.name!="label")
highesty1 = max(obj.uy() for obj in self.objs if obj.name!="label")
else:
highestx1=highesty1=None
if len(self.insts)>0:
highestx2 = max(inst.rx() for inst in self.insts)
highesty2 = max(inst.uy() for inst in self.insts)
else:
highestx2=highesty2=None
if highestx1==None:
return vector(highestx2,highesty2)
elif highestx2==None:
return vector(highestx1,highesty1)
else:
return vector(max(highestx1, highestx2), max(highesty1, highesty2))
def translate_all(self, offset):
@ -143,9 +166,11 @@ class layout(lef.lef):
debug.error("Nonrectilinear center rect!",-1)
elif start.x!=end.x:
offset = vector(0,0.5*minwidth_layer)
return self.add_rect(layer,start-offset,end.x-start.x,minwidth_layer)
else:
offset = vector(0.5*minwidth_layer,0)
return self.add_rect(layer,start-offset,end.x-start.x,minwidth_layer)
return self.add_rect(layer,start-offset,minwidth_layer,end.y-start.y)
def get_pin(self, text):
@ -308,42 +333,50 @@ class layout(lef.lef):
layer_stack=layers,
position_list=coordinates)
def add_contact(self, layers, offset, size=[1,1], mirror="R0", rotate=0):
def add_contact(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
""" This is just an alias for a via."""
return self.add_via(layers=layers,
offset=offset,
size=size,
mirror=mirror,
rotate=rotate)
rotate=rotate,
implant_type=implant_type,
well_type=well_type)
def add_contact_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0):
def add_contact_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
""" This is just an alias for a via."""
return self.add_via_center(layers=layers,
offset=offset,
size=size,
mirror=mirror,
rotate=rotate)
rotate=rotate,
implant_type=implant_type,
well_type=well_type)
def add_via(self, layers, offset, size=[1,1], mirror="R0", rotate=0):
def add_via(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
""" Add a three layer via structure. """
import contact
via = contact.contact(layer_stack=layers,
dimensions=size)
dimensions=size,
implant_type=implant_type,
well_type=well_type)
self.add_mod(via)
self.add_inst(name=via.name,
mod=via,
offset=offset,
mirror=mirror,
rotate=rotate)
inst=self.add_inst(name=via.name,
mod=via,
offset=offset,
mirror=mirror,
rotate=rotate)
# We don't model the logical connectivity of wires/paths
self.connect_inst([])
return via
return inst
def add_via_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0):
def add_via_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
""" Add a three layer via structure by the center coordinate accounting for mirroring and rotation. """
import contact
via = contact.contact(layer_stack=layers,
dimensions=size)
dimensions=size,
implant_type=implant_type,
well_type=well_type)
debug.check(mirror=="R0","Use rotate to rotate vias instead of mirror.")
@ -363,14 +396,14 @@ class layout(lef.lef):
self.add_mod(via)
self.add_inst(name=via.name,
mod=via,
offset=corrected_offset,
mirror=mirror,
rotate=rotate)
inst=self.add_inst(name=via.name,
mod=via,
offset=corrected_offset,
mirror=mirror,
rotate=rotate)
# We don't model the logical connectivity of wires/paths
self.connect_inst([])
return via
return inst
def add_ptx(self, offset, mirror="R0", rotate=0, width=1, mults=1, tx_type="nmos"):
"""Adds a ptx module to the design."""
@ -379,12 +412,12 @@ class layout(lef.lef):
mults=mults,
tx_type=tx_type)
self.add_mod(mos)
self.add_inst(name=mos.name,
mod=mos,
offset=offset,
mirror=mirror,
rotate=rotate)
return mos
inst=self.add_inst(name=mos.name,
mod=mos,
offset=offset,
mirror=mirror,
rotate=rotate)
return inst
@ -488,6 +521,26 @@ class layout(lef.lef):
return blockages
def add_enclosure(self, insts, layer="nwell"):
""" Add a layer that surrounds the given instances. Useful
for creating wells, for example. Doesn't check for minimum widths or
spacings."""
xmin=insts[0].lx()
ymin=insts[0].by()
xmax=insts[0].rx()
ymax=insts[0].uy()
for inst in insts:
xmin = min(xmin, inst.lx())
ymin = min(ymin, inst.by())
xmax = max(xmax, inst.rx())
ymax = max(ymax, inst.uy())
self.add_rect(layer=layer,
offset=vector(xmin,ymin),
width=xmax-xmin,
height=ymax-ymin)
def pdf_write(self, pdf_name):
# NOTE: Currently does not work (Needs further research)
#self.pdf_name = self.name + ".pdf"

View File

@ -126,6 +126,8 @@ class spice(verilog.verilog):
return
if self.pins == []:
return
# write out the first spice line (the subcircuit)
sp.write("\n.SUBCKT {0} {1}\n".format(self.name,
" ".join(self.pins)))
@ -146,9 +148,15 @@ class spice(verilog.verilog):
# these are wires and paths
if self.conns[i] == []:
continue
sp.write("X{0} {1} {2}\n".format(self.insts[i].name,
" ".join(self.conns[i]),
self.insts[i].mod.name))
if hasattr(self.insts[i].mod,"spice_device"):
sp.write(self.insts[i].mod.spice_device.format(self.insts[i].name,
" ".join(self.conns[i])))
sp.write("\n")
else:
sp.write("X{0} {1} {2}\n".format(self.insts[i].name,
" ".join(self.conns[i]),
self.insts[i].mod.name))
sp.write(".ENDS {0}\n".format(self.name))
@ -158,6 +166,7 @@ class spice(verilog.verilog):
#if os.path.isfile(self.sp_file):
# sp.write("\n* {0}\n".format(self.sp_file))
sp.write("\n".join(self.spice))
sp.write("\n")
def sp_write(self, spname):

View File

@ -20,8 +20,8 @@ class ms_flop_array(design.design):
design.design.__init__(self, name)
debug.info(1, "Creating {}".format(self.name))
c = reload(__import__(OPTS.config.ms_flop))
self.mod_ms_flop = getattr(c, OPTS.config.ms_flop)
c = reload(__import__(OPTS.ms_flop))
self.mod_ms_flop = getattr(c, OPTS.ms_flop)
self.ms = self.mod_ms_flop("ms_flop")
self.add_mod(self.ms)

View File

@ -39,19 +39,19 @@ globals.print_banner()
globals.init_openram(args[0])
# Check if all arguments are integers for bits, size, banks
if type(OPTS.config.word_size)!=int:
debug.error("{0} is not an integer in config file.".format(OPTS.config.word_size))
if type(OPTS.config.num_words)!=int:
debug.error("{0} is not an integer in config file.".format(OPTS.config.sram_size))
if type(OPTS.config.num_banks)!=int:
debug.error("{0} is not an integer in config file.".format(OPTS.config.num_banks))
if type(OPTS.word_size)!=int:
debug.error("{0} is not an integer in config file.".format(OPTS.word_size))
if type(OPTS.num_words)!=int:
debug.error("{0} is not an integer in config file.".format(OPTS.sram_size))
if type(OPTS.num_banks)!=int:
debug.error("{0} is not an integer in config file.".format(OPTS.num_banks))
if not OPTS.config.tech_name:
if not OPTS.tech_name:
debug.error("Tech name must be specified in config file.")
word_size = OPTS.config.word_size
num_words = OPTS.config.num_words
num_banks = OPTS.config.num_banks
word_size = OPTS.word_size
num_words = OPTS.num_words
num_banks = OPTS.num_banks
if (OPTS.output_name == ""):
OPTS.output_name = "sram_{0}_{1}_{2}_{3}".format(word_size,
@ -79,10 +79,6 @@ s = sram.sram(word_size=word_size,
num_banks=num_banks,
name=OPTS.output_name)
last_time=print_time("SRAM creation", datetime.datetime.now(), last_time)
# Measure design area
# Not working?
#cell_size = s.gds.measureSize(s.name)
#print("Area:", cell_size[0] * cell_size[1])
# Output the files for the resulting SRAM

View File

@ -4,7 +4,8 @@ import os
class options(optparse.Values):
"""
Class for holding all of the OpenRAM options.
Class for holding all of the OpenRAM options. All of these options can be over-riden in a configuration file
that is the sole required command-line positional argument for openram.py.
"""
# This is the technology directory.
@ -13,6 +14,7 @@ class options(optparse.Values):
tech_name = ""
# This is the temp directory where all intermediate results are stored.
openram_temp = "/tmp/openram_{0}_{1}_temp/".format(getpass.getuser(),os.getpid())
#openram_temp = "/Users/{}/openram_temp/".format(getpass.getuser())
# This is the verbosity level to control debug information. 0 is none, 1
# is minimal, etc.
debug_level = 0
@ -23,9 +25,9 @@ class options(optparse.Values):
# Should we print out the banner at startup
print_banner = True
# The DRC/LVS/PEX executable being used which is derived from the user PATH.
drc_exe = ""
lvs_exe = ""
pex_exe = ""
drc_exe = None
lvs_exe = None
pex_exe = None
# The spice executable being used which is derived from the user PATH.
spice_exe = ""
# Run with extracted parasitics
@ -35,8 +37,32 @@ class options(optparse.Values):
# Use detailed LEF blockages
detailed_blockages = True
# Define the output file paths
output_path = ""
output_path = "."
# Define the output file base name
output_name = ""
output_name = "sram"
# Use analytical delay models by default rather than (slow) characterization
analytical_delay = True
# Purge the temp directory after a successful run (doesn't purge on errors, anyhow)
purge_temp = True
# These are the default modules that can be over-riden
decoder = "hierarchical_decoder"
ms_flop = "ms_flop"
ms_flop_array = "ms_flop_array"
control_logic = "control_logic"
bitcell_array = "bitcell_array"
sense_amp = "sense_amp"
sense_amp_array = "sense_amp_array"
precharge_array = "precharge_array"
column_mux_array = "single_level_column_mux_array"
write_driver = "write_driver"
write_driver_array = "write_driver_array"
tri_gate = "tri_gate"
tri_gate_array = "tri_gate_array"
wordline_driver = "wordline_driver"
replica_bitline = "replica_bitline"
replica_bitcell = "replica_bitcell"
bitcell = "bitcell"
delay_chain = "delay_chain"

View File

@ -47,7 +47,7 @@ class pgate(design.design):
debug.check(nmos_gate_pin.ll().x==pmos_gate_pin.ll().x, "Connecting unaligned gates not supported.")
# Pick point on the left of NMOS and connect down to PMOS
nmos_gate_pos = nmos_gate_pin.ll() + vector(0.5*drc["minwidth_poly"],0)
nmos_gate_pos = nmos_gate_pin.ll() + vector(0.5*self.poly_width,0)
pmos_gate_pos = vector(nmos_gate_pos.x,pmos_gate_pin.bc().y)
self.add_path("poly",[nmos_gate_pos,pmos_gate_pos])
@ -97,93 +97,117 @@ class pgate(design.design):
def extend_wells(self, middle_position):
""" Extend the n/p wells to cover whole cell """
nwell_height = self.height - middle_position.y
# Add a rail width to extend the well to the top of the rail
max_y_offset = self.height + 0.5*self.m1_width
self.nwell_position = middle_position
nwell_height = max_y_offset - middle_position.y
if info["has_nwell"]:
self.add_rect(layer="nwell",
offset=middle_position,
width=self.well_width,
height=nwell_height)
self.add_rect(layer="vtg",
offset=middle_position,
offset=self.nwell_position,
width=self.well_width,
height=nwell_height)
pwell_position = vector(0,-0.5*self.m1_width)
pwell_height = middle_position.y-pwell_position.y
if info["has_pwell"]:
self.add_rect(layer="pwell",
offset=vector(0,0),
offset=pwell_position,
width=self.well_width,
height=middle_position.y)
height=pwell_height)
self.add_rect(layer="vtg",
offset=vector(0,0),
offset=pwell_position,
width=self.well_width,
height=middle_position.y)
height=pwell_height)
def add_nwell_contact(self, nmos, nmos_pos):
""" Add an nwell contact next to the given nmos device. """
def add_nwell_contact(self, pmos, pmos_pos):
""" Add an nwell contact next to the given pmos device. """
layer_stack = ("active", "contact", "metal1")
# To the right a spacing away from the nmos right active edge
nwell_contact_xoffset = nmos_pos.x + nmos.active_width + drc["active_to_body_active"]
nwell_contact_yoffset = nmos_pos.y
nwell_offset = vector(nwell_contact_xoffset, nwell_contact_yoffset)
# Offset by half a contact in x and y
nwell_offset += vector(0.5*nmos.active_contact.first_layer_width,
0.5*nmos.active_contact.first_layer_height)
self.nwell_contact=self.add_contact_center(layers=layer_stack,
offset=nwell_offset)
self.add_rect_center(layer="metal1",
offset=nwell_offset.scale(1,0.5),
width=self.nwell_contact.second_layer_width,
height=nwell_offset.y)
# Now add the full active and implant for the NMOS
nwell_offset = nmos_pos + vector(nmos.active_width,0)
nwell_contact_width = drc["active_to_body_active"] + nmos.active_contact.width
self.add_rect(layer="active",
offset=nwell_offset,
width=nwell_contact_width,
height=nmos.active_height)
implant_offset = nwell_offset + vector(drc["implant_to_implant"],0)
implant_width = nwell_contact_width - drc["implant_to_implant"]
self.add_rect(layer="pimplant",
offset=implant_offset,
width=implant_width,
height=nmos.active_height)
def add_pwell_contact(self, pmos, pmos_pos):
""" Add an pwell contact next to the given pmos device. """
layer_stack = ("active", "contact", "metal1")
# To the right a spacing away from the pmos right active edge
pwell_contact_xoffset = pmos_pos.x + pmos.active_width + drc["active_to_body_active"]
pwell_contact_yoffset = pmos_pos.y + pmos.active_height - pmos.active_contact.height
pwell_offset = vector(pwell_contact_xoffset, pwell_contact_yoffset)
# Offset by half a contact
pwell_offset += vector(0.5*pmos.active_contact.first_layer_width,
contact_xoffset = pmos_pos.x + pmos.active_width + drc["active_to_body_active"]
# Must be at least an well enclosure of active down from the top of the well
# OR align the active with the top of PMOS active.
max_y_offset = self.height + 0.5*self.m1_width
contact_yoffset = min(pmos_pos.y + pmos.active_height - pmos.active_contact.first_layer_height,
max_y_offset - pmos.active_contact.first_layer_height/2 - self.well_enclose_active)
contact_offset = vector(contact_xoffset, contact_yoffset)
# Offset by half a contact in x and y
contact_offset += vector(0.5*pmos.active_contact.first_layer_width,
0.5*pmos.active_contact.first_layer_height)
self.pwell_contact=self.add_contact_center(layers=layer_stack,
offset=pwell_offset)
self.nwell_contact=self.add_contact_center(layers=layer_stack,
offset=contact_offset,
implant_type="n",
well_type="n")
self.add_rect_center(layer="metal1",
offset=pwell_offset + vector(0,0.5*(self.height-pwell_offset.y)),
width=self.pwell_contact.second_layer_width,
height=self.height - pwell_offset.y)
# Now add the full active and implant for the PMOS
pwell_offset = pmos_pos + vector(pmos.active_width,0)
pwell_contact_width = drc["active_to_body_active"] + pmos.active_contact.width
self.add_rect(layer="active",
offset=pwell_offset,
width=pwell_contact_width,
height=pmos.active_height)
implant_offset = pwell_offset + vector(drc["implant_to_implant"],0)
implant_width = pwell_contact_width - drc["implant_to_implant"]
self.add_rect(layer="nimplant",
offset=implant_offset,
width=implant_width,
height=pmos.active_height)
offset=contact_offset + vector(0,0.5*(self.height-contact_offset.y)),
width=self.nwell_contact.mod.second_layer_width,
height=self.height - contact_offset.y)
# Now add the full active and implant for the PMOS
#active_offset = pmos_pos + vector(pmos.active_width,0)
# This might be needed if the spacing between the actives is not satisifed
# self.add_rect(layer="active",
# offset=active_offset,
# width=pmos.active_contact.width,
# height=pmos.active_height)
# we need to ensure implants don't overlap and are spaced far enough apart
# implant_spacing = self.implant_space+self.implant_enclose_active
# implant_offset = active_offset + vector(implant_spacing,0) - vector(0,self.implant_enclose_active)
# implant_width = pmos.active_contact.width + 2*self.implant_enclose_active
# implant_height = pmos.active_height + 2*self.implant_enclose_active
# self.add_rect(layer="nimplant",
# offset=implant_offset,
# width=implant_width,
# height=implant_height)
# Return the top of the well
def add_pwell_contact(self, nmos, nmos_pos):
""" Add an pwell contact next to the given nmos device. """
layer_stack = ("active", "contact", "metal1")
pwell_position = vector(0,-0.5*self.m1_width)
# To the right a spacing away from the nmos right active edge
contact_xoffset = nmos_pos.x + nmos.active_width + drc["active_to_body_active"]
# Must be at least an well enclosure of active up from the bottom of the well
contact_yoffset = max(nmos_pos.y,
self.well_enclose_active - nmos.active_contact.first_layer_height/2)
contact_offset = vector(contact_xoffset, contact_yoffset)
# Offset by half a contact
contact_offset += vector(0.5*nmos.active_contact.first_layer_width,
0.5*nmos.active_contact.first_layer_height)
self.pwell_contact=self.add_contact_center(layers=layer_stack,
offset=contact_offset,
implant_type="p",
well_type="p")
self.add_rect_center(layer="metal1",
offset=contact_offset.scale(1,0.5),
width=self.pwell_contact.mod.second_layer_width,
height=contact_offset.y)
# Now add the full active and implant for the NMOS
# active_offset = nmos_pos + vector(nmos.active_width,0)
# This might be needed if the spacing between the actives is not satisifed
# self.add_rect(layer="active",
# offset=active_offset,
# width=nmos.active_contact.width,
# height=nmos.active_height)
# implant_spacing = self.implant_space+self.implant_enclose_active
# implant_offset = active_offset + vector(implant_spacing,0) - vector(0,self.implant_enclose_active)
# implant_width = nmos.active_contact.width + 2*self.implant_enclose_active
# implant_height = nmos.active_height + 2*self.implant_enclose_active
# self.add_rect(layer="pimplant",
# offset=implant_offset,
# width=implant_width,
# height=implant_height)

View File

@ -17,8 +17,8 @@ class pinv(pgate.pgate):
from center of rail to rail.. The route_output will route the
output to the right side of the cell for easier access.
"""
c = reload(__import__(OPTS.config.bitcell))
bitcell = getattr(c, OPTS.config.bitcell)
c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.bitcell)
unique_id = 1
@ -57,8 +57,8 @@ class pinv(pgate.pgate):
self.setup_layout_constants()
self.add_supply_rails()
self.add_ptx()
self.extend_wells(self.well_pos)
self.add_well_contacts()
self.extend_wells(self.well_pos)
self.connect_rails()
self.route_input_gate(self.pmos_inst, self.nmos_inst, self.output_pos.y, "A", rotate=0)
self.route_outputs()
@ -128,9 +128,6 @@ class pinv(pgate.pgate):
self.width = self.well_width
# Height is an input parameter, so it is not recomputed.
# This will help with the wells
self.well_pos = vector(0,0.4*self.height)
def create_ptx(self):
@ -183,9 +180,14 @@ class pinv(pgate.pgate):
self.connect_inst(["Z", "A", "gnd", "gnd"])
# Output position will be in between the PMOS and NMOS
self.output_pos = vector(0,0.5*(self.pmos_pos.y+self.nmos_pos.y+self.nmos.active_height))
# Output position will be in between the PMOS and NMOS drains
pmos_drain_pos = self.pmos_inst.get_pin("D").ll()
nmos_drain_pos = self.nmos_inst.get_pin("D").ul()
self.output_pos = vector(0,0.5*(pmos_drain_pos.y+nmos_drain_pos.y))
# This will help with the wells
self.well_pos = vector(0,self.nmos_inst.uy())
def route_outputs(self):
@ -196,8 +198,8 @@ class pinv(pgate.pgate):
pmos_drain_pin = self.pmos_inst.get_pin("D")
# Pick point at right most of NMOS and connect down to PMOS
nmos_drain_pos = nmos_drain_pin.ur() - vector(0.5*self.m1_width,0)
pmos_drain_pos = vector(nmos_drain_pos.x,pmos_drain_pin.bc().y)
nmos_drain_pos = nmos_drain_pin.lr() - vector(0.5*self.m1_width,0)
pmos_drain_pos = vector(nmos_drain_pos.x, pmos_drain_pin.bc().y)
self.add_path("metal1",[nmos_drain_pos,pmos_drain_pos])
# Remember the mid for the output
@ -220,9 +222,9 @@ class pinv(pgate.pgate):
def add_well_contacts(self):
""" Add n/p well taps to the layout and connect to supplies """
self.add_nwell_contact(self.nmos, self.nmos_pos)
self.add_nwell_contact(self.pmos, self.pmos_pos)
self.add_pwell_contact(self.pmos, self.pmos_pos)
self.add_pwell_contact(self.nmos, self.nmos_pos)
def connect_rails(self):
""" Connect the nmos and pmos to its respective power rails """

View File

@ -12,8 +12,8 @@ class pnand2(pgate.pgate):
This model use ptx to generate a 2-input nand within a cetrain height.
"""
c = reload(__import__(OPTS.config.bitcell))
bitcell = getattr(c, OPTS.config.bitcell)
c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.bitcell)
unique_id = 1
@ -50,8 +50,8 @@ class pnand2(pgate.pgate):
self.setup_layout_constants()
self.add_supply_rails()
self.add_ptx()
self.add_well_contacts()
self.connect_rails()
self.add_well_contacts()
self.extend_wells(self.well_pos)
self.route_inputs()
self.route_output()
@ -94,9 +94,6 @@ class pnand2(pgate.pgate):
self.width = self.well_width
# Height is an input parameter, so it is not recomputed.
# This will help with the wells
self.well_pos = vector(0,0.4*self.height)
# This is the extra space needed to ensure DRC rules to the active contacts
extra_contact_space = max(-self.nmos.get_pin("D").by(),0)
# This is a poly-to-poly of a flipped cell
@ -139,22 +136,25 @@ class pnand2(pgate.pgate):
self.nmos1_inst=self.add_inst(name="pnand2_nmos1",
mod=self.nmos,
offset=nmos1_pos)
self.connect_inst(["Z", "A", "net1", "gnd"])
self.connect_inst(["Z", "B", "net1", "gnd"])
self.nmos2_pos = nmos1_pos + self.overlap_offset
self.nmos2_inst=self.add_inst(name="pnand2_nmos2",
mod=self.nmos,
offset=self.nmos2_pos)
self.connect_inst(["net1", "B", "gnd", "gnd"])
self.connect_inst(["net1", "A", "gnd", "gnd"])
# Output position will be in between the PMOS and NMOS
self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height))
# This will help with the wells
self.well_pos = vector(0,self.nmos1_inst.uy())
def add_well_contacts(self):
""" Add n/p well taps to the layout and connect to supplies """
""" Add n/p well taps to the layout and connect to supplies AFTER the wells are created """
self.add_nwell_contact(self.nmos, self.nmos2_pos)
self.add_pwell_contact(self.pmos, self.pmos2_pos)
self.add_nwell_contact(self.pmos, self.pmos2_pos)
self.add_pwell_contact(self.nmos, self.nmos2_pos)
def connect_rails(self):

View File

@ -12,8 +12,8 @@ class pnand3(pgate.pgate):
This model use ptx to generate a 2-input nand within a cetrain height.
"""
c = reload(__import__(OPTS.config.bitcell))
bitcell = getattr(c, OPTS.config.bitcell)
c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.bitcell)
unique_id = 1
@ -24,7 +24,9 @@ class pnand3(pgate.pgate):
pgate.pgate.__init__(self, name)
debug.info(2, "create pnand3 structure {0} with size of {1}".format(name, size))
self.nmos_size = 3*size
# We have trouble pitch matching a 3x sizes to the bitcell...
# If we relax this, we could size this better.
self.nmos_size = 2*size
self.pmos_size = parameter["beta"]*size
self.nmos_width = self.nmos_size*drc["minwidth_tx"]
self.pmos_width = self.pmos_size*drc["minwidth_tx"]
@ -50,8 +52,8 @@ class pnand3(pgate.pgate):
self.setup_layout_constants()
self.add_supply_rails()
self.add_ptx()
self.add_well_contacts()
self.connect_rails()
self.add_well_contacts()
self.extend_wells(self.well_pos)
self.route_inputs()
self.route_output()
@ -88,13 +90,13 @@ class pnand3(pgate.pgate):
# This will help with the wells and the input/output placement
self.output_pos = vector(0,0.5*self.height)
self.well_pos = vector(0,0.4*self.height)
# This is the extra space needed to ensure DRC rules to the active contacts
nmos = ptx(tx_type="nmos")
extra_contact_space = max(-nmos.get_pin("D").by(),0)
# This is a poly-to-poly of a flipped cell
# This is extra liberal for pnand3 because we know there are big transistor sizes
# and so contacts won't interfere with the rails. Therefore, ignore metal spacing.
# We need to do this to fit the 3 inputs in with M2M3 via accessibility.
self.top_bottom_space = max(drc["poly_extend_active"], self.poly_space)
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
drc["poly_extend_active"], self.poly_space)
def add_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """
@ -138,7 +140,7 @@ class pnand3(pgate.pgate):
self.nmos1_inst=self.add_inst(name="pnand3_nmos1",
mod=self.nmos,
offset=nmos1_pos)
self.connect_inst(["Z", "A", "net1", "gnd"])
self.connect_inst(["Z", "C", "net1", "gnd"])
nmos2_pos = nmos1_pos + self.overlap_offset
self.nmos2_inst=self.add_inst(name="pnand3_nmos2",
@ -151,14 +153,16 @@ class pnand3(pgate.pgate):
self.nmos3_inst=self.add_inst(name="pnand3_nmos3",
mod=self.nmos,
offset=self.nmos3_pos)
self.connect_inst(["net2", "C", "gnd", "gnd"])
self.connect_inst(["net2", "A", "gnd", "gnd"])
# This should be placed at the top of the NMOS well
self.well_pos = vector(0,self.nmos1_inst.uy())
def add_well_contacts(self):
""" Add n/p well taps to the layout and connect to supplies """
self.add_nwell_contact(self.nmos, self.nmos3_pos)
self.add_pwell_contact(self.pmos, self.pmos3_pos)
self.add_nwell_contact(self.pmos, self.pmos3_pos)
self.add_pwell_contact(self.nmos, self.nmos3_pos)
def connect_rails(self):

View File

@ -12,8 +12,8 @@ class pnor2(pgate.pgate):
This model use ptx to generate a 2-input nor within a cetrain height.
"""
c = reload(__import__(OPTS.config.bitcell))
bitcell = getattr(c, OPTS.config.bitcell)
c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.bitcell)
unique_id = 1
@ -51,8 +51,8 @@ class pnor2(pgate.pgate):
self.setup_layout_constants()
self.add_supply_rails()
self.add_ptx()
self.add_well_contacts()
self.connect_rails()
self.add_well_contacts()
self.extend_wells(self.well_pos)
self.route_inputs()
self.route_output()
@ -98,9 +98,6 @@ class pnor2(pgate.pgate):
self.width = self.well_width
# Height is an input parameter, so it is not recomputed.
# This will help with the wells
self.well_pos = vector(0,0.4*self.height)
# This is the extra space needed to ensure DRC rules to the active contacts
extra_contact_space = max(-self.nmos.get_pin("D").by(),0)
# This is a poly-to-poly of a flipped cell
@ -154,11 +151,14 @@ class pnor2(pgate.pgate):
# Output position will be in between the PMOS and NMOS
self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height))
# This will help with the wells
self.well_pos = vector(0,self.nmos1_inst.uy())
def add_well_contacts(self):
""" Add n/p well taps to the layout and connect to supplies """
self.add_nwell_contact(self.nmos, self.nmos2_pos)
self.add_pwell_contact(self.pmos, self.pmos2_pos)
self.add_nwell_contact(self.pmos, self.pmos2_pos)
self.add_pwell_contact(self.nmos, self.nmos2_pos)
def connect_rails(self):

View File

@ -16,8 +16,8 @@ class precharge(pgate.pgate):
pgate.pgate.__init__(self, name)
debug.info(2, "create single precharge cell: {0}".format(name))
c = reload(__import__(OPTS.config.bitcell))
self.mod_bitcell = getattr(c, OPTS.config.bitcell)
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
self.beta = parameter["beta"]
@ -128,15 +128,12 @@ class precharge(pgate.pgate):
"""Adds a nwell tap to connect to the vdd rail"""
# adds the contact from active to metal1
well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1,0) \
+ vector(0, self.upper_pmos1_pos.y + self.pmos.height + drc["well_extend_active"])
+ vector(0, self.upper_pmos1_inst.uy() + contact.well.height/2 + drc["well_extend_active"])
self.add_contact_center(layers=("active", "contact", "metal1"),
offset=well_contact_pos)
offset=well_contact_pos,
implant_type="n",
well_type="n")
# adds the implant to turn the contact into a nwell tap
self.add_rect_center(layer="nimplant",
offset=well_contact_pos,
width=contact.well.first_layer_width,
height=contact.well.first_layer_height)
self.height = well_contact_pos.y + contact.well.height
@ -175,19 +172,19 @@ class precharge(pgate.pgate):
def add_bitline_contacts(self):
"""Adds contacts/via from metal1 to metal2 for bit-lines"""
for stack in [("active","contact","metal1"),("metal1", "via1", "metal2")]:
pos = self.lower_pmos_inst.get_pin("S").center()
self.add_contact_center(layers=stack,
offset=pos)
pos = self.lower_pmos_inst.get_pin("D").center()
self.add_contact_center(layers=stack,
offset=pos)
pos = self.upper_pmos1_inst.get_pin("S").center()
self.add_contact_center(layers=stack,
offset=pos)
pos = self.upper_pmos2_inst.get_pin("D").center()
self.add_contact_center(layers=stack,
offset=pos)
stack=("metal1", "via1", "metal2")
pos = self.lower_pmos_inst.get_pin("S").center()
self.add_contact_center(layers=stack,
offset=pos)
pos = self.lower_pmos_inst.get_pin("D").center()
self.add_contact_center(layers=stack,
offset=pos)
pos = self.upper_pmos1_inst.get_pin("S").center()
self.add_contact_center(layers=stack,
offset=pos)
pos = self.upper_pmos2_inst.get_pin("D").center()
self.add_contact_center(layers=stack,
offset=pos)
def connect_pmos(self, pmos_pin, bit_pin):
""" Connect pmos pin to bitline pin """

View File

@ -17,7 +17,7 @@ class precharge_array(design.design):
self.columns = columns
self.pc_cell = precharge(name="precharge_cell", size=size)
self.pc_cell = precharge(name="precharge", size=size)
self.add_mod(self.pc_cell)
self.width = self.columns * self.pc_cell.width

View File

@ -61,15 +61,19 @@ class ptx(design.design):
def create_spice(self):
self.add_pin_list(["D", "G", "S", "B"])
self.spice.append("\n.SUBCKT {0} {1}".format(self.name,
" ".join(self.pins)))
self.spice.append("M{0} {1} {2} m={3} w={4}u l={5}u".format(self.tx_type,
" ".join(self.pins),
spice[self.tx_type],
self.mults,
self.tx_width,
drc["minwidth_poly"]))
self.spice.append(".ENDS {0}".format(self.name))
# self.spice.append("\n.SUBCKT {0} {1}".format(self.name,
# " ".join(self.pins)))
# Just make a guess since these will actually be decided in the layout later.
area_sd = 2.5*drc["minwidth_poly"]*self.tx_width
perimeter_sd = 2*drc["minwidth_poly"] + 2*self.tx_width
self.spice_device="M{{0}} {{1}} {0} m={1} w={2}u l={3}u pd={4}u ps={4}u as={5}p ad={5}p".format(spice[self.tx_type],
self.mults,
self.tx_width,
drc["minwidth_poly"],
perimeter_sd,
area_sd)
self.spice.append("\n* ptx " + self.spice_device)
# self.spice.append(".ENDS {0}".format(self.name))
def setup_layout_constants(self):
"""
@ -94,25 +98,19 @@ class ptx(design.design):
self.active_contact = contact(layer_stack=("active", "contact", "metal1"),
dimensions=(1, self.num_contacts))
# Standard DRC rules
self.min_active_width = drc["minwidth_active"]
self.contact_width = drc["minwidth_contact"]
self.poly_width = drc["minwidth_poly"]
self.poly_to_active = drc["poly_to_active"]
self.poly_extend_active = drc["poly_extend_active"]
# The contacted poly pitch (or uncontacted in an odd technology)
self.poly_pitch = max(2*drc["contact_to_poly"] + self.contact_width + self.poly_width,
drc["poly_to_poly"])
self.poly_pitch = max(2*self.contact_to_gate + self.contact_width + self.poly_width,
self.poly_space)
# The contacted poly pitch (or uncontacted in an odd technology)
self.contact_pitch = 2*drc["contact_to_poly"] + self.contact_width + self.poly_width
self.contact_pitch = 2*self.contact_to_gate + self.contact_width + self.poly_width
# The enclosure of an active contact. Not sure about second term.
active_enclose_contact = max(drc["active_enclosure_contact"],
(self.min_active_width - self.contact_width)/2)
(self.active_width - self.contact_width)/2)
# This is the distance from the edge of poly to the contacted end of active
self.end_to_poly = active_enclose_contact + self.contact_width + drc["contact_to_poly"]
self.end_to_poly = active_enclose_contact + self.contact_width + self.contact_to_gate
# Active width is determined by enclosure on both ends and contacted pitch,
@ -125,22 +123,25 @@ class ptx(design.design):
# Poly height must include poly extension over active
self.poly_height = self.tx_width + 2*self.poly_extend_active
# The active offset is due to the well extension
self.active_offset = vector([self.well_enclose_active]*2)
# Well enclosure of active, ensure minwidth as well
if info["has_{}well".format(self.well_type)]:
self.well_width = max(self.active_width + 2*drc["well_enclosure_active"],
drc["minwidth_well"])
self.well_height = max(self.tx_width + 2*drc["well_enclosure_active"],
drc["minwidth_well"])
self.height = self.well_height
self.width = self.well_width
self.cell_well_width = max(self.active_width + 2*self.well_enclose_active,
self.well_width)
self.cell_well_height = max(self.tx_width + 2*self.well_enclose_active,
self.well_width)
# We are going to shift the 0,0, so include that in the width and height
self.height = self.cell_well_height - self.active_offset.y
self.width = self.cell_well_width - self.active_offset.x
else:
# If no well, use the boundary of the active and poly
self.height = self.poly_height
self.width = self.active_width
# The active offset is due to the well extension
self.active_offset = vector([drc["well_enclosure_active"]]*2)
self.active_offset = vector([self.well_enclose_active]*2)
# This is the center of the first active contact offset (centered vertically)
self.contact_offset = self.active_offset + vector(active_enclose_contact + 0.5*self.contact_width,
@ -189,9 +190,9 @@ class ptx(design.design):
# This is the distance that we must route up or down from the center
# of the contacts to avoid DRC violations to the other contacts
pin_offset = vector(0, 0.5*self.active_contact.second_layer_height \
+ drc["metal1_to_metal1"] + 0.5*drc["minwidth_metal1"])
# This is the width of a contact to extend the ends of the pin
end_offset = vector(self.active_contact.second_layer_width/2,0)
+ self.m1_space + 0.5*self.m1_width)
# This is the width of a m1 extend the ends of the pin
end_offset = vector(self.m1_width/2,0)
# drains always go to the MIDDLE of the cell, so top of NMOS, bottom of PMOS
# so reverse the directions for NMOS compared to PMOS.
@ -264,6 +265,14 @@ class ptx(design.design):
offset=self.active_offset,
width=self.active_width,
height=self.active_height)
# If the implant must enclose the active, shift offset
# and increase width/height
enclose_width = drc["implant_enclosure_active"]
enclose_offset = [enclose_width]*2
self.add_rect(layer="{}implant".format(self.implant_type),
offset=self.active_offset - enclose_offset,
width=self.active_width + 2*enclose_width,
height=self.active_height + 2*enclose_width)
def add_well_implant(self):
"""
@ -272,16 +281,12 @@ class ptx(design.design):
if info["has_{}well".format(self.well_type)]:
self.add_rect(layer="{}well".format(self.well_type),
offset=(0,0),
width=self.well_width,
height=self.well_height)
width=self.cell_well_width,
height=self.cell_well_height)
self.add_rect(layer="vtg",
offset=(0,0),
width=self.well_width,
height=self.well_height)
self.add_rect(layer="{}implant".format(self.implant_type),
offset=self.active_offset,
width=self.active_width,
height=self.active_height)
width=self.cell_well_width,
height=self.cell_well_height)
def calculate_num_contacts(self):
@ -321,23 +326,27 @@ class ptx(design.design):
for pos in source_positions:
contact=self.add_contact_center(layers=("active", "contact", "metal1"),
offset=pos,
size=(1, self.num_contacts))
size=(1, self.num_contacts),
implant_type=self.implant_type,
well_type=self.well_type)
self.add_layout_pin_center_rect(text="S",
layer="metal1",
offset=pos,
width=contact.second_layer_width,
height=contact.second_layer_height)
width=contact.mod.second_layer_width,
height=contact.mod.second_layer_height)
for pos in drain_positions:
contact=self.add_contact_center(layers=("active", "contact", "metal1"),
offset=pos,
size=(1, self.num_contacts))
size=(1, self.num_contacts),
implant_type=self.implant_type,
well_type=self.well_type)
self.add_layout_pin_center_rect(text="D",
layer="metal1",
offset=pos,
width=contact.second_layer_width,
height=contact.second_layer_height)
width=contact.mod.second_layer_width,
height=contact.mod.second_layer_height)
if self.connect_active:
self.connect_fingered_active(drain_positions, source_positions)

View File

@ -18,14 +18,14 @@ class replica_bitline(design.design):
def __init__(self, rows, name="replica_bitline"):
design.design.__init__(self, name)
g = reload(__import__(OPTS.config.delay_chain))
self.mod_delay_chain = getattr(g, OPTS.config.delay_chain)
g = reload(__import__(OPTS.delay_chain))
self.mod_delay_chain = getattr(g, OPTS.delay_chain)
g = reload(__import__(OPTS.config.replica_bitcell))
self.mod_replica_bitcell = getattr(g, OPTS.config.replica_bitcell)
g = reload(__import__(OPTS.replica_bitcell))
self.mod_replica_bitcell = getattr(g, OPTS.replica_bitcell)
c = reload(__import__(OPTS.config.bitcell))
self.mod_bitcell = getattr(c, OPTS.config.bitcell)
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
for pin in ["en", "out", "vdd", "gnd"]:
self.add_pin(pin)
@ -240,55 +240,50 @@ class replica_bitline(design.design):
""" Route all signals connected to gnd """
# Add a rail in M1 from bottom to two along delay chain
gnd_start = self.rbl_inv_inst.get_pin("gnd").ll() - self.offset_fix
# It is the height of the entire RBL and bitcell
self.add_rect(layer="metal2",
offset=gnd_start,
width=self.m2_width,
height=self.rbl.height+self.bitcell.height+self.inv.width+self.m2_pitch)
self.add_layout_pin(text="gnd",
layer="metal1",
offset=gnd_start.scale(1,0),
width=self.m2_width,
height=2*self.inv.width)
gnd_start = self.rbl_inv_inst.get_pin("gnd").bc()
gnd_end = vector(gnd_start.x, self.rbl_inst.uy()+2*self.m2_pitch)
self.add_segment_center(layer="metal2",
start=gnd_start,
end=gnd_end)
self.add_layout_pin_center_segment(text="gnd",
layer="metal1",
start=gnd_start.scale(1,0),
end=gnd_start)
# Connect the WL pins directly to gnd
gnd_pin = self.get_pin("gnd").rc()
for row in range(self.rows):
wl = "wl[{}]".format(row)
pin = self.rbl_inst.get_pin(wl)
offset = vector(gnd_start.x,pin.by())
self.add_rect(layer="metal1",
offset=offset,
width=self.rbl_offset.x-gnd_start.x,
height=self.m1_width)
self.add_via(layers=("metal1", "via1", "metal2"),
offset=offset)
start = vector(gnd_pin.x,pin.cy())
self.add_segment_center(layer="metal1",
start=start,
end=pin.lc())
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=start)
# Add via for the delay chain
offset = self.delay_chain_offset - vector(0.5*self.m1_width,0) - self.offset_fix
self.add_via(layers=("metal1", "via1", "metal2"),
offset=offset)
offset = self.dc_inst.get_pins("gnd")[0].bc() + vector(0.5*contact.m1m2.width,0.5*contact.m1m2.height)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=offset)
# Add via for the inverter
offset = self.rbl_inv_offset - vector(0.5*self.m1_width,contact.m1m2.height) - self.offset_fix
self.add_via(layers=("metal1", "via1", "metal2"),
offset=offset)
offset = self.rbl_inv_inst.get_pin("gnd").bc() - vector(0,0.5*contact.m1m2.height)
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=offset)
# Connect the bitcell gnd pin to the rail
# Connect the bitcell gnd pins to the rail
gnd_pins = self.get_pins("gnd")
gnd_start = gnd_pins[0].uc()
gnd_start = gnd_pins[0].ul()
rbl_gnd_pins = self.rbl_inst.get_pins("gnd")
# Find the left most rail on M2
gnd_pin = None
# Add L shapes to each vertical gnd rail
for pin in rbl_gnd_pins:
if gnd_pin == None or (pin.layer=="metal2" and pin.lx()<gnd_pin.lx()):
gnd_pin = pin
gnd_end = gnd_pin.uc()
# Add a couple midpoints so that the wire will drop a via and then route horizontal on M1
gnd_mid1 = gnd_start + vector(0,self.m2_pitch)
gnd_mid2 = gnd_end + vector(0,self.m2_pitch)
self.add_wire(("metal1","via1","metal2"), [gnd_start, gnd_mid1, gnd_mid2, gnd_end])
if pin.layer != "metal2":
continue
gnd_end = pin.uc()
gnd_mid = vector(gnd_end.x, gnd_start.y)
self.add_wire(("metal1","via1","metal2"), [gnd_start, gnd_mid, gnd_end])
gnd_start = gnd_mid
# Add a second gnd pin to the second delay chain rail. No need for full length.

View File

@ -7,7 +7,7 @@ from vector3d import vector3d
class route():
"""
Object route
Object route (used by the router module)
Add a route of minimium metal width between a set of points.
The wire must be completely rectilinear and the
z-dimension of the points refers to the layers (plus via)

View File

@ -14,8 +14,8 @@ class sense_amp_array(design.design):
design.design.__init__(self, "sense_amp_array")
debug.info(1, "Creating {0}".format(self.name))
c = reload(__import__(OPTS.config.sense_amp))
self.mod_sense_amp = getattr(c, OPTS.config.sense_amp)
c = reload(__import__(OPTS.sense_amp))
self.mod_sense_amp = getattr(c, OPTS.sense_amp)
self.amp = self.mod_sense_amp("sense_amp")
self.add_mod(self.amp)

View File

@ -12,12 +12,13 @@ class single_level_column_mux(design.design):
Creates a single columnmux cell.
"""
def __init__(self, name, tx_size):
def __init__(self, tx_size):
name="single_level_column_mux_{}".format(tx_size)
design.design.__init__(self, name)
debug.info(2, "create single columnmux cell: {0}".format(name))
debug.info(2, "create single column mux cell: {0}".format(name))
c = reload(__import__(OPTS.config.bitcell))
self.mod_bitcell = getattr(c, OPTS.config.bitcell)
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
self.ptx_width = tx_size * drc["minwidth_tx"]
@ -27,9 +28,9 @@ class single_level_column_mux(design.design):
def create_layout(self):
self.add_ptx()
self.pin_height = 2*self.m2_width
self.width = self.bitcell.width
self.height = self.nmos2.uy()
self.height = self.nmos2.uy() + self.pin_height
self.connect_poly()
self.add_gnd_rail()
self.add_bitline_pins()
@ -42,26 +43,25 @@ class single_level_column_mux(design.design):
bl_pos = vector(self.bitcell.get_pin("BL").lx(), 0)
br_pos = vector(self.bitcell.get_pin("BR").lx(), 0)
pin_height = 2*self.m2_width
# bl and br
self.add_layout_pin(text="bl",
layer="metal2",
offset=bl_pos + vector(0,self.height - pin_height),
height=pin_height)
offset=bl_pos + vector(0,self.height - self.pin_height),
height=self.pin_height)
self.add_layout_pin(text="br",
layer="metal2",
offset=br_pos + vector(0,self.height - pin_height),
height=pin_height)
offset=br_pos + vector(0,self.height - self.pin_height),
height=self.pin_height)
# bl_out and br_out
self.add_layout_pin(text="bl_out",
layer="metal2",
offset=bl_pos,
height=pin_height)
height=self.pin_height)
self.add_layout_pin(text="br_out",
layer="metal2",
offset=br_pos,
height=pin_height)
height=self.pin_height)
def add_ptx(self):
@ -152,7 +152,6 @@ class single_level_column_mux(design.design):
def add_wells(self):
""" Add a well and implant over the whole cell. Also, add the pwell contact (if it exists) """
# find right most gnd rail
gnd_pins = self.bitcell.get_pins("gnd")
@ -167,26 +166,8 @@ class single_level_column_mux(design.design):
offset=m1m2_offset)
active_offset = right_gnd.bc() + vector(0,0.5*self.nmos.poly_height)
self.add_via_center(layers=("active", "contact", "metal1"),
offset=active_offset)
offset=active_offset,
implant_type="p",
well_type="p")
# implant must surround the active area
active_correct = vector(contact.well.width,contact.well.height).scale(0.5,0.5)
offset_implant = active_offset - vector([drc["implant_to_contact"]]*2) - active_correct
implant_width = 2*drc["implant_to_contact"] + contact.well.width
implant_height = 2*drc["implant_to_contact"] + contact.well.height
self.add_rect(layer="pimplant",
offset=offset_implant,
width=implant_width,
height=implant_height)
# Add a well around the whole cell
if info["has_pwell"]:
self.add_rect(layer="pwell",
offset=vector(0,0),
width=self.width + contact.well.width + drc["well_enclosure_active"],
height=self.height)
self.add_rect(layer="vtg",
offset=vector(0,0),
width=self.width + contact.well.width,
height=self.height)

View File

@ -40,26 +40,30 @@ class single_level_column_mux_array(design.design):
self.setup_layout_constants()
self.create_array()
self.add_routing()
# Find the highest shapes to determine height before adding well
highest = self.find_highest_coords()
self.height = highest.y
self.add_layout_pins()
self.add_enclosure(self.mux_inst, "pwell")
def add_modules(self):
self.mux = single_level_column_mux(name="single_level_column_mux",
tx_size=8)
# FIXME: Why is this 8x?
self.mux = single_level_column_mux(tx_size=8)
self.add_mod(self.mux)
def setup_layout_constants(self):
self.column_addr_size = num_of_inputs = int(self.words_per_row / 2)
self.width = self.columns * self.mux.width
self.m1_pitch = contact.m1m2.width + max(drc["metal1_to_metal1"],drc["metal2_to_metal2"])
# To correct the offset between M1 and M2 via enclosures
self.offset_fix = vector(0,0.5*(drc["minwidth_metal2"]-drc["minwidth_metal1"]))
# one set of metal1 routes for select signals and a pair to interconnect the mux outputs bl/br
# one extra route pitch is to space from the sense amp
self.route_height = (self.words_per_row + 3)*self.m1_pitch
# mux height plus routing signal height plus well spacing at the top
self.height = self.mux.height + self.route_height + drc["pwell_to_nwell"]
def create_array(self):
self.mux_inst = []
@ -70,28 +74,6 @@ class single_level_column_mux_array(design.design):
self.mux_inst.append(self.add_inst(name=name,
mod=self.mux,
offset=x_off))
offset = self.mux_inst[-1].get_pin("bl").ll()
self.add_layout_pin(text="bl[{}]".format(col_num),
layer="metal2",
offset=offset,
height=self.height-offset.y)
offset = self.mux_inst[-1].get_pin("br").ll()
self.add_layout_pin(text="br[{}]".format(col_num),
layer="metal2",
offset=offset,
height=self.height-offset.y)
gnd_pins = self.mux_inst[-1].get_pins("gnd")
for gnd_pin in gnd_pins:
# only do even colums to avoid duplicates
offset = gnd_pin.ll()
if col_num % 2 == 0:
self.add_layout_pin(text="gnd",
layer="metal2",
offset=offset.scale(1,0),
height=self.height)
self.connect_inst(["bl[{}]".format(col_num),
"br[{}]".format(col_num),
@ -100,7 +82,34 @@ class single_level_column_mux_array(design.design):
"sel[{}]".format(col_num % self.words_per_row),
"gnd"])
def add_layout_pins(self):
""" Add the pins after we determine the height. """
# For every column, add a pass gate
for col_num in range(self.columns):
mux_inst = self.mux_inst[col_num]
offset = mux_inst.get_pin("bl").ll()
self.add_layout_pin(text="bl[{}]".format(col_num),
layer="metal2",
offset=offset,
height=self.height-offset.y)
offset = mux_inst.get_pin("br").ll()
self.add_layout_pin(text="br[{}]".format(col_num),
layer="metal2",
offset=offset,
height=self.height-offset.y)
gnd_pins = mux_inst.get_pins("gnd")
for gnd_pin in gnd_pins:
# only do even colums to avoid duplicates
offset = gnd_pin.ll()
if col_num % 2 == 0:
self.add_layout_pin(text="gnd",
layer="metal2",
offset=offset.scale(1,0),
height=self.height)
def add_routing(self):
self.add_horizontal_input_rail()

View File

@ -19,18 +19,18 @@ class sram(design.design):
def __init__(self, word_size, num_words, num_banks, name):
c = reload(__import__(OPTS.config.control_logic))
self.mod_control_logic = getattr(c, OPTS.config.control_logic)
c = reload(__import__(OPTS.control_logic))
self.mod_control_logic = getattr(c, OPTS.control_logic)
c = reload(__import__(OPTS.config.ms_flop_array))
self.mod_ms_flop_array = getattr(c, OPTS.config.ms_flop_array)
c = reload(__import__(OPTS.ms_flop_array))
self.mod_ms_flop_array = getattr(c, OPTS.ms_flop_array)
c = reload(__import__(OPTS.config.bitcell))
self.mod_bitcell = getattr(c, OPTS.config.bitcell)
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
c = reload(__import__(OPTS.config.ms_flop))
self.mod_ms_flop = getattr(c, OPTS.config.ms_flop)
c = reload(__import__(OPTS.ms_flop))
self.mod_ms_flop = getattr(c, OPTS.ms_flop)
self.ms_flop = self.mod_ms_flop()
@ -72,7 +72,7 @@ class sram(design.design):
self.width = sizes[0]
self.height = sizes[1]
self.DRC_LVS()
self.DRC_LVS(final_verification=True)
def compute_sizes(self):
""" Computes the organization of the memory using bitcell size by trying to make it square."""
@ -650,7 +650,7 @@ class sram(design.design):
# Connect the output bar to select 0
msb_out_pin = self.msb_address_inst.get_pin("dout_bar[0]")
msb_out_pos = msb_out_pin.rc()
out_extend_right_pos = msb_out_pos + vector(self.m2_pitch,0)
out_extend_right_pos = msb_out_pos + vector(2*self.m2_pitch,0)
out_extend_up_pos = out_extend_right_pos + vector(0,self.m2_width)
rail_pos = vector(self.vert_control_bus_positions["bank_sel[0]"].x,out_extend_up_pos.y)
self.add_path("metal2",[msb_out_pos,out_extend_right_pos,out_extend_up_pos])
@ -660,7 +660,7 @@ class sram(design.design):
# Connect the output to select 1
msb_out_pin = self.msb_address_inst.get_pin("dout[0]")
msb_out_pos = msb_out_pin.rc()
out_extend_right_pos = msb_out_pos + vector(self.m2_pitch,0)
out_extend_right_pos = msb_out_pos + vector(2*self.m2_pitch,0)
out_extend_down_pos = out_extend_right_pos - vector(0,2*self.m1_pitch)
rail_pos = vector(self.vert_control_bus_positions["bank_sel[1]"].x,out_extend_down_pos.y)
self.add_path("metal2",[msb_out_pos,out_extend_right_pos,out_extend_down_pos])
@ -989,7 +989,13 @@ class sram(design.design):
############################################################
sp = open(sp_name, 'w')
sp.write("**************************************************\n")
sp.write("* OpenRAM generated memory.\n")
sp.write("* Words: {}\n".format(self.num_words))
sp.write("* Data bits: {}\n".format(self.word_size))
sp.write("* Banks: {}\n".format(self.num_banks))
sp.write("* Column mux: {}:1\n".format(self.words_per_row))
sp.write("**************************************************\n")
# This causes unit test mismatch
# sp.write("* Created: {0}\n".format(datetime.datetime.now()))
# sp.write("* User: {0}\n".format(getpass.getuser()))

View File

@ -0,0 +1,154 @@
#!/usr/bin/env python2.7
"Run a regresion test on a basic parameterized transistors"
import unittest
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
class ptx_test(unittest.TestCase):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import ptx
import tech
debug.info(2, "Checking three fingers PMOS")
fet = ptx.ptx(width=tech.drc["minwidth_tx"],
mults=4,
tx_type="pmos",
connect_active=True,
connect_poly=True)
self.local_check(fet)
OPTS.check_lvsdrc = True
globals.end_openram()
def add_mods(self, fet):
self.create_contacts()
self.add_well_extension(fet)
self.add_wire_extension(fet)
self.add_well_tiedown(fet)
self.add_poly_tiedown(fet)
def create_contacts(self):
layer_stack = ("active", "contact", "metal1")
self.well_contact = contact.contact(layer_stack)
layer_stack = ("poly", "contact", "metal1")
self.poly_contact = contact.contact(layer_stack)
def add_well_tiedown(self, fet):
offset = [fet.active_contact_positions[0][0],
fet.active_contact_positions[0][1] + fet.well_height]
fet.add_inst(name="well_tap",
mod=self.well_contact,
offset=offset,
mirror="R0",
rotate=0)
fet.well_contact = self.well_contact
fet.well_tiedown_location = offset
def add_well_extension(self, fet):
well_define = {"pmos": "nwell",
"nmos": "pwell"}
well_type = well_define[fet.tx_type]
offset = getattr(fet,"{}_position".format(well_type))
if tech.info["has_{0}".format(well_type)]:
fet.add_rect(layerNumber=tech.layer[well_type],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["{0}implant".format(fet.tx_type[0])],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["vtg"],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
well_type = "{0}well".format(fet.tx_type[0])
offset[1] = offset[1] - 3 * fet.well_height
if tech.info["has_{0}".format(well_type)]:
fet.add_rect(layerNumber=tech.layer[well_type],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["{0}implant".format(well_define[fet.tx_type][
0])],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["vtg"],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
def add_wire_extension(self, fet):
xcorrect = (fet.active_contact.width / 2) - (tech.drc["minwidth_metal1"] / 2)
offset = [fet.active_contact_positions[0][0] + xcorrect,
fet.active_contact_positions[0][1]]
fet.add_rect(layerNumber=tech.layer["metal1"],
offset=offset,
width=tech.drc["minwidth_metal1"],
height=fet.well_height)
offset = [fet.active_contact_positions[-1][0] + xcorrect,
fet.active_contact_positions[-1][1] - 2 * fet.well_height]
fet.add_rect(layerNumber=tech.layer["metal1"],
offset=offset,
width=tech.drc["minwidth_metal1"],
height=2 * fet.well_height)
offset = [fet.poly_positions[-1][0],
fet.poly_positions[-1][1] - (fet.well_height)]
fet.add_rect(layerNumber=tech.layer["poly"],
offset=offset,
width=tech.drc["minwidth_poly"],
height=fet.well_height)
def add_poly_tiedown(self, fet):
xcorrect = abs(self.poly_contact.upper_layer_vertical_enclosure -
self.poly_contact.lower_layer_vertical_enclosure)
offset = [fet.poly_positions[-1][0] - xcorrect,
fet.poly_positions[-1][1] - (fet.well_height)]
fet.add_inst(name="poly_contact",
mod=self.poly_contact,
offset=offset,
mirror="R270")
offset = [fet.active_contact_positions[-1][0], fet.active_contact_positions
[-1][1] - 2 * fet.well_height - self.well_contact.height]
fet.poly_tiedown_location = offset
fet.add_inst(name="n_tiedown",
mod=self.well_contact,
offset=offset)
tech.ptx_port.add_custom_layer(fet)
def local_check(self, fet):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
fet.sp_write(tempspice)
fet.gds_write(tempgds)
self.assertFalse(verify.run_drc(fet.name, tempgds))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy 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

@ -1,18 +1,13 @@
#!/usr/bin/env python2.7
import unittest
from testutils import header
import sys,os
from testutils import header,openram_test
import sys,os,re
sys.path.append(os.path.join(sys.path[0],".."))
import globals
import debug
import verify
import re
#@unittest.skip("SKIPPING 00_format check test")
class code_format_test(unittest.TestCase):
class code_format_test(openram_test):
"Run a test to check for tabs instead of spaces in the all source files."
def runTest(self):

View File

@ -2,23 +2,19 @@
"Run a regresion test the library cells for DRC"
import unittest
from testutils import header
import sys,os
from testutils import header,openram_test
import sys,os,re
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
import verify
import re
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 01_library_drc_test")
class library_drc_test(unittest.TestCase):
class library_drc_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
(gds_dir, gds_files) = setup_files()
drc_errors = 0

View File

@ -2,24 +2,18 @@
"Run a regresion test the library cells for LVS"
import unittest
from testutils import header
import sys,os
from testutils import header,openram_test
import sys,os,re
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
import verify
import re
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 02_lvs_test")
class library_lvs_test(unittest.TestCase):
class library_lvs_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
import verify
(gds_dir, sp_dir, allnames) = setup_files()
lvs_errors = 0
debug.info(1, "Performing LVS on: " + ", ".join(allnames))
@ -34,7 +28,7 @@ class library_lvs_test(unittest.TestCase):
lvs_errors += 1
debug.error("Missing SPICE file {}".format(gds_name))
lvs_errors += verify.run_lvs(f, gds_name, sp_name)
self.assertEqual(lvs_errors, 0)
# fail if the error count is not zero
self.assertEqual(lvs_errors, 0)
globals.end_openram()

View File

@ -2,22 +2,19 @@
"Run a regresion test for DRC on basic contacts of different array sizes"
import unittest
from testutils import header
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
import verify
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 03_contact_test")
class contact_test(unittest.TestCase):
class contact_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import contact
@ -29,31 +26,26 @@ class contact_test(unittest.TestCase):
# Check single 1 x 1 contact"
debug.info(2, "1 x 1 {} test".format(stack_name))
c = contact.contact(layer_stack, (1, 1))
self.local_check(c)
self.local_drc_check(c)
# check vertical array with one in the middle and two ends
debug.info(2, "1 x 3 {} test".format(stack_name))
c = contact.contact(layer_stack, (1, 3))
self.local_check(c)
self.local_drc_check(c)
# check horizontal array with one in the middle and two ends
debug.info(2, "3 x 1 {} test".format(stack_name))
c = contact.contact(layer_stack, (3, 1))
self.local_check(c)
self.local_drc_check(c)
# check 3x3 array for all possible neighbors
debug.info(2, "3 x 3 {} test".format(stack_name))
c = contact.contact(layer_stack, (3, 3))
self.local_check(c)
self.local_drc_check(c)
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, c):
tempgds = OPTS.openram_temp + "temp.gds"
c.gds_write(tempgds)
self.assertFalse(verify.run_drc(c.name, tempgds))
os.remove(tempgds)
# instantiate a copy of the class to actually run the test

View File

@ -2,22 +2,19 @@
"Run a regresion test on a basic path"
import unittest
from testutils import header
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
import verify
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 03_path_test")
class path_test(unittest.TestCase):
class path_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import path
@ -35,7 +32,7 @@ class path_test(unittest.TestCase):
[0, 6 * min_space ]]
w = design.design("path_test0")
path.path(w,layer_stack, position_list)
self.local_check(w)
self.local_drc_check(w)
min_space = 2 * tech.drc["minwidth_metal1"]
@ -52,7 +49,7 @@ class path_test(unittest.TestCase):
position_list = [[x+min_space, y+min_space] for x,y in old_position_list]
w = design.design("path_test1")
path.path(w,layer_stack, position_list)
self.local_check(w)
self.local_drc_check(w)
min_space = 2 * tech.drc["minwidth_metal2"]
layer_stack = ("metal2")
@ -68,7 +65,7 @@ class path_test(unittest.TestCase):
position_list = [[x-min_space, y-min_space] for x,y in old_position_list]
w = design.design("path_test2")
path.path(w, layer_stack, position_list)
self.local_check(w)
self.local_drc_check(w)
min_space = 2 * tech.drc["minwidth_metal3"]
layer_stack = ("metal3")
@ -85,17 +82,12 @@ class path_test(unittest.TestCase):
position_list.reverse()
w = design.design("path_test3")
path.path(w, layer_stack, position_list)
self.local_check(w)
self.local_drc_check(w)
# return it back to it's normal state
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, w):
tempgds = OPTS.openram_temp + "temp.gds"
w.gds_write(tempgds)
self.assertFalse(verify.run_drc(w.name, tempgds))
os.remove(tempgds)
# instantiate a copy of the class to actually run the test

View File

@ -2,23 +2,19 @@
"Run a regresion test on a basic parameterized transistors"
import unittest
from testutils import header
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
import verify
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 03_ptx_test")
class ptx_test(unittest.TestCase):
class ptx_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import ptx
@ -28,126 +24,12 @@ class ptx_test(unittest.TestCase):
fet = ptx.ptx(width=tech.drc["minwidth_tx"],
mults=1,
tx_type="nmos")
self.local_check(fet)
self.local_drc_check(fet)
OPTS.check_lvsdrc = True
globals.end_openram()
def add_mods(self, fet):
self.create_contacts()
self.add_well_extension(fet)
self.add_wire_extension(fet)
self.add_well_tiedown(fet)
self.add_poly_tiedown(fet)
def create_contacts(self):
layer_stack = ("active", "contact", "metal1")
self.well_contact = contact.contact(layer_stack)
layer_stack = ("poly", "contact", "metal1")
self.poly_contact = contact.contact(layer_stack)
def add_well_tiedown(self, fet):
offset = [fet.active_contact_positions[0][0],
fet.active_contact_positions[0][1] + fet.well_height]
fet.add_inst(name="well_tap",
mod=self.well_contact,
offset=offset,
mirror="R0",
rotate=0)
fet.well_contact = self.well_contact
fet.well_tiedown_location = offset
def add_well_extension(self, fet):
well_define = {"pmos": "nwell",
"nmos": "pwell"}
well_type = well_define[fet.tx_type]
offset = getattr(fet,"{}_position".format(well_type))
if tech.info["has_{0}".format(well_type)]:
fet.add_rect(layerNumber=tech.layer[well_type],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["{0}implant".format(fet.tx_type[0])],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["vtg"],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
well_type = "{0}well".format(fet.tx_type[0])
offset[1] = offset[1] - 3 * fet.well_height
if tech.info["has_{0}".format(well_type)]:
fet.add_rect(layerNumber=tech.layer[well_type],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["{0}implant".format(well_define[fet.tx_type][
0])],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["vtg"],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
def add_wire_extension(self, fet):
xcorrect = (fet.active_contact.width / 2) - (tech.drc["minwidth_metal1"] / 2)
offset = [fet.active_contact_positions[0][0] + xcorrect,
fet.active_contact_positions[0][1]]
fet.add_rect(layerNumber=tech.layer["metal1"],
offset=offset,
width=tech.drc["minwidth_metal1"],
height=fet.well_height)
offset = [fet.active_contact_positions[-1][0] + xcorrect,
fet.active_contact_positions[-1][1] - 2 * fet.well_height]
fet.add_rect(layerNumber=tech.layer["metal1"],
offset=offset,
width=tech.drc["minwidth_metal1"],
height=2 * fet.well_height)
offset = [fet.poly_positions[-1][0],
fet.poly_positions[-1][1] - (fet.well_height)]
fet.add_rect(layerNumber=tech.layer["poly"],
offset=offset,
width=tech.drc["minwidth_poly"],
height=fet.well_height)
def add_poly_tiedown(self, fet):
xcorrect = abs(self.poly_contact.upper_layer_vertical_enclosure -
self.poly_contact.lower_layer_vertical_enclosure)
offset = [fet.poly_positions[-1][0] - xcorrect,
fet.poly_positions[-1][1] - (fet.well_height)]
fet.add_inst(name="poly_contact",
mod=self.poly_contact,
offset=offset,
mirror="R270")
offset = [fet.active_contact_positions[-1][0], fet.active_contact_positions
[-1][1] - 2 * fet.well_height - self.well_contact.height]
fet.poly_tiedown_location = offset
fet.add_inst(name="n_tiedown",
mod=self.well_contact,
offset=offset)
tech.ptx_port.add_custom_layer(fet)
def local_check(self, fet):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
fet.sp_write(tempspice)
fet.gds_write(tempgds)
self.assertFalse(verify.run_drc(fet.name, tempgds))
globals.end_openram()
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -2,23 +2,19 @@
"Run a regresion test on a basic parameterized transistors"
import unittest
from testutils import header
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
import verify
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 03_ptx_test")
class ptx_test(unittest.TestCase):
class ptx_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import ptx
@ -28,127 +24,12 @@ class ptx_test(unittest.TestCase):
fet = ptx.ptx(width=tech.drc["minwidth_tx"],
mults=1,
tx_type="pmos")
self.local_check(fet)
self.local_drc_check(fet)
OPTS.check_lvsdrc = True
globals.end_openram()
def add_mods(self, fet):
self.create_contacts()
self.add_well_extension(fet)
self.add_wire_extension(fet)
self.add_well_tiedown(fet)
self.add_poly_tiedown(fet)
def create_contacts(self):
layer_stack = ("active", "contact", "metal1")
self.well_contact = contact.contact(layer_stack)
layer_stack = ("poly", "contact", "metal1")
self.poly_contact = contact.contact(layer_stack)
def add_well_tiedown(self, fet):
offset = [fet.active_contact_positions[0][0],
fet.active_contact_positions[0][1] + fet.well_height]
fet.add_inst(name="well_tap",
mod=self.well_contact,
offset=offset,
mirror="R0",
rotate=0)
fet.well_contact = self.well_contact
fet.well_tiedown_location = offset
def add_well_extension(self, fet):
well_define = {"pmos": "nwell",
"nmos": "pwell"}
well_type = well_define[fet.tx_type]
offset = getattr(fet,"{}_position".format(well_type))
if tech.info["has_{0}".format(well_type)]:
fet.add_rect(layerNumber=tech.layer[well_type],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["{0}implant".format(fet.tx_type[0])],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["vtg"],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
well_type = "{0}well".format(fet.tx_type[0])
offset[1] = offset[1] - 3 * fet.well_height
if tech.info["has_{0}".format(well_type)]:
fet.add_rect(layerNumber=tech.layer[well_type],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["{0}implant".format(well_define[fet.tx_type][
0])],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["vtg"],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
def add_wire_extension(self, fet):
xcorrect = (fet.active_contact.width / 2) - (tech.drc["minwidth_metal1"] / 2)
offset = [fet.active_contact_positions[0][0] + xcorrect,
fet.active_contact_positions[0][1]]
fet.add_rect(layerNumber=tech.layer["metal1"],
offset=offset,
width=tech.drc["minwidth_metal1"],
height=fet.well_height)
offset = [fet.active_contact_positions[-1][0] + xcorrect,
fet.active_contact_positions[-1][1] - 2 * fet.well_height]
fet.add_rect(layerNumber=tech.layer["metal1"],
offset=offset,
width=tech.drc["minwidth_metal1"],
height=2 * fet.well_height)
offset = [fet.poly_positions[-1][0],
fet.poly_positions[-1][1] - (fet.well_height)]
fet.add_rect(layerNumber=tech.layer["poly"],
offset=offset,
width=tech.drc["minwidth_poly"],
height=fet.well_height)
def add_poly_tiedown(self, fet):
xcorrect = abs(self.poly_contact.upper_layer_vertical_enclosure -
self.poly_contact.lower_layer_vertical_enclosure)
offset = [fet.poly_positions[-1][0] - xcorrect,
fet.poly_positions[-1][1] - (fet.well_height)]
fet.add_inst(name="poly_contact",
mod=self.poly_contact,
offset=offset,
mirror="R270")
offset = [fet.active_contact_positions[-1][0], fet.active_contact_positions
[-1][1] - 2 * fet.well_height - self.well_contact.height]
fet.poly_tiedown_location = offset
fet.add_inst(name="n_tiedown",
mod=self.well_contact,
offset=offset)
tech.ptx_port.add_custom_layer(fet)
def local_check(self, fet):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
fet.sp_write(tempspice)
fet.gds_write(tempgds)
self.assertFalse(verify.run_drc(fet.name, tempgds))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -2,23 +2,19 @@
"Run a regresion test on a basic parameterized transistors"
import unittest
from testutils import header
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
import verify
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 03_ptx_test")
class ptx_test(unittest.TestCase):
class ptx_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import ptx
@ -30,125 +26,11 @@ class ptx_test(unittest.TestCase):
tx_type="nmos",
connect_active=True,
connect_poly=True)
self.local_check(fet)
self.local_drc_check(fet)
OPTS.check_lvsdrc = True
globals.end_openram()
def add_mods(self, fet):
self.create_contacts()
self.add_well_extension(fet)
self.add_wire_extension(fet)
self.add_well_tiedown(fet)
self.add_poly_tiedown(fet)
def create_contacts(self):
layer_stack = ("active", "contact", "metal1")
self.well_contact = contact.contact(layer_stack)
layer_stack = ("poly", "contact", "metal1")
self.poly_contact = contact.contact(layer_stack)
def add_well_tiedown(self, fet):
offset = [fet.active_contact_positions[0][0],
fet.active_contact_positions[0][1] + fet.well_height]
fet.add_inst(name="well_tap",
mod=self.well_contact,
offset=offset,
mirror="R0",
rotate=0)
fet.well_contact = self.well_contact
fet.well_tiedown_location = offset
def add_well_extension(self, fet):
well_define = {"pmos": "nwell",
"nmos": "pwell"}
well_type = well_define[fet.tx_type]
offset = getattr(fet,"{}_position".format(well_type))
if tech.info["has_{0}".format(well_type)]:
fet.add_rect(layerNumber=tech.layer[well_type],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["{0}implant".format(fet.tx_type[0])],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["vtg"],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
well_type = "{0}well".format(fet.tx_type[0])
offset[1] = offset[1] - 3 * fet.well_height
if tech.info["has_{0}".format(well_type)]:
fet.add_rect(layerNumber=tech.layer[well_type],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["{0}implant".format(well_define[fet.tx_type][
0])],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["vtg"],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
def add_wire_extension(self, fet):
xcorrect = (fet.active_contact.width / 2) - (tech.drc["minwidth_metal1"] / 2)
offset = [fet.active_contact_positions[0][0] + xcorrect,
fet.active_contact_positions[0][1]]
fet.add_rect(layerNumber=tech.layer["metal1"],
offset=offset,
width=tech.drc["minwidth_metal1"],
height=fet.well_height)
offset = [fet.active_contact_positions[-1][0] + xcorrect,
fet.active_contact_positions[-1][1] - 2 * fet.well_height]
fet.add_rect(layerNumber=tech.layer["metal1"],
offset=offset,
width=tech.drc["minwidth_metal1"],
height=2 * fet.well_height)
offset = [fet.poly_positions[-1][0],
fet.poly_positions[-1][1] - (fet.well_height)]
fet.add_rect(layerNumber=tech.layer["poly"],
offset=offset,
width=tech.drc["minwidth_poly"],
height=fet.well_height)
def add_poly_tiedown(self, fet):
xcorrect = abs(self.poly_contact.upper_layer_vertical_enclosure -
self.poly_contact.lower_layer_vertical_enclosure)
offset = [fet.poly_positions[-1][0] - xcorrect,
fet.poly_positions[-1][1] - (fet.well_height)]
fet.add_inst(name="poly_contact",
mod=self.poly_contact,
offset=offset,
mirror="R270")
offset = [fet.active_contact_positions[-1][0], fet.active_contact_positions
[-1][1] - 2 * fet.well_height - self.well_contact.height]
fet.poly_tiedown_location = offset
fet.add_inst(name="n_tiedown",
mod=self.well_contact,
offset=offset)
tech.ptx_port.add_custom_layer(fet)
def local_check(self, fet):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
fet.sp_write(tempspice)
fet.gds_write(tempgds)
self.assertFalse(verify.run_drc(fet.name, tempgds))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":

View File

@ -2,23 +2,19 @@
"Run a regresion test on a basic parameterized transistors"
import unittest
from testutils import header
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
import verify
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 03_ptx_test")
class ptx_test(unittest.TestCase):
class ptx_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import ptx
@ -30,125 +26,11 @@ class ptx_test(unittest.TestCase):
tx_type="pmos",
connect_active=True,
connect_poly=True)
self.local_check(fet)
self.local_drc_check(fet)
OPTS.check_lvsdrc = True
globals.end_openram()
def add_mods(self, fet):
self.create_contacts()
self.add_well_extension(fet)
self.add_wire_extension(fet)
self.add_well_tiedown(fet)
self.add_poly_tiedown(fet)
def create_contacts(self):
layer_stack = ("active", "contact", "metal1")
self.well_contact = contact.contact(layer_stack)
layer_stack = ("poly", "contact", "metal1")
self.poly_contact = contact.contact(layer_stack)
def add_well_tiedown(self, fet):
offset = [fet.active_contact_positions[0][0],
fet.active_contact_positions[0][1] + fet.well_height]
fet.add_inst(name="well_tap",
mod=self.well_contact,
offset=offset,
mirror="R0",
rotate=0)
fet.well_contact = self.well_contact
fet.well_tiedown_location = offset
def add_well_extension(self, fet):
well_define = {"pmos": "nwell",
"nmos": "pwell"}
well_type = well_define[fet.tx_type]
offset = getattr(fet,"{}_position".format(well_type))
if tech.info["has_{0}".format(well_type)]:
fet.add_rect(layerNumber=tech.layer[well_type],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["{0}implant".format(fet.tx_type[0])],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["vtg"],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
well_type = "{0}well".format(fet.tx_type[0])
offset[1] = offset[1] - 3 * fet.well_height
if tech.info["has_{0}".format(well_type)]:
fet.add_rect(layerNumber=tech.layer[well_type],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["{0}implant".format(well_define[fet.tx_type][
0])],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["vtg"],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
def add_wire_extension(self, fet):
xcorrect = (fet.active_contact.width / 2) - (tech.drc["minwidth_metal1"] / 2)
offset = [fet.active_contact_positions[0][0] + xcorrect,
fet.active_contact_positions[0][1]]
fet.add_rect(layerNumber=tech.layer["metal1"],
offset=offset,
width=tech.drc["minwidth_metal1"],
height=fet.well_height)
offset = [fet.active_contact_positions[-1][0] + xcorrect,
fet.active_contact_positions[-1][1] - 2 * fet.well_height]
fet.add_rect(layerNumber=tech.layer["metal1"],
offset=offset,
width=tech.drc["minwidth_metal1"],
height=2 * fet.well_height)
offset = [fet.poly_positions[-1][0],
fet.poly_positions[-1][1] - (fet.well_height)]
fet.add_rect(layerNumber=tech.layer["poly"],
offset=offset,
width=tech.drc["minwidth_poly"],
height=fet.well_height)
def add_poly_tiedown(self, fet):
xcorrect = abs(self.poly_contact.upper_layer_vertical_enclosure -
self.poly_contact.lower_layer_vertical_enclosure)
offset = [fet.poly_positions[-1][0] - xcorrect,
fet.poly_positions[-1][1] - (fet.well_height)]
fet.add_inst(name="poly_contact",
mod=self.poly_contact,
offset=offset,
mirror="R270")
offset = [fet.active_contact_positions[-1][0], fet.active_contact_positions
[-1][1] - 2 * fet.well_height - self.well_contact.height]
fet.poly_tiedown_location = offset
fet.add_inst(name="n_tiedown",
mod=self.well_contact,
offset=offset)
tech.ptx_port.add_custom_layer(fet)
def local_check(self, fet):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
fet.sp_write(tempspice)
fet.gds_write(tempgds)
self.assertFalse(verify.run_drc(fet.name, tempgds))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":

View File

@ -2,23 +2,19 @@
"Run a regresion test on a basic parameterized transistors"
import unittest
from testutils import header
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
import verify
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 03_ptx_test")
class ptx_test(unittest.TestCase):
class ptx_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import ptx
@ -30,125 +26,11 @@ class ptx_test(unittest.TestCase):
tx_type="nmos",
connect_active=True,
connect_poly=True)
self.local_check(fet)
self.local_drc_check(fet)
OPTS.check_lvsdrc = True
globals.end_openram()
def add_mods(self, fet):
self.create_contacts()
self.add_well_extension(fet)
self.add_wire_extension(fet)
self.add_well_tiedown(fet)
self.add_poly_tiedown(fet)
def create_contacts(self):
layer_stack = ("active", "contact", "metal1")
self.well_contact = contact.contact(layer_stack)
layer_stack = ("poly", "contact", "metal1")
self.poly_contact = contact.contact(layer_stack)
def add_well_tiedown(self, fet):
offset = [fet.active_contact_positions[0][0],
fet.active_contact_positions[0][1] + fet.well_height]
fet.add_inst(name="well_tap",
mod=self.well_contact,
offset=offset,
mirror="R0",
rotate=0)
fet.well_contact = self.well_contact
fet.well_tiedown_location = offset
def add_well_extension(self, fet):
well_define = {"pmos": "nwell",
"nmos": "pwell"}
well_type = well_define[fet.tx_type]
offset = getattr(fet,"{}_position".format(well_type))
if tech.info["has_{0}".format(well_type)]:
fet.add_rect(layerNumber=tech.layer[well_type],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["{0}implant".format(fet.tx_type[0])],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["vtg"],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
well_type = "{0}well".format(fet.tx_type[0])
offset[1] = offset[1] - 3 * fet.well_height
if tech.info["has_{0}".format(well_type)]:
fet.add_rect(layerNumber=tech.layer[well_type],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["{0}implant".format(well_define[fet.tx_type][
0])],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["vtg"],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
def add_wire_extension(self, fet):
xcorrect = (fet.active_contact.width / 2) - (tech.drc["minwidth_metal1"] / 2)
offset = [fet.active_contact_positions[0][0] + xcorrect,
fet.active_contact_positions[0][1]]
fet.add_rect(layerNumber=tech.layer["metal1"],
offset=offset,
width=tech.drc["minwidth_metal1"],
height=fet.well_height)
offset = [fet.active_contact_positions[-1][0] + xcorrect,
fet.active_contact_positions[-1][1] - 2 * fet.well_height]
fet.add_rect(layerNumber=tech.layer["metal1"],
offset=offset,
width=tech.drc["minwidth_metal1"],
height=2 * fet.well_height)
offset = [fet.poly_positions[-1][0],
fet.poly_positions[-1][1] - (fet.well_height)]
fet.add_rect(layerNumber=tech.layer["poly"],
offset=offset,
width=tech.drc["minwidth_poly"],
height=fet.well_height)
def add_poly_tiedown(self, fet):
xcorrect = abs(self.poly_contact.upper_layer_vertical_enclosure -
self.poly_contact.lower_layer_vertical_enclosure)
offset = [fet.poly_positions[-1][0] - xcorrect,
fet.poly_positions[-1][1] - (fet.well_height)]
fet.add_inst(name="poly_contact",
mod=self.poly_contact,
offset=offset,
mirror="R270")
offset = [fet.active_contact_positions[-1][0], fet.active_contact_positions
[-1][1] - 2 * fet.well_height - self.well_contact.height]
fet.poly_tiedown_location = offset
fet.add_inst(name="n_tiedown",
mod=self.well_contact,
offset=offset)
tech.ptx_port.add_custom_layer(fet)
def local_check(self, fet):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
fet.sp_write(tempspice)
fet.gds_write(tempgds)
self.assertFalse(verify.run_drc(fet.name, tempgds))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":

View File

@ -2,23 +2,19 @@
"Run a regresion test on a basic parameterized transistors"
import unittest
from testutils import header
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
import verify
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 03_ptx_test")
class ptx_test(unittest.TestCase):
class ptx_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import ptx
@ -30,125 +26,11 @@ class ptx_test(unittest.TestCase):
tx_type="pmos",
connect_active=True,
connect_poly=True)
self.local_check(fet)
self.local_drc_check(fet)
OPTS.check_lvsdrc = True
globals.end_openram()
def add_mods(self, fet):
self.create_contacts()
self.add_well_extension(fet)
self.add_wire_extension(fet)
self.add_well_tiedown(fet)
self.add_poly_tiedown(fet)
def create_contacts(self):
layer_stack = ("active", "contact", "metal1")
self.well_contact = contact.contact(layer_stack)
layer_stack = ("poly", "contact", "metal1")
self.poly_contact = contact.contact(layer_stack)
def add_well_tiedown(self, fet):
offset = [fet.active_contact_positions[0][0],
fet.active_contact_positions[0][1] + fet.well_height]
fet.add_inst(name="well_tap",
mod=self.well_contact,
offset=offset,
mirror="R0",
rotate=0)
fet.well_contact = self.well_contact
fet.well_tiedown_location = offset
def add_well_extension(self, fet):
well_define = {"pmos": "nwell",
"nmos": "pwell"}
well_type = well_define[fet.tx_type]
offset = getattr(fet,"{}_position".format(well_type))
if tech.info["has_{0}".format(well_type)]:
fet.add_rect(layerNumber=tech.layer[well_type],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["{0}implant".format(fet.tx_type[0])],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["vtg"],
offset=offset,
width=fet.well_width,
height=2 * fet.well_height)
well_type = "{0}well".format(fet.tx_type[0])
offset[1] = offset[1] - 3 * fet.well_height
if tech.info["has_{0}".format(well_type)]:
fet.add_rect(layerNumber=tech.layer[well_type],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["{0}implant".format(well_define[fet.tx_type][
0])],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
fet.add_rect(layerNumber=tech.layer["vtg"],
offset=offset,
width=fet.well_width,
height=3 * fet.well_height)
def add_wire_extension(self, fet):
xcorrect = (fet.active_contact.width / 2) - (tech.drc["minwidth_metal1"] / 2)
offset = [fet.active_contact_positions[0][0] + xcorrect,
fet.active_contact_positions[0][1]]
fet.add_rect(layerNumber=tech.layer["metal1"],
offset=offset,
width=tech.drc["minwidth_metal1"],
height=fet.well_height)
offset = [fet.active_contact_positions[-1][0] + xcorrect,
fet.active_contact_positions[-1][1] - 2 * fet.well_height]
fet.add_rect(layerNumber=tech.layer["metal1"],
offset=offset,
width=tech.drc["minwidth_metal1"],
height=2 * fet.well_height)
offset = [fet.poly_positions[-1][0],
fet.poly_positions[-1][1] - (fet.well_height)]
fet.add_rect(layerNumber=tech.layer["poly"],
offset=offset,
width=tech.drc["minwidth_poly"],
height=fet.well_height)
def add_poly_tiedown(self, fet):
xcorrect = abs(self.poly_contact.upper_layer_vertical_enclosure -
self.poly_contact.lower_layer_vertical_enclosure)
offset = [fet.poly_positions[-1][0] - xcorrect,
fet.poly_positions[-1][1] - (fet.well_height)]
fet.add_inst(name="poly_contact",
mod=self.poly_contact,
offset=offset,
mirror="R270")
offset = [fet.active_contact_positions[-1][0], fet.active_contact_positions
[-1][1] - 2 * fet.well_height - self.well_contact.height]
fet.poly_tiedown_location = offset
fet.add_inst(name="n_tiedown",
mod=self.well_contact,
offset=offset)
tech.ptx_port.add_custom_layer(fet)
def local_check(self, fet):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
fet.sp_write(tempspice)
fet.gds_write(tempgds)
self.assertFalse(verify.run_drc(fet.name, tempgds))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":

View File

@ -2,22 +2,19 @@
"Run a regresion test on a basic wire"
import unittest
from testutils import header
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
import verify
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 03_wire_test")
class wire_test(unittest.TestCase):
class wire_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import wire
@ -39,7 +36,7 @@ class wire_test(unittest.TestCase):
position_list = [[x-min_space, y-min_space] for x,y in old_position_list]
w = design.design("wire_test1")
wire.wire(w, layer_stack, position_list)
self.local_check(w)
self.local_drc_check(w)
min_space = 2 * (tech.drc["minwidth_poly"] +
tech.drc["minwidth_metal1"])
@ -56,7 +53,7 @@ class wire_test(unittest.TestCase):
position_list = [[x+min_space, y+min_space] for x,y in old_position_list]
w = design.design("wire_test2")
wire.wire(w, layer_stack, position_list)
self.local_check(w)
self.local_drc_check(w)
min_space = 2 * (tech.drc["minwidth_metal2"] +
tech.drc["minwidth_metal1"])
@ -72,7 +69,7 @@ class wire_test(unittest.TestCase):
[-1 * min_space, 0]]
w = design.design("wire_test3")
wire.wire(w, layer_stack, position_list)
self.local_check(w)
self.local_drc_check(w)
min_space = 2 * (tech.drc["minwidth_metal2"] +
@ -89,7 +86,7 @@ class wire_test(unittest.TestCase):
[-1 * min_space, 0]]
w = design.design("wire_test4")
wire.wire(w, layer_stack, position_list)
self.local_check(w)
self.local_drc_check(w)
min_space = 2 * (tech.drc["minwidth_metal2"] +
tech.drc["minwidth_metal3"])
@ -106,7 +103,7 @@ class wire_test(unittest.TestCase):
position_list.reverse()
w = design.design("wire_test5")
wire.wire(w, layer_stack, position_list)
self.local_check(w)
self.local_drc_check(w)
min_space = 2 * (tech.drc["minwidth_metal2"] +
tech.drc["minwidth_metal3"])
@ -123,18 +120,12 @@ class wire_test(unittest.TestCase):
position_list.reverse()
w = design.design("wire_test6")
wire.wire(w, layer_stack, position_list)
self.local_check(w)
self.local_drc_check(w)
# return it back to it's normal state
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, w):
tempgds = OPTS.openram_temp + "temp.gds"
w.gds_write(tempgds)
self.assertFalse(verify.run_drc(w.name, tempgds))
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":

View File

@ -4,22 +4,19 @@ Run regresion tests on a parameterized inverter
"""
import unittest
from testutils import header
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
import verify
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 04_pinv_test")
class pinv_test(unittest.TestCase):
class pinv_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import pinv
@ -32,25 +29,6 @@ class pinv_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, tx):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
tx.sp_write(tempspice)
tx.gds_write(tempgds)
self.assertFalse(verify.run_drc(tx.name, tempgds))
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# reset the static duplicate name checker for unit tests
import design
design.design.name_map=[]
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":

View File

@ -4,22 +4,19 @@ Run regresion tests on a parameterized inverter
"""
import unittest
from testutils import header
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
import verify
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 04_pinv_test")
class pinv_test(unittest.TestCase):
class pinv_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import pinv
@ -32,26 +29,6 @@ class pinv_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, tx):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
tx.sp_write(tempspice)
tx.gds_write(tempgds)
self.assertFalse(verify.run_drc(tx.name, tempgds))
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# reset the static duplicate name checker for unit tests
import design
design.design.name_map=[]
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -1,26 +1,23 @@
#!/usr/bin/env python2.7
"""
Run regresion tests on a parameterized inverter
Run regression tests on a parameterized inverter
"""
import unittest
from testutils import header
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
import verify
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 04_pinv_test")
class pinv_test(unittest.TestCase):
class pinv_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import pinv
import tech
@ -32,26 +29,6 @@ class pinv_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, tx):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
tx.sp_write(tempspice)
tx.gds_write(tempgds)
self.assertFalse(verify.run_drc(tx.name, tempgds))
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# reset the static duplicate name checker for unit tests
import design
design.design.name_map=[]
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,22 +4,19 @@ Run regresion tests on a parameterized inverter
"""
import unittest
from testutils import header
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
import verify
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 04_pinv_test")
class pinv_test(unittest.TestCase):
class pinv_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import pinv
@ -32,25 +29,6 @@ class pinv_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, tx):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
tx.sp_write(tempspice)
tx.gds_write(tempgds)
self.assertFalse(verify.run_drc(tx.name, tempgds))
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# reset the static duplicate name checker for unit tests
import design
design.design.name_map=[]
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":

View File

@ -6,24 +6,19 @@ size 2-input nand gate.
"""
import unittest
from testutils import header
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
import verify
import sys
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 04_pnand2_test")
class pnand2_test(unittest.TestCase):
class pnand2_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import pnand2
@ -37,20 +32,6 @@ class pnand2_test(unittest.TestCase):
globals.end_openram()
def local_check(self, tx):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
tx.sp_write(tempspice)
tx.gds_write(tempgds)
self.assertFalse(verify.run_drc(tx.name, tempgds))
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -6,21 +6,19 @@ It generates only a minimum size 3-input nand gate.
"""
import unittest
from testutils import header
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
import verify
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 04_pnand3_test")
class pnand3_test(unittest.TestCase):
class pnand3_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import pnand3
@ -33,19 +31,6 @@ class pnand3_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, tx):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
tx.sp_write(tempspice)
tx.gds_write(tempgds)
self.assertFalse(verify.run_drc(tx.name, tempgds))
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":

View File

@ -6,24 +6,19 @@ size 2-input nor gate.
"""
import unittest
from testutils import header
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
import verify
import sys
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 04_pnor2_test")
class pnor2_test(unittest.TestCase):
class pnor2_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import pnor2
@ -36,21 +31,6 @@ class pnor2_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, tx):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
tx.sp_write(tempspice)
tx.gds_write(tempgds)
self.assertFalse(verify.run_drc(tx.name, tempgds))
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,21 +4,19 @@ Run a regresion test on a precharge cell
"""
import unittest
from testutils import header
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
import verify
import sys
OPTS = globals.OPTS
class precharge_test(unittest.TestCase):
class precharge_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import precharge
@ -31,20 +29,6 @@ class precharge_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, tx):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
tx.sp_write(tempspice)
tx.gds_write(tempgds)
self.assertFalse(verify.run_drc(tx.name, tempgds))
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,24 +4,21 @@ Run a regresion test on a wordline_driver array
"""
import unittest
from testutils import header
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
import verify
import sys
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 04_driver_test")
class wordline_driver_test(unittest.TestCase):
class wordline_driver_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import wordline_driver
@ -34,20 +31,6 @@ class wordline_driver_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, tx):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
tx.sp_write(tempspice)
tx.gds_write(tempgds)
self.assertFalse(verify.run_drc(tx.name, tempgds))
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,23 +4,21 @@ Run a regresion test on a basic array
"""
import unittest
from testutils import header
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
import verify
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 05_array_test")
class array_test(unittest.TestCase):
class array_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import bitcell_array
@ -32,21 +30,6 @@ class array_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
temppdf = OPTS.openram_temp + "temp.pdf"
a.sp_write(tempspice)
a.gds_write(tempgds)
self.assertFalse(verify.run_drc(a.name, tempgds))
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,20 +4,19 @@ Run a regresion test on a hierarchical_decoder.
"""
import unittest
from testutils import header
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
import verify
OPTS = globals.OPTS
class hierarchical_decoder_test(unittest.TestCase):
class hierarchical_decoder_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import hierarchical_decoder
@ -33,6 +32,10 @@ class hierarchical_decoder_test(unittest.TestCase):
# a = hierarchical_decoder.hierarchical_decoder(rows=8)
# self.local_check(a)
debug.info(1, "Testing 16 row sample for hierarchical_decoder")
a = hierarchical_decoder.hierarchical_decoder(rows=16)
self.local_check(a)
debug.info(1, "Testing 32 row sample for hierarchical_decoder")
a = hierarchical_decoder.hierarchical_decoder(rows=32)
self.local_check(a)
@ -48,24 +51,6 @@ class hierarchical_decoder_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
a.sp_write(tempspice)
a.gds_write(tempgds)
self.assertFalse(verify.run_drc(a.name, tempgds))
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# reset the static duplicate name checker for unit tests
import design
design.design.name_map=[]
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,21 +4,19 @@ Run a regresion test on a hierarchical_predecode2x4.
"""
import unittest
from testutils import header
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
import verify
OPTS = globals.OPTS
class hierarchical_predecode2x4_test(unittest.TestCase):
class hierarchical_predecode2x4_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import hierarchical_predecode2x4 as pre
@ -31,19 +29,6 @@ class hierarchical_predecode2x4_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
a.sp_write(tempspice)
a.gds_write(tempgds)
self.assertFalse(verify.run_drc(a.name, tempgds))
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,21 +4,19 @@ Run a regresion test on a hierarchical_predecode3x8.
"""
import unittest
from testutils import header
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
import verify
OPTS = globals.OPTS
class hierarchical_predecode3x8_test(unittest.TestCase):
class hierarchical_predecode3x8_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import hierarchical_predecode3x8 as pre
@ -31,19 +29,6 @@ class hierarchical_predecode3x8_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
a.sp_write(tempspice)
a.gds_write(tempgds)
self.assertFalse(verify.run_drc(a.name, tempgds))
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -3,21 +3,19 @@
Run a regresion test on a single transistor column_mux.
"""
import unittest
from testutils import header
from testutils import header,openram_test,unittest
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
import verify
class single_level_column_mux_test(unittest.TestCase):
class single_level_column_mux_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import single_level_column_mux_array
@ -37,22 +35,6 @@ class single_level_column_mux_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
a.sp_write(tempspice)
a.gds_write(tempgds)
self.assertFalse(verify.run_drc(a.name, tempgds))
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# reset the static duplicate name checker for unit tests
import design
design.design.name_map=[]
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":

View File

@ -4,22 +4,19 @@ Run a regresion test on a precharge array
"""
import unittest
from testutils import header
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
import verify
#@unittest.skip("SKIPPING 08_precharge_test")
class precharge_test(unittest.TestCase):
class precharge_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import precharge_array
@ -32,19 +29,6 @@ class precharge_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, pc):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
pc.sp_write(tempspice)
pc.gds_write(tempgds)
self.assertFalse(verify.run_drc(pc.name, tempgds))
self.assertFalse(verify.run_lvs(pc.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":

View File

@ -4,21 +4,19 @@ Run a regresion test on a sense amp array
"""
import unittest
from testutils import header
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
import verify
#@unittest.skip("SKIPPING 09_sense_amp_test")
class sense_amp_test(unittest.TestCase):
class sense_amp_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import sense_amp_array
@ -35,24 +33,6 @@ class sense_amp_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
a.sp_write(tempspice)
a.gds_write(tempgds)
self.assertFalse(verify.run_drc(a.name, tempgds))
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# reset the static duplicate name checker for unit tests
import design
design.design.name_map=[]
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,21 +4,19 @@ Run a regresion test on a write driver array
"""
import unittest
from testutils import header
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
import verify
#@unittest.skip("SKIPPING 10_write_driver_test")
class write_driver_test(unittest.TestCase):
class write_driver_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import write_driver_array
@ -34,24 +32,6 @@ class write_driver_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
a.sp_write(tempspice)
a.gds_write(tempgds)
self.assertFalse(verify.run_drc(a.name, tempgds))
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# reset the static duplicate name checker for unit tests
import design
design.design.name_map=[]
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,22 +4,19 @@ Run a regresion test on a dff_array.
"""
import unittest
from testutils import header
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
import verify
import importlib
#@unittest.skip("SKIPPING 20_sram_test")
class dff_array_test(unittest.TestCase):
class dff_array_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False
import ms_flop_array
@ -35,25 +32,6 @@ class dff_array_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
a.sp_write(tempspice)
a.gds_write(tempgds)
self.assertFalse(verify.run_drc(a.name, tempgds))
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# reset the static duplicate name checker for unit tests
import design
design.design.name_map=[]
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,20 +4,19 @@ Run a regresion test on a tri_gate_array.
"""
import unittest
from testutils import header
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
import verify
class tri_gate_array_test(unittest.TestCase):
class tri_gate_array_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import tri_gate_array
@ -33,24 +32,6 @@ class tri_gate_array_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
a.sp_write(tempspice)
a.gds_write(tempgds)
self.assertFalse(verify.run_drc(a.name, tempgds))
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# reset the static duplicate name checker for unit tests
import design
design.design.name_map=[]
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,20 +4,19 @@ Run a test on a delay chain
"""
import unittest
from testutils import header
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
import verify
#@unittest.skip("SKIPPING 14_delay_chain_test")
class delay_chain_test(unittest.TestCase):
class delay_chain_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import delay_chain
@ -29,19 +28,6 @@ class delay_chain_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
a.sp_write(tempspice)
a.gds_write(tempgds)
self.assertFalse(verify.run_drc(a.name, tempgds))
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,23 +4,19 @@ Run a test on a delay chain
"""
import unittest
from testutils import header
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
import verify
import importlib
#@unittest.skip("SKIPPING 14_delay_chain_test")
class replica_bitline_test(unittest.TestCase):
class replica_bitline_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import replica_bitline
@ -32,19 +28,6 @@ class replica_bitline_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
a.sp_write(tempspice)
a.gds_write(tempgds)
self.assertFalse(verify.run_drc(a.name, tempgds))
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,19 +4,19 @@ Run a regresion test on a control_logic
"""
import unittest
from testutils import header
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
import verify
class control_logic_test(unittest.TestCase):
class control_logic_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import control_logic
@ -29,20 +29,6 @@ class control_logic_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
a.sp_write(tempspice)
a.gds_write(tempgds)
self.assertFalse(verify.run_drc(a.name, tempgds))
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,19 +4,19 @@ Run a regresion test on various srams
"""
import unittest
from testutils import header
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
import verify
class multi_bank_test(unittest.TestCase):
class multi_bank_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import bank
@ -41,23 +41,6 @@ class multi_bank_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
a.sp_write(tempspice)
a.gds_write(tempgds)
self.assertFalse(verify.run_drc(a.name, tempgds))
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# reset the static duplicate name checker for unit tests
import design
design.design.name_map=[]
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,22 +4,19 @@ Run a regresion test on various srams
"""
import unittest
from testutils import header
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
import verify
#@unittest.skip("SKIPPING 20_sram_test")
class single_bank_test(unittest.TestCase):
class single_bank_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import bank
@ -44,23 +41,6 @@ class single_bank_test(unittest.TestCase):
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
a.sp_write(tempspice)
a.gds_write(tempgds)
self.assertFalse(verify.run_drc(a.name, tempgds))
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
os.remove(tempspice)
os.remove(tempgds)
# reset the static duplicate name checker for unit tests
import design
design.design.name_map=[]
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,59 +4,42 @@ Run a regresion test on a 1 bank SRAM
"""
import unittest
from testutils import header
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
import verify
#@unittest.skip("SKIPPING 20_sram_test")
class sram_1bank_test(unittest.TestCase):
class sram_1bank_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import sram
debug.info(1, "Single bank, no column mux with control logic")
a = sram.sram(word_size=4, num_words=16, num_banks=1, name="sram1")
self.local_check(a)
self.local_check(a, final_verification=True)
debug.info(1, "Single bank two way column mux with control logic")
a = sram.sram(word_size=4, num_words=32, num_banks=1, name="sram2")
self.local_check(a)
self.local_check(a, final_verification=True)
debug.info(1, "Single bank, four way column mux with control logic")
a = sram.sram(word_size=4, num_words=64, num_banks=1, name="sram3")
self.local_check(a)
self.local_check(a, final_verification=True)
# debug.info(1, "Single bank, eight way column mux with control logic")
# a = sram.sram(word_size=2, num_words=128, num_banks=1, name="sram4")
# self.local_check(a)
# self.local_check(a, final_verification=True)
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
a.sp_write(tempspice)
a.gds_write(tempgds)
self.assertFalse(verify.run_drc(a.name, tempgds))
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
#self.assertFalse(verify.run_pex(a.name, tempgds, tempspice, output=OPTS.openram_temp+"temp_pex.sp"))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,59 +4,42 @@ Run a regresion test on a 2 bank SRAM
"""
import unittest
from testutils import header
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
import verify
#@unittest.skip("SKIPPING 20_sram_test")
class sram_2bank_test(unittest.TestCase):
class sram_2bank_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import sram
debug.info(1, "Two bank, no column mux with control logic")
a = sram.sram(word_size=16, num_words=32, num_banks=2, name="sram1")
self.local_check(a)
self.local_check(a, final_verification=True)
debug.info(1, "Two bank two way column mux with control logic")
a = sram.sram(word_size=16, num_words=64, num_banks=2, name="sram2")
self.local_check(a)
self.local_check(a, final_verification=True)
debug.info(1, "Two bank, four way column mux with control logic")
a = sram.sram(word_size=16, num_words=128, num_banks=2, name="sram3")
self.local_check(a)
self.local_check(a, final_verification=True)
# debug.info(1, "Two bank, eight way column mux with control logic")
# a = sram.sram(word_size=2, num_words=256 num_banks=2, name="sram4")
# self.local_check(a)
# self.local_check(a, final_verification=True)
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
a.sp_write(tempspice)
a.gds_write(tempgds)
self.assertFalse(verify.run_drc(a.name, tempgds))
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
#self.assertFalse(verify.run_pex(a.name, tempgds, tempspice, output=OPTS.openram_temp+"temp_pex.sp"))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,59 +4,42 @@ Run a regresion test on a 4 bank SRAM
"""
import unittest
from testutils import header
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
import verify
#@unittest.skip("SKIPPING 20_sram_test")
class sram_4bank_test(unittest.TestCase):
class sram_4bank_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
global verify
import verify
OPTS.check_lvsdrc = False
import sram
debug.info(1, "Four bank, no column mux with control logic")
a = sram.sram(word_size=16, num_words=64, num_banks=4, name="sram1")
self.local_check(a)
self.local_check(a, final_verification=True)
debug.info(1, "Four bank two way column mux with control logic")
a = sram.sram(word_size=16, num_words=128, num_banks=4, name="sram2")
self.local_check(a)
self.local_check(a, final_verification=True)
debug.info(1, "Four bank, four way column mux with control logic")
a = sram.sram(word_size=16, num_words=256, num_banks=4, name="sram3")
self.local_check(a)
self.local_check(a, final_verification=True)
# debug.info(1, "Four bank, eight way column mux with control logic")
# a = sram.sram(word_size=2, num_words=256, num_banks=4, name="sram4")
# self.local_check(a)
# self.local_check(a, final_verification=True)
OPTS.check_lvsdrc = True
globals.end_openram()
def local_check(self, a):
tempspice = OPTS.openram_temp + "temp.sp"
tempgds = OPTS.openram_temp + "temp.gds"
a.sp_write(tempspice)
a.gds_write(tempgds)
self.assertFalse(verify.run_drc(a.name, tempgds))
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
#self.assertFalse(verify.run_pex(a.name, tempgds, tempspice, output=OPTS.openram_temp+"temp_pex.sp"))
os.remove(tempspice)
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,36 +4,34 @@ Run a regresion test on various srams
"""
import unittest
from testutils import header,isclose
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
import verify
#@unittest.skip("SKIPPING 21_timing_sram_test")
class timing_sram_test(unittest.TestCase):
class timing_sram_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.spice_name="hspice"
OPTS.analytical_delay = False
# This is a hack to reload the characterizer __init__ with the spice version
import characterizer
reload(characterizer)
from characterizer import delay
if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
import sram
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
s = sram.sram(word_size=OPTS.config.word_size,
num_words=OPTS.config.num_words,
num_banks=OPTS.config.num_banks,
s = sram.sram(word_size=OPTS.word_size,
num_words=OPTS.num_words,
num_banks=OPTS.num_banks,
name="sram1")
OPTS.check_lvsdrc = True
@ -51,25 +49,25 @@ class timing_sram_test(unittest.TestCase):
slews = [tech.spice["rise_time"]*2]
data = d.analyze(probe_address, probe_data,slews,loads)
if OPTS.tech_name == "freepdk45":
golden_data = {'read1_power': 0.0296933,
'read0_power': 0.029897899999999998,
'write0_power': 0.0258029,
'delay1': [0.049100700000000004],
'delay0': [0.13766139999999996],
'min_period': 0.322,
'write1_power': 0.0260398,
'slew0': [0.0265264],
'slew1': [0.0195507]}
golden_data = {'read1_power': 0.0339194,
'read0_power': 0.0340617,
'write0_power': 0.0287779,
'delay1': [0.0575725],
'delay0': [0.16744839999999997],
'min_period': 0.391,
'write1_power': 0.0299736,
'slew0': [0.026416],
'slew1': [0.020441199999999996]}
elif OPTS.tech_name == "scn3me_subm":
golden_data = {'read1_power': 4.3678,
'read0_power': 4.3914,
'write0_power': 2.9394,
'delay1': [0.8901521],
'delay0': [2.001],
'min_period': 5.781,
'write1_power': 2.7163,
'slew0': [1.3044000000000002],
'slew1': [0.9904079]}
golden_data = {'read1_power': 5.557800000000001,
'read0_power': 5.5712,
'write0_power': 3.8325,
'delay1': [1.0323],
'delay0': [2.2134],
'min_period': 6.25,
'write1_power': 3.6903,
'slew0': [1.3009000000000002],
'slew1': [0.983561]}
else:
self.assertTrue(False) # other techs fail
# Check if no too many or too few results
@ -78,9 +76,9 @@ class timing_sram_test(unittest.TestCase):
for k in data.keys():
if type(data[k])==list:
for i in range(len(data[k])):
self.assertTrue(isclose(data[k][i],golden_data[k][i],0.15))
self.isclose(data[k][i],golden_data[k][i],0.15)
else:
self.assertTrue(isclose(data[k],golden_data[k],0.15))
self.isclose(data[k],golden_data[k],0.15)
# reset these options

View File

@ -4,29 +4,28 @@ Run a regresion test on various srams
"""
import unittest
from testutils import header,isclose
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
import verify
#@unittest.skip("SKIPPING 21_timing_sram_test")
class timing_setup_test(unittest.TestCase):
class timing_setup_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.spice_name="hspice"
OPTS.analytical_delay = False
# This is a hack to reload the characterizer __init__ with the spice version
import characterizer
reload(characterizer)
from characterizer import setup_hold
if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
import sram
import tech
@ -54,9 +53,9 @@ class timing_setup_test(unittest.TestCase):
for k in data.keys():
if type(data[k])==list:
for i in range(len(data[k])):
self.assertTrue(isclose(data[k][i],golden_data[k][i],0.15))
self.isclose(data[k][i],golden_data[k][i],0.15)
else:
self.assertTrue(isclose(data[k],golden_data[k],0.15))
self.isclose(data[k],golden_data[k],0.15)
OPTS.check_lvsdrc = True
OPTS.analytical_delay = True

View File

@ -4,34 +4,34 @@ Run a regresion test on various srams
"""
import unittest
from testutils import header,isclose
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
import verify
#@unittest.skip("SKIPPING 21_ngspice_delay_test")
class timing_sram_test(unittest.TestCase):
class timing_sram_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.spice_name="ngspice"
OPTS.analytical_delay = False
# This is a hack to reload the characterizer __init__ with the spice version
import characterizer
reload(characterizer)
from characterizer import delay
if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
import sram
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
s = sram.sram(word_size=OPTS.config.word_size,
num_words=OPTS.config.num_words,
num_banks=OPTS.config.num_banks,
s = sram.sram(word_size=OPTS.word_size,
num_words=OPTS.num_words,
num_banks=OPTS.num_banks,
name="sram1")
tempspice = OPTS.openram_temp + "temp.sp"
@ -47,25 +47,25 @@ class timing_sram_test(unittest.TestCase):
slews = [tech.spice["rise_time"]*2]
data = d.analyze(probe_address, probe_data,slews,loads)
if OPTS.tech_name == "freepdk45":
golden_data = {'read1_power': 0.026660760000000002,
'read0_power': 0.02711731,
'write0_power': 0.02501428,
'delay1': [0.04867702],
'delay0': [0.1423633],
'min_period': 0.332,
'write1_power': 0.024162890000000003,
'slew0': [0.02733451],
'slew1': [0.02121624]}
golden_data = {'read1_power': 0.03228762,
'read0_power': 0.03281849,
'write0_power': 0.02902607,
'delay1': [0.059081419999999996],
'delay0': [0.1716648],
'min_period': 0.391,
'write1_power': 0.02879424,
'slew0': [0.02851539],
'slew1': [0.02319674]}
elif OPTS.tech_name == "scn3me_subm":
golden_data = {'read1_power': 4.250786000000001,
'read0_power': 4.093461,
'write0_power': 2.762675,
'delay1': [0.920068],
'delay0': [2.051821],
golden_data = {'read1_power': 5.063901,
'read0_power': 4.926464999999999,
'write0_power': 3.480712,
'delay1': [1.044746],
'delay0': [2.23024],
'min_period': 6.563,
'write1_power': 2.4545719999999998,
'slew0': [1.342015],
'slew1': [1.040868]}
'write1_power': 3.1949449999999997,
'slew0': [1.3469],
'slew1': [1.035352]}
else:
self.assertTrue(False) # other techs fail
@ -75,9 +75,9 @@ class timing_sram_test(unittest.TestCase):
for k in data.keys():
if type(data[k])==list:
for i in range(len(data[k])):
self.assertTrue(isclose(data[k][i],golden_data[k][i],0.15))
self.isclose(data[k][i],golden_data[k][i],0.15)
else:
self.assertTrue(isclose(data[k],golden_data[k],0.15))
self.isclose(data[k],golden_data[k],0.15)
# reset these options
OPTS.check_lvsdrc = True

View File

@ -4,30 +4,27 @@ Run a regresion test on various srams
"""
import unittest
from testutils import header,isclose
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
import verify
#@unittest.skip("SKIPPING 21_timing_sram_test")
class timing_setup_test(unittest.TestCase):
class timing_setup_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.spice_name="ngspice"
OPTS.analytical_delay = False
# This is a hack to reload the characterizer __init__ with the spice version
import characterizer
reload(characterizer)
from characterizer import setup_hold
if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
import sram
import tech
@ -55,9 +52,9 @@ class timing_setup_test(unittest.TestCase):
for k in data.keys():
if type(data[k])==list:
for i in range(len(data[k])):
self.assertTrue(isclose(data[k][i],golden_data[k][i],0.15))
self.isclose(data[k][i],golden_data[k][i],0.15)
else:
self.assertTrue(isclose(data[k],golden_data[k],0.15))
self.isclose(data[k],golden_data[k],0.15)
# reset these options
OPTS.check_lvsdrc = True

View File

@ -4,20 +4,20 @@ Run a regression test on an extracted SRAM to ensure functionality.
"""
import unittest
from testutils import header
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
import verify
@unittest.skip("SKIPPING 22_sram_func_test")
class sram_func_test(unittest.TestCase):
class sram_func_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
self.func_test(bank_num=1)
self.func_test(bank_num=2)
@ -33,9 +33,9 @@ class sram_func_test(unittest.TestCase):
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
OPTS.check_lvsdrc = False
OPTS.use_pex = True
s = sram.sram(word_size=OPTS.config.word_size,
num_words=OPTS.config.num_words,
num_banks=OPTS.config.num_banks,
s = sram.sram(word_size=OPTS.word_size,
num_words=OPTS.num_words,
num_banks=OPTS.num_banks,
name="test_sram1")
OPTS.check_lvsdrc = True
OPTS.use_pex = False

View File

@ -4,36 +4,34 @@ Run a regresion test on various srams
"""
import unittest
from testutils import header
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
import verify
#@unittest.skip("SKIPPING 21_timing_sram_test")
class sram_func_test(unittest.TestCase):
class sram_func_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.spice_name="hspice"
OPTS.spice_name="" # Unset to use any simulator
OPTS.analytical_delay = False
# This is a hack to reload the characterizer __init__ with the spice version
import characterizer
reload(characterizer)
from characterizer import delay
if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
import sram
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
s = sram.sram(word_size=OPTS.config.word_size,
num_words=OPTS.config.num_words,
num_banks=OPTS.config.num_banks,
s = sram.sram(word_size=OPTS.word_size,
num_words=OPTS.num_words,
num_banks=OPTS.num_banks,
name="sram_func_test")
OPTS.check_lvsdrc = True

View File

@ -4,19 +4,17 @@ Check the .lib file for an SRAM
"""
import unittest
from testutils import header,isapproxdiff
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
import verify
class lib_test(unittest.TestCase):
class lib_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
import sram
@ -24,8 +22,8 @@ class lib_test(unittest.TestCase):
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank")
s = sram.sram(word_size=2,
num_words=OPTS.config.num_words,
num_banks=OPTS.config.num_banks,
num_words=OPTS.num_words,
num_banks=OPTS.num_banks,
name="sram_2_16_1_{0}".format(OPTS.tech_name))
OPTS.check_lvsdrc = True
@ -38,7 +36,7 @@ class lib_test(unittest.TestCase):
# let's diff the result with a golden model
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
self.assertEqual(isapproxdiff(libname,golden,0.15),True)
self.isapproxdiff(libname,golden,0.15)
globals.end_openram()

View File

@ -4,32 +4,35 @@ Check the .lib file for an SRAM with pruning
"""
import unittest
from testutils import header,isapproxdiff
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
import verify
class lib_test(unittest.TestCase):
class lib_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.spice_name="hspice"
OPTS.spice_name="" # Unset to use any simulator
OPTS.analytical_delay = False
OPTS.trim_netlist = True
# This is a hack to reload the characterizer __init__ with the spice version
import characterizer
reload(characterizer)
from characterizer import lib
if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
import sram
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank")
s = sram.sram(word_size=2,
num_words=OPTS.config.num_words,
num_banks=OPTS.config.num_banks,
num_words=OPTS.num_words,
num_banks=OPTS.num_banks,
name="sram_2_16_1_{0}".format(OPTS.tech_name))
OPTS.check_lvsdrc = True
@ -42,7 +45,7 @@ class lib_test(unittest.TestCase):
# let's diff the result with a golden model
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
self.assertEqual(isapproxdiff(libname,golden,0.30),True)
self.isapproxdiff(libname,golden,0.30)
OPTS.analytical_delay = True
reload(characterizer)

View File

@ -4,32 +4,35 @@ Check the .lib file for an SRAM
"""
import unittest
from testutils import header,isapproxdiff
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
import verify
class lib_test(unittest.TestCase):
class lib_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.spice_name="" # Unset to use any simulator
OPTS.analytical_delay = False
OPTS.trim_netlist = False
# This is a hack to reload the characterizer __init__ with the spice version
import characterizer
reload(characterizer)
from characterizer import lib
if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
import sram
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank")
s = sram.sram(word_size=2,
num_words=OPTS.config.num_words,
num_banks=OPTS.config.num_banks,
num_words=OPTS.num_words,
num_banks=OPTS.num_banks,
name="sram_2_16_1_{0}".format(OPTS.tech_name))
OPTS.check_lvsdrc = True
@ -42,7 +45,7 @@ class lib_test(unittest.TestCase):
# let's diff the result with a golden model
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
self.assertEqual(isapproxdiff(libname,golden,0.15),True)
self.isapproxdiff(libname,golden,0.15)
OPTS.analytical_delay = True
OPTS.trim_netlist = True

View File

@ -4,16 +4,14 @@ Check the LEF file for an SRMA
"""
import unittest
from testutils import header,isdiff
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
import verify
class lef_test(unittest.TestCase):
class lef_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
@ -24,8 +22,8 @@ class lef_test(unittest.TestCase):
debug.info(1, "Testing LEF for sample 2 bit, 16 words SRAM with 1 bank")
s = sram.sram(word_size=2,
num_words=OPTS.config.num_words,
num_banks=OPTS.config.num_banks,
num_words=OPTS.num_words,
num_banks=OPTS.num_banks,
name="sram_2_16_1_{0}".format(OPTS.tech_name))
OPTS.check_lvsdrc = True
@ -39,7 +37,7 @@ class lef_test(unittest.TestCase):
# let's diff the result with a golden model
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),leffile)
self.assertEqual(isdiff(lefname,golden),True)
self.isdiff(lefname,golden)
os.system("rm {0}".format(gdsname))
os.system("rm {0}".format(lefname))

View File

@ -4,16 +4,14 @@ Check the .v file for an SRAM
"""
import unittest
from testutils import header,isdiff
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
import verify
class verilog_test(unittest.TestCase):
class verilog_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
@ -24,8 +22,8 @@ class verilog_test(unittest.TestCase):
debug.info(1, "Testing Verilog for sample 2 bit, 16 words SRAM with 1 bank")
s = sram.sram(word_size=2,
num_words=OPTS.config.num_words,
num_banks=OPTS.config.num_banks,
num_words=OPTS.num_words,
num_banks=OPTS.num_banks,
name="sram_2_16_1_{0}".format(OPTS.tech_name))
OPTS.check_lvsdrc = True
@ -37,7 +35,7 @@ class verilog_test(unittest.TestCase):
# let's diff the result with a golden model
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),vfile)
self.assertEqual(isdiff(vname,golden),True)
self.isdiff(vname,golden)
os.system("rm {0}".format(vname))

View File

@ -6,25 +6,22 @@ check that these files are right.
"""
import unittest
from testutils import header
import sys,os
from testutils import header,openram_test
import sys,os,re,shutil
sys.path.append(os.path.join(sys.path[0],".."))
import globals
from globals import OPTS
import debug
import os
import re
import shutil
class openram_test(unittest.TestCase):
class openram_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
debug.info(1, "Testing top-level openram.py with 2-bit, 16 word SRAM.")
out_file = "testsram"
# make a temp directory for output
out_path = OPTS.openram_temp + out_file
out_path = "/tmp/testsram"
# make sure we start without the files existing
if os.path.exists(out_path):
@ -70,7 +67,10 @@ class openram_test(unittest.TestCase):
shutil.rmtree(out_path, ignore_errors=True)
self.assertEqual(os.path.exists(out_path),False)
globals.end_openram()
# The default was on, so disable it.
OPTS.check_lvsdrc=False
globals.end_openram()
OPTS.check_lvsdrc=True
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":

View File

@ -4,25 +4,4 @@ num_banks = 1
tech_name = "freepdk45"
# Optional, will be over-ridden on command line.
output_path = "/tmp/freepdk45_sram"
output_name = "sram_2_16_1_freepdk45"
decoder = "hierarchical_decoder"
ms_flop = "ms_flop"
ms_flop_array = "ms_flop_array"
control_logic = "control_logic"
bitcell_array = "bitcell_array"
sense_amp = "sense_amp"
sense_amp_array = "sense_amp_array"
precharge_array = "precharge_array"
column_mux_array = "single_level_column_mux_array"
write_driver = "write_driver"
write_driver_array = "write_driver_array"
tri_gate = "tri_gate"
tri_gate_array = "tri_gate_array"
wordline_driver = "wordline_driver"
replica_bitline = "replica_bitline"
replica_bitcell = "replica_bitcell"
bitcell = "bitcell"
delay_chain = "delay_chain"

View File

@ -4,25 +4,3 @@ num_banks = 1
tech_name = "scn3me_subm"
# Optional, will be over-ridden on command line.
output_path = "/tmp/scn3me_subm_mysram"
output_name = "sram_2_16_1_scn3me_subm"
decoder = "hierarchical_decoder"
ms_flop = "ms_flop"
ms_flop_array = "ms_flop_array"
control_logic = "control_logic"
bitcell_array = "bitcell_array"
sense_amp = "sense_amp"
sense_amp_array = "sense_amp_array"
precharge_array = "precharge_array"
column_mux_array = "single_level_column_mux_array"
write_driver = "write_driver"
write_driver_array = "write_driver_array"
tri_gate = "tri_gate"
tri_gate_array = "tri_gate_array"
wordline_driver = "wordline_driver"
replica_bitline = "replica_bitline"
replica_bitcell = "replica_bitcell"
bitcell = "bitcell"
delay_chain = "delay_chain"

File diff suppressed because it is too large Load Diff

View File

@ -74,7 +74,7 @@ cell (sram_2_16_1_freepdk45){
dont_use : true;
map_only : true;
dont_touch : true;
area : 0.023625;
area : 918.5120625;
bus(DATA){
bus_type : DATA;
@ -92,19 +92,19 @@ cell (sram_2_16_1_freepdk45){
internal_power(){
when : "OEb & !clk";
rise_power(scalar){
values("0.027781");
values("0.032264359");
}
fall_power(scalar){
values("0.026752");
values("0.033266382");
}
}
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -129,10 +129,10 @@ cell (sram_2_16_1_freepdk45){
internal_power(){
when : "!OEb & !clk";
rise_power(scalar){
values("0.031198");
values("0.039765915");
}
fall_power(scalar){
values("0.031252");
values("0.039839075");
}
}
timing(){
@ -140,24 +140,24 @@ cell (sram_2_16_1_freepdk45){
related_pin : "clk";
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("0.046, 0.047, 0.054",\
"0.047, 0.047, 0.054",\
"0.052, 0.052, 0.059");
values("0.055, 0.056, 0.064",\
"0.056, 0.057, 0.064",\
"0.061, 0.062, 0.07");
}
cell_fall(CELL_TABLE) {
values("0.132, 0.133, 0.142",\
"0.133, 0.134, 0.142",\
"0.138, 0.139, 0.147");
values("0.17, 0.171, 0.179",\
"0.171, 0.172, 0.18",\
"0.176, 0.177, 0.185");
}
rise_transition(CELL_TABLE) {
values("0.014, 0.015, 0.027",\
"0.014, 0.015, 0.027",\
"0.014, 0.015, 0.027");
values("0.015, 0.016, 0.028",\
"0.015, 0.016, 0.028",\
"0.015, 0.016, 0.028");
}
fall_transition(CELL_TABLE) {
values("0.018, 0.02, 0.036",\
"0.019, 0.02, 0.036",\
"0.019, 0.02, 0.036");
values("0.019, 0.02, 0.035",\
"0.019, 0.02, 0.035",\
"0.019, 0.02, 0.035");
}
}
}
@ -174,9 +174,9 @@ cell (sram_2_16_1_freepdk45){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -208,9 +208,9 @@ cell (sram_2_16_1_freepdk45){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -241,9 +241,9 @@ cell (sram_2_16_1_freepdk45){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -274,9 +274,9 @@ cell (sram_2_16_1_freepdk45){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -308,20 +308,20 @@ cell (sram_2_16_1_freepdk45){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(scalar) {
values("0.1955");
values("0.2345");
}
fall_constraint(scalar) {
values("0.1955");
values("0.2345");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(scalar) {
values("0.391");
values("0.469");
}
fall_constraint(scalar) {
values("0.391");
values("0.469");
}
}
}

View File

@ -74,7 +74,7 @@ cell (sram_2_16_1_freepdk45){
dont_use : true;
map_only : true;
dont_touch : true;
area : 0.023625;
area : 918.5120625;
bus(DATA){
bus_type : DATA;

View File

@ -74,7 +74,7 @@ cell (sram_2_16_1_freepdk45){
dont_use : true;
map_only : true;
dont_touch : true;
area : 0.023625;
area : 918.5120625;
bus(DATA){
bus_type : DATA;
@ -92,19 +92,19 @@ cell (sram_2_16_1_freepdk45){
internal_power(){
when : "OEb & !clk";
rise_power(scalar){
values("0.027781");
values("0.043273977");
}
fall_power(scalar){
values("0.026752");
values("0.042322667");
}
}
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -129,10 +129,10 @@ cell (sram_2_16_1_freepdk45){
internal_power(){
when : "!OEb & !clk";
rise_power(scalar){
values("0.031198");
values("0.088241812");
}
fall_power(scalar){
values("0.031252");
values("0.088188668");
}
}
timing(){
@ -140,24 +140,24 @@ cell (sram_2_16_1_freepdk45){
related_pin : "clk";
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("0.046, 0.047, 0.054",\
"0.047, 0.047, 0.054",\
"0.052, 0.052, 0.059");
values("0.055, 0.055, 0.063",\
"0.055, 0.056, 0.063",\
"0.061, 0.062, 0.069");
}
cell_fall(CELL_TABLE) {
values("0.132, 0.133, 0.142",\
"0.133, 0.134, 0.142",\
"0.138, 0.139, 0.147");
values("0.162, 0.163, 0.171",\
"0.163, 0.164, 0.172",\
"0.168, 0.169, 0.178");
}
rise_transition(CELL_TABLE) {
values("0.014, 0.015, 0.027",\
"0.014, 0.015, 0.027",\
"0.014, 0.015, 0.027");
values("0.015, 0.016, 0.028",\
"0.015, 0.016, 0.028",\
"0.015, 0.016, 0.028");
}
fall_transition(CELL_TABLE) {
values("0.018, 0.02, 0.036",\
"0.019, 0.02, 0.036",\
"0.019, 0.02, 0.036");
values("0.018, 0.02, 0.035",\
"0.018, 0.02, 0.035",\
"0.018, 0.02, 0.035");
}
}
}
@ -174,9 +174,9 @@ cell (sram_2_16_1_freepdk45){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -208,9 +208,9 @@ cell (sram_2_16_1_freepdk45){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -241,9 +241,9 @@ cell (sram_2_16_1_freepdk45){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -274,9 +274,9 @@ cell (sram_2_16_1_freepdk45){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
@ -308,20 +308,20 @@ cell (sram_2_16_1_freepdk45){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(scalar) {
values("0.1955");
values("0.2245");
}
fall_constraint(scalar) {
values("0.1955");
values("0.2245");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(scalar) {
values("0.391");
values("0.449");
}
fall_constraint(scalar) {
values("0.391");
values("0.449");
}
}
}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More