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 of Regents for the Oklahoma Agricultural and Mechanical College
(acting for and on behalf of Oklahoma State University) (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: The OpenRAM compiler has very few dependencies:
* ngspice-26 (or later) or HSpice I-2013.12-1 (or later) or CustomSim 2017 (or later) * 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 2.7 and higher (currently excludes Python 3 and up)
* Python numpy
* a setup script for each technology * a setup script for each technology
* a technology directory for each technology with the base cells * 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 You must set two environment variables: OPENRAM_HOME should point to
the compiler source directory. OPENERAM_TECH should point to a root the compiler source directory. OPENERAM_TECH should point to a root
technology directory that contains subdirs of all other technologies. 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: We do not distribute the PDK, but you may get it from:
https://www.eda.ncsu.edu/wiki/FreePDK45:Contents 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 # 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", "bitcell_array", "sense_amp_array", "precharge_array",
"column_mux_array", "write_driver_array", "tri_gate_array"] "column_mux_array", "write_driver_array", "tri_gate_array"]
for mod_name in mod_list: 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)) class_file = reload(__import__(config_mod_name))
mod_class = getattr(class_file , config_mod_name) mod_class = getattr(class_file , config_mod_name)
setattr (self, "mod_"+mod_name, mod_class) setattr (self, "mod_"+mod_name, mod_class)
@ -99,8 +99,10 @@ class bank(design.design):
self.add_precharge_array() self.add_precharge_array()
if self.col_addr_size > 0: 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.add_column_mux_array()
self.column_mux_height = self.column_mux_array.height
else: else:
self.column_mux_height = 0 self.column_mux_height = 0
if self.col_addr_size > 1: # size 1 is from addr FF if self.col_addr_size > 1: # size 1 is from addr FF
@ -234,8 +236,8 @@ class bank(design.design):
""" Adding Precharge """ """ Adding Precharge """
# The wells must be far enough apart # The wells must be far enough apart
# We use two well spacings because the bitcells tend to have a shared rail in the height # 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"] 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", self.precharge_array_inst=self.add_inst(name="precharge_array",
mod=self.precharge_array, mod=self.precharge_array,
offset=vector(0,y_offset)) offset=vector(0,y_offset))
@ -249,7 +251,7 @@ class bank(design.design):
def add_column_mux_array(self): def add_column_mux_array(self):
""" Adding Column Mux when words_per_row > 1 . """ """ 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", self.col_mux_array_inst=self.add_inst(name="column_mux_array",
mod=self.column_mux_array, mod=self.column_mux_array,
offset=vector(0,y_offset).scale(-1,-1)) 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 # 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) # 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) 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 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.column_size = cols
self.row_size = rows self.row_size = rows
c = reload(__import__(OPTS.config.bitcell)) c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.config.bitcell) self.mod_bitcell = getattr(c, OPTS.bitcell)
self.cell = self.mod_bitcell() self.cell = self.mod_bitcell()
self.add_mod(self.cell) 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.width = self.column_size*self.cell.width
self.add_pins() self.add_pins()
@ -115,8 +116,8 @@ class bitcell_array(design.design):
gnd_pins = self.cell_inst[0,col].get_pins("gnd") gnd_pins = self.cell_inst[0,col].get_pins("gnd")
for gnd_pin in gnd_pins: for gnd_pin in gnd_pins:
# avoid duplicates by only doing even rows # avoid duplicates by only doing even rows
# also skip if it is not the full height (a through rail) # also skip if it isn't the pin that spans the entire cell down to the bottom
if gnd_pin.layer=="metal2" and col%2 == 0 and gnd_pin.height()>=self.cell.height: if gnd_pin.layer=="metal2" and gnd_pin.by()==lower_y:
self.add_layout_pin(text="gnd", self.add_layout_pin(text="gnd",
layer="metal2", layer="metal2",
offset=gnd_pin.ll(), offset=gnd_pin.ll(),

View File

@ -8,22 +8,22 @@ import setup_hold
debug.info(2,"Initializing characterizer...") debug.info(2,"Initializing characterizer...")
spice_exe = "" OPTS.spice_exe = ""
if not OPTS.analytical_delay: if not OPTS.analytical_delay:
if OPTS.spice_name != "": if OPTS.spice_name != "":
spice_exe=find_exe(OPTS.spice_name) OPTS.spice_exe=find_exe(OPTS.spice_name)
if spice_exe=="": if OPTS.spice_exe=="":
debug.error("{0} not found. Unable to perform characterization.".format(OPTS.spice_name),1) debug.error("{0} not found. Unable to perform characterization.".format(OPTS.spice_name),1)
else: else:
(choice,spice_exe) = get_tool("spice",["xa", "hspice", "ngspice", "ngspice.exe"]) (OPTS.spice_name,OPTS.spice_exe) = get_tool("spice",["xa", "hspice", "ngspice", "ngspice.exe"])
OPTS.spice_name = choice
# set the input dir for spice files if using ngspice # set the input dir for spice files if using ngspice
if OPTS.spice_name == "ngspice": if OPTS.spice_name == "ngspice":
os.environ["NGSPICE_INPUT_DIR"] = "{0}".format(OPTS.openram_temp) 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) 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): 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 """ Creates a stimulus file for simulations to probe a bitcell at a given clock period.
(probe-address form: '111010000' LSB=0, MSB=1) Address and bit were previously set with set_probe().
(probe_data form: number corresponding to the bit position of data-bus, begins with position 0) Input slew (in ns) and output capacitive load (in fF) are required for charaterization.
""" """
self.check_arguments() self.check_arguments()
@ -52,7 +52,7 @@ class delay():
# creates and opens stimulus file for writing # creates and opens stimulus file for writing
temp_stim = "{0}/stim.sp".format(OPTS.openram_temp) temp_stim = "{0}/stim.sp".format(OPTS.openram_temp)
self.sf = open(temp_stim, "w") 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 # include files in stimulus file
model_list = tech.spice["fet_models"] + [self.sram_sp_file] model_list = tech.spice["fet_models"] + [self.sram_sp_file]
@ -116,8 +116,8 @@ class delay():
self.write_measures(period) self.write_measures(period)
# run until the last cycle time # run until the end of the cycle time
stimuli.write_control(self.sf,self.cycle_times[-1]) stimuli.write_control(self.sf,self.cycle_times[-1] + period)
self.sf.close() self.sf.close()
@ -125,11 +125,14 @@ class delay():
# meas statement for delay and power measurements # meas statement for delay and power measurements
self.sf.write("* Measure statements for delay and power\n") 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" trig_name = "clk"
targ_name = "{0}".format("d[{0}]".format(self.probe_data)) targ_name = "{0}".format("d[{0}]".format(self.probe_data))
trig_val = targ_val = 0.5 * self.vdd trig_val = targ_val = 0.5 * self.vdd
# add measure statments for delay0 # 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, stimuli.gen_meas_delay(stim_file=self.sf,
meas_name="DELAY0", meas_name="DELAY0",
trig_name=trig_name, trig_name=trig_name,
@ -138,7 +141,8 @@ class delay():
targ_val=targ_val, targ_val=targ_val,
trig_dir="FALL", trig_dir="FALL",
targ_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, stimuli.gen_meas_delay(stim_file=self.sf,
meas_name="DELAY1", meas_name="DELAY1",
@ -148,7 +152,8 @@ class delay():
targ_val=targ_val, targ_val=targ_val,
trig_dir="FALL", trig_dir="FALL",
targ_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)
stimuli.gen_meas_delay(stim_file=self.sf, stimuli.gen_meas_delay(stim_file=self.sf,
meas_name="SLEW0", meas_name="SLEW0",
@ -158,7 +163,8 @@ class delay():
targ_val=0.1*self.vdd, targ_val=0.1*self.vdd,
trig_dir="FALL", trig_dir="FALL",
targ_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, stimuli.gen_meas_delay(stim_file=self.sf,
meas_name="SLEW1", meas_name="SLEW1",
@ -168,7 +174,8 @@ class delay():
targ_val=0.9*self.vdd, targ_val=0.9*self.vdd,
trig_dir="RISE", trig_dir="RISE",
targ_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 # add measure statements for power
t_initial = self.cycle_times[self.write0_cycle] 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 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: 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) return (False,0,0,0,0)
delay0 *= 1e9 delay0 *= 1e9
delay1 *= 1e9 delay1 *= 1e9
slew0 *= 1e9 slew0 *= 1e9
slew1 *= 1e9 slew1 *= 1e9
if delay0>period or delay1>period or slew0>period or slew1>period: 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) return (False,0,0,0,0)
else: 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)) 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 slew in slews:
for load in loads: for load in loads:
(success, delay1, slew1, delay0, slew0) = self.run_simulation(feasible_period, load, slew) (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) LH_delay.append(delay1)
HL_delay.append(delay0) HL_delay.append(delay0)
LH_slew.append(slew1) 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 of the cycles to do a timing evaluation. The last time is the end of the simulation
and does not need a rising edge.""" and does not need a rising edge."""
self.cycle_comments = []
# idle cycle, no operation # idle cycle, no operation
t_current = period t_current = period
self.cycle_times = [] self.cycle_times = []
# cycle0: W data 1 address 1111 to initialize cell to a value # cycle0: W data 1 address 1111 to initialize cell to a value
self.cycle_times.append(t_current) 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 t_current += period
# cycle1: W data 0 address 1111 (to ensure a write of value works) # cycle1: W data 0 address 1111 (to ensure a write of value works)
self.cycle_times.append(t_current) self.cycle_times.append(t_current)
self.write0_cycle=1 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 t_current += period
# cycle2: W data 1 address 0000 (to clear the data bus cap) # cycle2: W data 1 address 0000 (to clear the data bus cap)
self.cycle_times.append(t_current) 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 t_current += period
# cycle3: R data 0 address 1111 to check W0 works # cycle3: R data 0 address 1111 to check W0 works
self.cycle_times.append(t_current) self.cycle_times.append(t_current)
self.read0_cycle=3 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 t_current += period
# cycle4: W data 1 address 1111 (to ensure a write of value works) # cycle4: W data 1 address 1111 (to ensure a write of value works)
self.cycle_times.append(t_current) self.cycle_times.append(t_current)
self.write1_cycle=4 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 t_current += period
# cycle5: W data 0 address 0000 (to clear the data bus cap) # cycle5: W data 0 address 0000 (to clear the data bus cap)
self.cycle_times.append(t_current) 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 t_current += period
# cycle6: R data 1 address 1111 to check W1 works # cycle6: R data 1 address 1111 to check W1 works
self.cycle_times.append(t_current) self.cycle_times.append(t_current)
self.read1_cycle=6 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 t_current += period
# cycle7: wait a clock period to end the simulation # cycle7: wait a clock period to end the simulation
self.cycle_times.append(t_current) self.cycle_times.append(t_current)
self.cycle_comments.append("Cycle7 {}ns: Idle period to end simulation".format(t_current))
t_current += period t_current += period

View File

@ -145,7 +145,8 @@ class setup_hold():
targ_val=targ_val, targ_val=targ_val,
trig_dir="RISE", trig_dir="RISE",
targ_dir=dout_rise_or_fall, 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" targ_name = "data"
# Start triggers right after initialize value is returned to normal # Start triggers right after initialize value is returned to normal
@ -158,7 +159,8 @@ class setup_hold():
targ_val=targ_val, targ_val=targ_val,
trig_dir="RISE", trig_dir="RISE",
targ_dir=din_rise_or_fall, 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)) 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""" """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, stim_file.write(measure_string.format(meas_name,
trig_name, trig_name,
trig_val, trig_val,
trig_dir, trig_dir,
trig_td,
targ_name, targ_name,
targ_val, targ_val,
targ_dir, targ_dir,
td)) targ_td))
def gen_meas_power(stim_file, meas_name, t_initial, t_final): def gen_meas_power(stim_file, meas_name, t_initial, t_final):
"""Creates the .meas statement for the measurement of avg power""" """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): def write_control(stim_file, end_time):
# UIC is needed for ngspice to converge # UIC is needed for ngspice to converge
stim_file.write(".TRAN 5p {0}n UIC\n".format(end_time)) stim_file.write(".TRAN 5p {0}n UIC\n".format(end_time))
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") stim_file.write(".OPTIONS POST=1 RUNLVL=4 PROBE\n")
# create plots for all signals # create plots for all signals
stim_file.write("* probe is used for hspice/xa, while plot is used in ngspice\n") stim_file.write("* probe is used for hspice/xa, while plot is used in ngspice\n")
if OPTS.debug_level>0: if OPTS.debug_level>0:
@ -265,7 +272,10 @@ def write_control(stim_file, end_time):
def write_include(stim_file, models): def write_include(stim_file, models):
"""Writes include statements, inputs are lists of model files""" """Writes include statements, inputs are lists of model files"""
for item in list(models): for item in list(models):
if os.path.isfile(item):
stim_file.write(".include \"{0}\"\n\n".format(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): def write_supply(stim_file):
@ -282,26 +292,26 @@ def run_sim():
temp_stim = "{0}stim.sp".format(OPTS.openram_temp) temp_stim = "{0}stim.sp".format(OPTS.openram_temp)
import datetime import datetime
start_time = datetime.datetime.now() 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": if OPTS.spice_name == "xa":
# Output the xa configurations here. FIXME: Move this to write it once. # Output the xa configurations here. FIXME: Move this to write it once.
xa_cfg = open("{}xa.cfg".format(OPTS.openram_temp), "w") xa_cfg = open("{}xa.cfg".format(OPTS.openram_temp), "w")
xa_cfg.write("set_sim_level -level 7\n") xa_cfg.write("set_sim_level -level 7\n")
xa_cfg.write("set_powernet_level 7 -node vdd\n") xa_cfg.write("set_powernet_level 7 -node vdd\n")
xa_cfg.close() 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, temp_stim,
OPTS.openram_temp) OPTS.openram_temp)
valid_retcode=0 valid_retcode=0
elif OPTS.spice_name == "hspice": elif OPTS.spice_name == "hspice":
# TODO: Should make multithreading parameter a configuration option # 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, temp_stim,
OPTS.openram_temp) OPTS.openram_temp)
valid_retcode=0 valid_retcode=0
else: 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, temp_stim,
OPTS.openram_temp) OPTS.openram_temp)
# for some reason, ngspice-25 returns 1 when it only has acceptable warnings # for some reason, ngspice-25 returns 1 when it only has acceptable warnings

View File

@ -46,22 +46,32 @@ class trim_spice():
# Always start fresh if we do multiple reductions # Always start fresh if we do multiple reductions
self.sp_buffer = self.spice self.sp_buffer = self.spice
# Find the row and column indices for the removals # Split up the address and convert to an int
# Convert address froms tring to int wl_address = int(address[self.col_addr_size:],2)
address = int(address,2) if self.col_addr_size>1:
array_row = address >> self.col_addr_size col_address = int(address[0:self.col_addr_size],2)
# 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: else:
lower_address=0 col_address = 0
# Which bit in the array
array_bit = lower_address*self.word_size + data_bit
# 1. Keep cells in the bitcell array based on WL and BL # 1. Keep cells in the bitcell array based on WL and BL
wl_name = "wl[{}]".format(array_row) wl_name = "wl[{}]".format(wl_address)
bl_name = "bl[{}]".format(array_bit) 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]) self.remove_insts("bitcell_array",[wl_name,bl_name])
# 2. Keep sense amps basd on BL # 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. 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 This class has enclosure on multiple sides of the contact whereas a via may
have extension on two or four sides. 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]): 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], name = "{0}_{1}_{2}_{3}x{4}".format(layer_stack[0],
layer_stack[1], layer_stack[1],
layer_stack[2], layer_stack[2],
dimensions[0], dimensions[0],
dimensions[1]) dimensions[1])
design.design.__init__(self, name) design.design.__init__(self, name)
debug.info(4, "create contact object {0}".format(name)) debug.info(4, "create contact object {0}".format(name))
self.layer_stack = layer_stack self.layer_stack = layer_stack
self.dimensions = dimensions self.dimensions = dimensions
self.offset = vector(0,0) self.offset = vector(0,0)
self.implant_type = implant_type
self.well_type = well_type
self.pins = [] # used for matching parm lengths self.pins = [] # used for matching parm lengths
self.create_layout() self.create_layout()
@ -37,73 +52,111 @@ class contact(design.design):
self.height = max(obj.offset.y + obj.height for obj in self.objs) 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) 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): def setup_layers(self):
(first_layer, via_layer, second_layer) = self.layer_stack (first_layer, via_layer, second_layer) = self.layer_stack
self.first_layer_name = first_layer self.first_layer_name = first_layer
self.via_layer_name = via_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 self.second_layer_name = second_layer
def setup_layout_constants(self): def setup_layout_constants(self):
self.contact_width = drc["minwidth_{0}". format(self.via_layer_name)] self.contact_width = drc["minwidth_{0}". format(self.via_layer_name)]
self.contact_to_contact = drc["{0}_to_{0}".format(self.via_layer_name)] contact_to_contact = drc["{0}_to_{0}".format(self.via_layer_name)]
self.contact_pitch = self.contact_width + self.contact_to_contact 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_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 self.contact_array_height = self.contact_width + (self.dimensions[1] - 1) * self.contact_pitch
# FIME break this up # DRC rules
self.first_layer_horizontal_enclosure = max((drc["minwidth_{0}".format(self.first_layer_name)] - self.contact_array_width) / 2, first_layer_minwidth = drc["minwidth_{0}".format(self.first_layer_name)]
drc["{0}_enclosure_{1}".format(self.first_layer_name, self.via_layer_name)]) first_layer_minarea = drc["minarea_{0}".format(self.first_layer_name)]
self.first_layer_vertical_enclosure = max(utils.ceil((drc["minarea_{0}".format(self.first_layer_name)] first_layer_enclosure = drc["{0}_enclosure_{1}".format(self.first_layer_name, self.via_layer_name)]
/ (self.contact_array_width + 2 * self.first_layer_horizontal_enclosure) - self.contact_array_height) / 2), first_layer_extend = drc["{0}_extend_{1}".format(self.first_layer_name, self.via_layer_name)]
(drc["minheight_{0}".format(self.first_layer_name)] - self.contact_array_height) / 2, second_layer_minwidth = drc["minwidth_{0}".format(self.second_layer_name)]
drc["{0}_extend_{1}".format(self.first_layer_name, self.via_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, self.first_layer_horizontal_enclosure = max((first_layer_minwidth - self.contact_array_width) / 2,
drc["{0}_enclosure_{1}".format(self.second_layer_name, self.via_layer_name)]) first_layer_enclosure)
self.second_layer_vertical_enclosure = max(utils.ceil((drc["minarea_{0}".format(self.second_layer_name)] self.first_layer_vertical_enclosure = max(utils.ceil((first_layer_minarea
/ (self.contact_array_width + 2 * self.second_layer_horizontal_enclosure) - self.contact_array_height) / 2), / (self.contact_array_width + 2*self.first_layer_horizontal_enclosure)
(drc["minheight_{0}".format(self.second_layer_name)] - self.contact_array_height) / 2, - self.contact_array_height)/2),
drc["{0}_extend_{1}".format(self.second_layer_name, self.via_layer_name)]) (first_layer_minwidth - self.contact_array_height)/2,
# offset for the via array first_layer_extend)
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)) self.second_layer_horizontal_enclosure = max((second_layer_minwidth - self.contact_array_width)/2,
# this is if the first and second layers are different second_layer_enclosure)
self.first_layer_position = vector(max(self.second_layer_horizontal_enclosure - self.first_layer_horizontal_enclosure,0), self.second_layer_vertical_enclosure = max(utils.ceil((second_layer_minarea
max(self.second_layer_vertical_enclosure - self.first_layer_vertical_enclosure,0)) / (self.contact_array_width + 2*self.second_layer_horizontal_enclosure)
self.second_layer_position = vector(max(self.first_layer_horizontal_enclosure - self.second_layer_horizontal_enclosure,0), - self.contact_array_height)/2),
max(self.first_layer_vertical_enclosure - self.second_layer_vertical_enclosure,0)) (second_layer_minwidth - self.contact_array_height)/2,
second_layer_extend)
def create_contact_array(self): def create_contact_array(self):
""" Create the contact array at the origin""" """ 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))
for i in range(self.dimensions[1]): for i in range(self.dimensions[1]):
offset = self.via_layer_position + vector(0, self.contact_pitch * i) offset = self.via_layer_position + vector(0, self.contact_pitch * i)
for j in range(self.dimensions[0]): 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, offset=offset,
width=self.contact_width, width=self.contact_width,
height=self.contact_width) height=self.contact_width)
offset = offset + vector(self.contact_pitch,0) offset = offset + vector(self.contact_pitch,0)
def create_first_layer_enclosure(self): def create_first_layer_enclosure(self):
width = self.first_layer_width = self.contact_array_width \ # this is if the first and second layers are different
+ 2 * self.first_layer_horizontal_enclosure self.first_layer_position = vector(max(self.second_layer_horizontal_enclosure - self.first_layer_horizontal_enclosure,0),
height = self.first_layer_height = self.contact_array_height \ max(self.second_layer_vertical_enclosure - self.first_layer_vertical_enclosure,0))
+ 2 * self.first_layer_vertical_enclosure
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, self.add_rect(layer=self.first_layer_name,
offset=self.first_layer_position, offset=self.first_layer_position,
width=width, width=self.first_layer_width,
height=height) height=self.first_layer_height)
def create_second_layer_enclosure(self): def create_second_layer_enclosure(self):
width = self.second_layer_width = self.contact_array_width \ # this is if the first and second layers are different
+ 2 * self.second_layer_horizontal_enclosure self.second_layer_position = vector(max(self.first_layer_horizontal_enclosure - self.second_layer_horizontal_enclosure,0),
height = self.second_layer_height = self.contact_array_height \ max(self.first_layer_vertical_enclosure - self.second_layer_vertical_enclosure,0))
+ 2 * self.second_layer_vertical_enclosure
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, self.add_rect(layer=self.second_layer_name,
offset=self.second_layer_position, offset=self.second_layer_position,
width=width, width=self.second_layer_width,
height=height) 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)

View File

@ -59,15 +59,15 @@ class control_logic(design.design):
self.inv16 = pinv(16) self.inv16 = pinv(16)
self.add_mod(self.inv16) self.add_mod(self.inv16)
c = reload(__import__(OPTS.config.ms_flop_array)) c = reload(__import__(OPTS.ms_flop_array))
ms_flop_array = getattr(c, OPTS.config.ms_flop_array) ms_flop_array = getattr(c, OPTS.ms_flop_array)
self.msf_control = ms_flop_array(name="msf_control", self.msf_control = ms_flop_array(name="msf_control",
columns=3, columns=3,
word_size=3) word_size=3)
self.add_mod(self.msf_control) self.add_mod(self.msf_control)
c = reload(__import__(OPTS.config.replica_bitline)) c = reload(__import__(OPTS.replica_bitline))
replica_bitline = getattr(c, OPTS.config.replica_bitline) replica_bitline = getattr(c, OPTS.replica_bitline)
self.replica_bitline = replica_bitline(rows=int(math.ceil(self.num_rows / 10.0))) self.replica_bitline = replica_bitline(rows=int(math.ceil(self.num_rows / 10.0)))
self.add_mod(self.replica_bitline) 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 # 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) 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 # 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.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"]) 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. # 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"]) 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 # First RAIL Parameters: gnd, oe, oebar, cs, we, clk_buf, clk_bar
self.rail_1_start_x = 0 self.rail_1_start_x = 0
self.num_rails_1 = 8 self.num_rails_1 = 8
@ -275,7 +269,7 @@ class control_logic(design.design):
mod=self.nand2, mod=self.nand2,
offset=self.tri_en_bar_offset, offset=self.tri_en_bar_offset,
mirror="MX") 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.nand2.width
x_off += self.inv1.width + self.cell_gap x_off += self.inv1.width + self.cell_gap
@ -326,6 +320,7 @@ class control_logic(design.design):
x_off += self.inv1.width x_off += self.inv1.width
# BUFFER INVERTERS FOR W_EN # 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_offset = vector(x_off, y_off)
self.pre_w_en_bar=self.add_inst(name="inv_pre_w_en_bar", self.pre_w_en_bar=self.add_inst(name="inv_pre_w_en_bar",
mod=self.inv1, mod=self.inv1,
@ -512,10 +507,24 @@ class control_logic(design.design):
offset=clk_buf_rail_position, offset=clk_buf_rail_position,
rotate=90) rotate=90)
# clk_bar # clk_bar, routes over the clock buffer vdd rail
self.connect_rail_from_left_m2m3(self.clk_bar,"Z","clk_bar") 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"), 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) rotate=90)
# clk_buf to msf control flops # clk_buf to msf control flops

View File

@ -14,14 +14,13 @@ def check(check,str):
index) = inspect.getouterframes(inspect.currentframe())[1] index) = inspect.getouterframes(inspect.currentframe())[1]
if not check: if not check:
print("ERROR: file {0}: line {1}: {2}".format(os.path.basename(filename),line_number,str)) 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, (frame, filename, line_number, function_name, lines,
index) = inspect.getouterframes(inspect.currentframe())[1] index) = inspect.getouterframes(inspect.currentframe())[1]
print("ERROR: file {0}: line {1}: {2}".format(os.path.basename(filename),line_number,str)) print("ERROR: file {0}: line {1}: {2}".format(os.path.basename(filename),line_number,str))
if return_value: assert return_value==0
sys.exit(return_value)
def warning(str): def warning(str):
(frame, filename, line_number, function_name, lines, (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_inverters = 1 + sum(fanout_list)
self.num_top_half = round(self.num_inverters / 2.0) self.num_top_half = round(self.num_inverters / 2.0)
c = reload(__import__(OPTS.config.bitcell)) c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.config.bitcell) self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell() self.bitcell = self.mod_bitcell()
self.add_pins() 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 # Check if the name already exists, if so, give an error
# because each reference must be a unique name. # because each reference must be a unique name.
ok_list = ['ms_flop.ms_flop', 'bitcell.bitcell', 'contact.contact', # These modules ensure unique names or have no changes if they
'ptx.ptx', 'sram.sram', # aren't unique
ok_list = ['ms_flop.ms_flop',
'bitcell.bitcell',
'contact.contact',
'ptx.ptx',
'sram.sram',
'hierarchical_predecode2x4.hierarchical_predecode2x4', 'hierarchical_predecode2x4.hierarchical_predecode2x4',
'hierarchical_predecode3x8.hierarchical_predecode3x8'] 'hierarchical_predecode3x8.hierarchical_predecode3x8']
if name not in design.name_map: if name not in design.name_map:
@ -41,6 +46,7 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
def setup_drc_constants(self): def setup_drc_constants(self):
""" These are some DRC constants used in many places in the compiler.""" """ These are some DRC constants used in many places in the compiler."""
from tech import drc from tech import drc
self.well_width = drc["minwidth_well"]
self.poly_width = drc["minwidth_poly"] self.poly_width = drc["minwidth_poly"]
self.poly_space = drc["poly_to_poly"] self.poly_space = drc["poly_to_poly"]
self.m1_width = drc["minwidth_metal1"] self.m1_width = drc["minwidth_metal1"]
@ -49,6 +55,15 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
self.m2_space = drc["metal2_to_metal2"] self.m2_space = drc["metal2_to_metal2"]
self.m3_width = drc["minwidth_metal3"] self.m3_width = drc["minwidth_metal3"]
self.m3_space = drc["metal3_to_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): def get_layout_pins(self,inst):
""" Return a map of pin locations of the instance offset """ """ Return a map of pin locations of the instance offset """
@ -62,7 +77,7 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
return inst_map return inst_map
def DRC_LVS(self): def DRC_LVS(self, final_verification=False):
"""Checks both DRC and LVS for a module""" """Checks both DRC and LVS for a module"""
if OPTS.check_lvsdrc: if OPTS.check_lvsdrc:
tempspice = OPTS.openram_temp + "/temp.sp" tempspice = OPTS.openram_temp + "/temp.sp"
@ -70,7 +85,7 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
self.sp_write(tempspice) self.sp_write(tempspice)
self.gds_write(tempgds) self.gds_write(tempgds)
debug.check(verify.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name)) 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(tempspice)
os.remove(tempgds) 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)) debug.check(verify.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name))
os.remove(tempgds) os.remove(tempgds)
def LVS(self): def LVS(self, final_verification=False):
"""Checks LVS for a module""" """Checks LVS for a module"""
if OPTS.check_lvsdrc: if OPTS.check_lvsdrc:
tempspice = OPTS.openram_temp + "/temp.sp" tempspice = OPTS.openram_temp + "/temp.sp"
tempgds = OPTS.openram_temp + "/temp.gds" tempgds = OPTS.openram_temp + "/temp.gds"
self.sp_write(tempspice) self.sp_write(tempspice)
self.gds_write(tempgds) 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(tempspice)
os.remove(tempgds) os.remove(tempgds)

View File

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

View File

@ -21,8 +21,8 @@ class hierarchical_decoder(design.design):
def __init__(self, rows): def __init__(self, rows):
design.design.__init__(self, "hierarchical_decoder_{0}rows".format(rows)) design.design.__init__(self, "hierarchical_decoder_{0}rows".format(rows))
c = reload(__import__(OPTS.config.bitcell)) c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.config.bitcell) self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell_height = self.mod_bitcell.height self.bitcell_height = self.mod_bitcell.height
self.pre2x4_inst = [] 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)) 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)) design.design.__init__(self, name="pre{0}x{1}".format(self.number_of_inputs,self.number_of_outputs))
c = reload(__import__(OPTS.config.bitcell)) c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.config.bitcell) self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell_height = self.mod_bitcell.height self.bitcell_height = self.mod_bitcell.height

View File

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

View File

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

View File

@ -61,20 +61,43 @@ class layout(lef.lef):
"""Finds the lowest set of 2d cartesian coordinates within """Finds the lowest set of 2d cartesian coordinates within
this layout""" this layout"""
if len(self.objs)>0:
lowestx1 = min(obj.lx() for obj in self.objs if obj.name!="label") 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") 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) lowestx2 = min(inst.lx() for inst in self.insts)
lowesty2 = min(inst.by() 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)) return vector(min(lowestx1, lowestx2), min(lowesty1, lowesty2))
def find_highest_coords(self): def find_highest_coords(self):
"""Finds the highest set of 2d cartesian coordinates within """Finds the highest set of 2d cartesian coordinates within
this layout""" 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") if len(self.objs)>0:
highestx2 = min(inst.rx() for inst in self.insts) highestx1 = max(obj.rx() for obj in self.objs if obj.name!="label")
highesty2 = min(inst.uy() for inst in self.insts) highesty1 = max(obj.uy() for obj in self.objs if obj.name!="label")
return vector(min(highestx1, highestx2), min(highesty1, highesty2)) 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): def translate_all(self, offset):
@ -143,9 +166,11 @@ class layout(lef.lef):
debug.error("Nonrectilinear center rect!",-1) debug.error("Nonrectilinear center rect!",-1)
elif start.x!=end.x: elif start.x!=end.x:
offset = vector(0,0.5*minwidth_layer) offset = vector(0,0.5*minwidth_layer)
return self.add_rect(layer,start-offset,end.x-start.x,minwidth_layer)
else: else:
offset = vector(0.5*minwidth_layer,0) 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): def get_pin(self, text):
@ -308,42 +333,50 @@ class layout(lef.lef):
layer_stack=layers, layer_stack=layers,
position_list=coordinates) 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.""" """ This is just an alias for a via."""
return self.add_via(layers=layers, return self.add_via(layers=layers,
offset=offset, offset=offset,
size=size, size=size,
mirror=mirror, 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.""" """ This is just an alias for a via."""
return self.add_via_center(layers=layers, return self.add_via_center(layers=layers,
offset=offset, offset=offset,
size=size, size=size,
mirror=mirror, 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. """ """ Add a three layer via structure. """
import contact import contact
via = contact.contact(layer_stack=layers, via = contact.contact(layer_stack=layers,
dimensions=size) dimensions=size,
implant_type=implant_type,
well_type=well_type)
self.add_mod(via) self.add_mod(via)
self.add_inst(name=via.name, inst=self.add_inst(name=via.name,
mod=via, mod=via,
offset=offset, offset=offset,
mirror=mirror, mirror=mirror,
rotate=rotate) rotate=rotate)
# We don't model the logical connectivity of wires/paths # We don't model the logical connectivity of wires/paths
self.connect_inst([]) 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. """ """ Add a three layer via structure by the center coordinate accounting for mirroring and rotation. """
import contact import contact
via = contact.contact(layer_stack=layers, 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.") 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_mod(via)
self.add_inst(name=via.name, inst=self.add_inst(name=via.name,
mod=via, mod=via,
offset=corrected_offset, offset=corrected_offset,
mirror=mirror, mirror=mirror,
rotate=rotate) rotate=rotate)
# We don't model the logical connectivity of wires/paths # We don't model the logical connectivity of wires/paths
self.connect_inst([]) self.connect_inst([])
return via return inst
def add_ptx(self, offset, mirror="R0", rotate=0, width=1, mults=1, tx_type="nmos"): def add_ptx(self, offset, mirror="R0", rotate=0, width=1, mults=1, tx_type="nmos"):
"""Adds a ptx module to the design.""" """Adds a ptx module to the design."""
@ -379,12 +412,12 @@ class layout(lef.lef):
mults=mults, mults=mults,
tx_type=tx_type) tx_type=tx_type)
self.add_mod(mos) self.add_mod(mos)
self.add_inst(name=mos.name, inst=self.add_inst(name=mos.name,
mod=mos, mod=mos,
offset=offset, offset=offset,
mirror=mirror, mirror=mirror,
rotate=rotate) rotate=rotate)
return mos return inst
@ -488,6 +521,26 @@ class layout(lef.lef):
return blockages 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): def pdf_write(self, pdf_name):
# NOTE: Currently does not work (Needs further research) # NOTE: Currently does not work (Needs further research)
#self.pdf_name = self.name + ".pdf" #self.pdf_name = self.name + ".pdf"

View File

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

View File

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

View File

@ -39,19 +39,19 @@ globals.print_banner()
globals.init_openram(args[0]) globals.init_openram(args[0])
# Check if all arguments are integers for bits, size, banks # Check if all arguments are integers for bits, size, banks
if type(OPTS.config.word_size)!=int: if type(OPTS.word_size)!=int:
debug.error("{0} is not an integer in config file.".format(OPTS.config.word_size)) debug.error("{0} is not an integer in config file.".format(OPTS.word_size))
if type(OPTS.config.num_words)!=int: if type(OPTS.num_words)!=int:
debug.error("{0} is not an integer in config file.".format(OPTS.config.sram_size)) debug.error("{0} is not an integer in config file.".format(OPTS.sram_size))
if type(OPTS.config.num_banks)!=int: if type(OPTS.num_banks)!=int:
debug.error("{0} is not an integer in config file.".format(OPTS.config.num_banks)) 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.") debug.error("Tech name must be specified in config file.")
word_size = OPTS.config.word_size word_size = OPTS.word_size
num_words = OPTS.config.num_words num_words = OPTS.num_words
num_banks = OPTS.config.num_banks num_banks = OPTS.num_banks
if (OPTS.output_name == ""): if (OPTS.output_name == ""):
OPTS.output_name = "sram_{0}_{1}_{2}_{3}".format(word_size, 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, num_banks=num_banks,
name=OPTS.output_name) name=OPTS.output_name)
last_time=print_time("SRAM creation", datetime.datetime.now(), last_time) 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 # Output the files for the resulting SRAM

View File

@ -4,7 +4,8 @@ import os
class options(optparse.Values): 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. # This is the technology directory.
@ -13,6 +14,7 @@ class options(optparse.Values):
tech_name = "" tech_name = ""
# This is the temp directory where all intermediate results are stored. # 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 = "/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 # This is the verbosity level to control debug information. 0 is none, 1
# is minimal, etc. # is minimal, etc.
debug_level = 0 debug_level = 0
@ -23,9 +25,9 @@ class options(optparse.Values):
# Should we print out the banner at startup # Should we print out the banner at startup
print_banner = True print_banner = True
# The DRC/LVS/PEX executable being used which is derived from the user PATH. # The DRC/LVS/PEX executable being used which is derived from the user PATH.
drc_exe = "" drc_exe = None
lvs_exe = "" lvs_exe = None
pex_exe = "" pex_exe = None
# The spice executable being used which is derived from the user PATH. # The spice executable being used which is derived from the user PATH.
spice_exe = "" spice_exe = ""
# Run with extracted parasitics # Run with extracted parasitics
@ -35,8 +37,32 @@ class options(optparse.Values):
# Use detailed LEF blockages # Use detailed LEF blockages
detailed_blockages = True detailed_blockages = True
# Define the output file paths # Define the output file paths
output_path = "" output_path = "."
# Define the output file base name # Define the output file base name
output_name = "" output_name = "sram"
# Use analytical delay models by default rather than (slow) characterization # Use analytical delay models by default rather than (slow) characterization
analytical_delay = True 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.") 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 # 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) pmos_gate_pos = vector(nmos_gate_pos.x,pmos_gate_pin.bc().y)
self.add_path("poly",[nmos_gate_pos,pmos_gate_pos]) self.add_path("poly",[nmos_gate_pos,pmos_gate_pos])
@ -97,93 +97,117 @@ class pgate(design.design):
def extend_wells(self, middle_position): def extend_wells(self, middle_position):
""" Extend the n/p wells to cover whole cell """ """ 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"]: if info["has_nwell"]:
self.add_rect(layer="nwell", self.add_rect(layer="nwell",
offset=middle_position, offset=middle_position,
width=self.well_width, width=self.well_width,
height=nwell_height) height=nwell_height)
self.add_rect(layer="vtg", self.add_rect(layer="vtg",
offset=middle_position, offset=self.nwell_position,
width=self.well_width, width=self.well_width,
height=nwell_height) height=nwell_height)
pwell_position = vector(0,-0.5*self.m1_width)
pwell_height = middle_position.y-pwell_position.y
if info["has_pwell"]: if info["has_pwell"]:
self.add_rect(layer="pwell", self.add_rect(layer="pwell",
offset=vector(0,0), offset=pwell_position,
width=self.well_width, width=self.well_width,
height=middle_position.y) height=pwell_height)
self.add_rect(layer="vtg", self.add_rect(layer="vtg",
offset=vector(0,0), offset=pwell_position,
width=self.well_width, width=self.well_width,
height=middle_position.y) height=pwell_height)
def add_nwell_contact(self, nmos, nmos_pos): def add_nwell_contact(self, pmos, pmos_pos):
""" Add an nwell contact next to the given nmos device. """ """ Add an nwell contact next to the given pmos device. """
layer_stack = ("active", "contact", "metal1") 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 # 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"] 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 # Must be at least an well enclosure of active down from the top of the well
pwell_offset = vector(pwell_contact_xoffset, pwell_contact_yoffset) # OR align the active with the top of PMOS active.
# Offset by half a contact max_y_offset = self.height + 0.5*self.m1_width
pwell_offset += vector(0.5*pmos.active_contact.first_layer_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) 0.5*pmos.active_contact.first_layer_height)
self.pwell_contact=self.add_contact_center(layers=layer_stack, self.nwell_contact=self.add_contact_center(layers=layer_stack,
offset=pwell_offset) offset=contact_offset,
implant_type="n",
well_type="n")
self.add_rect_center(layer="metal1", self.add_rect_center(layer="metal1",
offset=pwell_offset + vector(0,0.5*(self.height-pwell_offset.y)), offset=contact_offset + vector(0,0.5*(self.height-contact_offset.y)),
width=self.pwell_contact.second_layer_width, width=self.nwell_contact.mod.second_layer_width,
height=self.height - pwell_offset.y) height=self.height - contact_offset.y)
# Now add the full active and implant for the PMOS # Now add the full active and implant for the PMOS
pwell_offset = pmos_pos + vector(pmos.active_width,0) #active_offset = pmos_pos + vector(pmos.active_width,0)
pwell_contact_width = drc["active_to_body_active"] + pmos.active_contact.width # This might be needed if the spacing between the actives is not satisifed
self.add_rect(layer="active", # self.add_rect(layer="active",
offset=pwell_offset, # offset=active_offset,
width=pwell_contact_width, # width=pmos.active_contact.width,
height=pmos.active_height) # 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)
implant_offset = pwell_offset + vector(drc["implant_to_implant"],0) # Return the top of the well
implant_width = pwell_contact_width - drc["implant_to_implant"]
self.add_rect(layer="nimplant", def add_pwell_contact(self, nmos, nmos_pos):
offset=implant_offset, """ Add an pwell contact next to the given nmos device. """
width=implant_width,
height=pmos.active_height) 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 from center of rail to rail.. The route_output will route the
output to the right side of the cell for easier access. output to the right side of the cell for easier access.
""" """
c = reload(__import__(OPTS.config.bitcell)) c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.config.bitcell) bitcell = getattr(c, OPTS.bitcell)
unique_id = 1 unique_id = 1
@ -57,8 +57,8 @@ class pinv(pgate.pgate):
self.setup_layout_constants() self.setup_layout_constants()
self.add_supply_rails() self.add_supply_rails()
self.add_ptx() self.add_ptx()
self.extend_wells(self.well_pos)
self.add_well_contacts() self.add_well_contacts()
self.extend_wells(self.well_pos)
self.connect_rails() self.connect_rails()
self.route_input_gate(self.pmos_inst, self.nmos_inst, self.output_pos.y, "A", rotate=0) self.route_input_gate(self.pmos_inst, self.nmos_inst, self.output_pos.y, "A", rotate=0)
self.route_outputs() self.route_outputs()
@ -128,9 +128,6 @@ class pinv(pgate.pgate):
self.width = self.well_width self.width = self.well_width
# Height is an input parameter, so it is not recomputed. # 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): def create_ptx(self):
@ -183,8 +180,13 @@ class pinv(pgate.pgate):
self.connect_inst(["Z", "A", "gnd", "gnd"]) self.connect_inst(["Z", "A", "gnd", "gnd"])
# Output position will be in between the PMOS and NMOS # Output position will be in between the PMOS and NMOS drains
self.output_pos = vector(0,0.5*(self.pmos_pos.y+self.nmos_pos.y+self.nmos.active_height)) 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())
@ -196,7 +198,7 @@ class pinv(pgate.pgate):
pmos_drain_pin = self.pmos_inst.get_pin("D") pmos_drain_pin = self.pmos_inst.get_pin("D")
# Pick point at right most of NMOS and connect down to PMOS # 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) 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) pmos_drain_pos = vector(nmos_drain_pos.x, pmos_drain_pin.bc().y)
self.add_path("metal1",[nmos_drain_pos,pmos_drain_pos]) self.add_path("metal1",[nmos_drain_pos,pmos_drain_pos])
@ -220,9 +222,9 @@ class pinv(pgate.pgate):
def add_well_contacts(self): 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 """
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): def connect_rails(self):
""" Connect the nmos and pmos to its respective power rails """ """ 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. This model use ptx to generate a 2-input nand within a cetrain height.
""" """
c = reload(__import__(OPTS.config.bitcell)) c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.config.bitcell) bitcell = getattr(c, OPTS.bitcell)
unique_id = 1 unique_id = 1
@ -50,8 +50,8 @@ class pnand2(pgate.pgate):
self.setup_layout_constants() self.setup_layout_constants()
self.add_supply_rails() self.add_supply_rails()
self.add_ptx() self.add_ptx()
self.add_well_contacts()
self.connect_rails() self.connect_rails()
self.add_well_contacts()
self.extend_wells(self.well_pos) self.extend_wells(self.well_pos)
self.route_inputs() self.route_inputs()
self.route_output() self.route_output()
@ -94,9 +94,6 @@ class pnand2(pgate.pgate):
self.width = self.well_width self.width = self.well_width
# Height is an input parameter, so it is not recomputed. # 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 # 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) extra_contact_space = max(-self.nmos.get_pin("D").by(),0)
# This is a poly-to-poly of a flipped cell # 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", self.nmos1_inst=self.add_inst(name="pnand2_nmos1",
mod=self.nmos, mod=self.nmos,
offset=nmos1_pos) 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_pos = nmos1_pos + self.overlap_offset
self.nmos2_inst=self.add_inst(name="pnand2_nmos2", self.nmos2_inst=self.add_inst(name="pnand2_nmos2",
mod=self.nmos, mod=self.nmos,
offset=self.nmos2_pos) 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 # 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)) self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height))
def add_well_contacts(self): # This will help with the wells
""" Add n/p well taps to the layout and connect to supplies """ self.well_pos = vector(0,self.nmos1_inst.uy())
self.add_nwell_contact(self.nmos, self.nmos2_pos) def add_well_contacts(self):
self.add_pwell_contact(self.pmos, self.pmos2_pos) """ Add n/p well taps to the layout and connect to supplies AFTER the wells are created """
self.add_nwell_contact(self.pmos, self.pmos2_pos)
self.add_pwell_contact(self.nmos, self.nmos2_pos)
def connect_rails(self): 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. This model use ptx to generate a 2-input nand within a cetrain height.
""" """
c = reload(__import__(OPTS.config.bitcell)) c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.config.bitcell) bitcell = getattr(c, OPTS.bitcell)
unique_id = 1 unique_id = 1
@ -24,7 +24,9 @@ class pnand3(pgate.pgate):
pgate.pgate.__init__(self, name) pgate.pgate.__init__(self, name)
debug.info(2, "create pnand3 structure {0} with size of {1}".format(name, size)) 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.pmos_size = parameter["beta"]*size
self.nmos_width = self.nmos_size*drc["minwidth_tx"] self.nmos_width = self.nmos_size*drc["minwidth_tx"]
self.pmos_width = self.pmos_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.setup_layout_constants()
self.add_supply_rails() self.add_supply_rails()
self.add_ptx() self.add_ptx()
self.add_well_contacts()
self.connect_rails() self.connect_rails()
self.add_well_contacts()
self.extend_wells(self.well_pos) self.extend_wells(self.well_pos)
self.route_inputs() self.route_inputs()
self.route_output() self.route_output()
@ -88,13 +90,13 @@ class pnand3(pgate.pgate):
# This will help with the wells and the input/output placement # This will help with the wells and the input/output placement
self.output_pos = vector(0,0.5*self.height) 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 a poly-to-poly of a flipped cell
# This is extra liberal for pnand3 because we know there are big transistor sizes self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
# and so contacts won't interfere with the rails. Therefore, ignore metal spacing. drc["poly_extend_active"], self.poly_space)
# 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)
def add_supply_rails(self): def add_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """ """ 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", self.nmos1_inst=self.add_inst(name="pnand3_nmos1",
mod=self.nmos, mod=self.nmos,
offset=nmos1_pos) offset=nmos1_pos)
self.connect_inst(["Z", "A", "net1", "gnd"]) self.connect_inst(["Z", "C", "net1", "gnd"])
nmos2_pos = nmos1_pos + self.overlap_offset nmos2_pos = nmos1_pos + self.overlap_offset
self.nmos2_inst=self.add_inst(name="pnand3_nmos2", 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", self.nmos3_inst=self.add_inst(name="pnand3_nmos3",
mod=self.nmos, mod=self.nmos,
offset=self.nmos3_pos) 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): 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 """
self.add_nwell_contact(self.nmos, self.nmos3_pos) self.add_nwell_contact(self.pmos, self.pmos3_pos)
self.add_pwell_contact(self.pmos, self.pmos3_pos) self.add_pwell_contact(self.nmos, self.nmos3_pos)
def connect_rails(self): 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. This model use ptx to generate a 2-input nor within a cetrain height.
""" """
c = reload(__import__(OPTS.config.bitcell)) c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.config.bitcell) bitcell = getattr(c, OPTS.bitcell)
unique_id = 1 unique_id = 1
@ -51,8 +51,8 @@ class pnor2(pgate.pgate):
self.setup_layout_constants() self.setup_layout_constants()
self.add_supply_rails() self.add_supply_rails()
self.add_ptx() self.add_ptx()
self.add_well_contacts()
self.connect_rails() self.connect_rails()
self.add_well_contacts()
self.extend_wells(self.well_pos) self.extend_wells(self.well_pos)
self.route_inputs() self.route_inputs()
self.route_output() self.route_output()
@ -98,9 +98,6 @@ class pnor2(pgate.pgate):
self.width = self.well_width self.width = self.well_width
# Height is an input parameter, so it is not recomputed. # 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 # 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) extra_contact_space = max(-self.nmos.get_pin("D").by(),0)
# This is a poly-to-poly of a flipped cell # 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 # 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)) 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): 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 """
self.add_nwell_contact(self.nmos, self.nmos2_pos) self.add_nwell_contact(self.pmos, self.pmos2_pos)
self.add_pwell_contact(self.pmos, self.pmos2_pos) self.add_pwell_contact(self.nmos, self.nmos2_pos)
def connect_rails(self): def connect_rails(self):

View File

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

View File

@ -17,7 +17,7 @@ class precharge_array(design.design):
self.columns = columns 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.add_mod(self.pc_cell)
self.width = self.columns * self.pc_cell.width self.width = self.columns * self.pc_cell.width

View File

@ -61,15 +61,19 @@ class ptx(design.design):
def create_spice(self): def create_spice(self):
self.add_pin_list(["D", "G", "S", "B"]) self.add_pin_list(["D", "G", "S", "B"])
self.spice.append("\n.SUBCKT {0} {1}".format(self.name, # self.spice.append("\n.SUBCKT {0} {1}".format(self.name,
" ".join(self.pins))) # " ".join(self.pins)))
self.spice.append("M{0} {1} {2} m={3} w={4}u l={5}u".format(self.tx_type, # Just make a guess since these will actually be decided in the layout later.
" ".join(self.pins), area_sd = 2.5*drc["minwidth_poly"]*self.tx_width
spice[self.tx_type], 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.mults,
self.tx_width, self.tx_width,
drc["minwidth_poly"])) drc["minwidth_poly"],
self.spice.append(".ENDS {0}".format(self.name)) 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): def setup_layout_constants(self):
""" """
@ -94,25 +98,19 @@ class ptx(design.design):
self.active_contact = contact(layer_stack=("active", "contact", "metal1"), self.active_contact = contact(layer_stack=("active", "contact", "metal1"),
dimensions=(1, self.num_contacts)) 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) # 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, self.poly_pitch = max(2*self.contact_to_gate + self.contact_width + self.poly_width,
drc["poly_to_poly"]) self.poly_space)
# The contacted poly pitch (or uncontacted in an odd technology) # 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. # The enclosure of an active contact. Not sure about second term.
active_enclose_contact = max(drc["active_enclosure_contact"], 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 # 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, # 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 # Poly height must include poly extension over active
self.poly_height = self.tx_width + 2*self.poly_extend_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 # Well enclosure of active, ensure minwidth as well
if info["has_{}well".format(self.well_type)]: if info["has_{}well".format(self.well_type)]:
self.well_width = max(self.active_width + 2*drc["well_enclosure_active"], self.cell_well_width = max(self.active_width + 2*self.well_enclose_active,
drc["minwidth_well"]) self.well_width)
self.well_height = max(self.tx_width + 2*drc["well_enclosure_active"], self.cell_well_height = max(self.tx_width + 2*self.well_enclose_active,
drc["minwidth_well"]) self.well_width)
# We are going to shift the 0,0, so include that in the width and height
self.height = self.well_height self.height = self.cell_well_height - self.active_offset.y
self.width = self.well_width self.width = self.cell_well_width - self.active_offset.x
else: else:
# If no well, use the boundary of the active and poly # If no well, use the boundary of the active and poly
self.height = self.poly_height self.height = self.poly_height
self.width = self.active_width self.width = self.active_width
# The active offset is due to the well extension # 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) # 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, 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 # 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 # of the contacts to avoid DRC violations to the other contacts
pin_offset = vector(0, 0.5*self.active_contact.second_layer_height \ pin_offset = vector(0, 0.5*self.active_contact.second_layer_height \
+ drc["metal1_to_metal1"] + 0.5*drc["minwidth_metal1"]) + self.m1_space + 0.5*self.m1_width)
# This is the width of a contact to extend the ends of the pin # This is the width of a m1 extend the ends of the pin
end_offset = vector(self.active_contact.second_layer_width/2,0) end_offset = vector(self.m1_width/2,0)
# drains always go to the MIDDLE of the cell, so top of NMOS, bottom of PMOS # 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. # so reverse the directions for NMOS compared to PMOS.
@ -264,6 +265,14 @@ class ptx(design.design):
offset=self.active_offset, offset=self.active_offset,
width=self.active_width, width=self.active_width,
height=self.active_height) 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): def add_well_implant(self):
""" """
@ -272,16 +281,12 @@ class ptx(design.design):
if info["has_{}well".format(self.well_type)]: if info["has_{}well".format(self.well_type)]:
self.add_rect(layer="{}well".format(self.well_type), self.add_rect(layer="{}well".format(self.well_type),
offset=(0,0), offset=(0,0),
width=self.well_width, width=self.cell_well_width,
height=self.well_height) height=self.cell_well_height)
self.add_rect(layer="vtg", self.add_rect(layer="vtg",
offset=(0,0), offset=(0,0),
width=self.well_width, width=self.cell_well_width,
height=self.well_height) height=self.cell_well_height)
self.add_rect(layer="{}implant".format(self.implant_type),
offset=self.active_offset,
width=self.active_width,
height=self.active_height)
def calculate_num_contacts(self): def calculate_num_contacts(self):
@ -321,23 +326,27 @@ class ptx(design.design):
for pos in source_positions: for pos in source_positions:
contact=self.add_contact_center(layers=("active", "contact", "metal1"), contact=self.add_contact_center(layers=("active", "contact", "metal1"),
offset=pos, 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", self.add_layout_pin_center_rect(text="S",
layer="metal1", layer="metal1",
offset=pos, offset=pos,
width=contact.second_layer_width, width=contact.mod.second_layer_width,
height=contact.second_layer_height) height=contact.mod.second_layer_height)
for pos in drain_positions: for pos in drain_positions:
contact=self.add_contact_center(layers=("active", "contact", "metal1"), contact=self.add_contact_center(layers=("active", "contact", "metal1"),
offset=pos, 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", self.add_layout_pin_center_rect(text="D",
layer="metal1", layer="metal1",
offset=pos, offset=pos,
width=contact.second_layer_width, width=contact.mod.second_layer_width,
height=contact.second_layer_height) height=contact.mod.second_layer_height)
if self.connect_active: if self.connect_active:
self.connect_fingered_active(drain_positions, source_positions) 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"): def __init__(self, rows, name="replica_bitline"):
design.design.__init__(self, name) design.design.__init__(self, name)
g = reload(__import__(OPTS.config.delay_chain)) g = reload(__import__(OPTS.delay_chain))
self.mod_delay_chain = getattr(g, OPTS.config.delay_chain) self.mod_delay_chain = getattr(g, OPTS.delay_chain)
g = reload(__import__(OPTS.config.replica_bitcell)) g = reload(__import__(OPTS.replica_bitcell))
self.mod_replica_bitcell = getattr(g, OPTS.config.replica_bitcell) self.mod_replica_bitcell = getattr(g, OPTS.replica_bitcell)
c = reload(__import__(OPTS.config.bitcell)) c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.config.bitcell) self.mod_bitcell = getattr(c, OPTS.bitcell)
for pin in ["en", "out", "vdd", "gnd"]: for pin in ["en", "out", "vdd", "gnd"]:
self.add_pin(pin) self.add_pin(pin)
@ -240,55 +240,50 @@ class replica_bitline(design.design):
""" Route all signals connected to gnd """ """ Route all signals connected to gnd """
# Add a rail in M1 from bottom to two along delay chain # 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 gnd_start = self.rbl_inv_inst.get_pin("gnd").bc()
gnd_end = vector(gnd_start.x, self.rbl_inst.uy()+2*self.m2_pitch)
# It is the height of the entire RBL and bitcell self.add_segment_center(layer="metal2",
self.add_rect(layer="metal2", start=gnd_start,
offset=gnd_start, end=gnd_end)
width=self.m2_width, self.add_layout_pin_center_segment(text="gnd",
height=self.rbl.height+self.bitcell.height+self.inv.width+self.m2_pitch)
self.add_layout_pin(text="gnd",
layer="metal1", layer="metal1",
offset=gnd_start.scale(1,0), start=gnd_start.scale(1,0),
width=self.m2_width, end=gnd_start)
height=2*self.inv.width)
# Connect the WL pins directly to gnd # Connect the WL pins directly to gnd
gnd_pin = self.get_pin("gnd").rc()
for row in range(self.rows): for row in range(self.rows):
wl = "wl[{}]".format(row) wl = "wl[{}]".format(row)
pin = self.rbl_inst.get_pin(wl) pin = self.rbl_inst.get_pin(wl)
offset = vector(gnd_start.x,pin.by()) start = vector(gnd_pin.x,pin.cy())
self.add_rect(layer="metal1", self.add_segment_center(layer="metal1",
offset=offset, start=start,
width=self.rbl_offset.x-gnd_start.x, end=pin.lc())
height=self.m1_width) self.add_via_center(layers=("metal1", "via1", "metal2"),
self.add_via(layers=("metal1", "via1", "metal2"), offset=start)
offset=offset)
# Add via for the delay chain # Add via for the delay chain
offset = self.delay_chain_offset - vector(0.5*self.m1_width,0) - self.offset_fix offset = self.dc_inst.get_pins("gnd")[0].bc() + vector(0.5*contact.m1m2.width,0.5*contact.m1m2.height)
self.add_via(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=offset) offset=offset)
# Add via for the inverter # Add via for the inverter
offset = self.rbl_inv_offset - vector(0.5*self.m1_width,contact.m1m2.height) - self.offset_fix offset = self.rbl_inv_inst.get_pin("gnd").bc() - vector(0,0.5*contact.m1m2.height)
self.add_via(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=offset) 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_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") rbl_gnd_pins = self.rbl_inst.get_pins("gnd")
# Find the left most rail on M2 # Add L shapes to each vertical gnd rail
gnd_pin = None
for pin in rbl_gnd_pins: for pin in rbl_gnd_pins:
if gnd_pin == None or (pin.layer=="metal2" and pin.lx()<gnd_pin.lx()): if pin.layer != "metal2":
gnd_pin = pin continue
gnd_end = gnd_pin.uc() gnd_end = pin.uc()
# Add a couple midpoints so that the wire will drop a via and then route horizontal on M1 gnd_mid = vector(gnd_end.x, gnd_start.y)
gnd_mid1 = gnd_start + vector(0,self.m2_pitch) self.add_wire(("metal1","via1","metal2"), [gnd_start, gnd_mid, gnd_end])
gnd_mid2 = gnd_end + vector(0,self.m2_pitch) gnd_start = gnd_mid
self.add_wire(("metal1","via1","metal2"), [gnd_start, gnd_mid1, gnd_mid2, gnd_end])
# Add a second gnd pin to the second delay chain rail. No need for full length. # 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(): class route():
""" """
Object route Object route (used by the router module)
Add a route of minimium metal width between a set of points. Add a route of minimium metal width between a set of points.
The wire must be completely rectilinear and the The wire must be completely rectilinear and the
z-dimension of the points refers to the layers (plus via) 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") design.design.__init__(self, "sense_amp_array")
debug.info(1, "Creating {0}".format(self.name)) debug.info(1, "Creating {0}".format(self.name))
c = reload(__import__(OPTS.config.sense_amp)) c = reload(__import__(OPTS.sense_amp))
self.mod_sense_amp = getattr(c, OPTS.config.sense_amp) self.mod_sense_amp = getattr(c, OPTS.sense_amp)
self.amp = self.mod_sense_amp("sense_amp") self.amp = self.mod_sense_amp("sense_amp")
self.add_mod(self.amp) self.add_mod(self.amp)

View File

@ -12,12 +12,13 @@ class single_level_column_mux(design.design):
Creates a single columnmux cell. 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) design.design.__init__(self, name)
debug.info(2, "create single column mux cell: {0}".format(name)) debug.info(2, "create single column mux cell: {0}".format(name))
c = reload(__import__(OPTS.config.bitcell)) c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.config.bitcell) self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell() self.bitcell = self.mod_bitcell()
self.ptx_width = tx_size * drc["minwidth_tx"] self.ptx_width = tx_size * drc["minwidth_tx"]
@ -27,9 +28,9 @@ class single_level_column_mux(design.design):
def create_layout(self): def create_layout(self):
self.add_ptx() self.add_ptx()
self.pin_height = 2*self.m2_width
self.width = self.bitcell.width self.width = self.bitcell.width
self.height = self.nmos2.uy() self.height = self.nmos2.uy() + self.pin_height
self.connect_poly() self.connect_poly()
self.add_gnd_rail() self.add_gnd_rail()
self.add_bitline_pins() 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) bl_pos = vector(self.bitcell.get_pin("BL").lx(), 0)
br_pos = vector(self.bitcell.get_pin("BR").lx(), 0) br_pos = vector(self.bitcell.get_pin("BR").lx(), 0)
pin_height = 2*self.m2_width
# bl and br # bl and br
self.add_layout_pin(text="bl", self.add_layout_pin(text="bl",
layer="metal2", layer="metal2",
offset=bl_pos + vector(0,self.height - pin_height), offset=bl_pos + vector(0,self.height - self.pin_height),
height=pin_height) height=self.pin_height)
self.add_layout_pin(text="br", self.add_layout_pin(text="br",
layer="metal2", layer="metal2",
offset=br_pos + vector(0,self.height - pin_height), offset=br_pos + vector(0,self.height - self.pin_height),
height=pin_height) height=self.pin_height)
# bl_out and br_out # bl_out and br_out
self.add_layout_pin(text="bl_out", self.add_layout_pin(text="bl_out",
layer="metal2", layer="metal2",
offset=bl_pos, offset=bl_pos,
height=pin_height) height=self.pin_height)
self.add_layout_pin(text="br_out", self.add_layout_pin(text="br_out",
layer="metal2", layer="metal2",
offset=br_pos, offset=br_pos,
height=pin_height) height=self.pin_height)
def add_ptx(self): def add_ptx(self):
@ -153,7 +153,6 @@ class single_level_column_mux(design.design):
def add_wells(self): def add_wells(self):
""" Add a well and implant over the whole cell. Also, add the pwell contact (if it exists) """ """ Add a well and implant over the whole cell. Also, add the pwell contact (if it exists) """
# find right most gnd rail # find right most gnd rail
gnd_pins = self.bitcell.get_pins("gnd") gnd_pins = self.bitcell.get_pins("gnd")
right_gnd = None right_gnd = None
@ -167,26 +166,8 @@ class single_level_column_mux(design.design):
offset=m1m2_offset) offset=m1m2_offset)
active_offset = right_gnd.bc() + vector(0,0.5*self.nmos.poly_height) active_offset = right_gnd.bc() + vector(0,0.5*self.nmos.poly_height)
self.add_via_center(layers=("active", "contact", "metal1"), 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,25 +40,29 @@ class single_level_column_mux_array(design.design):
self.setup_layout_constants() self.setup_layout_constants()
self.create_array() self.create_array()
self.add_routing() 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): def add_modules(self):
self.mux = single_level_column_mux(name="single_level_column_mux", # FIXME: Why is this 8x?
tx_size=8) self.mux = single_level_column_mux(tx_size=8)
self.add_mod(self.mux) self.add_mod(self.mux)
def setup_layout_constants(self): def setup_layout_constants(self):
self.column_addr_size = num_of_inputs = int(self.words_per_row / 2) self.column_addr_size = num_of_inputs = int(self.words_per_row / 2)
self.width = self.columns * self.mux.width self.width = self.columns * self.mux.width
self.m1_pitch = contact.m1m2.width + max(drc["metal1_to_metal1"],drc["metal2_to_metal2"]) 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 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 # one extra route pitch is to space from the sense amp
self.route_height = (self.words_per_row + 3)*self.m1_pitch 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): def create_array(self):
self.mux_inst = [] self.mux_inst = []
@ -71,19 +75,32 @@ class single_level_column_mux_array(design.design):
mod=self.mux, mod=self.mux,
offset=x_off)) offset=x_off))
offset = self.mux_inst[-1].get_pin("bl").ll() self.connect_inst(["bl[{}]".format(col_num),
"br[{}]".format(col_num),
"bl_out[{}]".format(int(col_num/self.words_per_row)),
"br_out[{}]".format(int(col_num/self.words_per_row)),
"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), self.add_layout_pin(text="bl[{}]".format(col_num),
layer="metal2", layer="metal2",
offset=offset, offset=offset,
height=self.height-offset.y) height=self.height-offset.y)
offset = self.mux_inst[-1].get_pin("br").ll() offset = mux_inst.get_pin("br").ll()
self.add_layout_pin(text="br[{}]".format(col_num), self.add_layout_pin(text="br[{}]".format(col_num),
layer="metal2", layer="metal2",
offset=offset, offset=offset,
height=self.height-offset.y) height=self.height-offset.y)
gnd_pins = self.mux_inst[-1].get_pins("gnd") gnd_pins = mux_inst.get_pins("gnd")
for gnd_pin in gnd_pins: for gnd_pin in gnd_pins:
# only do even colums to avoid duplicates # only do even colums to avoid duplicates
offset = gnd_pin.ll() offset = gnd_pin.ll()
@ -93,14 +110,6 @@ class single_level_column_mux_array(design.design):
offset=offset.scale(1,0), offset=offset.scale(1,0),
height=self.height) height=self.height)
self.connect_inst(["bl[{}]".format(col_num),
"br[{}]".format(col_num),
"bl_out[{}]".format(int(col_num/self.words_per_row)),
"br_out[{}]".format(int(col_num/self.words_per_row)),
"sel[{}]".format(col_num % self.words_per_row),
"gnd"])
def add_routing(self): def add_routing(self):
self.add_horizontal_input_rail() 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): def __init__(self, word_size, num_words, num_banks, name):
c = reload(__import__(OPTS.config.control_logic)) c = reload(__import__(OPTS.control_logic))
self.mod_control_logic = getattr(c, OPTS.config.control_logic) self.mod_control_logic = getattr(c, OPTS.control_logic)
c = reload(__import__(OPTS.config.ms_flop_array)) c = reload(__import__(OPTS.ms_flop_array))
self.mod_ms_flop_array = getattr(c, OPTS.config.ms_flop_array) self.mod_ms_flop_array = getattr(c, OPTS.ms_flop_array)
c = reload(__import__(OPTS.config.bitcell)) c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.config.bitcell) self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell() self.bitcell = self.mod_bitcell()
c = reload(__import__(OPTS.config.ms_flop)) c = reload(__import__(OPTS.ms_flop))
self.mod_ms_flop = getattr(c, OPTS.config.ms_flop) self.mod_ms_flop = getattr(c, OPTS.ms_flop)
self.ms_flop = self.mod_ms_flop() self.ms_flop = self.mod_ms_flop()
@ -72,7 +72,7 @@ class sram(design.design):
self.width = sizes[0] self.width = sizes[0]
self.height = sizes[1] self.height = sizes[1]
self.DRC_LVS() self.DRC_LVS(final_verification=True)
def compute_sizes(self): def compute_sizes(self):
""" Computes the organization of the memory using bitcell size by trying to make it square.""" """ 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 # Connect the output bar to select 0
msb_out_pin = self.msb_address_inst.get_pin("dout_bar[0]") msb_out_pin = self.msb_address_inst.get_pin("dout_bar[0]")
msb_out_pos = msb_out_pin.rc() 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) 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) 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]) 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 # Connect the output to select 1
msb_out_pin = self.msb_address_inst.get_pin("dout[0]") msb_out_pin = self.msb_address_inst.get_pin("dout[0]")
msb_out_pos = msb_out_pin.rc() 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) 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) 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]) 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 = open(sp_name, 'w')
sp.write("**************************************************\n")
sp.write("* OpenRAM generated memory.\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 # This causes unit test mismatch
# sp.write("* Created: {0}\n".format(datetime.datetime.now())) # sp.write("* Created: {0}\n".format(datetime.datetime.now()))
# sp.write("* User: {0}\n".format(getpass.getuser())) # 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 #!/usr/bin/env python2.7
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os,re
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
import debug import debug
import verify
import re
#@unittest.skip("SKIPPING 00_format check test") class code_format_test(openram_test):
class code_format_test(unittest.TestCase):
"Run a test to check for tabs instead of spaces in the all source files." "Run a test to check for tabs instead of spaces in the all source files."
def runTest(self): def runTest(self):

View File

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

View File

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

View File

@ -2,22 +2,19 @@
"Run a regresion test for DRC on basic contacts of different array sizes" "Run a regresion test for DRC on basic contacts of different array sizes"
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
OPTS = globals.OPTS class contact_test(openram_test):
#@unittest.skip("SKIPPING 03_contact_test")
class contact_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import contact import contact
@ -29,31 +26,26 @@ class contact_test(unittest.TestCase):
# Check single 1 x 1 contact" # Check single 1 x 1 contact"
debug.info(2, "1 x 1 {} test".format(stack_name)) debug.info(2, "1 x 1 {} test".format(stack_name))
c = contact.contact(layer_stack, (1, 1)) 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 # check vertical array with one in the middle and two ends
debug.info(2, "1 x 3 {} test".format(stack_name)) debug.info(2, "1 x 3 {} test".format(stack_name))
c = contact.contact(layer_stack, (1, 3)) 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 # check horizontal array with one in the middle and two ends
debug.info(2, "3 x 1 {} test".format(stack_name)) debug.info(2, "3 x 1 {} test".format(stack_name))
c = contact.contact(layer_stack, (3, 1)) c = contact.contact(layer_stack, (3, 1))
self.local_check(c) self.local_drc_check(c)
# check 3x3 array for all possible neighbors # check 3x3 array for all possible neighbors
debug.info(2, "3 x 3 {} test".format(stack_name)) debug.info(2, "3 x 3 {} test".format(stack_name))
c = contact.contact(layer_stack, (3, 3)) c = contact.contact(layer_stack, (3, 3))
self.local_check(c) self.local_drc_check(c)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # 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" "Run a regresion test on a basic path"
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
OPTS = globals.OPTS class path_test(openram_test):
#@unittest.skip("SKIPPING 03_path_test")
class path_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import path import path
@ -35,7 +32,7 @@ class path_test(unittest.TestCase):
[0, 6 * min_space ]] [0, 6 * min_space ]]
w = design.design("path_test0") w = design.design("path_test0")
path.path(w,layer_stack, position_list) path.path(w,layer_stack, position_list)
self.local_check(w) self.local_drc_check(w)
min_space = 2 * tech.drc["minwidth_metal1"] 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] position_list = [[x+min_space, y+min_space] for x,y in old_position_list]
w = design.design("path_test1") w = design.design("path_test1")
path.path(w,layer_stack, position_list) path.path(w,layer_stack, position_list)
self.local_check(w) self.local_drc_check(w)
min_space = 2 * tech.drc["minwidth_metal2"] min_space = 2 * tech.drc["minwidth_metal2"]
layer_stack = ("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] position_list = [[x-min_space, y-min_space] for x,y in old_position_list]
w = design.design("path_test2") w = design.design("path_test2")
path.path(w, layer_stack, position_list) path.path(w, layer_stack, position_list)
self.local_check(w) self.local_drc_check(w)
min_space = 2 * tech.drc["minwidth_metal3"] min_space = 2 * tech.drc["minwidth_metal3"]
layer_stack = ("metal3") layer_stack = ("metal3")
@ -85,17 +82,12 @@ class path_test(unittest.TestCase):
position_list.reverse() position_list.reverse()
w = design.design("path_test3") w = design.design("path_test3")
path.path(w, layer_stack, position_list) path.path(w, layer_stack, position_list)
self.local_check(w) self.local_drc_check(w)
# return it back to it's normal state # return it back to it's normal state
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # 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" "Run a regresion test on a basic parameterized transistors"
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
OPTS = globals.OPTS class ptx_test(openram_test):
#@unittest.skip("SKIPPING 03_ptx_test")
class ptx_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import ptx import ptx
@ -28,126 +24,12 @@ class ptx_test(unittest.TestCase):
fet = ptx.ptx(width=tech.drc["minwidth_tx"], fet = ptx.ptx(width=tech.drc["minwidth_tx"],
mults=1, mults=1,
tx_type="nmos") tx_type="nmos")
self.local_check(fet) self.local_drc_check(fet)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -2,23 +2,19 @@
"Run a regresion test on a basic parameterized transistors" "Run a regresion test on a basic parameterized transistors"
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
OPTS = globals.OPTS class ptx_test(openram_test):
#@unittest.skip("SKIPPING 03_ptx_test")
class ptx_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import ptx import ptx
@ -28,127 +24,12 @@ class ptx_test(unittest.TestCase):
fet = ptx.ptx(width=tech.drc["minwidth_tx"], fet = ptx.ptx(width=tech.drc["minwidth_tx"],
mults=1, mults=1,
tx_type="pmos") tx_type="pmos")
self.local_check(fet) self.local_drc_check(fet)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -2,23 +2,19 @@
"Run a regresion test on a basic parameterized transistors" "Run a regresion test on a basic parameterized transistors"
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
OPTS = globals.OPTS class ptx_test(openram_test):
#@unittest.skip("SKIPPING 03_ptx_test")
class ptx_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import ptx import ptx
@ -30,125 +26,11 @@ class ptx_test(unittest.TestCase):
tx_type="nmos", tx_type="nmos",
connect_active=True, connect_active=True,
connect_poly=True) connect_poly=True)
self.local_check(fet) self.local_drc_check(fet)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -2,23 +2,19 @@
"Run a regresion test on a basic parameterized transistors" "Run a regresion test on a basic parameterized transistors"
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
OPTS = globals.OPTS class ptx_test(openram_test):
#@unittest.skip("SKIPPING 03_ptx_test")
class ptx_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import ptx import ptx
@ -30,125 +26,11 @@ class ptx_test(unittest.TestCase):
tx_type="pmos", tx_type="pmos",
connect_active=True, connect_active=True,
connect_poly=True) connect_poly=True)
self.local_check(fet) self.local_drc_check(fet)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -2,23 +2,19 @@
"Run a regresion test on a basic parameterized transistors" "Run a regresion test on a basic parameterized transistors"
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
OPTS = globals.OPTS class ptx_test(openram_test):
#@unittest.skip("SKIPPING 03_ptx_test")
class ptx_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import ptx import ptx
@ -30,125 +26,11 @@ class ptx_test(unittest.TestCase):
tx_type="nmos", tx_type="nmos",
connect_active=True, connect_active=True,
connect_poly=True) connect_poly=True)
self.local_check(fet) self.local_drc_check(fet)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -2,23 +2,19 @@
"Run a regresion test on a basic parameterized transistors" "Run a regresion test on a basic parameterized transistors"
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
OPTS = globals.OPTS class ptx_test(openram_test):
#@unittest.skip("SKIPPING 03_ptx_test")
class ptx_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import ptx import ptx
@ -30,125 +26,11 @@ class ptx_test(unittest.TestCase):
tx_type="pmos", tx_type="pmos",
connect_active=True, connect_active=True,
connect_poly=True) connect_poly=True)
self.local_check(fet) self.local_drc_check(fet)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":

View File

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

View File

@ -4,22 +4,19 @@ Run regresion tests on a parameterized inverter
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
OPTS = globals.OPTS class pinv_test(openram_test):
#@unittest.skip("SKIPPING 04_pinv_test")
class pinv_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import pinv import pinv
@ -32,25 +29,6 @@ class pinv_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -4,22 +4,19 @@ Run regresion tests on a parameterized inverter
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
OPTS = globals.OPTS class pinv_test(openram_test):
#@unittest.skip("SKIPPING 04_pinv_test")
class pinv_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import pinv import pinv
@ -32,26 +29,6 @@ class pinv_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -1,27 +1,24 @@
#!/usr/bin/env python2.7 #!/usr/bin/env python2.7
""" """
Run regresion tests on a parameterized inverter Run regression tests on a parameterized inverter
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
OPTS = globals.OPTS class pinv_test(openram_test):
#@unittest.skip("SKIPPING 04_pinv_test")
class pinv_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import pinv import pinv
import tech import tech
@ -32,26 +29,6 @@ class pinv_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -4,22 +4,19 @@ Run regresion tests on a parameterized inverter
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
OPTS = globals.OPTS class pinv_test(openram_test):
#@unittest.skip("SKIPPING 04_pinv_test")
class pinv_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import pinv import pinv
@ -32,25 +29,6 @@ class pinv_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -6,24 +6,19 @@ size 2-input nand gate.
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
import sys
OPTS = globals.OPTS class pnand2_test(openram_test):
#@unittest.skip("SKIPPING 04_pnand2_test")
class pnand2_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import pnand2 import pnand2
@ -37,20 +32,6 @@ class pnand2_test(unittest.TestCase):
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -6,21 +6,19 @@ It generates only a minimum size 3-input nand gate.
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
OPTS = globals.OPTS class pnand3_test(openram_test):
#@unittest.skip("SKIPPING 04_pnand3_test")
class pnand3_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import pnand3 import pnand3
@ -33,19 +31,6 @@ class pnand3_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -6,24 +6,19 @@ size 2-input nor gate.
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
import sys
OPTS = globals.OPTS class pnor2_test(openram_test):
#@unittest.skip("SKIPPING 04_pnor2_test")
class pnor2_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import pnor2 import pnor2
@ -36,21 +31,6 @@ class pnor2_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -4,21 +4,19 @@ Run a regresion test on a precharge cell
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
import sys
OPTS = globals.OPTS class precharge_test(openram_test):
class precharge_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import precharge import precharge
@ -31,20 +29,6 @@ class precharge_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -4,24 +4,21 @@ Run a regresion test on a wordline_driver array
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
import sys
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 04_driver_test") #@unittest.skip("SKIPPING 04_driver_test")
class wordline_driver_test(openram_test):
class wordline_driver_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import wordline_driver import wordline_driver
@ -34,20 +31,6 @@ class wordline_driver_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -4,23 +4,21 @@ Run a regresion test on a basic array
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
OPTS = globals.OPTS
#@unittest.skip("SKIPPING 05_array_test") #@unittest.skip("SKIPPING 05_array_test")
class array_test(openram_test):
class array_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import bitcell_array import bitcell_array
@ -32,21 +30,6 @@ class array_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -4,20 +4,19 @@ Run a regresion test on a hierarchical_decoder.
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
OPTS = globals.OPTS class hierarchical_decoder_test(openram_test):
class hierarchical_decoder_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import hierarchical_decoder import hierarchical_decoder
@ -33,6 +32,10 @@ class hierarchical_decoder_test(unittest.TestCase):
# a = hierarchical_decoder.hierarchical_decoder(rows=8) # a = hierarchical_decoder.hierarchical_decoder(rows=8)
# self.local_check(a) # 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") debug.info(1, "Testing 32 row sample for hierarchical_decoder")
a = hierarchical_decoder.hierarchical_decoder(rows=32) a = hierarchical_decoder.hierarchical_decoder(rows=32)
self.local_check(a) self.local_check(a)
@ -48,24 +51,6 @@ class hierarchical_decoder_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copdsay of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -4,21 +4,19 @@ Run a regresion test on a hierarchical_predecode2x4.
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
OPTS = globals.OPTS class hierarchical_predecode2x4_test(openram_test):
class hierarchical_predecode2x4_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import hierarchical_predecode2x4 as pre import hierarchical_predecode2x4 as pre
@ -31,19 +29,6 @@ class hierarchical_predecode2x4_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copdsay of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -4,21 +4,19 @@ Run a regresion test on a hierarchical_predecode3x8.
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS
import debug import debug
import verify
OPTS = globals.OPTS class hierarchical_predecode3x8_test(openram_test):
class hierarchical_predecode3x8_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import hierarchical_predecode3x8 as pre import hierarchical_predecode3x8 as pre
@ -31,19 +29,6 @@ class hierarchical_predecode3x8_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copdsay of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -3,21 +3,19 @@
Run a regresion test on a single transistor column_mux. Run a regresion test on a single transistor column_mux.
""" """
import unittest from testutils import header,openram_test,unittest
from testutils import header
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
import verify
class single_level_column_mux_test(openram_test):
class single_level_column_mux_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import single_level_column_mux_array import single_level_column_mux_array
@ -37,22 +35,6 @@ class single_level_column_mux_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copdsay of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -4,22 +4,19 @@ Run a regresion test on a precharge array
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
import verify
class precharge_test(openram_test):
#@unittest.skip("SKIPPING 08_precharge_test")
class precharge_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import precharge_array import precharge_array
@ -32,19 +29,6 @@ class precharge_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -4,21 +4,19 @@ Run a regresion test on a sense amp array
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
import verify
#@unittest.skip("SKIPPING 09_sense_amp_test") class sense_amp_test(openram_test):
class sense_amp_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import sense_amp_array import sense_amp_array
@ -35,24 +33,6 @@ class sense_amp_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -4,21 +4,19 @@ Run a regresion test on a write driver array
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
import verify
#@unittest.skip("SKIPPING 10_write_driver_test") class write_driver_test(openram_test):
class write_driver_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import write_driver_array import write_driver_array
@ -34,24 +32,6 @@ class write_driver_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -4,22 +4,19 @@ Run a regresion test on a dff_array.
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
import verify
import importlib
#@unittest.skip("SKIPPING 20_sram_test") class dff_array_test(openram_test):
class dff_array_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import ms_flop_array import ms_flop_array
@ -35,25 +32,6 @@ class dff_array_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copdsay of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -4,20 +4,19 @@ Run a regresion test on a tri_gate_array.
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
import verify
class tri_gate_array_test(openram_test):
class tri_gate_array_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import tri_gate_array import tri_gate_array
@ -33,24 +32,6 @@ class tri_gate_array_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copdsay of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -4,20 +4,19 @@ Run a test on a delay chain
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
import verify
#@unittest.skip("SKIPPING 14_delay_chain_test") class delay_chain_test(openram_test):
class delay_chain_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import delay_chain import delay_chain
@ -29,19 +28,6 @@ class delay_chain_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -4,23 +4,19 @@ Run a test on a delay chain
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
import verify
import importlib
#@unittest.skip("SKIPPING 14_delay_chain_test") class replica_bitline_test(openram_test):
class replica_bitline_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import replica_bitline import replica_bitline
@ -32,19 +28,6 @@ class replica_bitline_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -4,19 +4,19 @@ Run a regresion test on a control_logic
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
import verify
class control_logic_test(unittest.TestCase): class control_logic_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import control_logic import control_logic
@ -29,20 +29,6 @@ class control_logic_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copdsay of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -4,19 +4,19 @@ Run a regresion test on various srams
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
import verify
class multi_bank_test(unittest.TestCase): class multi_bank_test(openram_test):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import bank import bank
@ -41,23 +41,6 @@ class multi_bank_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -4,22 +4,19 @@ Run a regresion test on various srams
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
import verify
#@unittest.skip("SKIPPING 20_sram_test") class single_bank_test(openram_test):
class single_bank_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import bank import bank
@ -44,23 +41,6 @@ class single_bank_test(unittest.TestCase):
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -4,59 +4,42 @@ Run a regresion test on a 1 bank SRAM
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
import verify
#@unittest.skip("SKIPPING 20_sram_test") class sram_1bank_test(openram_test):
class sram_1bank_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import sram import sram
debug.info(1, "Single bank, no column mux with control logic") 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") 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") 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") 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") 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") 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") # 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") # 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 OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -4,59 +4,42 @@ Run a regresion test on a 2 bank SRAM
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
import verify
#@unittest.skip("SKIPPING 20_sram_test") class sram_2bank_test(openram_test):
class sram_2bank_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import sram import sram
debug.info(1, "Two bank, no column mux with control logic") 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") 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") 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") 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") 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") 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") # 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") # 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 OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

@ -4,59 +4,42 @@ Run a regresion test on a 4 bank SRAM
""" """
import unittest import unittest
from testutils import header from testutils import header,openram_test
import sys,os import sys,os
sys.path.append(os.path.join(sys.path[0],"..")) sys.path.append(os.path.join(sys.path[0],".."))
import globals import globals
from globals import OPTS from globals import OPTS
import debug import debug
import verify
#@unittest.skip("SKIPPING 20_sram_test") class sram_4bank_test(openram_test):
class sram_4bank_test(unittest.TestCase):
def runTest(self): def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name)) globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc global verify
import verify
OPTS.check_lvsdrc = False OPTS.check_lvsdrc = False
import sram import sram
debug.info(1, "Four bank, no column mux with control logic") 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") 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") 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") 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") 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") 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") # debug.info(1, "Four bank, eight way column mux with control logic")
# a = sram.sram(word_size=2, num_words=256, num_banks=4, name="sram4") # a = sram.sram(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 OPTS.check_lvsdrc = True
globals.end_openram() 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 # instantiate a copy of the class to actually run the test
if __name__ == "__main__": if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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