mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev'
Add Magic+Netgen support. General improvements to designs to make them DRC portable.
This commit is contained in:
commit
bae83fc686
2
LICENSE
2
LICENSE
|
|
@ -1,4 +1,4 @@
|
|||
Copyright 2017 Regents of the University of California and The Board
|
||||
Copyright 2018 Regents of the University of California and The Board
|
||||
of Regents for the Oklahoma Agricultural and Mechanical College
|
||||
(acting for and on behalf of Oklahoma State University)
|
||||
|
||||
|
|
|
|||
11
README.md
11
README.md
|
|
@ -7,9 +7,14 @@ https://github.com/mguthaus/OpenRAM/blob/master/OpenRAM_ICCAD_2016_presentation.
|
|||
The OpenRAM compiler has very few dependencies:
|
||||
* ngspice-26 (or later) or HSpice I-2013.12-1 (or later) or CustomSim 2017 (or later)
|
||||
* Python 2.7 and higher (currently excludes Python 3 and up)
|
||||
* Python numpy
|
||||
* a setup script for each technology
|
||||
* a technology directory for each technology with the base cells
|
||||
|
||||
If you want to perform DRC and LVS, you will need either:
|
||||
* Calibre (for FreePDK45 or SCMOS)
|
||||
* Magic + Netgen (for SCMOS only)
|
||||
|
||||
You must set two environment variables: OPENRAM_HOME should point to
|
||||
the compiler source directory. OPENERAM_TECH should point to a root
|
||||
technology directory that contains subdirs of all other technologies.
|
||||
|
|
@ -36,6 +41,12 @@ For example, in csh/tcsh, add to your .tcshrc:
|
|||
We do not distribute the PDK, but you may get it from:
|
||||
https://www.eda.ncsu.edu/wiki/FreePDK45:Contents
|
||||
|
||||
If you are using SCMOS, you should install Magic and netgen from:
|
||||
http://opencircuitdesign.com/magic/
|
||||
http://opencircuitdesign.com/netgen/
|
||||
In addition, you will need to install the MOSIS SCMOS rules for scn3me_subm
|
||||
that are part of QFlow:
|
||||
http://opencircuitdesign.com/qflow/
|
||||
|
||||
# DIRECTORY STRUCTURE
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {} \;
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ class bank(design.design):
|
|||
"bitcell_array", "sense_amp_array", "precharge_array",
|
||||
"column_mux_array", "write_driver_array", "tri_gate_array"]
|
||||
for mod_name in mod_list:
|
||||
config_mod_name = getattr(OPTS.config, mod_name)
|
||||
config_mod_name = getattr(OPTS, mod_name)
|
||||
class_file = reload(__import__(config_mod_name))
|
||||
mod_class = getattr(class_file , config_mod_name)
|
||||
setattr (self, "mod_"+mod_name, mod_class)
|
||||
|
|
@ -99,8 +99,10 @@ class bank(design.design):
|
|||
self.add_precharge_array()
|
||||
|
||||
if self.col_addr_size > 0:
|
||||
# The m2 width is because the 6T cell may have vias on the boundary edge for
|
||||
# overlapping when making the array
|
||||
self.column_mux_height = self.column_mux_array.height + 0.5*self.m2_width
|
||||
self.add_column_mux_array()
|
||||
self.column_mux_height = self.column_mux_array.height
|
||||
else:
|
||||
self.column_mux_height = 0
|
||||
if self.col_addr_size > 1: # size 1 is from addr FF
|
||||
|
|
@ -234,8 +236,8 @@ class bank(design.design):
|
|||
""" Adding Precharge """
|
||||
|
||||
# The wells must be far enough apart
|
||||
# We use two well spacings because the bitcells tend to have a shared rail in the height
|
||||
y_offset = self.bitcell_array.height + 2*drc["pwell_to_nwell"]
|
||||
# The enclosure is for the well and the spacig is to the bitcell wells
|
||||
y_offset = self.bitcell_array.height + 2*drc["pwell_to_nwell"] + drc["well_enclosure_active"]
|
||||
self.precharge_array_inst=self.add_inst(name="precharge_array",
|
||||
mod=self.precharge_array,
|
||||
offset=vector(0,y_offset))
|
||||
|
|
@ -249,7 +251,7 @@ class bank(design.design):
|
|||
def add_column_mux_array(self):
|
||||
""" Adding Column Mux when words_per_row > 1 . """
|
||||
|
||||
y_offset = self.column_mux_array.height
|
||||
y_offset = self.column_mux_height
|
||||
self.col_mux_array_inst=self.add_inst(name="column_mux_array",
|
||||
mod=self.column_mux_array,
|
||||
offset=vector(0,y_offset).scale(-1,-1))
|
||||
|
|
@ -434,7 +436,8 @@ class bank(design.design):
|
|||
|
||||
|
||||
# Place the col decoder just to the left of the control bus
|
||||
x_off = self.m2_pitch + self.overall_central_bus_width + self.col_decoder.width
|
||||
gap = max(drc["pwell_to_nwell"], 2*self.m2_pitch)
|
||||
x_off = gap + self.overall_central_bus_width + self.col_decoder.width
|
||||
# Place the col decoder below the the address flops which are below the row decoder (lave some space for wells)
|
||||
vertical_gap = max(drc["pwell_to_nwell"], 2*self.m2_pitch)
|
||||
y_off = self.decoder.predecoder_height + self.msf_address.width + self.col_decoder.height + 2*vertical_gap
|
||||
|
|
|
|||
|
|
@ -21,12 +21,13 @@ class bitcell_array(design.design):
|
|||
self.column_size = cols
|
||||
self.row_size = rows
|
||||
|
||||
c = reload(__import__(OPTS.config.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.config.bitcell)
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.cell = self.mod_bitcell()
|
||||
self.add_mod(self.cell)
|
||||
|
||||
self.height = self.row_size*self.cell.height
|
||||
# We increase it by a well enclosure so the precharges don't overlap our wells
|
||||
self.height = self.row_size*self.cell.height + drc["well_enclosure_active"]
|
||||
self.width = self.column_size*self.cell.width
|
||||
|
||||
self.add_pins()
|
||||
|
|
@ -115,8 +116,8 @@ class bitcell_array(design.design):
|
|||
gnd_pins = self.cell_inst[0,col].get_pins("gnd")
|
||||
for gnd_pin in gnd_pins:
|
||||
# avoid duplicates by only doing even rows
|
||||
# also skip if it is not the full height (a through rail)
|
||||
if gnd_pin.layer=="metal2" and col%2 == 0 and gnd_pin.height()>=self.cell.height:
|
||||
# also skip if it isn't the pin that spans the entire cell down to the bottom
|
||||
if gnd_pin.layer=="metal2" and gnd_pin.by()==lower_y:
|
||||
self.add_layout_pin(text="gnd",
|
||||
layer="metal2",
|
||||
offset=gnd_pin.ll(),
|
||||
|
|
|
|||
|
|
@ -8,22 +8,22 @@ import setup_hold
|
|||
|
||||
debug.info(2,"Initializing characterizer...")
|
||||
|
||||
spice_exe = ""
|
||||
OPTS.spice_exe = ""
|
||||
|
||||
if not OPTS.analytical_delay:
|
||||
if OPTS.spice_name != "":
|
||||
spice_exe=find_exe(OPTS.spice_name)
|
||||
if spice_exe=="":
|
||||
OPTS.spice_exe=find_exe(OPTS.spice_name)
|
||||
if OPTS.spice_exe=="":
|
||||
debug.error("{0} not found. Unable to perform characterization.".format(OPTS.spice_name),1)
|
||||
else:
|
||||
(choice,spice_exe) = get_tool("spice",["xa", "hspice", "ngspice", "ngspice.exe"])
|
||||
OPTS.spice_name = choice
|
||||
(OPTS.spice_name,OPTS.spice_exe) = get_tool("spice",["xa", "hspice", "ngspice", "ngspice.exe"])
|
||||
|
||||
# set the input dir for spice files if using ngspice
|
||||
if OPTS.spice_name == "ngspice":
|
||||
os.environ["NGSPICE_INPUT_DIR"] = "{0}".format(OPTS.openram_temp)
|
||||
|
||||
if spice_exe == "":
|
||||
if OPTS.spice_exe == "":
|
||||
debug.error("No recognizable spice version found. Unable to perform characterization.",1)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -40,9 +40,9 @@ class delay():
|
|||
|
||||
|
||||
def write_stimulus(self, period, load, slew):
|
||||
"""Creates a stimulus file for simulations to probe a certain bitcell, given an address and data-position of the data-word
|
||||
(probe-address form: '111010000' LSB=0, MSB=1)
|
||||
(probe_data form: number corresponding to the bit position of data-bus, begins with position 0)
|
||||
""" Creates a stimulus file for simulations to probe a bitcell at a given clock period.
|
||||
Address and bit were previously set with set_probe().
|
||||
Input slew (in ns) and output capacitive load (in fF) are required for charaterization.
|
||||
"""
|
||||
self.check_arguments()
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ class delay():
|
|||
# creates and opens stimulus file for writing
|
||||
temp_stim = "{0}/stim.sp".format(OPTS.openram_temp)
|
||||
self.sf = open(temp_stim, "w")
|
||||
self.sf.write("* Stimulus for period of {0}n load={1} slew={2}\n\n".format(period,load,slew))
|
||||
self.sf.write("* Stimulus for period of {0}n load={1}fF slew={2}ns\n\n".format(period,load,slew))
|
||||
|
||||
# include files in stimulus file
|
||||
model_list = tech.spice["fet_models"] + [self.sram_sp_file]
|
||||
|
|
@ -116,8 +116,8 @@ class delay():
|
|||
|
||||
self.write_measures(period)
|
||||
|
||||
# run until the last cycle time
|
||||
stimuli.write_control(self.sf,self.cycle_times[-1])
|
||||
# run until the end of the cycle time
|
||||
stimuli.write_control(self.sf,self.cycle_times[-1] + period)
|
||||
|
||||
self.sf.close()
|
||||
|
||||
|
|
@ -125,11 +125,14 @@ class delay():
|
|||
# meas statement for delay and power measurements
|
||||
self.sf.write("* Measure statements for delay and power\n")
|
||||
|
||||
for comment in self.cycle_comments:
|
||||
self.sf.write("* {}\n".format(comment))
|
||||
|
||||
trig_name = "clk"
|
||||
targ_name = "{0}".format("d[{0}]".format(self.probe_data))
|
||||
trig_val = targ_val = 0.5 * self.vdd
|
||||
# add measure statments for delay0
|
||||
# delay the target to measure after the negetive edge
|
||||
# delay the target to measure after the negative edge
|
||||
stimuli.gen_meas_delay(stim_file=self.sf,
|
||||
meas_name="DELAY0",
|
||||
trig_name=trig_name,
|
||||
|
|
@ -138,7 +141,8 @@ class delay():
|
|||
targ_val=targ_val,
|
||||
trig_dir="FALL",
|
||||
targ_dir="FALL",
|
||||
td=self.cycle_times[self.read0_cycle]+0.5*period)
|
||||
trig_td=self.cycle_times[self.read0_cycle],
|
||||
targ_td=self.cycle_times[self.read0_cycle]+0.5*period)
|
||||
|
||||
stimuli.gen_meas_delay(stim_file=self.sf,
|
||||
meas_name="DELAY1",
|
||||
|
|
@ -148,7 +152,8 @@ class delay():
|
|||
targ_val=targ_val,
|
||||
trig_dir="FALL",
|
||||
targ_dir="RISE",
|
||||
td=self.cycle_times[self.read1_cycle]+0.5*period)
|
||||
trig_td=self.cycle_times[self.read1_cycle],
|
||||
targ_td=self.cycle_times[self.read1_cycle]+0.5*period)
|
||||
|
||||
stimuli.gen_meas_delay(stim_file=self.sf,
|
||||
meas_name="SLEW0",
|
||||
|
|
@ -158,7 +163,8 @@ class delay():
|
|||
targ_val=0.1*self.vdd,
|
||||
trig_dir="FALL",
|
||||
targ_dir="FALL",
|
||||
td=self.cycle_times[self.read0_cycle]+0.5*period)
|
||||
trig_td=self.cycle_times[self.read0_cycle],
|
||||
targ_td=self.cycle_times[self.read0_cycle]+0.5*period)
|
||||
|
||||
stimuli.gen_meas_delay(stim_file=self.sf,
|
||||
meas_name="SLEW1",
|
||||
|
|
@ -168,7 +174,8 @@ class delay():
|
|||
targ_val=0.9*self.vdd,
|
||||
trig_dir="RISE",
|
||||
targ_dir="RISE",
|
||||
td=self.cycle_times[self.read1_cycle]+0.5*period)
|
||||
trig_td=self.cycle_times[self.read1_cycle],
|
||||
targ_td=self.cycle_times[self.read1_cycle]+0.5*period)
|
||||
|
||||
# add measure statements for power
|
||||
t_initial = self.cycle_times[self.write0_cycle]
|
||||
|
|
@ -238,12 +245,14 @@ class delay():
|
|||
|
||||
# if it failed or the read was longer than a period
|
||||
if type(delay0)!=float or type(delay1)!=float or type(slew1)!=float or type(slew0)!=float:
|
||||
debug.info(2,"Failed simulation: period {0} load {1} slew {2}, delay0={3}n delay1={4}ns slew0={5}n slew1={6}n".format(period,load,slew,delay0,delay1,slew0,slew1))
|
||||
return (False,0,0,0,0)
|
||||
delay0 *= 1e9
|
||||
delay1 *= 1e9
|
||||
slew0 *= 1e9
|
||||
slew1 *= 1e9
|
||||
if delay0>period or delay1>period or slew0>period or slew1>period:
|
||||
debug.info(2,"UNsuccessful simulation: period {0} load {1} slew {2}, delay0={3}n delay1={4}ns slew0={5}n slew1={6}n".format(period,load,slew,delay0,delay1,slew0,slew1))
|
||||
return (False,0,0,0,0)
|
||||
else:
|
||||
debug.info(2,"Successful simulation: period {0} load {1} slew {2}, delay0={3}n delay1={4}ns slew0={5}n slew1={6}n".format(period,load,slew,delay0,delay1,slew0,slew1))
|
||||
|
|
@ -364,7 +373,7 @@ class delay():
|
|||
for slew in slews:
|
||||
for load in loads:
|
||||
(success, delay1, slew1, delay0, slew0) = self.run_simulation(feasible_period, load, slew)
|
||||
debug.check(success,"Couldn't run a simulation properly.\n")
|
||||
debug.check(success,"Couldn't run a simulation. slew={0} load={1}\n".format(slew,load))
|
||||
LH_delay.append(delay1)
|
||||
HL_delay.append(delay0)
|
||||
LH_slew.append(slew1)
|
||||
|
|
@ -394,44 +403,52 @@ class delay():
|
|||
of the cycles to do a timing evaluation. The last time is the end of the simulation
|
||||
and does not need a rising edge."""
|
||||
|
||||
self.cycle_comments = []
|
||||
# idle cycle, no operation
|
||||
t_current = period
|
||||
self.cycle_times = []
|
||||
|
||||
# cycle0: W data 1 address 1111 to initialize cell to a value
|
||||
self.cycle_times.append(t_current)
|
||||
self.cycle_comments.append("Cycle0 {}ns: W data 1 address 11..11 to initialize cell".format(t_current))
|
||||
t_current += period
|
||||
|
||||
# cycle1: W data 0 address 1111 (to ensure a write of value works)
|
||||
self.cycle_times.append(t_current)
|
||||
self.write0_cycle=1
|
||||
self.cycle_comments.append("Cycle1 {}ns: W data 0 address 11..11 (to ensure a write of value works)".format(t_current))
|
||||
t_current += period
|
||||
|
||||
# cycle2: W data 1 address 0000 (to clear the data bus cap)
|
||||
self.cycle_times.append(t_current)
|
||||
self.cycle_comments.append("Cycle2 {}ns: W data 1 address 00..00 (to clear bus caps)".format(t_current))
|
||||
t_current += period
|
||||
|
||||
# cycle3: R data 0 address 1111 to check W0 works
|
||||
self.cycle_times.append(t_current)
|
||||
self.read0_cycle=3
|
||||
self.cycle_comments.append("Cycle3 {}ns: R data 0 address 11..11 to check W0 worked".format(t_current))
|
||||
t_current += period
|
||||
|
||||
# cycle4: W data 1 address 1111 (to ensure a write of value works)
|
||||
self.cycle_times.append(t_current)
|
||||
self.write1_cycle=4
|
||||
self.cycle_comments.append("Cycle4 {}ns: W data 1 address 11..11 (to ensure a write of value worked)".format(t_current))
|
||||
t_current += period
|
||||
|
||||
# cycle5: W data 0 address 0000 (to clear the data bus cap)
|
||||
self.cycle_times.append(t_current)
|
||||
self.cycle_comments.append("Cycle5 {}ns: W data 0 address 00..00 (to clear bus caps)".format(t_current))
|
||||
t_current += period
|
||||
|
||||
# cycle6: R data 1 address 1111 to check W1 works
|
||||
self.cycle_times.append(t_current)
|
||||
self.read1_cycle=6
|
||||
self.cycle_comments.append("Cycle6 {}ns: R data 1 address 11..11 to check W1 worked".format(t_current))
|
||||
t_current += period
|
||||
|
||||
# cycle7: wait a clock period to end the simulation
|
||||
self.cycle_times.append(t_current)
|
||||
self.cycle_comments.append("Cycle7 {}ns: Idle period to end simulation".format(t_current))
|
||||
t_current += period
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,8 @@ class setup_hold():
|
|||
targ_val=targ_val,
|
||||
trig_dir="RISE",
|
||||
targ_dir=dout_rise_or_fall,
|
||||
td=1.9*self.period)
|
||||
trig_td=1.9*self.period,
|
||||
targ_td=1.9*self.period)
|
||||
|
||||
targ_name = "data"
|
||||
# Start triggers right after initialize value is returned to normal
|
||||
|
|
@ -158,7 +159,8 @@ class setup_hold():
|
|||
targ_val=targ_val,
|
||||
trig_dir="RISE",
|
||||
targ_dir=din_rise_or_fall,
|
||||
td=1.2*self.period)
|
||||
trig_td=1.2*self.period,
|
||||
targ_td=1.2*self.period)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -218,17 +218,18 @@ def get_inverse_value(value):
|
|||
debug.error("Invalid value to get an inverse of: {0}".format(value))
|
||||
|
||||
|
||||
def gen_meas_delay(stim_file, meas_name, trig_name, targ_name, trig_val, targ_val, trig_dir, targ_dir, td):
|
||||
def gen_meas_delay(stim_file, meas_name, trig_name, targ_name, trig_val, targ_val, trig_dir, targ_dir, trig_td, targ_td):
|
||||
"""Creates the .meas statement for the measurement of delay"""
|
||||
measure_string=".meas tran {0} TRIG v({1}) VAL={2} {3}=1 TD={7}n TARG v({4}) VAL={5} {6}=1 TD={7}n\n\n"
|
||||
measure_string=".meas tran {0} TRIG v({1}) VAL={2} {3}=1 TD={4}n TARG v({5}) VAL={6} {7}=1 TD={8}n\n\n"
|
||||
stim_file.write(measure_string.format(meas_name,
|
||||
trig_name,
|
||||
trig_val,
|
||||
trig_dir,
|
||||
trig_td,
|
||||
targ_name,
|
||||
targ_val,
|
||||
targ_dir,
|
||||
td))
|
||||
targ_td))
|
||||
|
||||
def gen_meas_power(stim_file, meas_name, t_initial, t_final):
|
||||
"""Creates the .meas statement for the measurement of avg power"""
|
||||
|
|
@ -246,7 +247,13 @@ def gen_meas_power(stim_file, meas_name, t_initial, t_final):
|
|||
def write_control(stim_file, end_time):
|
||||
# UIC is needed for ngspice to converge
|
||||
stim_file.write(".TRAN 5p {0}n UIC\n".format(end_time))
|
||||
stim_file.write(".OPTIONS POST=1 RUNLVL=4 PROBE\n")
|
||||
if OPTS.spice_name == "ngspice":
|
||||
# ngspice sometimes has convergence problems if not using gear method
|
||||
# which is more accurate, but slower than the default trapezoid method
|
||||
stim_file.write(".OPTIONS POST=1 RUNLVL=4 PROBE method=gear\n")
|
||||
else:
|
||||
stim_file.write(".OPTIONS POST=1 RUNLVL=4 PROBE\n")
|
||||
|
||||
# create plots for all signals
|
||||
stim_file.write("* probe is used for hspice/xa, while plot is used in ngspice\n")
|
||||
if OPTS.debug_level>0:
|
||||
|
|
@ -265,7 +272,10 @@ def write_control(stim_file, end_time):
|
|||
def write_include(stim_file, models):
|
||||
"""Writes include statements, inputs are lists of model files"""
|
||||
for item in list(models):
|
||||
stim_file.write(".include \"{0}\"\n\n".format(item))
|
||||
if os.path.isfile(item):
|
||||
stim_file.write(".include \"{0}\"\n\n".format(item))
|
||||
else:
|
||||
debug.error("Could not find spice model: {0}\nSet SPICE_MODEL_DIR to over-ride path.\n".format(item))
|
||||
|
||||
|
||||
def write_supply(stim_file):
|
||||
|
|
@ -282,26 +292,26 @@ def run_sim():
|
|||
temp_stim = "{0}stim.sp".format(OPTS.openram_temp)
|
||||
import datetime
|
||||
start_time = datetime.datetime.now()
|
||||
debug.check(OPTS.spice_exe!="","No spice simulator has been found.")
|
||||
|
||||
from characterizer import spice_exe
|
||||
if OPTS.spice_name == "xa":
|
||||
# Output the xa configurations here. FIXME: Move this to write it once.
|
||||
xa_cfg = open("{}xa.cfg".format(OPTS.openram_temp), "w")
|
||||
xa_cfg.write("set_sim_level -level 7\n")
|
||||
xa_cfg.write("set_powernet_level 7 -node vdd\n")
|
||||
xa_cfg.close()
|
||||
cmd = "{0} {1} -c {2}xa.cfg -o {2}xa -mt 20".format(spice_exe,
|
||||
cmd = "{0} {1} -c {2}xa.cfg -o {2}xa -mt 2".format(OPTS.spice_exe,
|
||||
temp_stim,
|
||||
OPTS.openram_temp)
|
||||
valid_retcode=0
|
||||
elif OPTS.spice_name == "hspice":
|
||||
# TODO: Should make multithreading parameter a configuration option
|
||||
cmd = "{0} -mt 2 -i {1} -o {2}timing".format(spice_exe,
|
||||
cmd = "{0} -mt 2 -i {1} -o {2}timing".format(OPTS.spice_exe,
|
||||
temp_stim,
|
||||
OPTS.openram_temp)
|
||||
valid_retcode=0
|
||||
else:
|
||||
cmd = "{0} -b -o {2}timing.lis {1}".format(spice_exe,
|
||||
cmd = "{0} -b -o {2}timing.lis {1}".format(OPTS.spice_exe,
|
||||
temp_stim,
|
||||
OPTS.openram_temp)
|
||||
# for some reason, ngspice-25 returns 1 when it only has acceptable warnings
|
||||
|
|
|
|||
|
|
@ -45,23 +45,33 @@ class trim_spice():
|
|||
|
||||
# Always start fresh if we do multiple reductions
|
||||
self.sp_buffer = self.spice
|
||||
|
||||
# Find the row and column indices for the removals
|
||||
# Convert address froms tring to int
|
||||
address = int(address,2)
|
||||
array_row = address >> self.col_addr_size
|
||||
# Which word in the array (0 if only one word)
|
||||
if self.col_addr_size>0:
|
||||
lower_mask = int(self.col_addr_size-1)
|
||||
lower_address = address & lower_mask
|
||||
else:
|
||||
lower_address=0
|
||||
# Which bit in the array
|
||||
array_bit = lower_address*self.word_size + data_bit
|
||||
|
||||
# Split up the address and convert to an int
|
||||
wl_address = int(address[self.col_addr_size:],2)
|
||||
if self.col_addr_size>1:
|
||||
col_address = int(address[0:self.col_addr_size],2)
|
||||
else:
|
||||
col_address = 0
|
||||
# 1. Keep cells in the bitcell array based on WL and BL
|
||||
wl_name = "wl[{}]".format(array_row)
|
||||
bl_name = "bl[{}]".format(array_bit)
|
||||
wl_name = "wl[{}]".format(wl_address)
|
||||
bl_name = "bl[{}]".format(self.words_per_row*data_bit + col_address)
|
||||
|
||||
# Prepend info about the trimming
|
||||
addr_msg = "Keeping {} address".format(address)
|
||||
self.sp_buffer.insert(0, "* "+addr_msg)
|
||||
debug.info(1,addr_msg)
|
||||
data_msg = "Keeping {} data bit".format(data_bit)
|
||||
self.sp_buffer.insert(0, "* "+data_msg)
|
||||
debug.info(1,data_msg)
|
||||
bl_msg = "Keeping {} (trimming other BLs)".format(bl_name)
|
||||
wl_msg = "Keeping {} (trimming other WLs)".format(wl_name)
|
||||
self.sp_buffer.insert(0, "* "+bl_msg)
|
||||
debug.info(1,bl_msg)
|
||||
self.sp_buffer.insert(0, "* "+wl_msg)
|
||||
debug.info(1,wl_msg)
|
||||
self.sp_buffer.insert(0, "* It should NOT be used for LVS!!")
|
||||
self.sp_buffer.insert(0, "* WARNING: This is a TRIMMED NETLIST.")
|
||||
|
||||
self.remove_insts("bitcell_array",[wl_name,bl_name])
|
||||
|
||||
# 2. Keep sense amps basd on BL
|
||||
|
|
|
|||
|
|
@ -11,19 +11,34 @@ class contact(design.design):
|
|||
Creates a contact array minimum active or poly enclosure and metal1 enclosure.
|
||||
This class has enclosure on multiple sides of the contact whereas a via may
|
||||
have extension on two or four sides.
|
||||
The well/implant_type is an option to add a select/implant layer enclosing the contact. This is
|
||||
necessary to import layouts into Magic which requires the select to be in the same GDS
|
||||
hierarchy as the contact.
|
||||
"""
|
||||
def __init__(self, layer_stack, dimensions=[1,1]):
|
||||
name = "{0}_{1}_{2}_{3}x{4}".format(layer_stack[0],
|
||||
layer_stack[1],
|
||||
layer_stack[2],
|
||||
dimensions[0],
|
||||
dimensions[1])
|
||||
def __init__(self, layer_stack, dimensions=[1,1], implant_type=None, well_type=None):
|
||||
if implant_type or well_type:
|
||||
name = "{0}_{1}_{2}_{3}x{4}_{5}{6}".format(layer_stack[0],
|
||||
layer_stack[1],
|
||||
layer_stack[2],
|
||||
dimensions[0],
|
||||
dimensions[1],
|
||||
implant_type,
|
||||
well_type)
|
||||
else:
|
||||
name = "{0}_{1}_{2}_{3}x{4}".format(layer_stack[0],
|
||||
layer_stack[1],
|
||||
layer_stack[2],
|
||||
dimensions[0],
|
||||
dimensions[1])
|
||||
|
||||
design.design.__init__(self, name)
|
||||
debug.info(4, "create contact object {0}".format(name))
|
||||
|
||||
self.layer_stack = layer_stack
|
||||
self.dimensions = dimensions
|
||||
self.offset = vector(0,0)
|
||||
self.implant_type = implant_type
|
||||
self.well_type = well_type
|
||||
self.pins = [] # used for matching parm lengths
|
||||
self.create_layout()
|
||||
|
||||
|
|
@ -37,74 +52,112 @@ class contact(design.design):
|
|||
self.height = max(obj.offset.y + obj.height for obj in self.objs)
|
||||
self.width = max(obj.offset.x + obj.width for obj in self.objs)
|
||||
|
||||
# Do not include the select layer in the height/width
|
||||
if self.implant_type and self.well_type:
|
||||
self.create_implant_well_enclosures()
|
||||
elif self.implant_type or self.well_type:
|
||||
debug.error(-1,"Must define both implant and well type or none at all.")
|
||||
|
||||
def setup_layers(self):
|
||||
(first_layer, via_layer, second_layer) = self.layer_stack
|
||||
self.first_layer_name = first_layer
|
||||
self.via_layer_name = via_layer
|
||||
# Some technologies have a separate active contact from the poly contact
|
||||
# We will use contact for DRC, but active_contact for output
|
||||
if first_layer=="active" or second_layer=="active":
|
||||
self.via_layer_name_expanded = "active_"+via_layer
|
||||
else:
|
||||
self.via_layer_name_expanded = via_layer
|
||||
self.second_layer_name = second_layer
|
||||
|
||||
def setup_layout_constants(self):
|
||||
self.contact_width = drc["minwidth_{0}". format(self.via_layer_name)]
|
||||
self.contact_to_contact = drc["{0}_to_{0}".format(self.via_layer_name)]
|
||||
self.contact_pitch = self.contact_width + self.contact_to_contact
|
||||
contact_to_contact = drc["{0}_to_{0}".format(self.via_layer_name)]
|
||||
self.contact_pitch = self.contact_width + contact_to_contact
|
||||
self.contact_array_width = self.contact_width + (self.dimensions[0] - 1) * self.contact_pitch
|
||||
self.contact_array_height = self.contact_width + (self.dimensions[1] - 1) * self.contact_pitch
|
||||
|
||||
# FIME break this up
|
||||
self.first_layer_horizontal_enclosure = max((drc["minwidth_{0}".format(self.first_layer_name)] - self.contact_array_width) / 2,
|
||||
drc["{0}_enclosure_{1}".format(self.first_layer_name, self.via_layer_name)])
|
||||
self.first_layer_vertical_enclosure = max(utils.ceil((drc["minarea_{0}".format(self.first_layer_name)]
|
||||
/ (self.contact_array_width + 2 * self.first_layer_horizontal_enclosure) - self.contact_array_height) / 2),
|
||||
(drc["minheight_{0}".format(self.first_layer_name)] - self.contact_array_height) / 2,
|
||||
drc["{0}_extend_{1}".format(self.first_layer_name, self.via_layer_name)])
|
||||
# DRC rules
|
||||
first_layer_minwidth = drc["minwidth_{0}".format(self.first_layer_name)]
|
||||
first_layer_minarea = drc["minarea_{0}".format(self.first_layer_name)]
|
||||
first_layer_enclosure = drc["{0}_enclosure_{1}".format(self.first_layer_name, self.via_layer_name)]
|
||||
first_layer_extend = drc["{0}_extend_{1}".format(self.first_layer_name, self.via_layer_name)]
|
||||
second_layer_minwidth = drc["minwidth_{0}".format(self.second_layer_name)]
|
||||
second_layer_minarea = drc["minarea_{0}".format(self.second_layer_name)]
|
||||
second_layer_enclosure = drc["{0}_enclosure_{1}".format(self.second_layer_name, self.via_layer_name)]
|
||||
second_layer_extend = drc["{0}_extend_{1}".format(self.second_layer_name, self.via_layer_name)]
|
||||
|
||||
self.second_layer_horizontal_enclosure = max((drc["minwidth_{0}".format(self.second_layer_name)] - self.contact_array_width) / 2,
|
||||
drc["{0}_enclosure_{1}".format(self.second_layer_name, self.via_layer_name)])
|
||||
self.second_layer_vertical_enclosure = max(utils.ceil((drc["minarea_{0}".format(self.second_layer_name)]
|
||||
/ (self.contact_array_width + 2 * self.second_layer_horizontal_enclosure) - self.contact_array_height) / 2),
|
||||
(drc["minheight_{0}".format(self.second_layer_name)] - self.contact_array_height) / 2,
|
||||
drc["{0}_extend_{1}".format(self.second_layer_name, self.via_layer_name)])
|
||||
self.first_layer_horizontal_enclosure = max((first_layer_minwidth - self.contact_array_width) / 2,
|
||||
first_layer_enclosure)
|
||||
self.first_layer_vertical_enclosure = max(utils.ceil((first_layer_minarea
|
||||
/ (self.contact_array_width + 2*self.first_layer_horizontal_enclosure)
|
||||
- self.contact_array_height)/2),
|
||||
(first_layer_minwidth - self.contact_array_height)/2,
|
||||
first_layer_extend)
|
||||
|
||||
self.second_layer_horizontal_enclosure = max((second_layer_minwidth - self.contact_array_width)/2,
|
||||
second_layer_enclosure)
|
||||
self.second_layer_vertical_enclosure = max(utils.ceil((second_layer_minarea
|
||||
/ (self.contact_array_width + 2*self.second_layer_horizontal_enclosure)
|
||||
- self.contact_array_height)/2),
|
||||
(second_layer_minwidth - self.contact_array_height)/2,
|
||||
second_layer_extend)
|
||||
|
||||
def create_contact_array(self):
|
||||
""" Create the contact array at the origin"""
|
||||
# offset for the via array
|
||||
self.via_layer_position =vector(max(self.first_layer_horizontal_enclosure,self.second_layer_horizontal_enclosure),
|
||||
max(self.first_layer_vertical_enclosure,self.second_layer_vertical_enclosure))
|
||||
# this is if the first and second layers are different
|
||||
self.first_layer_position = vector(max(self.second_layer_horizontal_enclosure - self.first_layer_horizontal_enclosure,0),
|
||||
max(self.second_layer_vertical_enclosure - self.first_layer_vertical_enclosure,0))
|
||||
self.second_layer_position = vector(max(self.first_layer_horizontal_enclosure - self.second_layer_horizontal_enclosure,0),
|
||||
max(self.first_layer_vertical_enclosure - self.second_layer_vertical_enclosure,0))
|
||||
|
||||
def create_contact_array(self):
|
||||
""" Create the contact array at the origin"""
|
||||
for i in range(self.dimensions[1]):
|
||||
offset = self.via_layer_position + vector(0, self.contact_pitch * i)
|
||||
for j in range(self.dimensions[0]):
|
||||
self.add_rect(layer=self.via_layer_name,
|
||||
self.add_rect(layer=self.via_layer_name_expanded,
|
||||
offset=offset,
|
||||
width=self.contact_width,
|
||||
height=self.contact_width)
|
||||
offset = offset + vector(self.contact_pitch,0)
|
||||
|
||||
def create_first_layer_enclosure(self):
|
||||
width = self.first_layer_width = self.contact_array_width \
|
||||
+ 2 * self.first_layer_horizontal_enclosure
|
||||
height = self.first_layer_height = self.contact_array_height \
|
||||
+ 2 * self.first_layer_vertical_enclosure
|
||||
# this is if the first and second layers are different
|
||||
self.first_layer_position = vector(max(self.second_layer_horizontal_enclosure - self.first_layer_horizontal_enclosure,0),
|
||||
max(self.second_layer_vertical_enclosure - self.first_layer_vertical_enclosure,0))
|
||||
|
||||
self.first_layer_width = self.contact_array_width + 2*self.first_layer_horizontal_enclosure
|
||||
self.first_layer_height = self.contact_array_height + 2*self.first_layer_vertical_enclosure
|
||||
self.add_rect(layer=self.first_layer_name,
|
||||
offset=self.first_layer_position,
|
||||
width=width,
|
||||
height=height)
|
||||
width=self.first_layer_width,
|
||||
height=self.first_layer_height)
|
||||
|
||||
def create_second_layer_enclosure(self):
|
||||
width = self.second_layer_width = self.contact_array_width \
|
||||
+ 2 * self.second_layer_horizontal_enclosure
|
||||
height = self.second_layer_height = self.contact_array_height \
|
||||
+ 2 * self.second_layer_vertical_enclosure
|
||||
# this is if the first and second layers are different
|
||||
self.second_layer_position = vector(max(self.first_layer_horizontal_enclosure - self.second_layer_horizontal_enclosure,0),
|
||||
max(self.first_layer_vertical_enclosure - self.second_layer_vertical_enclosure,0))
|
||||
|
||||
self.second_layer_width = self.contact_array_width + 2*self.second_layer_horizontal_enclosure
|
||||
self.second_layer_height = self.contact_array_height + 2*self.second_layer_vertical_enclosure
|
||||
self.add_rect(layer=self.second_layer_name,
|
||||
offset=self.second_layer_position,
|
||||
width=width,
|
||||
height=height)
|
||||
width=self.second_layer_width,
|
||||
height=self.second_layer_height)
|
||||
|
||||
def create_implant_well_enclosures(self):
|
||||
implant_position = self.first_layer_position - [drc["implant_enclosure_active"]]*2
|
||||
implant_width = self.first_layer_width + 2*drc["implant_enclosure_active"]
|
||||
implant_height = self.first_layer_height + 2*drc["implant_enclosure_active"]
|
||||
self.add_rect(layer="{}implant".format(self.implant_type),
|
||||
offset=implant_position,
|
||||
width=implant_width,
|
||||
height=implant_height)
|
||||
well_position = self.first_layer_position - [drc["well_enclosure_active"]]*2
|
||||
well_width = self.first_layer_width + 2*drc["well_enclosure_active"]
|
||||
well_height = self.first_layer_height + 2*drc["well_enclosure_active"]
|
||||
self.add_rect(layer="{}well".format(self.well_type),
|
||||
offset=well_position,
|
||||
width=well_width,
|
||||
height=well_height)
|
||||
|
||||
|
||||
|
||||
# This is not instantiated and used for calculations only.
|
||||
|
|
|
|||
|
|
@ -59,15 +59,15 @@ class control_logic(design.design):
|
|||
self.inv16 = pinv(16)
|
||||
self.add_mod(self.inv16)
|
||||
|
||||
c = reload(__import__(OPTS.config.ms_flop_array))
|
||||
ms_flop_array = getattr(c, OPTS.config.ms_flop_array)
|
||||
c = reload(__import__(OPTS.ms_flop_array))
|
||||
ms_flop_array = getattr(c, OPTS.ms_flop_array)
|
||||
self.msf_control = ms_flop_array(name="msf_control",
|
||||
columns=3,
|
||||
word_size=3)
|
||||
self.add_mod(self.msf_control)
|
||||
|
||||
c = reload(__import__(OPTS.config.replica_bitline))
|
||||
replica_bitline = getattr(c, OPTS.config.replica_bitline)
|
||||
c = reload(__import__(OPTS.replica_bitline))
|
||||
replica_bitline = getattr(c, OPTS.replica_bitline)
|
||||
self.replica_bitline = replica_bitline(rows=int(math.ceil(self.num_rows / 10.0)))
|
||||
self.add_mod(self.replica_bitline)
|
||||
|
||||
|
|
@ -77,8 +77,6 @@ class control_logic(design.design):
|
|||
# These aren't for instantiating, but we use them to get the dimensions
|
||||
self.poly_contact_offset = vector(0.5*contact.poly.width,0.5*contact.poly.height)
|
||||
|
||||
# For different layer width vias
|
||||
self.m1m2_offset_fix = vector(0,0.5*(drc["minwidth_metal2"]-drc["minwidth_metal1"]))
|
||||
# M1/M2 routing pitch is based on contacted pitch
|
||||
self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(drc["metal1_to_metal1"],drc["metal2_to_metal2"])
|
||||
self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(drc["metal2_to_metal2"],drc["metal3_to_metal3"])
|
||||
|
|
@ -87,10 +85,6 @@ class control_logic(design.design):
|
|||
# Some cells may have pwell/nwell spacing problems too when the wells are different heights.
|
||||
self.cell_gap = max(self.m2_pitch,drc["pwell_to_nwell"])
|
||||
|
||||
# Amount to shift a 90 degree rotated via from center-line path routing to it's offset
|
||||
self.m1m2_via_offset = vector(contact.m1m2.first_layer_height,-0.5*drc["minwidth_metal2"])
|
||||
self.m2m3_via_offset = vector(contact.m2m3.first_layer_height,-0.5*drc["minwidth_metal3"])
|
||||
|
||||
# First RAIL Parameters: gnd, oe, oebar, cs, we, clk_buf, clk_bar
|
||||
self.rail_1_start_x = 0
|
||||
self.num_rails_1 = 8
|
||||
|
|
@ -275,7 +269,7 @@ class control_logic(design.design):
|
|||
mod=self.nand2,
|
||||
offset=self.tri_en_bar_offset,
|
||||
mirror="MX")
|
||||
self.connect_inst(["oe", "clk_bar", "tri_en_bar", "vdd", "gnd"])
|
||||
self.connect_inst(["clk_bar", "oe", "tri_en_bar", "vdd", "gnd"])
|
||||
x_off += self.nand2.width
|
||||
|
||||
x_off += self.inv1.width + self.cell_gap
|
||||
|
|
@ -326,6 +320,7 @@ class control_logic(design.design):
|
|||
x_off += self.inv1.width
|
||||
|
||||
# BUFFER INVERTERS FOR W_EN
|
||||
# FIXME: Can we remove these two invs and size the previous one?
|
||||
self.pre_w_en_bar_offset = vector(x_off, y_off)
|
||||
self.pre_w_en_bar=self.add_inst(name="inv_pre_w_en_bar",
|
||||
mod=self.inv1,
|
||||
|
|
@ -512,11 +507,25 @@ class control_logic(design.design):
|
|||
offset=clk_buf_rail_position,
|
||||
rotate=90)
|
||||
|
||||
# clk_bar
|
||||
self.connect_rail_from_left_m2m3(self.clk_bar,"Z","clk_bar")
|
||||
# clk_bar, routes over the clock buffer vdd rail
|
||||
clk_pin = self.clk_bar.get_pin("Z")
|
||||
vdd_pin = self.clk_bar.get_pin("vdd")
|
||||
# move the output pin up to metal2
|
||||
self.add_via_center(layers=("metal1","via1","metal2"),
|
||||
offset=self.clk_bar.get_pin("Z").rc(),
|
||||
offset=clk_pin.rc(),
|
||||
rotate=90)
|
||||
# route to a position over the supply rail
|
||||
in_pos = vector(clk_pin.rx(), vdd_pin.cy())
|
||||
self.add_path("metal2",[clk_pin.rc(), in_pos])
|
||||
# connect that position to the control bus
|
||||
rail_pos = vector(self.rail_1_x_offsets["clk_bar"], in_pos.y)
|
||||
self.add_wire(("metal3","via2","metal2"),[in_pos, rail_pos])
|
||||
self.add_via_center(layers=("metal2","via2","metal3"),
|
||||
offset=in_pos,
|
||||
rotate=90)
|
||||
self.add_via_center(layers=("metal2","via2","metal3"),
|
||||
offset=rail_pos,
|
||||
rotate=90)
|
||||
|
||||
# clk_buf to msf control flops
|
||||
msf_clk_pos = self.msf_inst.get_pin("clk").bc()
|
||||
|
|
|
|||
|
|
@ -14,14 +14,13 @@ def check(check,str):
|
|||
index) = inspect.getouterframes(inspect.currentframe())[1]
|
||||
if not check:
|
||||
print("ERROR: file {0}: line {1}: {2}".format(os.path.basename(filename),line_number,str))
|
||||
sys.exit(-1)
|
||||
assert 0
|
||||
|
||||
def error(str,return_value=None):
|
||||
def error(str,return_value=0):
|
||||
(frame, filename, line_number, function_name, lines,
|
||||
index) = inspect.getouterframes(inspect.currentframe())[1]
|
||||
print("ERROR: file {0}: line {1}: {2}".format(os.path.basename(filename),line_number,str))
|
||||
if return_value:
|
||||
sys.exit(return_value)
|
||||
assert return_value==0
|
||||
|
||||
def warning(str):
|
||||
(frame, filename, line_number, function_name, lines,
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ class delay_chain(design.design):
|
|||
self.num_inverters = 1 + sum(fanout_list)
|
||||
self.num_top_half = round(self.num_inverters / 2.0)
|
||||
|
||||
c = reload(__import__(OPTS.config.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.config.bitcell)
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
|
||||
self.add_pins()
|
||||
|
|
|
|||
|
|
@ -27,8 +27,13 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
|
|||
|
||||
# Check if the name already exists, if so, give an error
|
||||
# because each reference must be a unique name.
|
||||
ok_list = ['ms_flop.ms_flop', 'bitcell.bitcell', 'contact.contact',
|
||||
'ptx.ptx', 'sram.sram',
|
||||
# These modules ensure unique names or have no changes if they
|
||||
# aren't unique
|
||||
ok_list = ['ms_flop.ms_flop',
|
||||
'bitcell.bitcell',
|
||||
'contact.contact',
|
||||
'ptx.ptx',
|
||||
'sram.sram',
|
||||
'hierarchical_predecode2x4.hierarchical_predecode2x4',
|
||||
'hierarchical_predecode3x8.hierarchical_predecode3x8']
|
||||
if name not in design.name_map:
|
||||
|
|
@ -41,6 +46,7 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
|
|||
def setup_drc_constants(self):
|
||||
""" These are some DRC constants used in many places in the compiler."""
|
||||
from tech import drc
|
||||
self.well_width = drc["minwidth_well"]
|
||||
self.poly_width = drc["minwidth_poly"]
|
||||
self.poly_space = drc["poly_to_poly"]
|
||||
self.m1_width = drc["minwidth_metal1"]
|
||||
|
|
@ -49,7 +55,16 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
|
|||
self.m2_space = drc["metal2_to_metal2"]
|
||||
self.m3_width = drc["minwidth_metal3"]
|
||||
self.m3_space = drc["metal3_to_metal3"]
|
||||
|
||||
self.active_width = drc["minwidth_active"]
|
||||
self.contact_width = drc["minwidth_contact"]
|
||||
|
||||
self.poly_to_active = drc["poly_to_active"]
|
||||
self.poly_extend_active = drc["poly_extend_active"]
|
||||
self.contact_to_gate = drc["contact_to_gate"]
|
||||
self.well_enclose_active = drc["well_enclosure_active"]
|
||||
self.implant_enclose_active = drc["implant_enclosure_active"]
|
||||
self.implant_space = drc["implant_to_implant"]
|
||||
|
||||
def get_layout_pins(self,inst):
|
||||
""" Return a map of pin locations of the instance offset """
|
||||
# find the instance
|
||||
|
|
@ -62,7 +77,7 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
|
|||
return inst_map
|
||||
|
||||
|
||||
def DRC_LVS(self):
|
||||
def DRC_LVS(self, final_verification=False):
|
||||
"""Checks both DRC and LVS for a module"""
|
||||
if OPTS.check_lvsdrc:
|
||||
tempspice = OPTS.openram_temp + "/temp.sp"
|
||||
|
|
@ -70,7 +85,7 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
|
|||
self.sp_write(tempspice)
|
||||
self.gds_write(tempgds)
|
||||
debug.check(verify.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name))
|
||||
debug.check(verify.run_lvs(self.name, tempgds, tempspice) == 0,"LVS failed for {0}".format(self.name))
|
||||
debug.check(verify.run_lvs(self.name, tempgds, tempspice, final_verification) == 0,"LVS failed for {0}".format(self.name))
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
|
|
@ -82,14 +97,14 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
|
|||
debug.check(verify.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name))
|
||||
os.remove(tempgds)
|
||||
|
||||
def LVS(self):
|
||||
def LVS(self, final_verification=False):
|
||||
"""Checks LVS for a module"""
|
||||
if OPTS.check_lvsdrc:
|
||||
tempspice = OPTS.openram_temp + "/temp.sp"
|
||||
tempgds = OPTS.openram_temp + "/temp.gds"
|
||||
self.sp_write(tempspice)
|
||||
self.gds_write(tempgds)
|
||||
debug.check(verify.run_lvs(self.name, tempgds, tempspice) == 0,"LVS failed for {0}".format(self.name))
|
||||
debug.check(verify.run_lvs(self.name, tempgds, tempspice, final_verification) == 0,"LVS failed for {0}".format(self.name))
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,24 +4,6 @@ num_banks = 1
|
|||
|
||||
tech_name = "freepdk45"
|
||||
|
||||
output_path = "/tmp/mysram"
|
||||
output_path = "temp"
|
||||
output_name = "sram_2_16_1_freepdk45"
|
||||
|
||||
decoder = "hierarchical_decoder"
|
||||
ms_flop = "ms_flop"
|
||||
ms_flop_array = "ms_flop_array"
|
||||
control_logic = "control_logic"
|
||||
bitcell_array = "bitcell_array"
|
||||
sense_amp = "sense_amp"
|
||||
sense_amp_array = "sense_amp_array"
|
||||
precharge_array = "precharge_array"
|
||||
column_mux_array = "single_level_column_mux_array"
|
||||
write_driver = "write_driver"
|
||||
write_driver_array = "write_driver_array"
|
||||
tri_gate = "tri_gate"
|
||||
tri_gate_array = "tri_gate_array"
|
||||
wordline_driver = "wordline_driver"
|
||||
replica_bitline = "replica_bitline"
|
||||
replica_bitcell = "replica_bitcell"
|
||||
bitcell = "bitcell"
|
||||
delay_chain = "delay_chain"
|
||||
|
|
|
|||
|
|
@ -1,27 +1,9 @@
|
|||
word_size = 1
|
||||
word_size = 2
|
||||
num_words = 16
|
||||
num_banks = 1
|
||||
|
||||
tech_name = "scn3me_subm"
|
||||
|
||||
output_path = "/tmp/mysram"
|
||||
output_path = "temp"
|
||||
output_name = "sram_2_16_1_scn3me_subm"
|
||||
|
||||
decoder = "hierarchical_decoder"
|
||||
ms_flop = "ms_flop"
|
||||
ms_flop_array = "ms_flop_array"
|
||||
control_logic = "control_logic"
|
||||
bitcell_array = "bitcell_array"
|
||||
sense_amp = "sense_amp"
|
||||
sense_amp_array = "sense_amp_array"
|
||||
precharge_array = "precharge_array"
|
||||
column_mux_array = "single_level_column_mux_array"
|
||||
write_driver = "write_driver"
|
||||
write_driver_array = "write_driver_array"
|
||||
tri_gate = "tri_gate"
|
||||
tri_gate_array = "tri_gate_array"
|
||||
wordline_driver = "wordline_driver"
|
||||
replica_bitline = "replica_bitline"
|
||||
replica_bitcell = "replica_bitcell"
|
||||
bitcell = "bitcell"
|
||||
delay_chain = "delay_chain"
|
||||
|
|
|
|||
|
|
@ -11,9 +11,6 @@ import sys
|
|||
import re
|
||||
import importlib
|
||||
|
||||
# Current version of OpenRAM.
|
||||
VERSION = "1.01"
|
||||
|
||||
USAGE = "Usage: openram.py [options] <config file>\nUse -h for help.\n"
|
||||
|
||||
# Anonymous object that will be the options
|
||||
|
|
@ -50,22 +47,26 @@ def parse_args():
|
|||
optparse.make_option("-r", "--remove_netlist_trimming", action="store_false", dest="trim_netlist",
|
||||
help="Disable removal of noncritical memory cells during characterization"),
|
||||
optparse.make_option("-c", "--characterize", action="store_false", dest="analytical_delay",
|
||||
help="Perform characterization to calculate delays (default is analytical models)")
|
||||
help="Perform characterization to calculate delays (default is analytical models)"),
|
||||
optparse.make_option("-d", "--dontpurge", action="store_false", dest="purge_temp",
|
||||
help="Don't purge the contents of the temp directory after a successful run")
|
||||
# -h --help is implicit.
|
||||
}
|
||||
|
||||
parser = optparse.OptionParser(option_list=option_list,
|
||||
description="Compile and/or characterize an SRAM.",
|
||||
usage=USAGE,
|
||||
version="OpenRAM v" + VERSION)
|
||||
version="OpenRAM")
|
||||
|
||||
(options, args) = parser.parse_args(values=OPTS)
|
||||
|
||||
# If we don't specify a tech, assume freepdk45.
|
||||
# This may be overridden when we read a config file though...
|
||||
if OPTS.tech_name == "":
|
||||
OPTS.tech_name = "freepdk45"
|
||||
|
||||
# Alias SCMOS to AMI 0.5um
|
||||
if OPTS.tech_name == "scmos":
|
||||
OPTS.tech_name = "scn3me_subm"
|
||||
|
||||
return (options, args)
|
||||
|
||||
def print_banner():
|
||||
|
|
@ -75,7 +76,7 @@ def print_banner():
|
|||
return
|
||||
|
||||
print("|==============================================================================|")
|
||||
name = "OpenRAM Compiler v"+VERSION
|
||||
name = "OpenRAM Compiler"
|
||||
print("|=========" + name.center(60) + "=========|")
|
||||
print("|=========" + " ".center(60) + "=========|")
|
||||
print("|=========" + "VLSI Design and Automation Lab".center(60) + "=========|")
|
||||
|
|
@ -99,13 +100,13 @@ def init_openram(config_file):
|
|||
|
||||
import_tech()
|
||||
|
||||
|
||||
def get_tool(tool_type, preferences):
|
||||
"""
|
||||
Find which tool we have from a list of preferences and return the
|
||||
one selected and its full path.
|
||||
"""
|
||||
debug.info(2,"Finding {} tool...".format(tool_type))
|
||||
global OPTS
|
||||
|
||||
for name in preferences:
|
||||
exe_name = find_exe(name)
|
||||
|
|
@ -125,6 +126,8 @@ def read_config(config_file):
|
|||
config file is just a Python file that defines some config
|
||||
options.
|
||||
"""
|
||||
global OPTS
|
||||
|
||||
# Create a full path relative to current dir unless it is already an abs path
|
||||
if not os.path.isabs(config_file):
|
||||
config_file = os.getcwd() + "/" + config_file
|
||||
|
|
@ -140,18 +143,17 @@ def read_config(config_file):
|
|||
# Import the configuration file of which modules to use
|
||||
debug.info(1, "Configuration file is " + config_file + ".py")
|
||||
try:
|
||||
OPTS.config = importlib.import_module(file_name)
|
||||
config = importlib.import_module(file_name)
|
||||
except:
|
||||
debug.error("Unable to read configuration file: {0}".format(config_file),2)
|
||||
|
||||
# This path must be setup after the config file.
|
||||
try:
|
||||
# If path not set on command line, try config file.
|
||||
if OPTS.output_path=="":
|
||||
OPTS.output_path=OPTS.config.output_path
|
||||
except:
|
||||
# Default to current directory.
|
||||
OPTS.output_path="."
|
||||
for k,v in config.__dict__.items():
|
||||
# The command line will over-ride the config file
|
||||
# except in the case of the tech name! This is because the tech name
|
||||
# is sometimes used to specify the config file itself (e.g. unit tests)
|
||||
if not k in OPTS.__dict__ or k=="tech_name":
|
||||
OPTS.__dict__[k]=v
|
||||
|
||||
if not OPTS.output_path.endswith('/'):
|
||||
OPTS.output_path += "/"
|
||||
debug.info(1, "Output saved in " + OPTS.output_path)
|
||||
|
|
@ -172,16 +174,15 @@ def end_openram():
|
|||
""" Clean up openram for a proper exit """
|
||||
cleanup_paths()
|
||||
|
||||
# Reset the static duplicate name checker for unit tests.
|
||||
# This is needed for running unit tests.
|
||||
import design
|
||||
design.design.name_map=[]
|
||||
|
||||
|
||||
def cleanup_paths():
|
||||
"""
|
||||
We should clean up the temp directory after execution.
|
||||
"""
|
||||
if not OPTS.purge_temp:
|
||||
debug.info(0,"Preserving temp directory: {}".format(OPTS.openram_temp))
|
||||
return
|
||||
if os.path.exists(OPTS.openram_temp):
|
||||
shutil.rmtree(OPTS.openram_temp, ignore_errors=True)
|
||||
|
||||
|
|
@ -242,7 +243,7 @@ def import_tech():
|
|||
debug.info(2,"Importing technology: " + OPTS.tech_name)
|
||||
|
||||
# Set the tech to the config file we read in instead of the command line value.
|
||||
OPTS.tech_name = OPTS.config.tech_name
|
||||
OPTS.tech_name = OPTS.tech_name
|
||||
|
||||
|
||||
# environment variable should point to the technology dir
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ class hierarchical_decoder(design.design):
|
|||
def __init__(self, rows):
|
||||
design.design.__init__(self, "hierarchical_decoder_{0}rows".format(rows))
|
||||
|
||||
c = reload(__import__(OPTS.config.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.config.bitcell)
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell_height = self.mod_bitcell.height
|
||||
|
||||
self.pre2x4_inst = []
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ class hierarchical_predecode(design.design):
|
|||
self.number_of_outputs = int(math.pow(2, self.number_of_inputs))
|
||||
design.design.__init__(self, name="pre{0}x{1}".format(self.number_of_inputs,self.number_of_outputs))
|
||||
|
||||
c = reload(__import__(OPTS.config.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.config.bitcell)
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell_height = self.mod_bitcell.height
|
||||
|
||||
|
||||
|
|
@ -252,7 +252,7 @@ class hierarchical_predecode(design.design):
|
|||
if self.number_of_inputs == 2:
|
||||
gate_lst = ["A","B"]
|
||||
else:
|
||||
gate_lst = ["A","B","C"]
|
||||
gate_lst = ["A","B","C"]
|
||||
|
||||
# this will connect pins A,B or A,B,C
|
||||
for rail_pin,gate_pin in zip(index_lst,gate_lst):
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
|||
self.create_rails()
|
||||
self.add_input_inverters()
|
||||
self.add_output_inverters()
|
||||
connections =[["in[0]", "in[1]", "Z[3]", "vdd", "gnd"],
|
||||
["inbar[0]", "in[1]", "Z[2]", "vdd", "gnd"],
|
||||
connections =[["inbar[0]", "inbar[1]", "Z[0]", "vdd", "gnd"],
|
||||
["in[0]", "inbar[1]", "Z[1]", "vdd", "gnd"],
|
||||
["inbar[0]", "inbar[1]", "Z[0]", "vdd", "gnd"]]
|
||||
["inbar[0]", "in[1]", "Z[2]", "vdd", "gnd"],
|
||||
["in[0]", "in[1]", "Z[3]", "vdd", "gnd"]]
|
||||
self.add_nand(connections)
|
||||
self.route()
|
||||
|
||||
|
|
|
|||
|
|
@ -27,26 +27,26 @@ class hierarchical_predecode3x8(hierarchical_predecode):
|
|||
self.create_rails()
|
||||
self.add_input_inverters()
|
||||
self.add_output_inverters()
|
||||
connections=[["in[0]", "in[1]", "in[2]", "Z[7]", "vdd", "gnd"],
|
||||
["in[0]", "in[1]", "inbar[2]", "Z[6]", "vdd", "gnd"],
|
||||
["in[0]", "inbar[1]", "in[2]", "Z[5]", "vdd", "gnd"],
|
||||
["in[0]", "inbar[1]", "inbar[2]", "Z[4]", "vdd", "gnd"],
|
||||
["inbar[0]", "in[1]", "in[2]", "Z[3]", "vdd", "gnd"],
|
||||
connections=[["inbar[0]", "inbar[1]", "inbar[2]", "Z[0]", "vdd", "gnd"],
|
||||
["in[0]", "inbar[1]", "inbar[2]", "Z[1]", "vdd", "gnd"],
|
||||
["inbar[0]", "in[1]", "inbar[2]", "Z[2]", "vdd", "gnd"],
|
||||
["inbar[0]", "inbar[1]", "in[2]", "Z[1]", "vdd", "gnd"],
|
||||
["inbar[0]", "inbar[1]", "inbar[2]", "Z[0]", "vdd", "gnd"]]
|
||||
["in[0]", "in[1]", "inbar[2]", "Z[3]", "vdd", "gnd"],
|
||||
["inbar[0]", "inbar[1]", "in[2]", "Z[4]", "vdd", "gnd"],
|
||||
["in[0]", "inbar[1]", "in[2]", "Z[5]", "vdd", "gnd"],
|
||||
["inbar[0]", "in[1]", "in[2]", "Z[6]", "vdd", "gnd"],
|
||||
["in[0]", "in[1]", "in[2]", "Z[7]", "vdd", "gnd"]]
|
||||
self.add_nand(connections)
|
||||
self.route()
|
||||
|
||||
def get_nand_input_line_combination(self):
|
||||
""" These are the decoder connections of the NAND gates to the A,B,C pins """
|
||||
combination = [["Abar[0]", "Abar[1]", "Abar[2]"],
|
||||
["Abar[0]", "Abar[1]", "A[2]"],
|
||||
["Abar[0]", "A[1]", "Abar[2]"],
|
||||
["Abar[0]", "A[1]", "A[2]"],
|
||||
["A[0]", "Abar[1]", "Abar[2]"],
|
||||
["A[0]", "Abar[1]", "A[2]"],
|
||||
["Abar[0]", "A[1]", "Abar[2]"],
|
||||
["A[0]", "A[1]", "Abar[2]"],
|
||||
["Abar[0]", "Abar[1]", "A[2]"],
|
||||
["A[0]", "Abar[1]", "A[2]"],
|
||||
["Abar[0]", "A[1]", "A[2]"],
|
||||
["A[0]", "A[1]", "A[2]"]]
|
||||
return combination
|
||||
|
||||
|
|
|
|||
|
|
@ -60,21 +60,44 @@ class layout(lef.lef):
|
|||
def find_lowest_coords(self):
|
||||
"""Finds the lowest set of 2d cartesian coordinates within
|
||||
this layout"""
|
||||
|
||||
lowestx1 = min(obj.lx() for obj in self.objs if obj.name!="label")
|
||||
lowesty1 = min(obj.by() for obj in self.objs if obj.name!="label")
|
||||
lowestx2 = min(inst.lx() for inst in self.insts)
|
||||
lowesty2 = min(inst.by() for inst in self.insts)
|
||||
return vector(min(lowestx1, lowestx2), min(lowesty1, lowesty2))
|
||||
|
||||
if len(self.objs)>0:
|
||||
lowestx1 = min(obj.lx() for obj in self.objs if obj.name!="label")
|
||||
lowesty1 = min(obj.by() for obj in self.objs if obj.name!="label")
|
||||
else:
|
||||
lowestx1=lowesty1=None
|
||||
if len(self.insts)>0:
|
||||
lowestx2 = min(inst.lx() for inst in self.insts)
|
||||
lowesty2 = min(inst.by() for inst in self.insts)
|
||||
else:
|
||||
lowestx2=lowesty2=None
|
||||
if lowestx1==None:
|
||||
return vector(lowestx2,lowesty2)
|
||||
elif lowestx2==None:
|
||||
return vector(lowestx1,lowesty1)
|
||||
else:
|
||||
return vector(min(lowestx1, lowestx2), min(lowesty1, lowesty2))
|
||||
|
||||
def find_highest_coords(self):
|
||||
"""Finds the highest set of 2d cartesian coordinates within
|
||||
this layout"""
|
||||
highestx1 = min(obj.rx() for obj in self.objs if obj.name!="label")
|
||||
highesty1 = min(obj.uy() for obj in self.objs if obj.name!="label")
|
||||
highestx2 = min(inst.rx() for inst in self.insts)
|
||||
highesty2 = min(inst.uy() for inst in self.insts)
|
||||
return vector(min(highestx1, highestx2), min(highesty1, highesty2))
|
||||
|
||||
if len(self.objs)>0:
|
||||
highestx1 = max(obj.rx() for obj in self.objs if obj.name!="label")
|
||||
highesty1 = max(obj.uy() for obj in self.objs if obj.name!="label")
|
||||
else:
|
||||
highestx1=highesty1=None
|
||||
if len(self.insts)>0:
|
||||
highestx2 = max(inst.rx() for inst in self.insts)
|
||||
highesty2 = max(inst.uy() for inst in self.insts)
|
||||
else:
|
||||
highestx2=highesty2=None
|
||||
if highestx1==None:
|
||||
return vector(highestx2,highesty2)
|
||||
elif highestx2==None:
|
||||
return vector(highestx1,highesty1)
|
||||
else:
|
||||
return vector(max(highestx1, highestx2), max(highesty1, highesty2))
|
||||
|
||||
|
||||
def translate_all(self, offset):
|
||||
|
|
@ -143,9 +166,11 @@ class layout(lef.lef):
|
|||
debug.error("Nonrectilinear center rect!",-1)
|
||||
elif start.x!=end.x:
|
||||
offset = vector(0,0.5*minwidth_layer)
|
||||
return self.add_rect(layer,start-offset,end.x-start.x,minwidth_layer)
|
||||
else:
|
||||
offset = vector(0.5*minwidth_layer,0)
|
||||
return self.add_rect(layer,start-offset,end.x-start.x,minwidth_layer)
|
||||
return self.add_rect(layer,start-offset,minwidth_layer,end.y-start.y)
|
||||
|
||||
|
||||
|
||||
def get_pin(self, text):
|
||||
|
|
@ -308,42 +333,50 @@ class layout(lef.lef):
|
|||
layer_stack=layers,
|
||||
position_list=coordinates)
|
||||
|
||||
def add_contact(self, layers, offset, size=[1,1], mirror="R0", rotate=0):
|
||||
def add_contact(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
|
||||
""" This is just an alias for a via."""
|
||||
return self.add_via(layers=layers,
|
||||
offset=offset,
|
||||
size=size,
|
||||
mirror=mirror,
|
||||
rotate=rotate)
|
||||
rotate=rotate,
|
||||
implant_type=implant_type,
|
||||
well_type=well_type)
|
||||
|
||||
def add_contact_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0):
|
||||
def add_contact_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
|
||||
""" This is just an alias for a via."""
|
||||
return self.add_via_center(layers=layers,
|
||||
offset=offset,
|
||||
size=size,
|
||||
mirror=mirror,
|
||||
rotate=rotate)
|
||||
rotate=rotate,
|
||||
implant_type=implant_type,
|
||||
well_type=well_type)
|
||||
|
||||
def add_via(self, layers, offset, size=[1,1], mirror="R0", rotate=0):
|
||||
def add_via(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
|
||||
""" Add a three layer via structure. """
|
||||
import contact
|
||||
via = contact.contact(layer_stack=layers,
|
||||
dimensions=size)
|
||||
dimensions=size,
|
||||
implant_type=implant_type,
|
||||
well_type=well_type)
|
||||
self.add_mod(via)
|
||||
self.add_inst(name=via.name,
|
||||
mod=via,
|
||||
offset=offset,
|
||||
mirror=mirror,
|
||||
rotate=rotate)
|
||||
inst=self.add_inst(name=via.name,
|
||||
mod=via,
|
||||
offset=offset,
|
||||
mirror=mirror,
|
||||
rotate=rotate)
|
||||
# We don't model the logical connectivity of wires/paths
|
||||
self.connect_inst([])
|
||||
return via
|
||||
return inst
|
||||
|
||||
def add_via_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0):
|
||||
def add_via_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
|
||||
""" Add a three layer via structure by the center coordinate accounting for mirroring and rotation. """
|
||||
import contact
|
||||
via = contact.contact(layer_stack=layers,
|
||||
dimensions=size)
|
||||
dimensions=size,
|
||||
implant_type=implant_type,
|
||||
well_type=well_type)
|
||||
|
||||
debug.check(mirror=="R0","Use rotate to rotate vias instead of mirror.")
|
||||
|
||||
|
|
@ -363,14 +396,14 @@ class layout(lef.lef):
|
|||
|
||||
|
||||
self.add_mod(via)
|
||||
self.add_inst(name=via.name,
|
||||
mod=via,
|
||||
offset=corrected_offset,
|
||||
mirror=mirror,
|
||||
rotate=rotate)
|
||||
inst=self.add_inst(name=via.name,
|
||||
mod=via,
|
||||
offset=corrected_offset,
|
||||
mirror=mirror,
|
||||
rotate=rotate)
|
||||
# We don't model the logical connectivity of wires/paths
|
||||
self.connect_inst([])
|
||||
return via
|
||||
return inst
|
||||
|
||||
def add_ptx(self, offset, mirror="R0", rotate=0, width=1, mults=1, tx_type="nmos"):
|
||||
"""Adds a ptx module to the design."""
|
||||
|
|
@ -379,12 +412,12 @@ class layout(lef.lef):
|
|||
mults=mults,
|
||||
tx_type=tx_type)
|
||||
self.add_mod(mos)
|
||||
self.add_inst(name=mos.name,
|
||||
mod=mos,
|
||||
offset=offset,
|
||||
mirror=mirror,
|
||||
rotate=rotate)
|
||||
return mos
|
||||
inst=self.add_inst(name=mos.name,
|
||||
mod=mos,
|
||||
offset=offset,
|
||||
mirror=mirror,
|
||||
rotate=rotate)
|
||||
return inst
|
||||
|
||||
|
||||
|
||||
|
|
@ -488,6 +521,26 @@ class layout(lef.lef):
|
|||
|
||||
return blockages
|
||||
|
||||
def add_enclosure(self, insts, layer="nwell"):
|
||||
""" Add a layer that surrounds the given instances. Useful
|
||||
for creating wells, for example. Doesn't check for minimum widths or
|
||||
spacings."""
|
||||
|
||||
xmin=insts[0].lx()
|
||||
ymin=insts[0].by()
|
||||
xmax=insts[0].rx()
|
||||
ymax=insts[0].uy()
|
||||
for inst in insts:
|
||||
xmin = min(xmin, inst.lx())
|
||||
ymin = min(ymin, inst.by())
|
||||
xmax = max(xmax, inst.rx())
|
||||
ymax = max(ymax, inst.uy())
|
||||
|
||||
self.add_rect(layer=layer,
|
||||
offset=vector(xmin,ymin),
|
||||
width=xmax-xmin,
|
||||
height=ymax-ymin)
|
||||
|
||||
def pdf_write(self, pdf_name):
|
||||
# NOTE: Currently does not work (Needs further research)
|
||||
#self.pdf_name = self.name + ".pdf"
|
||||
|
|
|
|||
|
|
@ -126,6 +126,8 @@ class spice(verilog.verilog):
|
|||
return
|
||||
if self.pins == []:
|
||||
return
|
||||
|
||||
|
||||
# write out the first spice line (the subcircuit)
|
||||
sp.write("\n.SUBCKT {0} {1}\n".format(self.name,
|
||||
" ".join(self.pins)))
|
||||
|
|
@ -146,9 +148,15 @@ class spice(verilog.verilog):
|
|||
# these are wires and paths
|
||||
if self.conns[i] == []:
|
||||
continue
|
||||
sp.write("X{0} {1} {2}\n".format(self.insts[i].name,
|
||||
" ".join(self.conns[i]),
|
||||
self.insts[i].mod.name))
|
||||
if hasattr(self.insts[i].mod,"spice_device"):
|
||||
sp.write(self.insts[i].mod.spice_device.format(self.insts[i].name,
|
||||
" ".join(self.conns[i])))
|
||||
sp.write("\n")
|
||||
|
||||
else:
|
||||
sp.write("X{0} {1} {2}\n".format(self.insts[i].name,
|
||||
" ".join(self.conns[i]),
|
||||
self.insts[i].mod.name))
|
||||
|
||||
sp.write(".ENDS {0}\n".format(self.name))
|
||||
|
||||
|
|
@ -158,6 +166,7 @@ class spice(verilog.verilog):
|
|||
#if os.path.isfile(self.sp_file):
|
||||
# sp.write("\n* {0}\n".format(self.sp_file))
|
||||
sp.write("\n".join(self.spice))
|
||||
|
||||
sp.write("\n")
|
||||
|
||||
def sp_write(self, spname):
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ class ms_flop_array(design.design):
|
|||
design.design.__init__(self, name)
|
||||
debug.info(1, "Creating {}".format(self.name))
|
||||
|
||||
c = reload(__import__(OPTS.config.ms_flop))
|
||||
self.mod_ms_flop = getattr(c, OPTS.config.ms_flop)
|
||||
c = reload(__import__(OPTS.ms_flop))
|
||||
self.mod_ms_flop = getattr(c, OPTS.ms_flop)
|
||||
self.ms = self.mod_ms_flop("ms_flop")
|
||||
self.add_mod(self.ms)
|
||||
|
||||
|
|
|
|||
|
|
@ -39,19 +39,19 @@ globals.print_banner()
|
|||
globals.init_openram(args[0])
|
||||
|
||||
# Check if all arguments are integers for bits, size, banks
|
||||
if type(OPTS.config.word_size)!=int:
|
||||
debug.error("{0} is not an integer in config file.".format(OPTS.config.word_size))
|
||||
if type(OPTS.config.num_words)!=int:
|
||||
debug.error("{0} is not an integer in config file.".format(OPTS.config.sram_size))
|
||||
if type(OPTS.config.num_banks)!=int:
|
||||
debug.error("{0} is not an integer in config file.".format(OPTS.config.num_banks))
|
||||
if type(OPTS.word_size)!=int:
|
||||
debug.error("{0} is not an integer in config file.".format(OPTS.word_size))
|
||||
if type(OPTS.num_words)!=int:
|
||||
debug.error("{0} is not an integer in config file.".format(OPTS.sram_size))
|
||||
if type(OPTS.num_banks)!=int:
|
||||
debug.error("{0} is not an integer in config file.".format(OPTS.num_banks))
|
||||
|
||||
if not OPTS.config.tech_name:
|
||||
if not OPTS.tech_name:
|
||||
debug.error("Tech name must be specified in config file.")
|
||||
|
||||
word_size = OPTS.config.word_size
|
||||
num_words = OPTS.config.num_words
|
||||
num_banks = OPTS.config.num_banks
|
||||
word_size = OPTS.word_size
|
||||
num_words = OPTS.num_words
|
||||
num_banks = OPTS.num_banks
|
||||
|
||||
if (OPTS.output_name == ""):
|
||||
OPTS.output_name = "sram_{0}_{1}_{2}_{3}".format(word_size,
|
||||
|
|
@ -79,10 +79,6 @@ s = sram.sram(word_size=word_size,
|
|||
num_banks=num_banks,
|
||||
name=OPTS.output_name)
|
||||
last_time=print_time("SRAM creation", datetime.datetime.now(), last_time)
|
||||
# Measure design area
|
||||
# Not working?
|
||||
#cell_size = s.gds.measureSize(s.name)
|
||||
#print("Area:", cell_size[0] * cell_size[1])
|
||||
|
||||
# Output the files for the resulting SRAM
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ import os
|
|||
|
||||
class options(optparse.Values):
|
||||
"""
|
||||
Class for holding all of the OpenRAM options.
|
||||
Class for holding all of the OpenRAM options. All of these options can be over-riden in a configuration file
|
||||
that is the sole required command-line positional argument for openram.py.
|
||||
"""
|
||||
|
||||
# This is the technology directory.
|
||||
|
|
@ -13,6 +14,7 @@ class options(optparse.Values):
|
|||
tech_name = ""
|
||||
# This is the temp directory where all intermediate results are stored.
|
||||
openram_temp = "/tmp/openram_{0}_{1}_temp/".format(getpass.getuser(),os.getpid())
|
||||
#openram_temp = "/Users/{}/openram_temp/".format(getpass.getuser())
|
||||
# This is the verbosity level to control debug information. 0 is none, 1
|
||||
# is minimal, etc.
|
||||
debug_level = 0
|
||||
|
|
@ -23,9 +25,9 @@ class options(optparse.Values):
|
|||
# Should we print out the banner at startup
|
||||
print_banner = True
|
||||
# The DRC/LVS/PEX executable being used which is derived from the user PATH.
|
||||
drc_exe = ""
|
||||
lvs_exe = ""
|
||||
pex_exe = ""
|
||||
drc_exe = None
|
||||
lvs_exe = None
|
||||
pex_exe = None
|
||||
# The spice executable being used which is derived from the user PATH.
|
||||
spice_exe = ""
|
||||
# Run with extracted parasitics
|
||||
|
|
@ -35,8 +37,32 @@ class options(optparse.Values):
|
|||
# Use detailed LEF blockages
|
||||
detailed_blockages = True
|
||||
# Define the output file paths
|
||||
output_path = ""
|
||||
output_path = "."
|
||||
# Define the output file base name
|
||||
output_name = ""
|
||||
output_name = "sram"
|
||||
# Use analytical delay models by default rather than (slow) characterization
|
||||
analytical_delay = True
|
||||
# Purge the temp directory after a successful run (doesn't purge on errors, anyhow)
|
||||
purge_temp = True
|
||||
|
||||
|
||||
# These are the default modules that can be over-riden
|
||||
decoder = "hierarchical_decoder"
|
||||
ms_flop = "ms_flop"
|
||||
ms_flop_array = "ms_flop_array"
|
||||
control_logic = "control_logic"
|
||||
bitcell_array = "bitcell_array"
|
||||
sense_amp = "sense_amp"
|
||||
sense_amp_array = "sense_amp_array"
|
||||
precharge_array = "precharge_array"
|
||||
column_mux_array = "single_level_column_mux_array"
|
||||
write_driver = "write_driver"
|
||||
write_driver_array = "write_driver_array"
|
||||
tri_gate = "tri_gate"
|
||||
tri_gate_array = "tri_gate_array"
|
||||
wordline_driver = "wordline_driver"
|
||||
replica_bitline = "replica_bitline"
|
||||
replica_bitcell = "replica_bitcell"
|
||||
bitcell = "bitcell"
|
||||
delay_chain = "delay_chain"
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class pgate(design.design):
|
|||
debug.check(nmos_gate_pin.ll().x==pmos_gate_pin.ll().x, "Connecting unaligned gates not supported.")
|
||||
|
||||
# Pick point on the left of NMOS and connect down to PMOS
|
||||
nmos_gate_pos = nmos_gate_pin.ll() + vector(0.5*drc["minwidth_poly"],0)
|
||||
nmos_gate_pos = nmos_gate_pin.ll() + vector(0.5*self.poly_width,0)
|
||||
pmos_gate_pos = vector(nmos_gate_pos.x,pmos_gate_pin.bc().y)
|
||||
self.add_path("poly",[nmos_gate_pos,pmos_gate_pos])
|
||||
|
||||
|
|
@ -97,93 +97,117 @@ class pgate(design.design):
|
|||
def extend_wells(self, middle_position):
|
||||
""" Extend the n/p wells to cover whole cell """
|
||||
|
||||
nwell_height = self.height - middle_position.y
|
||||
# Add a rail width to extend the well to the top of the rail
|
||||
max_y_offset = self.height + 0.5*self.m1_width
|
||||
self.nwell_position = middle_position
|
||||
nwell_height = max_y_offset - middle_position.y
|
||||
if info["has_nwell"]:
|
||||
self.add_rect(layer="nwell",
|
||||
offset=middle_position,
|
||||
width=self.well_width,
|
||||
height=nwell_height)
|
||||
self.add_rect(layer="vtg",
|
||||
offset=middle_position,
|
||||
offset=self.nwell_position,
|
||||
width=self.well_width,
|
||||
height=nwell_height)
|
||||
|
||||
pwell_position = vector(0,-0.5*self.m1_width)
|
||||
pwell_height = middle_position.y-pwell_position.y
|
||||
if info["has_pwell"]:
|
||||
self.add_rect(layer="pwell",
|
||||
offset=vector(0,0),
|
||||
offset=pwell_position,
|
||||
width=self.well_width,
|
||||
height=middle_position.y)
|
||||
height=pwell_height)
|
||||
self.add_rect(layer="vtg",
|
||||
offset=vector(0,0),
|
||||
offset=pwell_position,
|
||||
width=self.well_width,
|
||||
height=middle_position.y)
|
||||
height=pwell_height)
|
||||
|
||||
def add_nwell_contact(self, nmos, nmos_pos):
|
||||
""" Add an nwell contact next to the given nmos device. """
|
||||
def add_nwell_contact(self, pmos, pmos_pos):
|
||||
""" Add an nwell contact next to the given pmos device. """
|
||||
|
||||
layer_stack = ("active", "contact", "metal1")
|
||||
|
||||
# To the right a spacing away from the nmos right active edge
|
||||
nwell_contact_xoffset = nmos_pos.x + nmos.active_width + drc["active_to_body_active"]
|
||||
nwell_contact_yoffset = nmos_pos.y
|
||||
nwell_offset = vector(nwell_contact_xoffset, nwell_contact_yoffset)
|
||||
# Offset by half a contact in x and y
|
||||
nwell_offset += vector(0.5*nmos.active_contact.first_layer_width,
|
||||
0.5*nmos.active_contact.first_layer_height)
|
||||
self.nwell_contact=self.add_contact_center(layers=layer_stack,
|
||||
offset=nwell_offset)
|
||||
self.add_rect_center(layer="metal1",
|
||||
offset=nwell_offset.scale(1,0.5),
|
||||
width=self.nwell_contact.second_layer_width,
|
||||
height=nwell_offset.y)
|
||||
# Now add the full active and implant for the NMOS
|
||||
nwell_offset = nmos_pos + vector(nmos.active_width,0)
|
||||
nwell_contact_width = drc["active_to_body_active"] + nmos.active_contact.width
|
||||
self.add_rect(layer="active",
|
||||
offset=nwell_offset,
|
||||
width=nwell_contact_width,
|
||||
height=nmos.active_height)
|
||||
|
||||
implant_offset = nwell_offset + vector(drc["implant_to_implant"],0)
|
||||
implant_width = nwell_contact_width - drc["implant_to_implant"]
|
||||
self.add_rect(layer="pimplant",
|
||||
offset=implant_offset,
|
||||
width=implant_width,
|
||||
height=nmos.active_height)
|
||||
|
||||
|
||||
def add_pwell_contact(self, pmos, pmos_pos):
|
||||
""" Add an pwell contact next to the given pmos device. """
|
||||
|
||||
layer_stack = ("active", "contact", "metal1")
|
||||
|
||||
|
||||
# To the right a spacing away from the pmos right active edge
|
||||
pwell_contact_xoffset = pmos_pos.x + pmos.active_width + drc["active_to_body_active"]
|
||||
pwell_contact_yoffset = pmos_pos.y + pmos.active_height - pmos.active_contact.height
|
||||
pwell_offset = vector(pwell_contact_xoffset, pwell_contact_yoffset)
|
||||
# Offset by half a contact
|
||||
pwell_offset += vector(0.5*pmos.active_contact.first_layer_width,
|
||||
contact_xoffset = pmos_pos.x + pmos.active_width + drc["active_to_body_active"]
|
||||
# Must be at least an well enclosure of active down from the top of the well
|
||||
# OR align the active with the top of PMOS active.
|
||||
max_y_offset = self.height + 0.5*self.m1_width
|
||||
contact_yoffset = min(pmos_pos.y + pmos.active_height - pmos.active_contact.first_layer_height,
|
||||
max_y_offset - pmos.active_contact.first_layer_height/2 - self.well_enclose_active)
|
||||
contact_offset = vector(contact_xoffset, contact_yoffset)
|
||||
# Offset by half a contact in x and y
|
||||
contact_offset += vector(0.5*pmos.active_contact.first_layer_width,
|
||||
0.5*pmos.active_contact.first_layer_height)
|
||||
self.pwell_contact=self.add_contact_center(layers=layer_stack,
|
||||
offset=pwell_offset)
|
||||
self.nwell_contact=self.add_contact_center(layers=layer_stack,
|
||||
offset=contact_offset,
|
||||
implant_type="n",
|
||||
well_type="n")
|
||||
self.add_rect_center(layer="metal1",
|
||||
offset=pwell_offset + vector(0,0.5*(self.height-pwell_offset.y)),
|
||||
width=self.pwell_contact.second_layer_width,
|
||||
height=self.height - pwell_offset.y)
|
||||
# Now add the full active and implant for the PMOS
|
||||
pwell_offset = pmos_pos + vector(pmos.active_width,0)
|
||||
pwell_contact_width = drc["active_to_body_active"] + pmos.active_contact.width
|
||||
self.add_rect(layer="active",
|
||||
offset=pwell_offset,
|
||||
width=pwell_contact_width,
|
||||
height=pmos.active_height)
|
||||
|
||||
|
||||
implant_offset = pwell_offset + vector(drc["implant_to_implant"],0)
|
||||
implant_width = pwell_contact_width - drc["implant_to_implant"]
|
||||
self.add_rect(layer="nimplant",
|
||||
offset=implant_offset,
|
||||
width=implant_width,
|
||||
height=pmos.active_height)
|
||||
offset=contact_offset + vector(0,0.5*(self.height-contact_offset.y)),
|
||||
width=self.nwell_contact.mod.second_layer_width,
|
||||
height=self.height - contact_offset.y)
|
||||
|
||||
# Now add the full active and implant for the PMOS
|
||||
#active_offset = pmos_pos + vector(pmos.active_width,0)
|
||||
# This might be needed if the spacing between the actives is not satisifed
|
||||
# self.add_rect(layer="active",
|
||||
# offset=active_offset,
|
||||
# width=pmos.active_contact.width,
|
||||
# height=pmos.active_height)
|
||||
|
||||
# we need to ensure implants don't overlap and are spaced far enough apart
|
||||
# implant_spacing = self.implant_space+self.implant_enclose_active
|
||||
# implant_offset = active_offset + vector(implant_spacing,0) - vector(0,self.implant_enclose_active)
|
||||
# implant_width = pmos.active_contact.width + 2*self.implant_enclose_active
|
||||
# implant_height = pmos.active_height + 2*self.implant_enclose_active
|
||||
# self.add_rect(layer="nimplant",
|
||||
# offset=implant_offset,
|
||||
# width=implant_width,
|
||||
# height=implant_height)
|
||||
|
||||
# Return the top of the well
|
||||
|
||||
def add_pwell_contact(self, nmos, nmos_pos):
|
||||
""" Add an pwell contact next to the given nmos device. """
|
||||
|
||||
layer_stack = ("active", "contact", "metal1")
|
||||
|
||||
pwell_position = vector(0,-0.5*self.m1_width)
|
||||
|
||||
# To the right a spacing away from the nmos right active edge
|
||||
contact_xoffset = nmos_pos.x + nmos.active_width + drc["active_to_body_active"]
|
||||
# Must be at least an well enclosure of active up from the bottom of the well
|
||||
contact_yoffset = max(nmos_pos.y,
|
||||
self.well_enclose_active - nmos.active_contact.first_layer_height/2)
|
||||
contact_offset = vector(contact_xoffset, contact_yoffset)
|
||||
|
||||
# Offset by half a contact
|
||||
contact_offset += vector(0.5*nmos.active_contact.first_layer_width,
|
||||
0.5*nmos.active_contact.first_layer_height)
|
||||
self.pwell_contact=self.add_contact_center(layers=layer_stack,
|
||||
offset=contact_offset,
|
||||
implant_type="p",
|
||||
well_type="p")
|
||||
self.add_rect_center(layer="metal1",
|
||||
offset=contact_offset.scale(1,0.5),
|
||||
width=self.pwell_contact.mod.second_layer_width,
|
||||
height=contact_offset.y)
|
||||
|
||||
# Now add the full active and implant for the NMOS
|
||||
# active_offset = nmos_pos + vector(nmos.active_width,0)
|
||||
# This might be needed if the spacing between the actives is not satisifed
|
||||
# self.add_rect(layer="active",
|
||||
# offset=active_offset,
|
||||
# width=nmos.active_contact.width,
|
||||
# height=nmos.active_height)
|
||||
|
||||
# implant_spacing = self.implant_space+self.implant_enclose_active
|
||||
# implant_offset = active_offset + vector(implant_spacing,0) - vector(0,self.implant_enclose_active)
|
||||
# implant_width = nmos.active_contact.width + 2*self.implant_enclose_active
|
||||
# implant_height = nmos.active_height + 2*self.implant_enclose_active
|
||||
# self.add_rect(layer="pimplant",
|
||||
# offset=implant_offset,
|
||||
# width=implant_width,
|
||||
# height=implant_height)
|
||||
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ class pinv(pgate.pgate):
|
|||
from center of rail to rail.. The route_output will route the
|
||||
output to the right side of the cell for easier access.
|
||||
"""
|
||||
c = reload(__import__(OPTS.config.bitcell))
|
||||
bitcell = getattr(c, OPTS.config.bitcell)
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
bitcell = getattr(c, OPTS.bitcell)
|
||||
|
||||
unique_id = 1
|
||||
|
||||
|
|
@ -57,8 +57,8 @@ class pinv(pgate.pgate):
|
|||
self.setup_layout_constants()
|
||||
self.add_supply_rails()
|
||||
self.add_ptx()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.add_well_contacts()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.connect_rails()
|
||||
self.route_input_gate(self.pmos_inst, self.nmos_inst, self.output_pos.y, "A", rotate=0)
|
||||
self.route_outputs()
|
||||
|
|
@ -128,9 +128,6 @@ class pinv(pgate.pgate):
|
|||
self.width = self.well_width
|
||||
# Height is an input parameter, so it is not recomputed.
|
||||
|
||||
# This will help with the wells
|
||||
self.well_pos = vector(0,0.4*self.height)
|
||||
|
||||
|
||||
|
||||
def create_ptx(self):
|
||||
|
|
@ -183,9 +180,14 @@ class pinv(pgate.pgate):
|
|||
self.connect_inst(["Z", "A", "gnd", "gnd"])
|
||||
|
||||
|
||||
# Output position will be in between the PMOS and NMOS
|
||||
self.output_pos = vector(0,0.5*(self.pmos_pos.y+self.nmos_pos.y+self.nmos.active_height))
|
||||
# Output position will be in between the PMOS and NMOS drains
|
||||
pmos_drain_pos = self.pmos_inst.get_pin("D").ll()
|
||||
nmos_drain_pos = self.nmos_inst.get_pin("D").ul()
|
||||
self.output_pos = vector(0,0.5*(pmos_drain_pos.y+nmos_drain_pos.y))
|
||||
|
||||
# This will help with the wells
|
||||
self.well_pos = vector(0,self.nmos_inst.uy())
|
||||
|
||||
|
||||
|
||||
def route_outputs(self):
|
||||
|
|
@ -196,8 +198,8 @@ class pinv(pgate.pgate):
|
|||
pmos_drain_pin = self.pmos_inst.get_pin("D")
|
||||
|
||||
# Pick point at right most of NMOS and connect down to PMOS
|
||||
nmos_drain_pos = nmos_drain_pin.ur() - vector(0.5*self.m1_width,0)
|
||||
pmos_drain_pos = vector(nmos_drain_pos.x,pmos_drain_pin.bc().y)
|
||||
nmos_drain_pos = nmos_drain_pin.lr() - vector(0.5*self.m1_width,0)
|
||||
pmos_drain_pos = vector(nmos_drain_pos.x, pmos_drain_pin.bc().y)
|
||||
self.add_path("metal1",[nmos_drain_pos,pmos_drain_pos])
|
||||
|
||||
# Remember the mid for the output
|
||||
|
|
@ -220,9 +222,9 @@ class pinv(pgate.pgate):
|
|||
def add_well_contacts(self):
|
||||
""" Add n/p well taps to the layout and connect to supplies """
|
||||
|
||||
self.add_nwell_contact(self.nmos, self.nmos_pos)
|
||||
self.add_nwell_contact(self.pmos, self.pmos_pos)
|
||||
|
||||
self.add_pwell_contact(self.pmos, self.pmos_pos)
|
||||
self.add_pwell_contact(self.nmos, self.nmos_pos)
|
||||
|
||||
def connect_rails(self):
|
||||
""" Connect the nmos and pmos to its respective power rails """
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ class pnand2(pgate.pgate):
|
|||
This model use ptx to generate a 2-input nand within a cetrain height.
|
||||
"""
|
||||
|
||||
c = reload(__import__(OPTS.config.bitcell))
|
||||
bitcell = getattr(c, OPTS.config.bitcell)
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
bitcell = getattr(c, OPTS.bitcell)
|
||||
|
||||
unique_id = 1
|
||||
|
||||
|
|
@ -50,8 +50,8 @@ class pnand2(pgate.pgate):
|
|||
self.setup_layout_constants()
|
||||
self.add_supply_rails()
|
||||
self.add_ptx()
|
||||
self.add_well_contacts()
|
||||
self.connect_rails()
|
||||
self.add_well_contacts()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.route_inputs()
|
||||
self.route_output()
|
||||
|
|
@ -94,9 +94,6 @@ class pnand2(pgate.pgate):
|
|||
self.width = self.well_width
|
||||
# Height is an input parameter, so it is not recomputed.
|
||||
|
||||
# This will help with the wells
|
||||
self.well_pos = vector(0,0.4*self.height)
|
||||
|
||||
# This is the extra space needed to ensure DRC rules to the active contacts
|
||||
extra_contact_space = max(-self.nmos.get_pin("D").by(),0)
|
||||
# This is a poly-to-poly of a flipped cell
|
||||
|
|
@ -139,22 +136,25 @@ class pnand2(pgate.pgate):
|
|||
self.nmos1_inst=self.add_inst(name="pnand2_nmos1",
|
||||
mod=self.nmos,
|
||||
offset=nmos1_pos)
|
||||
self.connect_inst(["Z", "A", "net1", "gnd"])
|
||||
self.connect_inst(["Z", "B", "net1", "gnd"])
|
||||
|
||||
self.nmos2_pos = nmos1_pos + self.overlap_offset
|
||||
self.nmos2_inst=self.add_inst(name="pnand2_nmos2",
|
||||
mod=self.nmos,
|
||||
offset=self.nmos2_pos)
|
||||
self.connect_inst(["net1", "B", "gnd", "gnd"])
|
||||
self.connect_inst(["net1", "A", "gnd", "gnd"])
|
||||
|
||||
# Output position will be in between the PMOS and NMOS
|
||||
self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height))
|
||||
|
||||
# This will help with the wells
|
||||
self.well_pos = vector(0,self.nmos1_inst.uy())
|
||||
|
||||
def add_well_contacts(self):
|
||||
""" Add n/p well taps to the layout and connect to supplies """
|
||||
""" Add n/p well taps to the layout and connect to supplies AFTER the wells are created """
|
||||
|
||||
self.add_nwell_contact(self.nmos, self.nmos2_pos)
|
||||
self.add_pwell_contact(self.pmos, self.pmos2_pos)
|
||||
self.add_nwell_contact(self.pmos, self.pmos2_pos)
|
||||
self.add_pwell_contact(self.nmos, self.nmos2_pos)
|
||||
|
||||
|
||||
def connect_rails(self):
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ class pnand3(pgate.pgate):
|
|||
This model use ptx to generate a 2-input nand within a cetrain height.
|
||||
"""
|
||||
|
||||
c = reload(__import__(OPTS.config.bitcell))
|
||||
bitcell = getattr(c, OPTS.config.bitcell)
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
bitcell = getattr(c, OPTS.bitcell)
|
||||
|
||||
unique_id = 1
|
||||
|
||||
|
|
@ -24,7 +24,9 @@ class pnand3(pgate.pgate):
|
|||
pgate.pgate.__init__(self, name)
|
||||
debug.info(2, "create pnand3 structure {0} with size of {1}".format(name, size))
|
||||
|
||||
self.nmos_size = 3*size
|
||||
# We have trouble pitch matching a 3x sizes to the bitcell...
|
||||
# If we relax this, we could size this better.
|
||||
self.nmos_size = 2*size
|
||||
self.pmos_size = parameter["beta"]*size
|
||||
self.nmos_width = self.nmos_size*drc["minwidth_tx"]
|
||||
self.pmos_width = self.pmos_size*drc["minwidth_tx"]
|
||||
|
|
@ -50,8 +52,8 @@ class pnand3(pgate.pgate):
|
|||
self.setup_layout_constants()
|
||||
self.add_supply_rails()
|
||||
self.add_ptx()
|
||||
self.add_well_contacts()
|
||||
self.connect_rails()
|
||||
self.add_well_contacts()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.route_inputs()
|
||||
self.route_output()
|
||||
|
|
@ -88,13 +90,13 @@ class pnand3(pgate.pgate):
|
|||
|
||||
# This will help with the wells and the input/output placement
|
||||
self.output_pos = vector(0,0.5*self.height)
|
||||
self.well_pos = vector(0,0.4*self.height)
|
||||
|
||||
# This is the extra space needed to ensure DRC rules to the active contacts
|
||||
nmos = ptx(tx_type="nmos")
|
||||
extra_contact_space = max(-nmos.get_pin("D").by(),0)
|
||||
# This is a poly-to-poly of a flipped cell
|
||||
# This is extra liberal for pnand3 because we know there are big transistor sizes
|
||||
# and so contacts won't interfere with the rails. Therefore, ignore metal spacing.
|
||||
# We need to do this to fit the 3 inputs in with M2M3 via accessibility.
|
||||
self.top_bottom_space = max(drc["poly_extend_active"], self.poly_space)
|
||||
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
|
||||
drc["poly_extend_active"], self.poly_space)
|
||||
|
||||
def add_supply_rails(self):
|
||||
""" Add vdd/gnd rails to the top and bottom. """
|
||||
|
|
@ -138,7 +140,7 @@ class pnand3(pgate.pgate):
|
|||
self.nmos1_inst=self.add_inst(name="pnand3_nmos1",
|
||||
mod=self.nmos,
|
||||
offset=nmos1_pos)
|
||||
self.connect_inst(["Z", "A", "net1", "gnd"])
|
||||
self.connect_inst(["Z", "C", "net1", "gnd"])
|
||||
|
||||
nmos2_pos = nmos1_pos + self.overlap_offset
|
||||
self.nmos2_inst=self.add_inst(name="pnand3_nmos2",
|
||||
|
|
@ -151,14 +153,16 @@ class pnand3(pgate.pgate):
|
|||
self.nmos3_inst=self.add_inst(name="pnand3_nmos3",
|
||||
mod=self.nmos,
|
||||
offset=self.nmos3_pos)
|
||||
self.connect_inst(["net2", "C", "gnd", "gnd"])
|
||||
self.connect_inst(["net2", "A", "gnd", "gnd"])
|
||||
|
||||
# This should be placed at the top of the NMOS well
|
||||
self.well_pos = vector(0,self.nmos1_inst.uy())
|
||||
|
||||
def add_well_contacts(self):
|
||||
""" Add n/p well taps to the layout and connect to supplies """
|
||||
|
||||
self.add_nwell_contact(self.nmos, self.nmos3_pos)
|
||||
self.add_pwell_contact(self.pmos, self.pmos3_pos)
|
||||
self.add_nwell_contact(self.pmos, self.pmos3_pos)
|
||||
self.add_pwell_contact(self.nmos, self.nmos3_pos)
|
||||
|
||||
|
||||
def connect_rails(self):
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ class pnor2(pgate.pgate):
|
|||
This model use ptx to generate a 2-input nor within a cetrain height.
|
||||
"""
|
||||
|
||||
c = reload(__import__(OPTS.config.bitcell))
|
||||
bitcell = getattr(c, OPTS.config.bitcell)
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
bitcell = getattr(c, OPTS.bitcell)
|
||||
|
||||
unique_id = 1
|
||||
|
||||
|
|
@ -51,8 +51,8 @@ class pnor2(pgate.pgate):
|
|||
self.setup_layout_constants()
|
||||
self.add_supply_rails()
|
||||
self.add_ptx()
|
||||
self.add_well_contacts()
|
||||
self.connect_rails()
|
||||
self.add_well_contacts()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.route_inputs()
|
||||
self.route_output()
|
||||
|
|
@ -98,9 +98,6 @@ class pnor2(pgate.pgate):
|
|||
self.width = self.well_width
|
||||
# Height is an input parameter, so it is not recomputed.
|
||||
|
||||
# This will help with the wells
|
||||
self.well_pos = vector(0,0.4*self.height)
|
||||
|
||||
# This is the extra space needed to ensure DRC rules to the active contacts
|
||||
extra_contact_space = max(-self.nmos.get_pin("D").by(),0)
|
||||
# This is a poly-to-poly of a flipped cell
|
||||
|
|
@ -154,11 +151,14 @@ class pnor2(pgate.pgate):
|
|||
# Output position will be in between the PMOS and NMOS
|
||||
self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height))
|
||||
|
||||
# This will help with the wells
|
||||
self.well_pos = vector(0,self.nmos1_inst.uy())
|
||||
|
||||
def add_well_contacts(self):
|
||||
""" Add n/p well taps to the layout and connect to supplies """
|
||||
|
||||
self.add_nwell_contact(self.nmos, self.nmos2_pos)
|
||||
self.add_pwell_contact(self.pmos, self.pmos2_pos)
|
||||
self.add_nwell_contact(self.pmos, self.pmos2_pos)
|
||||
self.add_pwell_contact(self.nmos, self.nmos2_pos)
|
||||
|
||||
|
||||
def connect_rails(self):
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ class precharge(pgate.pgate):
|
|||
pgate.pgate.__init__(self, name)
|
||||
debug.info(2, "create single precharge cell: {0}".format(name))
|
||||
|
||||
c = reload(__import__(OPTS.config.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.config.bitcell)
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
|
||||
self.beta = parameter["beta"]
|
||||
|
|
@ -128,15 +128,12 @@ class precharge(pgate.pgate):
|
|||
"""Adds a nwell tap to connect to the vdd rail"""
|
||||
# adds the contact from active to metal1
|
||||
well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1,0) \
|
||||
+ vector(0, self.upper_pmos1_pos.y + self.pmos.height + drc["well_extend_active"])
|
||||
+ vector(0, self.upper_pmos1_inst.uy() + contact.well.height/2 + drc["well_extend_active"])
|
||||
self.add_contact_center(layers=("active", "contact", "metal1"),
|
||||
offset=well_contact_pos)
|
||||
offset=well_contact_pos,
|
||||
implant_type="n",
|
||||
well_type="n")
|
||||
|
||||
# adds the implant to turn the contact into a nwell tap
|
||||
self.add_rect_center(layer="nimplant",
|
||||
offset=well_contact_pos,
|
||||
width=contact.well.first_layer_width,
|
||||
height=contact.well.first_layer_height)
|
||||
|
||||
self.height = well_contact_pos.y + contact.well.height
|
||||
|
||||
|
|
@ -175,19 +172,19 @@ class precharge(pgate.pgate):
|
|||
def add_bitline_contacts(self):
|
||||
"""Adds contacts/via from metal1 to metal2 for bit-lines"""
|
||||
|
||||
for stack in [("active","contact","metal1"),("metal1", "via1", "metal2")]:
|
||||
pos = self.lower_pmos_inst.get_pin("S").center()
|
||||
self.add_contact_center(layers=stack,
|
||||
offset=pos)
|
||||
pos = self.lower_pmos_inst.get_pin("D").center()
|
||||
self.add_contact_center(layers=stack,
|
||||
offset=pos)
|
||||
pos = self.upper_pmos1_inst.get_pin("S").center()
|
||||
self.add_contact_center(layers=stack,
|
||||
offset=pos)
|
||||
pos = self.upper_pmos2_inst.get_pin("D").center()
|
||||
self.add_contact_center(layers=stack,
|
||||
offset=pos)
|
||||
stack=("metal1", "via1", "metal2")
|
||||
pos = self.lower_pmos_inst.get_pin("S").center()
|
||||
self.add_contact_center(layers=stack,
|
||||
offset=pos)
|
||||
pos = self.lower_pmos_inst.get_pin("D").center()
|
||||
self.add_contact_center(layers=stack,
|
||||
offset=pos)
|
||||
pos = self.upper_pmos1_inst.get_pin("S").center()
|
||||
self.add_contact_center(layers=stack,
|
||||
offset=pos)
|
||||
pos = self.upper_pmos2_inst.get_pin("D").center()
|
||||
self.add_contact_center(layers=stack,
|
||||
offset=pos)
|
||||
|
||||
def connect_pmos(self, pmos_pin, bit_pin):
|
||||
""" Connect pmos pin to bitline pin """
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class precharge_array(design.design):
|
|||
|
||||
self.columns = columns
|
||||
|
||||
self.pc_cell = precharge(name="precharge_cell", size=size)
|
||||
self.pc_cell = precharge(name="precharge", size=size)
|
||||
self.add_mod(self.pc_cell)
|
||||
|
||||
self.width = self.columns * self.pc_cell.width
|
||||
|
|
|
|||
|
|
@ -61,15 +61,19 @@ class ptx(design.design):
|
|||
def create_spice(self):
|
||||
self.add_pin_list(["D", "G", "S", "B"])
|
||||
|
||||
self.spice.append("\n.SUBCKT {0} {1}".format(self.name,
|
||||
" ".join(self.pins)))
|
||||
self.spice.append("M{0} {1} {2} m={3} w={4}u l={5}u".format(self.tx_type,
|
||||
" ".join(self.pins),
|
||||
spice[self.tx_type],
|
||||
self.mults,
|
||||
self.tx_width,
|
||||
drc["minwidth_poly"]))
|
||||
self.spice.append(".ENDS {0}".format(self.name))
|
||||
# self.spice.append("\n.SUBCKT {0} {1}".format(self.name,
|
||||
# " ".join(self.pins)))
|
||||
# Just make a guess since these will actually be decided in the layout later.
|
||||
area_sd = 2.5*drc["minwidth_poly"]*self.tx_width
|
||||
perimeter_sd = 2*drc["minwidth_poly"] + 2*self.tx_width
|
||||
self.spice_device="M{{0}} {{1}} {0} m={1} w={2}u l={3}u pd={4}u ps={4}u as={5}p ad={5}p".format(spice[self.tx_type],
|
||||
self.mults,
|
||||
self.tx_width,
|
||||
drc["minwidth_poly"],
|
||||
perimeter_sd,
|
||||
area_sd)
|
||||
self.spice.append("\n* ptx " + self.spice_device)
|
||||
# self.spice.append(".ENDS {0}".format(self.name))
|
||||
|
||||
def setup_layout_constants(self):
|
||||
"""
|
||||
|
|
@ -94,25 +98,19 @@ class ptx(design.design):
|
|||
self.active_contact = contact(layer_stack=("active", "contact", "metal1"),
|
||||
dimensions=(1, self.num_contacts))
|
||||
|
||||
# Standard DRC rules
|
||||
self.min_active_width = drc["minwidth_active"]
|
||||
self.contact_width = drc["minwidth_contact"]
|
||||
self.poly_width = drc["minwidth_poly"]
|
||||
self.poly_to_active = drc["poly_to_active"]
|
||||
self.poly_extend_active = drc["poly_extend_active"]
|
||||
|
||||
# The contacted poly pitch (or uncontacted in an odd technology)
|
||||
self.poly_pitch = max(2*drc["contact_to_poly"] + self.contact_width + self.poly_width,
|
||||
drc["poly_to_poly"])
|
||||
self.poly_pitch = max(2*self.contact_to_gate + self.contact_width + self.poly_width,
|
||||
self.poly_space)
|
||||
|
||||
# The contacted poly pitch (or uncontacted in an odd technology)
|
||||
self.contact_pitch = 2*drc["contact_to_poly"] + self.contact_width + self.poly_width
|
||||
self.contact_pitch = 2*self.contact_to_gate + self.contact_width + self.poly_width
|
||||
|
||||
# The enclosure of an active contact. Not sure about second term.
|
||||
active_enclose_contact = max(drc["active_enclosure_contact"],
|
||||
(self.min_active_width - self.contact_width)/2)
|
||||
(self.active_width - self.contact_width)/2)
|
||||
# This is the distance from the edge of poly to the contacted end of active
|
||||
self.end_to_poly = active_enclose_contact + self.contact_width + drc["contact_to_poly"]
|
||||
self.end_to_poly = active_enclose_contact + self.contact_width + self.contact_to_gate
|
||||
|
||||
|
||||
# Active width is determined by enclosure on both ends and contacted pitch,
|
||||
|
|
@ -125,22 +123,25 @@ class ptx(design.design):
|
|||
# Poly height must include poly extension over active
|
||||
self.poly_height = self.tx_width + 2*self.poly_extend_active
|
||||
|
||||
# The active offset is due to the well extension
|
||||
self.active_offset = vector([self.well_enclose_active]*2)
|
||||
|
||||
# Well enclosure of active, ensure minwidth as well
|
||||
if info["has_{}well".format(self.well_type)]:
|
||||
self.well_width = max(self.active_width + 2*drc["well_enclosure_active"],
|
||||
drc["minwidth_well"])
|
||||
self.well_height = max(self.tx_width + 2*drc["well_enclosure_active"],
|
||||
drc["minwidth_well"])
|
||||
|
||||
self.height = self.well_height
|
||||
self.width = self.well_width
|
||||
self.cell_well_width = max(self.active_width + 2*self.well_enclose_active,
|
||||
self.well_width)
|
||||
self.cell_well_height = max(self.tx_width + 2*self.well_enclose_active,
|
||||
self.well_width)
|
||||
# We are going to shift the 0,0, so include that in the width and height
|
||||
self.height = self.cell_well_height - self.active_offset.y
|
||||
self.width = self.cell_well_width - self.active_offset.x
|
||||
else:
|
||||
# If no well, use the boundary of the active and poly
|
||||
self.height = self.poly_height
|
||||
self.width = self.active_width
|
||||
|
||||
# The active offset is due to the well extension
|
||||
self.active_offset = vector([drc["well_enclosure_active"]]*2)
|
||||
self.active_offset = vector([self.well_enclose_active]*2)
|
||||
|
||||
# This is the center of the first active contact offset (centered vertically)
|
||||
self.contact_offset = self.active_offset + vector(active_enclose_contact + 0.5*self.contact_width,
|
||||
|
|
@ -189,9 +190,9 @@ class ptx(design.design):
|
|||
# This is the distance that we must route up or down from the center
|
||||
# of the contacts to avoid DRC violations to the other contacts
|
||||
pin_offset = vector(0, 0.5*self.active_contact.second_layer_height \
|
||||
+ drc["metal1_to_metal1"] + 0.5*drc["minwidth_metal1"])
|
||||
# This is the width of a contact to extend the ends of the pin
|
||||
end_offset = vector(self.active_contact.second_layer_width/2,0)
|
||||
+ self.m1_space + 0.5*self.m1_width)
|
||||
# This is the width of a m1 extend the ends of the pin
|
||||
end_offset = vector(self.m1_width/2,0)
|
||||
|
||||
# drains always go to the MIDDLE of the cell, so top of NMOS, bottom of PMOS
|
||||
# so reverse the directions for NMOS compared to PMOS.
|
||||
|
|
@ -264,6 +265,14 @@ class ptx(design.design):
|
|||
offset=self.active_offset,
|
||||
width=self.active_width,
|
||||
height=self.active_height)
|
||||
# If the implant must enclose the active, shift offset
|
||||
# and increase width/height
|
||||
enclose_width = drc["implant_enclosure_active"]
|
||||
enclose_offset = [enclose_width]*2
|
||||
self.add_rect(layer="{}implant".format(self.implant_type),
|
||||
offset=self.active_offset - enclose_offset,
|
||||
width=self.active_width + 2*enclose_width,
|
||||
height=self.active_height + 2*enclose_width)
|
||||
|
||||
def add_well_implant(self):
|
||||
"""
|
||||
|
|
@ -272,16 +281,12 @@ class ptx(design.design):
|
|||
if info["has_{}well".format(self.well_type)]:
|
||||
self.add_rect(layer="{}well".format(self.well_type),
|
||||
offset=(0,0),
|
||||
width=self.well_width,
|
||||
height=self.well_height)
|
||||
width=self.cell_well_width,
|
||||
height=self.cell_well_height)
|
||||
self.add_rect(layer="vtg",
|
||||
offset=(0,0),
|
||||
width=self.well_width,
|
||||
height=self.well_height)
|
||||
self.add_rect(layer="{}implant".format(self.implant_type),
|
||||
offset=self.active_offset,
|
||||
width=self.active_width,
|
||||
height=self.active_height)
|
||||
width=self.cell_well_width,
|
||||
height=self.cell_well_height)
|
||||
|
||||
|
||||
def calculate_num_contacts(self):
|
||||
|
|
@ -321,23 +326,27 @@ class ptx(design.design):
|
|||
for pos in source_positions:
|
||||
contact=self.add_contact_center(layers=("active", "contact", "metal1"),
|
||||
offset=pos,
|
||||
size=(1, self.num_contacts))
|
||||
size=(1, self.num_contacts),
|
||||
implant_type=self.implant_type,
|
||||
well_type=self.well_type)
|
||||
self.add_layout_pin_center_rect(text="S",
|
||||
layer="metal1",
|
||||
offset=pos,
|
||||
width=contact.second_layer_width,
|
||||
height=contact.second_layer_height)
|
||||
width=contact.mod.second_layer_width,
|
||||
height=contact.mod.second_layer_height)
|
||||
|
||||
|
||||
for pos in drain_positions:
|
||||
contact=self.add_contact_center(layers=("active", "contact", "metal1"),
|
||||
offset=pos,
|
||||
size=(1, self.num_contacts))
|
||||
size=(1, self.num_contacts),
|
||||
implant_type=self.implant_type,
|
||||
well_type=self.well_type)
|
||||
self.add_layout_pin_center_rect(text="D",
|
||||
layer="metal1",
|
||||
offset=pos,
|
||||
width=contact.second_layer_width,
|
||||
height=contact.second_layer_height)
|
||||
width=contact.mod.second_layer_width,
|
||||
height=contact.mod.second_layer_height)
|
||||
|
||||
if self.connect_active:
|
||||
self.connect_fingered_active(drain_positions, source_positions)
|
||||
|
|
|
|||
|
|
@ -18,14 +18,14 @@ class replica_bitline(design.design):
|
|||
def __init__(self, rows, name="replica_bitline"):
|
||||
design.design.__init__(self, name)
|
||||
|
||||
g = reload(__import__(OPTS.config.delay_chain))
|
||||
self.mod_delay_chain = getattr(g, OPTS.config.delay_chain)
|
||||
g = reload(__import__(OPTS.delay_chain))
|
||||
self.mod_delay_chain = getattr(g, OPTS.delay_chain)
|
||||
|
||||
g = reload(__import__(OPTS.config.replica_bitcell))
|
||||
self.mod_replica_bitcell = getattr(g, OPTS.config.replica_bitcell)
|
||||
g = reload(__import__(OPTS.replica_bitcell))
|
||||
self.mod_replica_bitcell = getattr(g, OPTS.replica_bitcell)
|
||||
|
||||
c = reload(__import__(OPTS.config.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.config.bitcell)
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
|
||||
for pin in ["en", "out", "vdd", "gnd"]:
|
||||
self.add_pin(pin)
|
||||
|
|
@ -240,55 +240,50 @@ class replica_bitline(design.design):
|
|||
""" Route all signals connected to gnd """
|
||||
|
||||
# Add a rail in M1 from bottom to two along delay chain
|
||||
gnd_start = self.rbl_inv_inst.get_pin("gnd").ll() - self.offset_fix
|
||||
|
||||
# It is the height of the entire RBL and bitcell
|
||||
self.add_rect(layer="metal2",
|
||||
offset=gnd_start,
|
||||
width=self.m2_width,
|
||||
height=self.rbl.height+self.bitcell.height+self.inv.width+self.m2_pitch)
|
||||
self.add_layout_pin(text="gnd",
|
||||
layer="metal1",
|
||||
offset=gnd_start.scale(1,0),
|
||||
width=self.m2_width,
|
||||
height=2*self.inv.width)
|
||||
gnd_start = self.rbl_inv_inst.get_pin("gnd").bc()
|
||||
gnd_end = vector(gnd_start.x, self.rbl_inst.uy()+2*self.m2_pitch)
|
||||
self.add_segment_center(layer="metal2",
|
||||
start=gnd_start,
|
||||
end=gnd_end)
|
||||
self.add_layout_pin_center_segment(text="gnd",
|
||||
layer="metal1",
|
||||
start=gnd_start.scale(1,0),
|
||||
end=gnd_start)
|
||||
|
||||
# Connect the WL pins directly to gnd
|
||||
gnd_pin = self.get_pin("gnd").rc()
|
||||
for row in range(self.rows):
|
||||
wl = "wl[{}]".format(row)
|
||||
pin = self.rbl_inst.get_pin(wl)
|
||||
offset = vector(gnd_start.x,pin.by())
|
||||
self.add_rect(layer="metal1",
|
||||
offset=offset,
|
||||
width=self.rbl_offset.x-gnd_start.x,
|
||||
height=self.m1_width)
|
||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||
offset=offset)
|
||||
start = vector(gnd_pin.x,pin.cy())
|
||||
self.add_segment_center(layer="metal1",
|
||||
start=start,
|
||||
end=pin.lc())
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=start)
|
||||
|
||||
# Add via for the delay chain
|
||||
offset = self.delay_chain_offset - vector(0.5*self.m1_width,0) - self.offset_fix
|
||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||
offset=offset)
|
||||
offset = self.dc_inst.get_pins("gnd")[0].bc() + vector(0.5*contact.m1m2.width,0.5*contact.m1m2.height)
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=offset)
|
||||
|
||||
# Add via for the inverter
|
||||
offset = self.rbl_inv_offset - vector(0.5*self.m1_width,contact.m1m2.height) - self.offset_fix
|
||||
self.add_via(layers=("metal1", "via1", "metal2"),
|
||||
offset=offset)
|
||||
offset = self.rbl_inv_inst.get_pin("gnd").bc() - vector(0,0.5*contact.m1m2.height)
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=offset)
|
||||
|
||||
# Connect the bitcell gnd pin to the rail
|
||||
# Connect the bitcell gnd pins to the rail
|
||||
gnd_pins = self.get_pins("gnd")
|
||||
gnd_start = gnd_pins[0].uc()
|
||||
gnd_start = gnd_pins[0].ul()
|
||||
rbl_gnd_pins = self.rbl_inst.get_pins("gnd")
|
||||
# Find the left most rail on M2
|
||||
gnd_pin = None
|
||||
# Add L shapes to each vertical gnd rail
|
||||
for pin in rbl_gnd_pins:
|
||||
if gnd_pin == None or (pin.layer=="metal2" and pin.lx()<gnd_pin.lx()):
|
||||
gnd_pin = pin
|
||||
gnd_end = gnd_pin.uc()
|
||||
# Add a couple midpoints so that the wire will drop a via and then route horizontal on M1
|
||||
gnd_mid1 = gnd_start + vector(0,self.m2_pitch)
|
||||
gnd_mid2 = gnd_end + vector(0,self.m2_pitch)
|
||||
self.add_wire(("metal1","via1","metal2"), [gnd_start, gnd_mid1, gnd_mid2, gnd_end])
|
||||
if pin.layer != "metal2":
|
||||
continue
|
||||
gnd_end = pin.uc()
|
||||
gnd_mid = vector(gnd_end.x, gnd_start.y)
|
||||
self.add_wire(("metal1","via1","metal2"), [gnd_start, gnd_mid, gnd_end])
|
||||
gnd_start = gnd_mid
|
||||
|
||||
|
||||
# Add a second gnd pin to the second delay chain rail. No need for full length.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from vector3d import vector3d
|
|||
|
||||
class route():
|
||||
"""
|
||||
Object route
|
||||
Object route (used by the router module)
|
||||
Add a route of minimium metal width between a set of points.
|
||||
The wire must be completely rectilinear and the
|
||||
z-dimension of the points refers to the layers (plus via)
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ class sense_amp_array(design.design):
|
|||
design.design.__init__(self, "sense_amp_array")
|
||||
debug.info(1, "Creating {0}".format(self.name))
|
||||
|
||||
c = reload(__import__(OPTS.config.sense_amp))
|
||||
self.mod_sense_amp = getattr(c, OPTS.config.sense_amp)
|
||||
c = reload(__import__(OPTS.sense_amp))
|
||||
self.mod_sense_amp = getattr(c, OPTS.sense_amp)
|
||||
self.amp = self.mod_sense_amp("sense_amp")
|
||||
self.add_mod(self.amp)
|
||||
|
||||
|
|
|
|||
|
|
@ -12,12 +12,13 @@ class single_level_column_mux(design.design):
|
|||
Creates a single columnmux cell.
|
||||
"""
|
||||
|
||||
def __init__(self, name, tx_size):
|
||||
def __init__(self, tx_size):
|
||||
name="single_level_column_mux_{}".format(tx_size)
|
||||
design.design.__init__(self, name)
|
||||
debug.info(2, "create single columnmux cell: {0}".format(name))
|
||||
debug.info(2, "create single column mux cell: {0}".format(name))
|
||||
|
||||
c = reload(__import__(OPTS.config.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.config.bitcell)
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
|
||||
self.ptx_width = tx_size * drc["minwidth_tx"]
|
||||
|
|
@ -27,9 +28,9 @@ class single_level_column_mux(design.design):
|
|||
def create_layout(self):
|
||||
|
||||
self.add_ptx()
|
||||
|
||||
self.pin_height = 2*self.m2_width
|
||||
self.width = self.bitcell.width
|
||||
self.height = self.nmos2.uy()
|
||||
self.height = self.nmos2.uy() + self.pin_height
|
||||
self.connect_poly()
|
||||
self.add_gnd_rail()
|
||||
self.add_bitline_pins()
|
||||
|
|
@ -42,26 +43,25 @@ class single_level_column_mux(design.design):
|
|||
bl_pos = vector(self.bitcell.get_pin("BL").lx(), 0)
|
||||
br_pos = vector(self.bitcell.get_pin("BR").lx(), 0)
|
||||
|
||||
pin_height = 2*self.m2_width
|
||||
# bl and br
|
||||
self.add_layout_pin(text="bl",
|
||||
layer="metal2",
|
||||
offset=bl_pos + vector(0,self.height - pin_height),
|
||||
height=pin_height)
|
||||
offset=bl_pos + vector(0,self.height - self.pin_height),
|
||||
height=self.pin_height)
|
||||
self.add_layout_pin(text="br",
|
||||
layer="metal2",
|
||||
offset=br_pos + vector(0,self.height - pin_height),
|
||||
height=pin_height)
|
||||
offset=br_pos + vector(0,self.height - self.pin_height),
|
||||
height=self.pin_height)
|
||||
|
||||
# bl_out and br_out
|
||||
self.add_layout_pin(text="bl_out",
|
||||
layer="metal2",
|
||||
offset=bl_pos,
|
||||
height=pin_height)
|
||||
height=self.pin_height)
|
||||
self.add_layout_pin(text="br_out",
|
||||
layer="metal2",
|
||||
offset=br_pos,
|
||||
height=pin_height)
|
||||
height=self.pin_height)
|
||||
|
||||
|
||||
def add_ptx(self):
|
||||
|
|
@ -152,7 +152,6 @@ class single_level_column_mux(design.design):
|
|||
|
||||
def add_wells(self):
|
||||
""" Add a well and implant over the whole cell. Also, add the pwell contact (if it exists) """
|
||||
|
||||
|
||||
# find right most gnd rail
|
||||
gnd_pins = self.bitcell.get_pins("gnd")
|
||||
|
|
@ -167,26 +166,8 @@ class single_level_column_mux(design.design):
|
|||
offset=m1m2_offset)
|
||||
active_offset = right_gnd.bc() + vector(0,0.5*self.nmos.poly_height)
|
||||
self.add_via_center(layers=("active", "contact", "metal1"),
|
||||
offset=active_offset)
|
||||
offset=active_offset,
|
||||
implant_type="p",
|
||||
well_type="p")
|
||||
|
||||
# implant must surround the active area
|
||||
active_correct = vector(contact.well.width,contact.well.height).scale(0.5,0.5)
|
||||
offset_implant = active_offset - vector([drc["implant_to_contact"]]*2) - active_correct
|
||||
implant_width = 2*drc["implant_to_contact"] + contact.well.width
|
||||
implant_height = 2*drc["implant_to_contact"] + contact.well.height
|
||||
self.add_rect(layer="pimplant",
|
||||
offset=offset_implant,
|
||||
width=implant_width,
|
||||
height=implant_height)
|
||||
|
||||
# Add a well around the whole cell
|
||||
if info["has_pwell"]:
|
||||
self.add_rect(layer="pwell",
|
||||
offset=vector(0,0),
|
||||
width=self.width + contact.well.width + drc["well_enclosure_active"],
|
||||
height=self.height)
|
||||
self.add_rect(layer="vtg",
|
||||
offset=vector(0,0),
|
||||
width=self.width + contact.well.width,
|
||||
height=self.height)
|
||||
|
||||
|
|
|
|||
|
|
@ -40,26 +40,30 @@ class single_level_column_mux_array(design.design):
|
|||
self.setup_layout_constants()
|
||||
self.create_array()
|
||||
self.add_routing()
|
||||
# Find the highest shapes to determine height before adding well
|
||||
highest = self.find_highest_coords()
|
||||
self.height = highest.y
|
||||
self.add_layout_pins()
|
||||
self.add_enclosure(self.mux_inst, "pwell")
|
||||
|
||||
|
||||
|
||||
def add_modules(self):
|
||||
self.mux = single_level_column_mux(name="single_level_column_mux",
|
||||
tx_size=8)
|
||||
# FIXME: Why is this 8x?
|
||||
self.mux = single_level_column_mux(tx_size=8)
|
||||
self.add_mod(self.mux)
|
||||
|
||||
|
||||
def setup_layout_constants(self):
|
||||
self.column_addr_size = num_of_inputs = int(self.words_per_row / 2)
|
||||
self.width = self.columns * self.mux.width
|
||||
|
||||
self.m1_pitch = contact.m1m2.width + max(drc["metal1_to_metal1"],drc["metal2_to_metal2"])
|
||||
# To correct the offset between M1 and M2 via enclosures
|
||||
self.offset_fix = vector(0,0.5*(drc["minwidth_metal2"]-drc["minwidth_metal1"]))
|
||||
# one set of metal1 routes for select signals and a pair to interconnect the mux outputs bl/br
|
||||
# one extra route pitch is to space from the sense amp
|
||||
self.route_height = (self.words_per_row + 3)*self.m1_pitch
|
||||
# mux height plus routing signal height plus well spacing at the top
|
||||
self.height = self.mux.height + self.route_height + drc["pwell_to_nwell"]
|
||||
|
||||
|
||||
|
||||
def create_array(self):
|
||||
self.mux_inst = []
|
||||
|
||||
|
|
@ -70,28 +74,6 @@ class single_level_column_mux_array(design.design):
|
|||
self.mux_inst.append(self.add_inst(name=name,
|
||||
mod=self.mux,
|
||||
offset=x_off))
|
||||
|
||||
offset = self.mux_inst[-1].get_pin("bl").ll()
|
||||
self.add_layout_pin(text="bl[{}]".format(col_num),
|
||||
layer="metal2",
|
||||
offset=offset,
|
||||
height=self.height-offset.y)
|
||||
|
||||
offset = self.mux_inst[-1].get_pin("br").ll()
|
||||
self.add_layout_pin(text="br[{}]".format(col_num),
|
||||
layer="metal2",
|
||||
offset=offset,
|
||||
height=self.height-offset.y)
|
||||
|
||||
gnd_pins = self.mux_inst[-1].get_pins("gnd")
|
||||
for gnd_pin in gnd_pins:
|
||||
# only do even colums to avoid duplicates
|
||||
offset = gnd_pin.ll()
|
||||
if col_num % 2 == 0:
|
||||
self.add_layout_pin(text="gnd",
|
||||
layer="metal2",
|
||||
offset=offset.scale(1,0),
|
||||
height=self.height)
|
||||
|
||||
self.connect_inst(["bl[{}]".format(col_num),
|
||||
"br[{}]".format(col_num),
|
||||
|
|
@ -100,7 +82,34 @@ class single_level_column_mux_array(design.design):
|
|||
"sel[{}]".format(col_num % self.words_per_row),
|
||||
"gnd"])
|
||||
|
||||
|
||||
|
||||
def add_layout_pins(self):
|
||||
""" Add the pins after we determine the height. """
|
||||
# For every column, add a pass gate
|
||||
for col_num in range(self.columns):
|
||||
mux_inst = self.mux_inst[col_num]
|
||||
offset = mux_inst.get_pin("bl").ll()
|
||||
self.add_layout_pin(text="bl[{}]".format(col_num),
|
||||
layer="metal2",
|
||||
offset=offset,
|
||||
height=self.height-offset.y)
|
||||
|
||||
offset = mux_inst.get_pin("br").ll()
|
||||
self.add_layout_pin(text="br[{}]".format(col_num),
|
||||
layer="metal2",
|
||||
offset=offset,
|
||||
height=self.height-offset.y)
|
||||
|
||||
gnd_pins = mux_inst.get_pins("gnd")
|
||||
for gnd_pin in gnd_pins:
|
||||
# only do even colums to avoid duplicates
|
||||
offset = gnd_pin.ll()
|
||||
if col_num % 2 == 0:
|
||||
self.add_layout_pin(text="gnd",
|
||||
layer="metal2",
|
||||
offset=offset.scale(1,0),
|
||||
height=self.height)
|
||||
|
||||
|
||||
def add_routing(self):
|
||||
self.add_horizontal_input_rail()
|
||||
|
|
|
|||
|
|
@ -19,18 +19,18 @@ class sram(design.design):
|
|||
|
||||
def __init__(self, word_size, num_words, num_banks, name):
|
||||
|
||||
c = reload(__import__(OPTS.config.control_logic))
|
||||
self.mod_control_logic = getattr(c, OPTS.config.control_logic)
|
||||
c = reload(__import__(OPTS.control_logic))
|
||||
self.mod_control_logic = getattr(c, OPTS.control_logic)
|
||||
|
||||
c = reload(__import__(OPTS.config.ms_flop_array))
|
||||
self.mod_ms_flop_array = getattr(c, OPTS.config.ms_flop_array)
|
||||
c = reload(__import__(OPTS.ms_flop_array))
|
||||
self.mod_ms_flop_array = getattr(c, OPTS.ms_flop_array)
|
||||
|
||||
c = reload(__import__(OPTS.config.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.config.bitcell)
|
||||
c = reload(__import__(OPTS.bitcell))
|
||||
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
||||
self.bitcell = self.mod_bitcell()
|
||||
|
||||
c = reload(__import__(OPTS.config.ms_flop))
|
||||
self.mod_ms_flop = getattr(c, OPTS.config.ms_flop)
|
||||
c = reload(__import__(OPTS.ms_flop))
|
||||
self.mod_ms_flop = getattr(c, OPTS.ms_flop)
|
||||
self.ms_flop = self.mod_ms_flop()
|
||||
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ class sram(design.design):
|
|||
self.width = sizes[0]
|
||||
self.height = sizes[1]
|
||||
|
||||
self.DRC_LVS()
|
||||
self.DRC_LVS(final_verification=True)
|
||||
|
||||
def compute_sizes(self):
|
||||
""" Computes the organization of the memory using bitcell size by trying to make it square."""
|
||||
|
|
@ -650,7 +650,7 @@ class sram(design.design):
|
|||
# Connect the output bar to select 0
|
||||
msb_out_pin = self.msb_address_inst.get_pin("dout_bar[0]")
|
||||
msb_out_pos = msb_out_pin.rc()
|
||||
out_extend_right_pos = msb_out_pos + vector(self.m2_pitch,0)
|
||||
out_extend_right_pos = msb_out_pos + vector(2*self.m2_pitch,0)
|
||||
out_extend_up_pos = out_extend_right_pos + vector(0,self.m2_width)
|
||||
rail_pos = vector(self.vert_control_bus_positions["bank_sel[0]"].x,out_extend_up_pos.y)
|
||||
self.add_path("metal2",[msb_out_pos,out_extend_right_pos,out_extend_up_pos])
|
||||
|
|
@ -660,7 +660,7 @@ class sram(design.design):
|
|||
# Connect the output to select 1
|
||||
msb_out_pin = self.msb_address_inst.get_pin("dout[0]")
|
||||
msb_out_pos = msb_out_pin.rc()
|
||||
out_extend_right_pos = msb_out_pos + vector(self.m2_pitch,0)
|
||||
out_extend_right_pos = msb_out_pos + vector(2*self.m2_pitch,0)
|
||||
out_extend_down_pos = out_extend_right_pos - vector(0,2*self.m1_pitch)
|
||||
rail_pos = vector(self.vert_control_bus_positions["bank_sel[1]"].x,out_extend_down_pos.y)
|
||||
self.add_path("metal2",[msb_out_pos,out_extend_right_pos,out_extend_down_pos])
|
||||
|
|
@ -989,7 +989,13 @@ class sram(design.design):
|
|||
############################################################
|
||||
sp = open(sp_name, 'w')
|
||||
|
||||
sp.write("**************************************************\n")
|
||||
sp.write("* OpenRAM generated memory.\n")
|
||||
sp.write("* Words: {}\n".format(self.num_words))
|
||||
sp.write("* Data bits: {}\n".format(self.word_size))
|
||||
sp.write("* Banks: {}\n".format(self.num_banks))
|
||||
sp.write("* Column mux: {}:1\n".format(self.words_per_row))
|
||||
sp.write("**************************************************\n")
|
||||
# This causes unit test mismatch
|
||||
# sp.write("* Created: {0}\n".format(datetime.datetime.now()))
|
||||
# sp.write("* User: {0}\n".format(getpass.getuser()))
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -1,18 +1,13 @@
|
|||
#!/usr/bin/env python2.7
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
import sys,os
|
||||
from testutils import header,openram_test
|
||||
import sys,os,re
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
import debug
|
||||
import verify
|
||||
import re
|
||||
|
||||
#@unittest.skip("SKIPPING 00_format check test")
|
||||
|
||||
|
||||
class code_format_test(unittest.TestCase):
|
||||
class code_format_test(openram_test):
|
||||
"Run a test to check for tabs instead of spaces in the all source files."
|
||||
|
||||
def runTest(self):
|
||||
|
|
|
|||
|
|
@ -2,23 +2,19 @@
|
|||
"Run a regresion test the library cells for DRC"
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
import sys,os
|
||||
from testutils import header,openram_test
|
||||
import sys,os,re
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
import re
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 01_library_drc_test")
|
||||
|
||||
|
||||
class library_drc_test(unittest.TestCase):
|
||||
class library_drc_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
global verify
|
||||
import verify
|
||||
|
||||
(gds_dir, gds_files) = setup_files()
|
||||
drc_errors = 0
|
||||
|
|
|
|||
|
|
@ -2,24 +2,18 @@
|
|||
"Run a regresion test the library cells for LVS"
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
import sys,os
|
||||
from testutils import header,openram_test
|
||||
import sys,os,re
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
import re
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 02_lvs_test")
|
||||
|
||||
|
||||
class library_lvs_test(unittest.TestCase):
|
||||
class library_lvs_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
|
||||
import verify
|
||||
(gds_dir, sp_dir, allnames) = setup_files()
|
||||
lvs_errors = 0
|
||||
debug.info(1, "Performing LVS on: " + ", ".join(allnames))
|
||||
|
|
@ -34,7 +28,7 @@ class library_lvs_test(unittest.TestCase):
|
|||
lvs_errors += 1
|
||||
debug.error("Missing SPICE file {}".format(gds_name))
|
||||
lvs_errors += verify.run_lvs(f, gds_name, sp_name)
|
||||
|
||||
self.assertEqual(lvs_errors, 0)
|
||||
# fail if the error count is not zero
|
||||
self.assertEqual(lvs_errors, 0)
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -2,22 +2,19 @@
|
|||
"Run a regresion test for DRC on basic contacts of different array sizes"
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 03_contact_test")
|
||||
|
||||
|
||||
class contact_test(unittest.TestCase):
|
||||
class contact_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import contact
|
||||
|
|
@ -29,31 +26,26 @@ class contact_test(unittest.TestCase):
|
|||
# Check single 1 x 1 contact"
|
||||
debug.info(2, "1 x 1 {} test".format(stack_name))
|
||||
c = contact.contact(layer_stack, (1, 1))
|
||||
self.local_check(c)
|
||||
self.local_drc_check(c)
|
||||
|
||||
# check vertical array with one in the middle and two ends
|
||||
debug.info(2, "1 x 3 {} test".format(stack_name))
|
||||
c = contact.contact(layer_stack, (1, 3))
|
||||
self.local_check(c)
|
||||
self.local_drc_check(c)
|
||||
|
||||
# check horizontal array with one in the middle and two ends
|
||||
debug.info(2, "3 x 1 {} test".format(stack_name))
|
||||
c = contact.contact(layer_stack, (3, 1))
|
||||
self.local_check(c)
|
||||
self.local_drc_check(c)
|
||||
|
||||
# check 3x3 array for all possible neighbors
|
||||
debug.info(2, "3 x 3 {} test".format(stack_name))
|
||||
c = contact.contact(layer_stack, (3, 3))
|
||||
self.local_check(c)
|
||||
self.local_drc_check(c)
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, c):
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
c.gds_write(tempgds)
|
||||
self.assertFalse(verify.run_drc(c.name, tempgds))
|
||||
os.remove(tempgds)
|
||||
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
|
|
|
|||
|
|
@ -2,22 +2,19 @@
|
|||
"Run a regresion test on a basic path"
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 03_path_test")
|
||||
|
||||
|
||||
class path_test(unittest.TestCase):
|
||||
class path_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import path
|
||||
|
|
@ -35,7 +32,7 @@ class path_test(unittest.TestCase):
|
|||
[0, 6 * min_space ]]
|
||||
w = design.design("path_test0")
|
||||
path.path(w,layer_stack, position_list)
|
||||
self.local_check(w)
|
||||
self.local_drc_check(w)
|
||||
|
||||
|
||||
min_space = 2 * tech.drc["minwidth_metal1"]
|
||||
|
|
@ -52,7 +49,7 @@ class path_test(unittest.TestCase):
|
|||
position_list = [[x+min_space, y+min_space] for x,y in old_position_list]
|
||||
w = design.design("path_test1")
|
||||
path.path(w,layer_stack, position_list)
|
||||
self.local_check(w)
|
||||
self.local_drc_check(w)
|
||||
|
||||
min_space = 2 * tech.drc["minwidth_metal2"]
|
||||
layer_stack = ("metal2")
|
||||
|
|
@ -68,7 +65,7 @@ class path_test(unittest.TestCase):
|
|||
position_list = [[x-min_space, y-min_space] for x,y in old_position_list]
|
||||
w = design.design("path_test2")
|
||||
path.path(w, layer_stack, position_list)
|
||||
self.local_check(w)
|
||||
self.local_drc_check(w)
|
||||
|
||||
min_space = 2 * tech.drc["minwidth_metal3"]
|
||||
layer_stack = ("metal3")
|
||||
|
|
@ -85,17 +82,12 @@ class path_test(unittest.TestCase):
|
|||
position_list.reverse()
|
||||
w = design.design("path_test3")
|
||||
path.path(w, layer_stack, position_list)
|
||||
self.local_check(w)
|
||||
self.local_drc_check(w)
|
||||
|
||||
# return it back to it's normal state
|
||||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, w):
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
w.gds_write(tempgds)
|
||||
self.assertFalse(verify.run_drc(w.name, tempgds))
|
||||
os.remove(tempgds)
|
||||
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
|
|
|
|||
|
|
@ -2,23 +2,19 @@
|
|||
"Run a regresion test on a basic parameterized transistors"
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 03_ptx_test")
|
||||
|
||||
|
||||
class ptx_test(unittest.TestCase):
|
||||
class ptx_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import ptx
|
||||
|
|
@ -28,126 +24,12 @@ class ptx_test(unittest.TestCase):
|
|||
fet = ptx.ptx(width=tech.drc["minwidth_tx"],
|
||||
mults=1,
|
||||
tx_type="nmos")
|
||||
self.local_check(fet)
|
||||
self.local_drc_check(fet)
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
|
||||
def add_mods(self, fet):
|
||||
self.create_contacts()
|
||||
self.add_well_extension(fet)
|
||||
self.add_wire_extension(fet)
|
||||
self.add_well_tiedown(fet)
|
||||
self.add_poly_tiedown(fet)
|
||||
|
||||
def create_contacts(self):
|
||||
layer_stack = ("active", "contact", "metal1")
|
||||
self.well_contact = contact.contact(layer_stack)
|
||||
|
||||
layer_stack = ("poly", "contact", "metal1")
|
||||
self.poly_contact = contact.contact(layer_stack)
|
||||
|
||||
def add_well_tiedown(self, fet):
|
||||
offset = [fet.active_contact_positions[0][0],
|
||||
fet.active_contact_positions[0][1] + fet.well_height]
|
||||
fet.add_inst(name="well_tap",
|
||||
mod=self.well_contact,
|
||||
offset=offset,
|
||||
mirror="R0",
|
||||
rotate=0)
|
||||
fet.well_contact = self.well_contact
|
||||
fet.well_tiedown_location = offset
|
||||
|
||||
def add_well_extension(self, fet):
|
||||
well_define = {"pmos": "nwell",
|
||||
"nmos": "pwell"}
|
||||
well_type = well_define[fet.tx_type]
|
||||
offset = getattr(fet,"{}_position".format(well_type))
|
||||
if tech.info["has_{0}".format(well_type)]:
|
||||
fet.add_rect(layerNumber=tech.layer[well_type],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=2 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["{0}implant".format(fet.tx_type[0])],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=2 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["vtg"],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=2 * fet.well_height)
|
||||
|
||||
well_type = "{0}well".format(fet.tx_type[0])
|
||||
offset[1] = offset[1] - 3 * fet.well_height
|
||||
if tech.info["has_{0}".format(well_type)]:
|
||||
fet.add_rect(layerNumber=tech.layer[well_type],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=3 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["{0}implant".format(well_define[fet.tx_type][
|
||||
0])],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=3 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["vtg"],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=3 * fet.well_height)
|
||||
|
||||
def add_wire_extension(self, fet):
|
||||
xcorrect = (fet.active_contact.width / 2) - (tech.drc["minwidth_metal1"] / 2)
|
||||
offset = [fet.active_contact_positions[0][0] + xcorrect,
|
||||
fet.active_contact_positions[0][1]]
|
||||
fet.add_rect(layerNumber=tech.layer["metal1"],
|
||||
offset=offset,
|
||||
width=tech.drc["minwidth_metal1"],
|
||||
height=fet.well_height)
|
||||
|
||||
offset = [fet.active_contact_positions[-1][0] + xcorrect,
|
||||
fet.active_contact_positions[-1][1] - 2 * fet.well_height]
|
||||
fet.add_rect(layerNumber=tech.layer["metal1"],
|
||||
offset=offset,
|
||||
width=tech.drc["minwidth_metal1"],
|
||||
height=2 * fet.well_height)
|
||||
|
||||
offset = [fet.poly_positions[-1][0],
|
||||
fet.poly_positions[-1][1] - (fet.well_height)]
|
||||
fet.add_rect(layerNumber=tech.layer["poly"],
|
||||
offset=offset,
|
||||
width=tech.drc["minwidth_poly"],
|
||||
height=fet.well_height)
|
||||
|
||||
def add_poly_tiedown(self, fet):
|
||||
xcorrect = abs(self.poly_contact.upper_layer_vertical_enclosure -
|
||||
self.poly_contact.lower_layer_vertical_enclosure)
|
||||
offset = [fet.poly_positions[-1][0] - xcorrect,
|
||||
fet.poly_positions[-1][1] - (fet.well_height)]
|
||||
fet.add_inst(name="poly_contact",
|
||||
mod=self.poly_contact,
|
||||
offset=offset,
|
||||
mirror="R270")
|
||||
|
||||
|
||||
offset = [fet.active_contact_positions[-1][0], fet.active_contact_positions
|
||||
[-1][1] - 2 * fet.well_height - self.well_contact.height]
|
||||
fet.poly_tiedown_location = offset
|
||||
fet.add_inst(name="n_tiedown",
|
||||
mod=self.well_contact,
|
||||
offset=offset)
|
||||
tech.ptx_port.add_custom_layer(fet)
|
||||
|
||||
def local_check(self, fet):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
fet.sp_write(tempspice)
|
||||
fet.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(fet.name, tempgds))
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -2,23 +2,19 @@
|
|||
"Run a regresion test on a basic parameterized transistors"
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 03_ptx_test")
|
||||
|
||||
|
||||
class ptx_test(unittest.TestCase):
|
||||
class ptx_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import ptx
|
||||
|
|
@ -28,127 +24,12 @@ class ptx_test(unittest.TestCase):
|
|||
fet = ptx.ptx(width=tech.drc["minwidth_tx"],
|
||||
mults=1,
|
||||
tx_type="pmos")
|
||||
self.local_check(fet)
|
||||
self.local_drc_check(fet)
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
|
||||
def add_mods(self, fet):
|
||||
self.create_contacts()
|
||||
self.add_well_extension(fet)
|
||||
self.add_wire_extension(fet)
|
||||
self.add_well_tiedown(fet)
|
||||
self.add_poly_tiedown(fet)
|
||||
|
||||
def create_contacts(self):
|
||||
layer_stack = ("active", "contact", "metal1")
|
||||
self.well_contact = contact.contact(layer_stack)
|
||||
|
||||
layer_stack = ("poly", "contact", "metal1")
|
||||
self.poly_contact = contact.contact(layer_stack)
|
||||
|
||||
def add_well_tiedown(self, fet):
|
||||
offset = [fet.active_contact_positions[0][0],
|
||||
fet.active_contact_positions[0][1] + fet.well_height]
|
||||
fet.add_inst(name="well_tap",
|
||||
mod=self.well_contact,
|
||||
offset=offset,
|
||||
mirror="R0",
|
||||
rotate=0)
|
||||
fet.well_contact = self.well_contact
|
||||
fet.well_tiedown_location = offset
|
||||
|
||||
def add_well_extension(self, fet):
|
||||
well_define = {"pmos": "nwell",
|
||||
"nmos": "pwell"}
|
||||
well_type = well_define[fet.tx_type]
|
||||
offset = getattr(fet,"{}_position".format(well_type))
|
||||
if tech.info["has_{0}".format(well_type)]:
|
||||
fet.add_rect(layerNumber=tech.layer[well_type],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=2 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["{0}implant".format(fet.tx_type[0])],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=2 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["vtg"],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=2 * fet.well_height)
|
||||
|
||||
well_type = "{0}well".format(fet.tx_type[0])
|
||||
offset[1] = offset[1] - 3 * fet.well_height
|
||||
if tech.info["has_{0}".format(well_type)]:
|
||||
fet.add_rect(layerNumber=tech.layer[well_type],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=3 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["{0}implant".format(well_define[fet.tx_type][
|
||||
0])],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=3 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["vtg"],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=3 * fet.well_height)
|
||||
|
||||
def add_wire_extension(self, fet):
|
||||
xcorrect = (fet.active_contact.width / 2) - (tech.drc["minwidth_metal1"] / 2)
|
||||
offset = [fet.active_contact_positions[0][0] + xcorrect,
|
||||
fet.active_contact_positions[0][1]]
|
||||
fet.add_rect(layerNumber=tech.layer["metal1"],
|
||||
offset=offset,
|
||||
width=tech.drc["minwidth_metal1"],
|
||||
height=fet.well_height)
|
||||
|
||||
offset = [fet.active_contact_positions[-1][0] + xcorrect,
|
||||
fet.active_contact_positions[-1][1] - 2 * fet.well_height]
|
||||
fet.add_rect(layerNumber=tech.layer["metal1"],
|
||||
offset=offset,
|
||||
width=tech.drc["minwidth_metal1"],
|
||||
height=2 * fet.well_height)
|
||||
|
||||
offset = [fet.poly_positions[-1][0],
|
||||
fet.poly_positions[-1][1] - (fet.well_height)]
|
||||
fet.add_rect(layerNumber=tech.layer["poly"],
|
||||
offset=offset,
|
||||
width=tech.drc["minwidth_poly"],
|
||||
height=fet.well_height)
|
||||
|
||||
def add_poly_tiedown(self, fet):
|
||||
xcorrect = abs(self.poly_contact.upper_layer_vertical_enclosure -
|
||||
self.poly_contact.lower_layer_vertical_enclosure)
|
||||
offset = [fet.poly_positions[-1][0] - xcorrect,
|
||||
fet.poly_positions[-1][1] - (fet.well_height)]
|
||||
fet.add_inst(name="poly_contact",
|
||||
mod=self.poly_contact,
|
||||
offset=offset,
|
||||
mirror="R270")
|
||||
|
||||
|
||||
offset = [fet.active_contact_positions[-1][0], fet.active_contact_positions
|
||||
[-1][1] - 2 * fet.well_height - self.well_contact.height]
|
||||
fet.poly_tiedown_location = offset
|
||||
fet.add_inst(name="n_tiedown",
|
||||
mod=self.well_contact,
|
||||
offset=offset)
|
||||
tech.ptx_port.add_custom_layer(fet)
|
||||
|
||||
def local_check(self, fet):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
fet.sp_write(tempspice)
|
||||
fet.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(fet.name, tempgds))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -2,23 +2,19 @@
|
|||
"Run a regresion test on a basic parameterized transistors"
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 03_ptx_test")
|
||||
|
||||
|
||||
class ptx_test(unittest.TestCase):
|
||||
class ptx_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import ptx
|
||||
|
|
@ -30,125 +26,11 @@ class ptx_test(unittest.TestCase):
|
|||
tx_type="nmos",
|
||||
connect_active=True,
|
||||
connect_poly=True)
|
||||
self.local_check(fet)
|
||||
self.local_drc_check(fet)
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def add_mods(self, fet):
|
||||
self.create_contacts()
|
||||
self.add_well_extension(fet)
|
||||
self.add_wire_extension(fet)
|
||||
self.add_well_tiedown(fet)
|
||||
self.add_poly_tiedown(fet)
|
||||
|
||||
def create_contacts(self):
|
||||
layer_stack = ("active", "contact", "metal1")
|
||||
self.well_contact = contact.contact(layer_stack)
|
||||
|
||||
layer_stack = ("poly", "contact", "metal1")
|
||||
self.poly_contact = contact.contact(layer_stack)
|
||||
|
||||
def add_well_tiedown(self, fet):
|
||||
offset = [fet.active_contact_positions[0][0],
|
||||
fet.active_contact_positions[0][1] + fet.well_height]
|
||||
fet.add_inst(name="well_tap",
|
||||
mod=self.well_contact,
|
||||
offset=offset,
|
||||
mirror="R0",
|
||||
rotate=0)
|
||||
fet.well_contact = self.well_contact
|
||||
fet.well_tiedown_location = offset
|
||||
|
||||
def add_well_extension(self, fet):
|
||||
well_define = {"pmos": "nwell",
|
||||
"nmos": "pwell"}
|
||||
well_type = well_define[fet.tx_type]
|
||||
offset = getattr(fet,"{}_position".format(well_type))
|
||||
if tech.info["has_{0}".format(well_type)]:
|
||||
fet.add_rect(layerNumber=tech.layer[well_type],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=2 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["{0}implant".format(fet.tx_type[0])],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=2 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["vtg"],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=2 * fet.well_height)
|
||||
|
||||
well_type = "{0}well".format(fet.tx_type[0])
|
||||
offset[1] = offset[1] - 3 * fet.well_height
|
||||
if tech.info["has_{0}".format(well_type)]:
|
||||
fet.add_rect(layerNumber=tech.layer[well_type],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=3 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["{0}implant".format(well_define[fet.tx_type][
|
||||
0])],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=3 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["vtg"],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=3 * fet.well_height)
|
||||
|
||||
def add_wire_extension(self, fet):
|
||||
xcorrect = (fet.active_contact.width / 2) - (tech.drc["minwidth_metal1"] / 2)
|
||||
offset = [fet.active_contact_positions[0][0] + xcorrect,
|
||||
fet.active_contact_positions[0][1]]
|
||||
fet.add_rect(layerNumber=tech.layer["metal1"],
|
||||
offset=offset,
|
||||
width=tech.drc["minwidth_metal1"],
|
||||
height=fet.well_height)
|
||||
|
||||
offset = [fet.active_contact_positions[-1][0] + xcorrect,
|
||||
fet.active_contact_positions[-1][1] - 2 * fet.well_height]
|
||||
fet.add_rect(layerNumber=tech.layer["metal1"],
|
||||
offset=offset,
|
||||
width=tech.drc["minwidth_metal1"],
|
||||
height=2 * fet.well_height)
|
||||
|
||||
offset = [fet.poly_positions[-1][0],
|
||||
fet.poly_positions[-1][1] - (fet.well_height)]
|
||||
fet.add_rect(layerNumber=tech.layer["poly"],
|
||||
offset=offset,
|
||||
width=tech.drc["minwidth_poly"],
|
||||
height=fet.well_height)
|
||||
|
||||
def add_poly_tiedown(self, fet):
|
||||
xcorrect = abs(self.poly_contact.upper_layer_vertical_enclosure -
|
||||
self.poly_contact.lower_layer_vertical_enclosure)
|
||||
offset = [fet.poly_positions[-1][0] - xcorrect,
|
||||
fet.poly_positions[-1][1] - (fet.well_height)]
|
||||
fet.add_inst(name="poly_contact",
|
||||
mod=self.poly_contact,
|
||||
offset=offset,
|
||||
mirror="R270")
|
||||
|
||||
|
||||
offset = [fet.active_contact_positions[-1][0], fet.active_contact_positions
|
||||
[-1][1] - 2 * fet.well_height - self.well_contact.height]
|
||||
fet.poly_tiedown_location = offset
|
||||
fet.add_inst(name="n_tiedown",
|
||||
mod=self.well_contact,
|
||||
offset=offset)
|
||||
tech.ptx_port.add_custom_layer(fet)
|
||||
|
||||
def local_check(self, fet):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
fet.sp_write(tempspice)
|
||||
fet.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(fet.name, tempgds))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -2,23 +2,19 @@
|
|||
"Run a regresion test on a basic parameterized transistors"
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 03_ptx_test")
|
||||
|
||||
|
||||
class ptx_test(unittest.TestCase):
|
||||
class ptx_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import ptx
|
||||
|
|
@ -30,125 +26,11 @@ class ptx_test(unittest.TestCase):
|
|||
tx_type="pmos",
|
||||
connect_active=True,
|
||||
connect_poly=True)
|
||||
self.local_check(fet)
|
||||
self.local_drc_check(fet)
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def add_mods(self, fet):
|
||||
self.create_contacts()
|
||||
self.add_well_extension(fet)
|
||||
self.add_wire_extension(fet)
|
||||
self.add_well_tiedown(fet)
|
||||
self.add_poly_tiedown(fet)
|
||||
|
||||
def create_contacts(self):
|
||||
layer_stack = ("active", "contact", "metal1")
|
||||
self.well_contact = contact.contact(layer_stack)
|
||||
|
||||
layer_stack = ("poly", "contact", "metal1")
|
||||
self.poly_contact = contact.contact(layer_stack)
|
||||
|
||||
def add_well_tiedown(self, fet):
|
||||
offset = [fet.active_contact_positions[0][0],
|
||||
fet.active_contact_positions[0][1] + fet.well_height]
|
||||
fet.add_inst(name="well_tap",
|
||||
mod=self.well_contact,
|
||||
offset=offset,
|
||||
mirror="R0",
|
||||
rotate=0)
|
||||
fet.well_contact = self.well_contact
|
||||
fet.well_tiedown_location = offset
|
||||
|
||||
def add_well_extension(self, fet):
|
||||
well_define = {"pmos": "nwell",
|
||||
"nmos": "pwell"}
|
||||
well_type = well_define[fet.tx_type]
|
||||
offset = getattr(fet,"{}_position".format(well_type))
|
||||
if tech.info["has_{0}".format(well_type)]:
|
||||
fet.add_rect(layerNumber=tech.layer[well_type],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=2 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["{0}implant".format(fet.tx_type[0])],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=2 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["vtg"],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=2 * fet.well_height)
|
||||
|
||||
well_type = "{0}well".format(fet.tx_type[0])
|
||||
offset[1] = offset[1] - 3 * fet.well_height
|
||||
if tech.info["has_{0}".format(well_type)]:
|
||||
fet.add_rect(layerNumber=tech.layer[well_type],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=3 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["{0}implant".format(well_define[fet.tx_type][
|
||||
0])],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=3 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["vtg"],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=3 * fet.well_height)
|
||||
|
||||
def add_wire_extension(self, fet):
|
||||
xcorrect = (fet.active_contact.width / 2) - (tech.drc["minwidth_metal1"] / 2)
|
||||
offset = [fet.active_contact_positions[0][0] + xcorrect,
|
||||
fet.active_contact_positions[0][1]]
|
||||
fet.add_rect(layerNumber=tech.layer["metal1"],
|
||||
offset=offset,
|
||||
width=tech.drc["minwidth_metal1"],
|
||||
height=fet.well_height)
|
||||
|
||||
offset = [fet.active_contact_positions[-1][0] + xcorrect,
|
||||
fet.active_contact_positions[-1][1] - 2 * fet.well_height]
|
||||
fet.add_rect(layerNumber=tech.layer["metal1"],
|
||||
offset=offset,
|
||||
width=tech.drc["minwidth_metal1"],
|
||||
height=2 * fet.well_height)
|
||||
|
||||
offset = [fet.poly_positions[-1][0],
|
||||
fet.poly_positions[-1][1] - (fet.well_height)]
|
||||
fet.add_rect(layerNumber=tech.layer["poly"],
|
||||
offset=offset,
|
||||
width=tech.drc["minwidth_poly"],
|
||||
height=fet.well_height)
|
||||
|
||||
def add_poly_tiedown(self, fet):
|
||||
xcorrect = abs(self.poly_contact.upper_layer_vertical_enclosure -
|
||||
self.poly_contact.lower_layer_vertical_enclosure)
|
||||
offset = [fet.poly_positions[-1][0] - xcorrect,
|
||||
fet.poly_positions[-1][1] - (fet.well_height)]
|
||||
fet.add_inst(name="poly_contact",
|
||||
mod=self.poly_contact,
|
||||
offset=offset,
|
||||
mirror="R270")
|
||||
|
||||
|
||||
offset = [fet.active_contact_positions[-1][0], fet.active_contact_positions
|
||||
[-1][1] - 2 * fet.well_height - self.well_contact.height]
|
||||
fet.poly_tiedown_location = offset
|
||||
fet.add_inst(name="n_tiedown",
|
||||
mod=self.well_contact,
|
||||
offset=offset)
|
||||
tech.ptx_port.add_custom_layer(fet)
|
||||
|
||||
def local_check(self, fet):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
fet.sp_write(tempspice)
|
||||
fet.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(fet.name, tempgds))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -2,23 +2,19 @@
|
|||
"Run a regresion test on a basic parameterized transistors"
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 03_ptx_test")
|
||||
|
||||
|
||||
class ptx_test(unittest.TestCase):
|
||||
class ptx_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import ptx
|
||||
|
|
@ -30,125 +26,11 @@ class ptx_test(unittest.TestCase):
|
|||
tx_type="nmos",
|
||||
connect_active=True,
|
||||
connect_poly=True)
|
||||
self.local_check(fet)
|
||||
self.local_drc_check(fet)
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def add_mods(self, fet):
|
||||
self.create_contacts()
|
||||
self.add_well_extension(fet)
|
||||
self.add_wire_extension(fet)
|
||||
self.add_well_tiedown(fet)
|
||||
self.add_poly_tiedown(fet)
|
||||
|
||||
def create_contacts(self):
|
||||
layer_stack = ("active", "contact", "metal1")
|
||||
self.well_contact = contact.contact(layer_stack)
|
||||
|
||||
layer_stack = ("poly", "contact", "metal1")
|
||||
self.poly_contact = contact.contact(layer_stack)
|
||||
|
||||
def add_well_tiedown(self, fet):
|
||||
offset = [fet.active_contact_positions[0][0],
|
||||
fet.active_contact_positions[0][1] + fet.well_height]
|
||||
fet.add_inst(name="well_tap",
|
||||
mod=self.well_contact,
|
||||
offset=offset,
|
||||
mirror="R0",
|
||||
rotate=0)
|
||||
fet.well_contact = self.well_contact
|
||||
fet.well_tiedown_location = offset
|
||||
|
||||
def add_well_extension(self, fet):
|
||||
well_define = {"pmos": "nwell",
|
||||
"nmos": "pwell"}
|
||||
well_type = well_define[fet.tx_type]
|
||||
offset = getattr(fet,"{}_position".format(well_type))
|
||||
if tech.info["has_{0}".format(well_type)]:
|
||||
fet.add_rect(layerNumber=tech.layer[well_type],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=2 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["{0}implant".format(fet.tx_type[0])],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=2 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["vtg"],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=2 * fet.well_height)
|
||||
|
||||
well_type = "{0}well".format(fet.tx_type[0])
|
||||
offset[1] = offset[1] - 3 * fet.well_height
|
||||
if tech.info["has_{0}".format(well_type)]:
|
||||
fet.add_rect(layerNumber=tech.layer[well_type],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=3 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["{0}implant".format(well_define[fet.tx_type][
|
||||
0])],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=3 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["vtg"],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=3 * fet.well_height)
|
||||
|
||||
def add_wire_extension(self, fet):
|
||||
xcorrect = (fet.active_contact.width / 2) - (tech.drc["minwidth_metal1"] / 2)
|
||||
offset = [fet.active_contact_positions[0][0] + xcorrect,
|
||||
fet.active_contact_positions[0][1]]
|
||||
fet.add_rect(layerNumber=tech.layer["metal1"],
|
||||
offset=offset,
|
||||
width=tech.drc["minwidth_metal1"],
|
||||
height=fet.well_height)
|
||||
|
||||
offset = [fet.active_contact_positions[-1][0] + xcorrect,
|
||||
fet.active_contact_positions[-1][1] - 2 * fet.well_height]
|
||||
fet.add_rect(layerNumber=tech.layer["metal1"],
|
||||
offset=offset,
|
||||
width=tech.drc["minwidth_metal1"],
|
||||
height=2 * fet.well_height)
|
||||
|
||||
offset = [fet.poly_positions[-1][0],
|
||||
fet.poly_positions[-1][1] - (fet.well_height)]
|
||||
fet.add_rect(layerNumber=tech.layer["poly"],
|
||||
offset=offset,
|
||||
width=tech.drc["minwidth_poly"],
|
||||
height=fet.well_height)
|
||||
|
||||
def add_poly_tiedown(self, fet):
|
||||
xcorrect = abs(self.poly_contact.upper_layer_vertical_enclosure -
|
||||
self.poly_contact.lower_layer_vertical_enclosure)
|
||||
offset = [fet.poly_positions[-1][0] - xcorrect,
|
||||
fet.poly_positions[-1][1] - (fet.well_height)]
|
||||
fet.add_inst(name="poly_contact",
|
||||
mod=self.poly_contact,
|
||||
offset=offset,
|
||||
mirror="R270")
|
||||
|
||||
|
||||
offset = [fet.active_contact_positions[-1][0], fet.active_contact_positions
|
||||
[-1][1] - 2 * fet.well_height - self.well_contact.height]
|
||||
fet.poly_tiedown_location = offset
|
||||
fet.add_inst(name="n_tiedown",
|
||||
mod=self.well_contact,
|
||||
offset=offset)
|
||||
tech.ptx_port.add_custom_layer(fet)
|
||||
|
||||
def local_check(self, fet):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
fet.sp_write(tempspice)
|
||||
fet.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(fet.name, tempgds))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -2,23 +2,19 @@
|
|||
"Run a regresion test on a basic parameterized transistors"
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 03_ptx_test")
|
||||
|
||||
|
||||
class ptx_test(unittest.TestCase):
|
||||
class ptx_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import ptx
|
||||
|
|
@ -30,125 +26,11 @@ class ptx_test(unittest.TestCase):
|
|||
tx_type="pmos",
|
||||
connect_active=True,
|
||||
connect_poly=True)
|
||||
self.local_check(fet)
|
||||
self.local_drc_check(fet)
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def add_mods(self, fet):
|
||||
self.create_contacts()
|
||||
self.add_well_extension(fet)
|
||||
self.add_wire_extension(fet)
|
||||
self.add_well_tiedown(fet)
|
||||
self.add_poly_tiedown(fet)
|
||||
|
||||
def create_contacts(self):
|
||||
layer_stack = ("active", "contact", "metal1")
|
||||
self.well_contact = contact.contact(layer_stack)
|
||||
|
||||
layer_stack = ("poly", "contact", "metal1")
|
||||
self.poly_contact = contact.contact(layer_stack)
|
||||
|
||||
def add_well_tiedown(self, fet):
|
||||
offset = [fet.active_contact_positions[0][0],
|
||||
fet.active_contact_positions[0][1] + fet.well_height]
|
||||
fet.add_inst(name="well_tap",
|
||||
mod=self.well_contact,
|
||||
offset=offset,
|
||||
mirror="R0",
|
||||
rotate=0)
|
||||
fet.well_contact = self.well_contact
|
||||
fet.well_tiedown_location = offset
|
||||
|
||||
def add_well_extension(self, fet):
|
||||
well_define = {"pmos": "nwell",
|
||||
"nmos": "pwell"}
|
||||
well_type = well_define[fet.tx_type]
|
||||
offset = getattr(fet,"{}_position".format(well_type))
|
||||
if tech.info["has_{0}".format(well_type)]:
|
||||
fet.add_rect(layerNumber=tech.layer[well_type],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=2 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["{0}implant".format(fet.tx_type[0])],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=2 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["vtg"],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=2 * fet.well_height)
|
||||
|
||||
well_type = "{0}well".format(fet.tx_type[0])
|
||||
offset[1] = offset[1] - 3 * fet.well_height
|
||||
if tech.info["has_{0}".format(well_type)]:
|
||||
fet.add_rect(layerNumber=tech.layer[well_type],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=3 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["{0}implant".format(well_define[fet.tx_type][
|
||||
0])],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=3 * fet.well_height)
|
||||
fet.add_rect(layerNumber=tech.layer["vtg"],
|
||||
offset=offset,
|
||||
width=fet.well_width,
|
||||
height=3 * fet.well_height)
|
||||
|
||||
def add_wire_extension(self, fet):
|
||||
xcorrect = (fet.active_contact.width / 2) - (tech.drc["minwidth_metal1"] / 2)
|
||||
offset = [fet.active_contact_positions[0][0] + xcorrect,
|
||||
fet.active_contact_positions[0][1]]
|
||||
fet.add_rect(layerNumber=tech.layer["metal1"],
|
||||
offset=offset,
|
||||
width=tech.drc["minwidth_metal1"],
|
||||
height=fet.well_height)
|
||||
|
||||
offset = [fet.active_contact_positions[-1][0] + xcorrect,
|
||||
fet.active_contact_positions[-1][1] - 2 * fet.well_height]
|
||||
fet.add_rect(layerNumber=tech.layer["metal1"],
|
||||
offset=offset,
|
||||
width=tech.drc["minwidth_metal1"],
|
||||
height=2 * fet.well_height)
|
||||
|
||||
offset = [fet.poly_positions[-1][0],
|
||||
fet.poly_positions[-1][1] - (fet.well_height)]
|
||||
fet.add_rect(layerNumber=tech.layer["poly"],
|
||||
offset=offset,
|
||||
width=tech.drc["minwidth_poly"],
|
||||
height=fet.well_height)
|
||||
|
||||
def add_poly_tiedown(self, fet):
|
||||
xcorrect = abs(self.poly_contact.upper_layer_vertical_enclosure -
|
||||
self.poly_contact.lower_layer_vertical_enclosure)
|
||||
offset = [fet.poly_positions[-1][0] - xcorrect,
|
||||
fet.poly_positions[-1][1] - (fet.well_height)]
|
||||
fet.add_inst(name="poly_contact",
|
||||
mod=self.poly_contact,
|
||||
offset=offset,
|
||||
mirror="R270")
|
||||
|
||||
|
||||
offset = [fet.active_contact_positions[-1][0], fet.active_contact_positions
|
||||
[-1][1] - 2 * fet.well_height - self.well_contact.height]
|
||||
fet.poly_tiedown_location = offset
|
||||
fet.add_inst(name="n_tiedown",
|
||||
mod=self.well_contact,
|
||||
offset=offset)
|
||||
tech.ptx_port.add_custom_layer(fet)
|
||||
|
||||
def local_check(self, fet):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
fet.sp_write(tempspice)
|
||||
fet.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(fet.name, tempgds))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -2,22 +2,19 @@
|
|||
"Run a regresion test on a basic wire"
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 03_wire_test")
|
||||
|
||||
|
||||
class wire_test(unittest.TestCase):
|
||||
class wire_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import wire
|
||||
|
|
@ -39,7 +36,7 @@ class wire_test(unittest.TestCase):
|
|||
position_list = [[x-min_space, y-min_space] for x,y in old_position_list]
|
||||
w = design.design("wire_test1")
|
||||
wire.wire(w, layer_stack, position_list)
|
||||
self.local_check(w)
|
||||
self.local_drc_check(w)
|
||||
|
||||
min_space = 2 * (tech.drc["minwidth_poly"] +
|
||||
tech.drc["minwidth_metal1"])
|
||||
|
|
@ -56,7 +53,7 @@ class wire_test(unittest.TestCase):
|
|||
position_list = [[x+min_space, y+min_space] for x,y in old_position_list]
|
||||
w = design.design("wire_test2")
|
||||
wire.wire(w, layer_stack, position_list)
|
||||
self.local_check(w)
|
||||
self.local_drc_check(w)
|
||||
|
||||
min_space = 2 * (tech.drc["minwidth_metal2"] +
|
||||
tech.drc["minwidth_metal1"])
|
||||
|
|
@ -72,7 +69,7 @@ class wire_test(unittest.TestCase):
|
|||
[-1 * min_space, 0]]
|
||||
w = design.design("wire_test3")
|
||||
wire.wire(w, layer_stack, position_list)
|
||||
self.local_check(w)
|
||||
self.local_drc_check(w)
|
||||
|
||||
|
||||
min_space = 2 * (tech.drc["minwidth_metal2"] +
|
||||
|
|
@ -89,7 +86,7 @@ class wire_test(unittest.TestCase):
|
|||
[-1 * min_space, 0]]
|
||||
w = design.design("wire_test4")
|
||||
wire.wire(w, layer_stack, position_list)
|
||||
self.local_check(w)
|
||||
self.local_drc_check(w)
|
||||
|
||||
min_space = 2 * (tech.drc["minwidth_metal2"] +
|
||||
tech.drc["minwidth_metal3"])
|
||||
|
|
@ -106,7 +103,7 @@ class wire_test(unittest.TestCase):
|
|||
position_list.reverse()
|
||||
w = design.design("wire_test5")
|
||||
wire.wire(w, layer_stack, position_list)
|
||||
self.local_check(w)
|
||||
self.local_drc_check(w)
|
||||
|
||||
min_space = 2 * (tech.drc["minwidth_metal2"] +
|
||||
tech.drc["minwidth_metal3"])
|
||||
|
|
@ -123,18 +120,12 @@ class wire_test(unittest.TestCase):
|
|||
position_list.reverse()
|
||||
w = design.design("wire_test6")
|
||||
wire.wire(w, layer_stack, position_list)
|
||||
self.local_check(w)
|
||||
self.local_drc_check(w)
|
||||
|
||||
# return it back to it's normal state
|
||||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, w):
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
w.gds_write(tempgds)
|
||||
self.assertFalse(verify.run_drc(w.name, tempgds))
|
||||
os.remove(tempgds)
|
||||
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -4,22 +4,19 @@ Run regresion tests on a parameterized inverter
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 04_pinv_test")
|
||||
|
||||
|
||||
class pinv_test(unittest.TestCase):
|
||||
class pinv_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import pinv
|
||||
|
|
@ -32,25 +29,6 @@ class pinv_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, tx):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
tx.sp_write(tempspice)
|
||||
tx.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(tx.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# reset the static duplicate name checker for unit tests
|
||||
import design
|
||||
design.design.name_map=[]
|
||||
|
||||
|
||||
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -4,22 +4,19 @@ Run regresion tests on a parameterized inverter
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 04_pinv_test")
|
||||
|
||||
|
||||
class pinv_test(unittest.TestCase):
|
||||
class pinv_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import pinv
|
||||
|
|
@ -32,26 +29,6 @@ class pinv_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, tx):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
tx.sp_write(tempspice)
|
||||
tx.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(tx.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# reset the static duplicate name checker for unit tests
|
||||
import design
|
||||
design.design.name_map=[]
|
||||
|
||||
|
||||
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -1,26 +1,23 @@
|
|||
#!/usr/bin/env python2.7
|
||||
"""
|
||||
Run regresion tests on a parameterized inverter
|
||||
Run regression tests on a parameterized inverter
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 04_pinv_test")
|
||||
|
||||
|
||||
class pinv_test(unittest.TestCase):
|
||||
class pinv_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
|
||||
import pinv
|
||||
import tech
|
||||
|
|
@ -32,26 +29,6 @@ class pinv_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, tx):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
tx.sp_write(tempspice)
|
||||
tx.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(tx.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# reset the static duplicate name checker for unit tests
|
||||
import design
|
||||
design.design.name_map=[]
|
||||
|
||||
|
||||
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,22 +4,19 @@ Run regresion tests on a parameterized inverter
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 04_pinv_test")
|
||||
|
||||
|
||||
class pinv_test(unittest.TestCase):
|
||||
class pinv_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import pinv
|
||||
|
|
@ -32,25 +29,6 @@ class pinv_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, tx):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
tx.sp_write(tempspice)
|
||||
tx.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(tx.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# reset the static duplicate name checker for unit tests
|
||||
import design
|
||||
design.design.name_map=[]
|
||||
|
||||
|
||||
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -6,24 +6,19 @@ size 2-input nand gate.
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
import sys
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 04_pnand2_test")
|
||||
|
||||
|
||||
class pnand2_test(unittest.TestCase):
|
||||
class pnand2_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import pnand2
|
||||
|
|
@ -37,20 +32,6 @@ class pnand2_test(unittest.TestCase):
|
|||
globals.end_openram()
|
||||
|
||||
|
||||
def local_check(self, tx):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
tx.sp_write(tempspice)
|
||||
tx.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(tx.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -6,21 +6,19 @@ It generates only a minimum size 3-input nand gate.
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 04_pnand3_test")
|
||||
class pnand3_test(unittest.TestCase):
|
||||
class pnand3_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import pnand3
|
||||
|
|
@ -33,19 +31,6 @@ class pnand3_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, tx):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
tx.sp_write(tempspice)
|
||||
tx.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(tx.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -6,24 +6,19 @@ size 2-input nor gate.
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
import sys
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 04_pnor2_test")
|
||||
|
||||
|
||||
class pnor2_test(unittest.TestCase):
|
||||
class pnor2_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import pnor2
|
||||
|
|
@ -36,21 +31,6 @@ class pnor2_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
|
||||
def local_check(self, tx):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
tx.sp_write(tempspice)
|
||||
tx.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(tx.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,21 +4,19 @@ Run a regresion test on a precharge cell
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
import sys
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
class precharge_test(unittest.TestCase):
|
||||
class precharge_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import precharge
|
||||
|
|
@ -31,20 +29,6 @@ class precharge_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, tx):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
tx.sp_write(tempspice)
|
||||
tx.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(tx.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,24 +4,21 @@ Run a regresion test on a wordline_driver array
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
import sys
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 04_driver_test")
|
||||
|
||||
|
||||
class wordline_driver_test(unittest.TestCase):
|
||||
class wordline_driver_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import wordline_driver
|
||||
|
|
@ -34,20 +31,6 @@ class wordline_driver_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, tx):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
tx.sp_write(tempspice)
|
||||
tx.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(tx.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(tx.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,23 +4,21 @@ Run a regresion test on a basic array
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
#@unittest.skip("SKIPPING 05_array_test")
|
||||
|
||||
|
||||
class array_test(unittest.TestCase):
|
||||
class array_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import bitcell_array
|
||||
|
|
@ -32,21 +30,6 @@ class array_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, a):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
temppdf = OPTS.openram_temp + "temp.pdf"
|
||||
|
||||
a.sp_write(tempspice)
|
||||
a.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(a.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,20 +4,19 @@ Run a regresion test on a hierarchical_decoder.
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
|
||||
class hierarchical_decoder_test(unittest.TestCase):
|
||||
class hierarchical_decoder_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import hierarchical_decoder
|
||||
|
|
@ -33,6 +32,10 @@ class hierarchical_decoder_test(unittest.TestCase):
|
|||
# a = hierarchical_decoder.hierarchical_decoder(rows=8)
|
||||
# self.local_check(a)
|
||||
|
||||
debug.info(1, "Testing 16 row sample for hierarchical_decoder")
|
||||
a = hierarchical_decoder.hierarchical_decoder(rows=16)
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(1, "Testing 32 row sample for hierarchical_decoder")
|
||||
a = hierarchical_decoder.hierarchical_decoder(rows=32)
|
||||
self.local_check(a)
|
||||
|
|
@ -48,24 +51,6 @@ class hierarchical_decoder_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, a):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
a.sp_write(tempspice)
|
||||
a.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(a.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# reset the static duplicate name checker for unit tests
|
||||
import design
|
||||
design.design.name_map=[]
|
||||
|
||||
|
||||
# instantiate a copdsay of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,21 +4,19 @@ Run a regresion test on a hierarchical_predecode2x4.
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
|
||||
class hierarchical_predecode2x4_test(unittest.TestCase):
|
||||
class hierarchical_predecode2x4_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import hierarchical_predecode2x4 as pre
|
||||
|
|
@ -31,19 +29,6 @@ class hierarchical_predecode2x4_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, a):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
a.sp_write(tempspice)
|
||||
a.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(a.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# instantiate a copdsay of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,21 +4,19 @@ Run a regresion test on a hierarchical_predecode3x8.
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
OPTS = globals.OPTS
|
||||
|
||||
|
||||
class hierarchical_predecode3x8_test(unittest.TestCase):
|
||||
class hierarchical_predecode3x8_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import hierarchical_predecode3x8 as pre
|
||||
|
|
@ -31,19 +29,6 @@ class hierarchical_predecode3x8_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, a):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
a.sp_write(tempspice)
|
||||
a.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(a.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# instantiate a copdsay of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -3,21 +3,19 @@
|
|||
Run a regresion test on a single transistor column_mux.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test,unittest
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
|
||||
class single_level_column_mux_test(unittest.TestCase):
|
||||
class single_level_column_mux_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import single_level_column_mux_array
|
||||
|
|
@ -37,22 +35,6 @@ class single_level_column_mux_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, a):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
a.sp_write(tempspice)
|
||||
a.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(a.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# reset the static duplicate name checker for unit tests
|
||||
import design
|
||||
design.design.name_map=[]
|
||||
|
||||
# instantiate a copdsay of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -4,22 +4,19 @@ Run a regresion test on a precharge array
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
|
||||
#@unittest.skip("SKIPPING 08_precharge_test")
|
||||
|
||||
|
||||
class precharge_test(unittest.TestCase):
|
||||
class precharge_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import precharge_array
|
||||
|
|
@ -32,19 +29,6 @@ class precharge_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, pc):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
pc.sp_write(tempspice)
|
||||
pc.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(pc.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(pc.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -4,21 +4,19 @@ Run a regresion test on a sense amp array
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
#@unittest.skip("SKIPPING 09_sense_amp_test")
|
||||
|
||||
|
||||
class sense_amp_test(unittest.TestCase):
|
||||
class sense_amp_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import sense_amp_array
|
||||
|
|
@ -35,24 +33,6 @@ class sense_amp_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, a):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
a.sp_write(tempspice)
|
||||
a.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(a.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# reset the static duplicate name checker for unit tests
|
||||
import design
|
||||
design.design.name_map=[]
|
||||
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,21 +4,19 @@ Run a regresion test on a write driver array
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
#@unittest.skip("SKIPPING 10_write_driver_test")
|
||||
|
||||
|
||||
class write_driver_test(unittest.TestCase):
|
||||
class write_driver_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import write_driver_array
|
||||
|
|
@ -34,24 +32,6 @@ class write_driver_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, a):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
a.sp_write(tempspice)
|
||||
a.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(a.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# reset the static duplicate name checker for unit tests
|
||||
import design
|
||||
design.design.name_map=[]
|
||||
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,22 +4,19 @@ Run a regresion test on a dff_array.
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
import importlib
|
||||
|
||||
#@unittest.skip("SKIPPING 20_sram_test")
|
||||
|
||||
|
||||
class dff_array_test(unittest.TestCase):
|
||||
class dff_array_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import ms_flop_array
|
||||
|
|
@ -35,25 +32,6 @@ class dff_array_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, a):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
a.sp_write(tempspice)
|
||||
a.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(a.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# reset the static duplicate name checker for unit tests
|
||||
import design
|
||||
design.design.name_map=[]
|
||||
|
||||
|
||||
|
||||
# instantiate a copdsay of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,20 +4,19 @@ Run a regresion test on a tri_gate_array.
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
|
||||
class tri_gate_array_test(unittest.TestCase):
|
||||
class tri_gate_array_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import tri_gate_array
|
||||
|
|
@ -33,24 +32,6 @@ class tri_gate_array_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, a):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
a.sp_write(tempspice)
|
||||
a.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(a.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# reset the static duplicate name checker for unit tests
|
||||
import design
|
||||
design.design.name_map=[]
|
||||
|
||||
|
||||
# instantiate a copdsay of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,20 +4,19 @@ Run a test on a delay chain
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
#@unittest.skip("SKIPPING 14_delay_chain_test")
|
||||
class delay_chain_test(unittest.TestCase):
|
||||
class delay_chain_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import delay_chain
|
||||
|
|
@ -29,19 +28,6 @@ class delay_chain_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, a):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
a.sp_write(tempspice)
|
||||
a.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(a.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,23 +4,19 @@ Run a test on a delay chain
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
import importlib
|
||||
|
||||
#@unittest.skip("SKIPPING 14_delay_chain_test")
|
||||
|
||||
|
||||
class replica_bitline_test(unittest.TestCase):
|
||||
class replica_bitline_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import replica_bitline
|
||||
|
|
@ -32,19 +28,6 @@ class replica_bitline_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, a):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
a.sp_write(tempspice)
|
||||
a.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(a.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,19 +4,19 @@ Run a regresion test on a control_logic
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
class control_logic_test(unittest.TestCase):
|
||||
class control_logic_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import control_logic
|
||||
|
|
@ -29,20 +29,6 @@ class control_logic_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, a):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
a.sp_write(tempspice)
|
||||
a.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(a.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
|
||||
# instantiate a copdsay of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,19 +4,19 @@ Run a regresion test on various srams
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
class multi_bank_test(unittest.TestCase):
|
||||
class multi_bank_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import bank
|
||||
|
|
@ -41,23 +41,6 @@ class multi_bank_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, a):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
a.sp_write(tempspice)
|
||||
a.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(a.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# reset the static duplicate name checker for unit tests
|
||||
import design
|
||||
design.design.name_map=[]
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,22 +4,19 @@ Run a regresion test on various srams
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
#@unittest.skip("SKIPPING 20_sram_test")
|
||||
|
||||
|
||||
class single_bank_test(unittest.TestCase):
|
||||
class single_bank_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import bank
|
||||
|
|
@ -44,23 +41,6 @@ class single_bank_test(unittest.TestCase):
|
|||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, a):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
a.sp_write(tempspice)
|
||||
a.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(a.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# reset the static duplicate name checker for unit tests
|
||||
import design
|
||||
design.design.name_map=[]
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,59 +4,42 @@ Run a regresion test on a 1 bank SRAM
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
#@unittest.skip("SKIPPING 20_sram_test")
|
||||
|
||||
|
||||
class sram_1bank_test(unittest.TestCase):
|
||||
class sram_1bank_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import sram
|
||||
|
||||
debug.info(1, "Single bank, no column mux with control logic")
|
||||
a = sram.sram(word_size=4, num_words=16, num_banks=1, name="sram1")
|
||||
self.local_check(a)
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
debug.info(1, "Single bank two way column mux with control logic")
|
||||
a = sram.sram(word_size=4, num_words=32, num_banks=1, name="sram2")
|
||||
self.local_check(a)
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
debug.info(1, "Single bank, four way column mux with control logic")
|
||||
a = sram.sram(word_size=4, num_words=64, num_banks=1, name="sram3")
|
||||
self.local_check(a)
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
# debug.info(1, "Single bank, eight way column mux with control logic")
|
||||
# a = sram.sram(word_size=2, num_words=128, num_banks=1, name="sram4")
|
||||
# self.local_check(a)
|
||||
# self.local_check(a, final_verification=True)
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, a):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
a.sp_write(tempspice)
|
||||
a.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(a.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
|
||||
#self.assertFalse(verify.run_pex(a.name, tempgds, tempspice, output=OPTS.openram_temp+"temp_pex.sp"))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,59 +4,42 @@ Run a regresion test on a 2 bank SRAM
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
#@unittest.skip("SKIPPING 20_sram_test")
|
||||
|
||||
|
||||
class sram_2bank_test(unittest.TestCase):
|
||||
class sram_2bank_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import sram
|
||||
|
||||
debug.info(1, "Two bank, no column mux with control logic")
|
||||
a = sram.sram(word_size=16, num_words=32, num_banks=2, name="sram1")
|
||||
self.local_check(a)
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
debug.info(1, "Two bank two way column mux with control logic")
|
||||
a = sram.sram(word_size=16, num_words=64, num_banks=2, name="sram2")
|
||||
self.local_check(a)
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
debug.info(1, "Two bank, four way column mux with control logic")
|
||||
a = sram.sram(word_size=16, num_words=128, num_banks=2, name="sram3")
|
||||
self.local_check(a)
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
# debug.info(1, "Two bank, eight way column mux with control logic")
|
||||
# a = sram.sram(word_size=2, num_words=256 num_banks=2, name="sram4")
|
||||
# self.local_check(a)
|
||||
# self.local_check(a, final_verification=True)
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, a):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
a.sp_write(tempspice)
|
||||
a.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(a.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
|
||||
#self.assertFalse(verify.run_pex(a.name, tempgds, tempspice, output=OPTS.openram_temp+"temp_pex.sp"))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,59 +4,42 @@ Run a regresion test on a 4 bank SRAM
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
#@unittest.skip("SKIPPING 20_sram_test")
|
||||
|
||||
|
||||
class sram_4bank_test(unittest.TestCase):
|
||||
class sram_4bank_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
global verify
|
||||
import verify
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import sram
|
||||
|
||||
debug.info(1, "Four bank, no column mux with control logic")
|
||||
a = sram.sram(word_size=16, num_words=64, num_banks=4, name="sram1")
|
||||
self.local_check(a)
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
debug.info(1, "Four bank two way column mux with control logic")
|
||||
a = sram.sram(word_size=16, num_words=128, num_banks=4, name="sram2")
|
||||
self.local_check(a)
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
debug.info(1, "Four bank, four way column mux with control logic")
|
||||
a = sram.sram(word_size=16, num_words=256, num_banks=4, name="sram3")
|
||||
self.local_check(a)
|
||||
self.local_check(a, final_verification=True)
|
||||
|
||||
# debug.info(1, "Four bank, eight way column mux with control logic")
|
||||
# a = sram.sram(word_size=2, num_words=256, num_banks=4, name="sram4")
|
||||
# self.local_check(a)
|
||||
# self.local_check(a, final_verification=True)
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
globals.end_openram()
|
||||
|
||||
def local_check(self, a):
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
|
||||
a.sp_write(tempspice)
|
||||
a.gds_write(tempgds)
|
||||
|
||||
self.assertFalse(verify.run_drc(a.name, tempgds))
|
||||
self.assertFalse(verify.run_lvs(a.name, tempgds, tempspice))
|
||||
#self.assertFalse(verify.run_pex(a.name, tempgds, tempspice, output=OPTS.openram_temp+"temp_pex.sp"))
|
||||
|
||||
os.remove(tempspice)
|
||||
os.remove(tempgds)
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
|
|||
|
|
@ -4,36 +4,34 @@ Run a regresion test on various srams
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header,isclose
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
#@unittest.skip("SKIPPING 21_timing_sram_test")
|
||||
|
||||
|
||||
class timing_sram_test(unittest.TestCase):
|
||||
class timing_sram_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
OPTS.check_lvsdrc = False
|
||||
OPTS.spice_name="hspice"
|
||||
OPTS.analytical_delay = False
|
||||
|
||||
# This is a hack to reload the characterizer __init__ with the spice version
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import delay
|
||||
if not OPTS.spice_exe:
|
||||
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
|
||||
|
||||
import sram
|
||||
|
||||
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
|
||||
s = sram.sram(word_size=OPTS.config.word_size,
|
||||
num_words=OPTS.config.num_words,
|
||||
num_banks=OPTS.config.num_banks,
|
||||
s = sram.sram(word_size=OPTS.word_size,
|
||||
num_words=OPTS.num_words,
|
||||
num_banks=OPTS.num_banks,
|
||||
name="sram1")
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
|
|
@ -51,25 +49,25 @@ class timing_sram_test(unittest.TestCase):
|
|||
slews = [tech.spice["rise_time"]*2]
|
||||
data = d.analyze(probe_address, probe_data,slews,loads)
|
||||
if OPTS.tech_name == "freepdk45":
|
||||
golden_data = {'read1_power': 0.0296933,
|
||||
'read0_power': 0.029897899999999998,
|
||||
'write0_power': 0.0258029,
|
||||
'delay1': [0.049100700000000004],
|
||||
'delay0': [0.13766139999999996],
|
||||
'min_period': 0.322,
|
||||
'write1_power': 0.0260398,
|
||||
'slew0': [0.0265264],
|
||||
'slew1': [0.0195507]}
|
||||
golden_data = {'read1_power': 0.0339194,
|
||||
'read0_power': 0.0340617,
|
||||
'write0_power': 0.0287779,
|
||||
'delay1': [0.0575725],
|
||||
'delay0': [0.16744839999999997],
|
||||
'min_period': 0.391,
|
||||
'write1_power': 0.0299736,
|
||||
'slew0': [0.026416],
|
||||
'slew1': [0.020441199999999996]}
|
||||
elif OPTS.tech_name == "scn3me_subm":
|
||||
golden_data = {'read1_power': 4.3678,
|
||||
'read0_power': 4.3914,
|
||||
'write0_power': 2.9394,
|
||||
'delay1': [0.8901521],
|
||||
'delay0': [2.001],
|
||||
'min_period': 5.781,
|
||||
'write1_power': 2.7163,
|
||||
'slew0': [1.3044000000000002],
|
||||
'slew1': [0.9904079]}
|
||||
golden_data = {'read1_power': 5.557800000000001,
|
||||
'read0_power': 5.5712,
|
||||
'write0_power': 3.8325,
|
||||
'delay1': [1.0323],
|
||||
'delay0': [2.2134],
|
||||
'min_period': 6.25,
|
||||
'write1_power': 3.6903,
|
||||
'slew0': [1.3009000000000002],
|
||||
'slew1': [0.983561]}
|
||||
else:
|
||||
self.assertTrue(False) # other techs fail
|
||||
# Check if no too many or too few results
|
||||
|
|
@ -78,9 +76,9 @@ class timing_sram_test(unittest.TestCase):
|
|||
for k in data.keys():
|
||||
if type(data[k])==list:
|
||||
for i in range(len(data[k])):
|
||||
self.assertTrue(isclose(data[k][i],golden_data[k][i],0.15))
|
||||
self.isclose(data[k][i],golden_data[k][i],0.15)
|
||||
else:
|
||||
self.assertTrue(isclose(data[k],golden_data[k],0.15))
|
||||
self.isclose(data[k],golden_data[k],0.15)
|
||||
|
||||
|
||||
# reset these options
|
||||
|
|
|
|||
|
|
@ -4,29 +4,28 @@ Run a regresion test on various srams
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header,isclose
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
#@unittest.skip("SKIPPING 21_timing_sram_test")
|
||||
|
||||
|
||||
class timing_setup_test(unittest.TestCase):
|
||||
class timing_setup_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
|
||||
# we will manually run lvs/drc
|
||||
OPTS.check_lvsdrc = False
|
||||
OPTS.spice_name="hspice"
|
||||
OPTS.analytical_delay = False
|
||||
|
||||
# This is a hack to reload the characterizer __init__ with the spice version
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import setup_hold
|
||||
if not OPTS.spice_exe:
|
||||
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
|
||||
|
||||
|
||||
import sram
|
||||
import tech
|
||||
|
|
@ -54,9 +53,9 @@ class timing_setup_test(unittest.TestCase):
|
|||
for k in data.keys():
|
||||
if type(data[k])==list:
|
||||
for i in range(len(data[k])):
|
||||
self.assertTrue(isclose(data[k][i],golden_data[k][i],0.15))
|
||||
self.isclose(data[k][i],golden_data[k][i],0.15)
|
||||
else:
|
||||
self.assertTrue(isclose(data[k],golden_data[k],0.15))
|
||||
self.isclose(data[k],golden_data[k],0.15)
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
OPTS.analytical_delay = True
|
||||
|
|
|
|||
|
|
@ -4,34 +4,34 @@ Run a regresion test on various srams
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header,isclose
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
#@unittest.skip("SKIPPING 21_ngspice_delay_test")
|
||||
class timing_sram_test(unittest.TestCase):
|
||||
class timing_sram_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
OPTS.check_lvsdrc = False
|
||||
OPTS.spice_name="ngspice"
|
||||
OPTS.analytical_delay = False
|
||||
|
||||
# This is a hack to reload the characterizer __init__ with the spice version
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import delay
|
||||
if not OPTS.spice_exe:
|
||||
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
|
||||
|
||||
import sram
|
||||
|
||||
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
|
||||
s = sram.sram(word_size=OPTS.config.word_size,
|
||||
num_words=OPTS.config.num_words,
|
||||
num_banks=OPTS.config.num_banks,
|
||||
s = sram.sram(word_size=OPTS.word_size,
|
||||
num_words=OPTS.num_words,
|
||||
num_banks=OPTS.num_banks,
|
||||
name="sram1")
|
||||
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
|
|
@ -47,25 +47,25 @@ class timing_sram_test(unittest.TestCase):
|
|||
slews = [tech.spice["rise_time"]*2]
|
||||
data = d.analyze(probe_address, probe_data,slews,loads)
|
||||
if OPTS.tech_name == "freepdk45":
|
||||
golden_data = {'read1_power': 0.026660760000000002,
|
||||
'read0_power': 0.02711731,
|
||||
'write0_power': 0.02501428,
|
||||
'delay1': [0.04867702],
|
||||
'delay0': [0.1423633],
|
||||
'min_period': 0.332,
|
||||
'write1_power': 0.024162890000000003,
|
||||
'slew0': [0.02733451],
|
||||
'slew1': [0.02121624]}
|
||||
golden_data = {'read1_power': 0.03228762,
|
||||
'read0_power': 0.03281849,
|
||||
'write0_power': 0.02902607,
|
||||
'delay1': [0.059081419999999996],
|
||||
'delay0': [0.1716648],
|
||||
'min_period': 0.391,
|
||||
'write1_power': 0.02879424,
|
||||
'slew0': [0.02851539],
|
||||
'slew1': [0.02319674]}
|
||||
elif OPTS.tech_name == "scn3me_subm":
|
||||
golden_data = {'read1_power': 4.250786000000001,
|
||||
'read0_power': 4.093461,
|
||||
'write0_power': 2.762675,
|
||||
'delay1': [0.920068],
|
||||
'delay0': [2.051821],
|
||||
golden_data = {'read1_power': 5.063901,
|
||||
'read0_power': 4.926464999999999,
|
||||
'write0_power': 3.480712,
|
||||
'delay1': [1.044746],
|
||||
'delay0': [2.23024],
|
||||
'min_period': 6.563,
|
||||
'write1_power': 2.4545719999999998,
|
||||
'slew0': [1.342015],
|
||||
'slew1': [1.040868]}
|
||||
'write1_power': 3.1949449999999997,
|
||||
'slew0': [1.3469],
|
||||
'slew1': [1.035352]}
|
||||
else:
|
||||
self.assertTrue(False) # other techs fail
|
||||
|
||||
|
|
@ -75,9 +75,9 @@ class timing_sram_test(unittest.TestCase):
|
|||
for k in data.keys():
|
||||
if type(data[k])==list:
|
||||
for i in range(len(data[k])):
|
||||
self.assertTrue(isclose(data[k][i],golden_data[k][i],0.15))
|
||||
self.isclose(data[k][i],golden_data[k][i],0.15)
|
||||
else:
|
||||
self.assertTrue(isclose(data[k],golden_data[k],0.15))
|
||||
self.isclose(data[k],golden_data[k],0.15)
|
||||
|
||||
# reset these options
|
||||
OPTS.check_lvsdrc = True
|
||||
|
|
|
|||
|
|
@ -4,30 +4,27 @@ Run a regresion test on various srams
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header,isclose
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
#@unittest.skip("SKIPPING 21_timing_sram_test")
|
||||
|
||||
|
||||
class timing_setup_test(unittest.TestCase):
|
||||
class timing_setup_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
|
||||
# we will manually run lvs/drc
|
||||
OPTS.check_lvsdrc = False
|
||||
OPTS.spice_name="ngspice"
|
||||
OPTS.analytical_delay = False
|
||||
|
||||
# This is a hack to reload the characterizer __init__ with the spice version
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import setup_hold
|
||||
if not OPTS.spice_exe:
|
||||
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
|
||||
|
||||
import sram
|
||||
import tech
|
||||
|
|
@ -55,9 +52,9 @@ class timing_setup_test(unittest.TestCase):
|
|||
for k in data.keys():
|
||||
if type(data[k])==list:
|
||||
for i in range(len(data[k])):
|
||||
self.assertTrue(isclose(data[k][i],golden_data[k][i],0.15))
|
||||
self.isclose(data[k][i],golden_data[k][i],0.15)
|
||||
else:
|
||||
self.assertTrue(isclose(data[k],golden_data[k],0.15))
|
||||
self.isclose(data[k],golden_data[k],0.15)
|
||||
|
||||
# reset these options
|
||||
OPTS.check_lvsdrc = True
|
||||
|
|
|
|||
|
|
@ -4,20 +4,20 @@ Run a regression test on an extracted SRAM to ensure functionality.
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
|
||||
@unittest.skip("SKIPPING 22_sram_func_test")
|
||||
class sram_func_test(unittest.TestCase):
|
||||
class sram_func_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
global verify
|
||||
import verify
|
||||
|
||||
self.func_test(bank_num=1)
|
||||
self.func_test(bank_num=2)
|
||||
|
|
@ -33,9 +33,9 @@ class sram_func_test(unittest.TestCase):
|
|||
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
|
||||
OPTS.check_lvsdrc = False
|
||||
OPTS.use_pex = True
|
||||
s = sram.sram(word_size=OPTS.config.word_size,
|
||||
num_words=OPTS.config.num_words,
|
||||
num_banks=OPTS.config.num_banks,
|
||||
s = sram.sram(word_size=OPTS.word_size,
|
||||
num_words=OPTS.num_words,
|
||||
num_banks=OPTS.num_banks,
|
||||
name="test_sram1")
|
||||
OPTS.check_lvsdrc = True
|
||||
OPTS.use_pex = False
|
||||
|
|
|
|||
|
|
@ -4,36 +4,34 @@ Run a regresion test on various srams
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
#@unittest.skip("SKIPPING 21_timing_sram_test")
|
||||
|
||||
|
||||
class sram_func_test(unittest.TestCase):
|
||||
class sram_func_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
|
||||
# we will manually run lvs/drc
|
||||
OPTS.check_lvsdrc = False
|
||||
OPTS.spice_name="hspice"
|
||||
OPTS.spice_name="" # Unset to use any simulator
|
||||
OPTS.analytical_delay = False
|
||||
|
||||
# This is a hack to reload the characterizer __init__ with the spice version
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import delay
|
||||
if not OPTS.spice_exe:
|
||||
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
|
||||
|
||||
import sram
|
||||
|
||||
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
|
||||
s = sram.sram(word_size=OPTS.config.word_size,
|
||||
num_words=OPTS.config.num_words,
|
||||
num_banks=OPTS.config.num_banks,
|
||||
s = sram.sram(word_size=OPTS.word_size,
|
||||
num_words=OPTS.num_words,
|
||||
num_banks=OPTS.num_banks,
|
||||
name="sram_func_test")
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
|
|
|
|||
|
|
@ -4,19 +4,17 @@ Check the .lib file for an SRAM
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header,isapproxdiff
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
class lib_test(unittest.TestCase):
|
||||
class lib_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
import sram
|
||||
|
|
@ -24,8 +22,8 @@ class lib_test(unittest.TestCase):
|
|||
|
||||
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank")
|
||||
s = sram.sram(word_size=2,
|
||||
num_words=OPTS.config.num_words,
|
||||
num_banks=OPTS.config.num_banks,
|
||||
num_words=OPTS.num_words,
|
||||
num_banks=OPTS.num_banks,
|
||||
name="sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
OPTS.check_lvsdrc = True
|
||||
|
||||
|
|
@ -38,7 +36,7 @@ class lib_test(unittest.TestCase):
|
|||
|
||||
# let's diff the result with a golden model
|
||||
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
|
||||
self.assertEqual(isapproxdiff(libname,golden,0.15),True)
|
||||
self.isapproxdiff(libname,golden,0.15)
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
|
|
|
|||
|
|
@ -4,32 +4,35 @@ Check the .lib file for an SRAM with pruning
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header,isapproxdiff
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
class lib_test(unittest.TestCase):
|
||||
class lib_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
OPTS.check_lvsdrc = False
|
||||
OPTS.spice_name="hspice"
|
||||
OPTS.spice_name="" # Unset to use any simulator
|
||||
OPTS.analytical_delay = False
|
||||
OPTS.trim_netlist = True
|
||||
|
||||
# This is a hack to reload the characterizer __init__ with the spice version
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import lib
|
||||
if not OPTS.spice_exe:
|
||||
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
|
||||
|
||||
import sram
|
||||
|
||||
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank")
|
||||
s = sram.sram(word_size=2,
|
||||
num_words=OPTS.config.num_words,
|
||||
num_banks=OPTS.config.num_banks,
|
||||
num_words=OPTS.num_words,
|
||||
num_banks=OPTS.num_banks,
|
||||
name="sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
OPTS.check_lvsdrc = True
|
||||
|
||||
|
|
@ -42,7 +45,7 @@ class lib_test(unittest.TestCase):
|
|||
|
||||
# let's diff the result with a golden model
|
||||
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
|
||||
self.assertEqual(isapproxdiff(libname,golden,0.30),True)
|
||||
self.isapproxdiff(libname,golden,0.30)
|
||||
|
||||
OPTS.analytical_delay = True
|
||||
reload(characterizer)
|
||||
|
|
|
|||
|
|
@ -4,32 +4,35 @@ Check the .lib file for an SRAM
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header,isapproxdiff
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
class lib_test(unittest.TestCase):
|
||||
class lib_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
# we will manually run lvs/drc
|
||||
OPTS.check_lvsdrc = False
|
||||
OPTS.spice_name="" # Unset to use any simulator
|
||||
OPTS.analytical_delay = False
|
||||
OPTS.trim_netlist = False
|
||||
|
||||
# This is a hack to reload the characterizer __init__ with the spice version
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import lib
|
||||
if not OPTS.spice_exe:
|
||||
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
|
||||
|
||||
import sram
|
||||
|
||||
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank")
|
||||
s = sram.sram(word_size=2,
|
||||
num_words=OPTS.config.num_words,
|
||||
num_banks=OPTS.config.num_banks,
|
||||
num_words=OPTS.num_words,
|
||||
num_banks=OPTS.num_banks,
|
||||
name="sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
OPTS.check_lvsdrc = True
|
||||
|
||||
|
|
@ -42,7 +45,7 @@ class lib_test(unittest.TestCase):
|
|||
|
||||
# let's diff the result with a golden model
|
||||
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
|
||||
self.assertEqual(isapproxdiff(libname,golden,0.15),True)
|
||||
self.isapproxdiff(libname,golden,0.15)
|
||||
|
||||
OPTS.analytical_delay = True
|
||||
OPTS.trim_netlist = True
|
||||
|
|
|
|||
|
|
@ -4,16 +4,14 @@ Check the LEF file for an SRMA
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header,isdiff
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
|
||||
class lef_test(unittest.TestCase):
|
||||
class lef_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
|
|
@ -24,8 +22,8 @@ class lef_test(unittest.TestCase):
|
|||
|
||||
debug.info(1, "Testing LEF for sample 2 bit, 16 words SRAM with 1 bank")
|
||||
s = sram.sram(word_size=2,
|
||||
num_words=OPTS.config.num_words,
|
||||
num_banks=OPTS.config.num_banks,
|
||||
num_words=OPTS.num_words,
|
||||
num_banks=OPTS.num_banks,
|
||||
name="sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
|
|
@ -39,7 +37,7 @@ class lef_test(unittest.TestCase):
|
|||
|
||||
# let's diff the result with a golden model
|
||||
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),leffile)
|
||||
self.assertEqual(isdiff(lefname,golden),True)
|
||||
self.isdiff(lefname,golden)
|
||||
|
||||
os.system("rm {0}".format(gdsname))
|
||||
os.system("rm {0}".format(lefname))
|
||||
|
|
|
|||
|
|
@ -4,16 +4,14 @@ Check the .v file for an SRAM
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header,isdiff
|
||||
from testutils import header,openram_test
|
||||
import sys,os
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import verify
|
||||
|
||||
|
||||
class verilog_test(unittest.TestCase):
|
||||
class verilog_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
|
|
@ -24,8 +22,8 @@ class verilog_test(unittest.TestCase):
|
|||
|
||||
debug.info(1, "Testing Verilog for sample 2 bit, 16 words SRAM with 1 bank")
|
||||
s = sram.sram(word_size=2,
|
||||
num_words=OPTS.config.num_words,
|
||||
num_banks=OPTS.config.num_banks,
|
||||
num_words=OPTS.num_words,
|
||||
num_banks=OPTS.num_banks,
|
||||
name="sram_2_16_1_{0}".format(OPTS.tech_name))
|
||||
|
||||
OPTS.check_lvsdrc = True
|
||||
|
|
@ -37,7 +35,7 @@ class verilog_test(unittest.TestCase):
|
|||
|
||||
# let's diff the result with a golden model
|
||||
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),vfile)
|
||||
self.assertEqual(isdiff(vname,golden),True)
|
||||
self.isdiff(vname,golden)
|
||||
|
||||
os.system("rm {0}".format(vname))
|
||||
|
||||
|
|
|
|||
|
|
@ -6,25 +6,22 @@ check that these files are right.
|
|||
"""
|
||||
|
||||
import unittest
|
||||
from testutils import header
|
||||
import sys,os
|
||||
from testutils import header,openram_test
|
||||
import sys,os,re,shutil
|
||||
sys.path.append(os.path.join(sys.path[0],".."))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
import debug
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
|
||||
class openram_test(unittest.TestCase):
|
||||
class openram_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||
|
||||
|
||||
debug.info(1, "Testing top-level openram.py with 2-bit, 16 word SRAM.")
|
||||
out_file = "testsram"
|
||||
# make a temp directory for output
|
||||
out_path = OPTS.openram_temp + out_file
|
||||
out_path = "/tmp/testsram"
|
||||
|
||||
# make sure we start without the files existing
|
||||
if os.path.exists(out_path):
|
||||
|
|
@ -70,7 +67,10 @@ class openram_test(unittest.TestCase):
|
|||
shutil.rmtree(out_path, ignore_errors=True)
|
||||
self.assertEqual(os.path.exists(out_path),False)
|
||||
|
||||
globals.end_openram()
|
||||
# The default was on, so disable it.
|
||||
OPTS.check_lvsdrc=False
|
||||
globals.end_openram()
|
||||
OPTS.check_lvsdrc=True
|
||||
|
||||
# instantiate a copy of the class to actually run the test
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -4,25 +4,4 @@ num_banks = 1
|
|||
|
||||
tech_name = "freepdk45"
|
||||
|
||||
# Optional, will be over-ridden on command line.
|
||||
output_path = "/tmp/freepdk45_sram"
|
||||
output_name = "sram_2_16_1_freepdk45"
|
||||
|
||||
decoder = "hierarchical_decoder"
|
||||
ms_flop = "ms_flop"
|
||||
ms_flop_array = "ms_flop_array"
|
||||
control_logic = "control_logic"
|
||||
bitcell_array = "bitcell_array"
|
||||
sense_amp = "sense_amp"
|
||||
sense_amp_array = "sense_amp_array"
|
||||
precharge_array = "precharge_array"
|
||||
column_mux_array = "single_level_column_mux_array"
|
||||
write_driver = "write_driver"
|
||||
write_driver_array = "write_driver_array"
|
||||
tri_gate = "tri_gate"
|
||||
tri_gate_array = "tri_gate_array"
|
||||
wordline_driver = "wordline_driver"
|
||||
replica_bitline = "replica_bitline"
|
||||
replica_bitcell = "replica_bitcell"
|
||||
bitcell = "bitcell"
|
||||
delay_chain = "delay_chain"
|
||||
|
|
|
|||
|
|
@ -4,25 +4,3 @@ num_banks = 1
|
|||
|
||||
tech_name = "scn3me_subm"
|
||||
|
||||
# Optional, will be over-ridden on command line.
|
||||
output_path = "/tmp/scn3me_subm_mysram"
|
||||
output_name = "sram_2_16_1_scn3me_subm"
|
||||
|
||||
decoder = "hierarchical_decoder"
|
||||
ms_flop = "ms_flop"
|
||||
ms_flop_array = "ms_flop_array"
|
||||
control_logic = "control_logic"
|
||||
bitcell_array = "bitcell_array"
|
||||
sense_amp = "sense_amp"
|
||||
sense_amp_array = "sense_amp_array"
|
||||
precharge_array = "precharge_array"
|
||||
column_mux_array = "single_level_column_mux_array"
|
||||
write_driver = "write_driver"
|
||||
write_driver_array = "write_driver_array"
|
||||
tri_gate = "tri_gate"
|
||||
tri_gate_array = "tri_gate_array"
|
||||
wordline_driver = "wordline_driver"
|
||||
replica_bitline = "replica_bitline"
|
||||
replica_bitcell = "replica_bitcell"
|
||||
bitcell = "bitcell"
|
||||
delay_chain = "delay_chain"
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -74,7 +74,7 @@ cell (sram_2_16_1_freepdk45){
|
|||
dont_use : true;
|
||||
map_only : true;
|
||||
dont_touch : true;
|
||||
area : 0.023625;
|
||||
area : 918.5120625;
|
||||
|
||||
bus(DATA){
|
||||
bus_type : DATA;
|
||||
|
|
@ -92,19 +92,19 @@ cell (sram_2_16_1_freepdk45){
|
|||
internal_power(){
|
||||
when : "OEb & !clk";
|
||||
rise_power(scalar){
|
||||
values("0.027781");
|
||||
values("0.032264359");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("0.026752");
|
||||
values("0.033266382");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027");
|
||||
values("0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.015",\
|
||||
|
|
@ -129,10 +129,10 @@ cell (sram_2_16_1_freepdk45){
|
|||
internal_power(){
|
||||
when : "!OEb & !clk";
|
||||
rise_power(scalar){
|
||||
values("0.031198");
|
||||
values("0.039765915");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("0.031252");
|
||||
values("0.039839075");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
|
|
@ -140,24 +140,24 @@ cell (sram_2_16_1_freepdk45){
|
|||
related_pin : "clk";
|
||||
timing_type : falling_edge;
|
||||
cell_rise(CELL_TABLE) {
|
||||
values("0.046, 0.047, 0.054",\
|
||||
"0.047, 0.047, 0.054",\
|
||||
"0.052, 0.052, 0.059");
|
||||
values("0.055, 0.056, 0.064",\
|
||||
"0.056, 0.057, 0.064",\
|
||||
"0.061, 0.062, 0.07");
|
||||
}
|
||||
cell_fall(CELL_TABLE) {
|
||||
values("0.132, 0.133, 0.142",\
|
||||
"0.133, 0.134, 0.142",\
|
||||
"0.138, 0.139, 0.147");
|
||||
values("0.17, 0.171, 0.179",\
|
||||
"0.171, 0.172, 0.18",\
|
||||
"0.176, 0.177, 0.185");
|
||||
}
|
||||
rise_transition(CELL_TABLE) {
|
||||
values("0.014, 0.015, 0.027",\
|
||||
"0.014, 0.015, 0.027",\
|
||||
"0.014, 0.015, 0.027");
|
||||
values("0.015, 0.016, 0.028",\
|
||||
"0.015, 0.016, 0.028",\
|
||||
"0.015, 0.016, 0.028");
|
||||
}
|
||||
fall_transition(CELL_TABLE) {
|
||||
values("0.018, 0.02, 0.036",\
|
||||
"0.019, 0.02, 0.036",\
|
||||
"0.019, 0.02, 0.036");
|
||||
values("0.019, 0.02, 0.035",\
|
||||
"0.019, 0.02, 0.035",\
|
||||
"0.019, 0.02, 0.035");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -174,9 +174,9 @@ cell (sram_2_16_1_freepdk45){
|
|||
timing_type : setup_rising;
|
||||
related_pin : "clk";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027");
|
||||
values("0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.015",\
|
||||
|
|
@ -208,9 +208,9 @@ cell (sram_2_16_1_freepdk45){
|
|||
timing_type : setup_rising;
|
||||
related_pin : "clk";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027");
|
||||
values("0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.015",\
|
||||
|
|
@ -241,9 +241,9 @@ cell (sram_2_16_1_freepdk45){
|
|||
timing_type : setup_rising;
|
||||
related_pin : "clk";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027");
|
||||
values("0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.015",\
|
||||
|
|
@ -274,9 +274,9 @@ cell (sram_2_16_1_freepdk45){
|
|||
timing_type : setup_rising;
|
||||
related_pin : "clk";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027");
|
||||
values("0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.015",\
|
||||
|
|
@ -308,20 +308,20 @@ cell (sram_2_16_1_freepdk45){
|
|||
timing_type :"min_pulse_width";
|
||||
related_pin : clk;
|
||||
rise_constraint(scalar) {
|
||||
values("0.1955");
|
||||
values("0.2345");
|
||||
}
|
||||
fall_constraint(scalar) {
|
||||
values("0.1955");
|
||||
values("0.2345");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type :"minimum_period";
|
||||
related_pin : clk;
|
||||
rise_constraint(scalar) {
|
||||
values("0.391");
|
||||
values("0.469");
|
||||
}
|
||||
fall_constraint(scalar) {
|
||||
values("0.391");
|
||||
values("0.469");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ cell (sram_2_16_1_freepdk45){
|
|||
dont_use : true;
|
||||
map_only : true;
|
||||
dont_touch : true;
|
||||
area : 0.023625;
|
||||
area : 918.5120625;
|
||||
|
||||
bus(DATA){
|
||||
bus_type : DATA;
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ cell (sram_2_16_1_freepdk45){
|
|||
dont_use : true;
|
||||
map_only : true;
|
||||
dont_touch : true;
|
||||
area : 0.023625;
|
||||
area : 918.5120625;
|
||||
|
||||
bus(DATA){
|
||||
bus_type : DATA;
|
||||
|
|
@ -92,19 +92,19 @@ cell (sram_2_16_1_freepdk45){
|
|||
internal_power(){
|
||||
when : "OEb & !clk";
|
||||
rise_power(scalar){
|
||||
values("0.027781");
|
||||
values("0.043273977");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("0.026752");
|
||||
values("0.042322667");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type : setup_rising;
|
||||
related_pin : "clk";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027");
|
||||
values("0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.015",\
|
||||
|
|
@ -129,10 +129,10 @@ cell (sram_2_16_1_freepdk45){
|
|||
internal_power(){
|
||||
when : "!OEb & !clk";
|
||||
rise_power(scalar){
|
||||
values("0.031198");
|
||||
values("0.088241812");
|
||||
}
|
||||
fall_power(scalar){
|
||||
values("0.031252");
|
||||
values("0.088188668");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
|
|
@ -140,24 +140,24 @@ cell (sram_2_16_1_freepdk45){
|
|||
related_pin : "clk";
|
||||
timing_type : falling_edge;
|
||||
cell_rise(CELL_TABLE) {
|
||||
values("0.046, 0.047, 0.054",\
|
||||
"0.047, 0.047, 0.054",\
|
||||
"0.052, 0.052, 0.059");
|
||||
values("0.055, 0.055, 0.063",\
|
||||
"0.055, 0.056, 0.063",\
|
||||
"0.061, 0.062, 0.069");
|
||||
}
|
||||
cell_fall(CELL_TABLE) {
|
||||
values("0.132, 0.133, 0.142",\
|
||||
"0.133, 0.134, 0.142",\
|
||||
"0.138, 0.139, 0.147");
|
||||
values("0.162, 0.163, 0.171",\
|
||||
"0.163, 0.164, 0.172",\
|
||||
"0.168, 0.169, 0.178");
|
||||
}
|
||||
rise_transition(CELL_TABLE) {
|
||||
values("0.014, 0.015, 0.027",\
|
||||
"0.014, 0.015, 0.027",\
|
||||
"0.014, 0.015, 0.027");
|
||||
values("0.015, 0.016, 0.028",\
|
||||
"0.015, 0.016, 0.028",\
|
||||
"0.015, 0.016, 0.028");
|
||||
}
|
||||
fall_transition(CELL_TABLE) {
|
||||
values("0.018, 0.02, 0.036",\
|
||||
"0.019, 0.02, 0.036",\
|
||||
"0.019, 0.02, 0.036");
|
||||
values("0.018, 0.02, 0.035",\
|
||||
"0.018, 0.02, 0.035",\
|
||||
"0.018, 0.02, 0.035");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -174,9 +174,9 @@ cell (sram_2_16_1_freepdk45){
|
|||
timing_type : setup_rising;
|
||||
related_pin : "clk";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027");
|
||||
values("0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.015",\
|
||||
|
|
@ -208,9 +208,9 @@ cell (sram_2_16_1_freepdk45){
|
|||
timing_type : setup_rising;
|
||||
related_pin : "clk";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027");
|
||||
values("0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.015",\
|
||||
|
|
@ -241,9 +241,9 @@ cell (sram_2_16_1_freepdk45){
|
|||
timing_type : setup_rising;
|
||||
related_pin : "clk";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027");
|
||||
values("0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.015",\
|
||||
|
|
@ -274,9 +274,9 @@ cell (sram_2_16_1_freepdk45){
|
|||
timing_type : setup_rising;
|
||||
related_pin : "clk";
|
||||
rise_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027",\
|
||||
"0.009, 0.015, 0.027");
|
||||
values("0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021",\
|
||||
"0.009, 0.015, 0.021");
|
||||
}
|
||||
fall_constraint(CONSTRAINT_TABLE) {
|
||||
values("0.009, 0.009, 0.015",\
|
||||
|
|
@ -308,20 +308,20 @@ cell (sram_2_16_1_freepdk45){
|
|||
timing_type :"min_pulse_width";
|
||||
related_pin : clk;
|
||||
rise_constraint(scalar) {
|
||||
values("0.1955");
|
||||
values("0.2245");
|
||||
}
|
||||
fall_constraint(scalar) {
|
||||
values("0.1955");
|
||||
values("0.2245");
|
||||
}
|
||||
}
|
||||
timing(){
|
||||
timing_type :"minimum_period";
|
||||
related_pin : clk;
|
||||
rise_constraint(scalar) {
|
||||
values("0.391");
|
||||
values("0.449");
|
||||
}
|
||||
fall_constraint(scalar) {
|
||||
values("0.391");
|
||||
values("0.449");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue