mirror of https://github.com/VLSIDA/OpenRAM.git
Fail simulation tests if correct spice is not found. Correctly load spice characterizer.
This commit is contained in:
parent
50107636a0
commit
369aa85cd2
|
|
@ -8,22 +8,22 @@ import setup_hold
|
||||||
|
|
||||||
debug.info(2,"Initializing characterizer...")
|
debug.info(2,"Initializing characterizer...")
|
||||||
|
|
||||||
spice_exe = ""
|
OPTS.spice_exe = ""
|
||||||
|
|
||||||
if not OPTS.analytical_delay:
|
if not OPTS.analytical_delay:
|
||||||
if OPTS.spice_name != "":
|
if OPTS.spice_name != "":
|
||||||
spice_exe=find_exe(OPTS.spice_name)
|
OPTS.spice_exe=find_exe(OPTS.spice_name)
|
||||||
if spice_exe=="":
|
if OPTS.spice_exe=="":
|
||||||
debug.error("{0} not found. Unable to perform characterization.".format(OPTS.spice_name),1)
|
debug.error("{0} not found. Unable to perform characterization.".format(OPTS.spice_name),1)
|
||||||
else:
|
else:
|
||||||
(choice,spice_exe) = get_tool("spice",["xa", "hspice", "ngspice", "ngspice.exe"])
|
(OPTS.spice_name,OPTS.spice_exe) = get_tool("spice",["xa", "hspice", "ngspice", "ngspice.exe"])
|
||||||
OPTS.spice_name = choice
|
|
||||||
|
|
||||||
# set the input dir for spice files if using ngspice
|
# set the input dir for spice files if using ngspice
|
||||||
if OPTS.spice_name == "ngspice":
|
if OPTS.spice_name == "ngspice":
|
||||||
os.environ["NGSPICE_INPUT_DIR"] = "{0}".format(OPTS.openram_temp)
|
os.environ["NGSPICE_INPUT_DIR"] = "{0}".format(OPTS.openram_temp)
|
||||||
|
|
||||||
if spice_exe == "":
|
if OPTS.spice_exe == "":
|
||||||
debug.error("No recognizable spice version found. Unable to perform characterization.",1)
|
debug.error("No recognizable spice version found. Unable to perform characterization.",1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -283,25 +283,24 @@ def run_sim():
|
||||||
import datetime
|
import datetime
|
||||||
start_time = datetime.datetime.now()
|
start_time = datetime.datetime.now()
|
||||||
|
|
||||||
from characterizer import spice_exe
|
|
||||||
if OPTS.spice_name == "xa":
|
if OPTS.spice_name == "xa":
|
||||||
# Output the xa configurations here. FIXME: Move this to write it once.
|
# Output the xa configurations here. FIXME: Move this to write it once.
|
||||||
xa_cfg = open("{}xa.cfg".format(OPTS.openram_temp), "w")
|
xa_cfg = open("{}xa.cfg".format(OPTS.openram_temp), "w")
|
||||||
xa_cfg.write("set_sim_level -level 7\n")
|
xa_cfg.write("set_sim_level -level 7\n")
|
||||||
xa_cfg.write("set_powernet_level 7 -node vdd\n")
|
xa_cfg.write("set_powernet_level 7 -node vdd\n")
|
||||||
xa_cfg.close()
|
xa_cfg.close()
|
||||||
cmd = "{0} {1} -c {2}xa.cfg -o {2}xa -mt 20".format(spice_exe,
|
cmd = "{0} {1} -c {2}xa.cfg -o {2}xa -mt 20".format(OPTS.spice_exe,
|
||||||
temp_stim,
|
temp_stim,
|
||||||
OPTS.openram_temp)
|
OPTS.openram_temp)
|
||||||
valid_retcode=0
|
valid_retcode=0
|
||||||
elif OPTS.spice_name == "hspice":
|
elif OPTS.spice_name == "hspice":
|
||||||
# TODO: Should make multithreading parameter a configuration option
|
# TODO: Should make multithreading parameter a configuration option
|
||||||
cmd = "{0} -mt 2 -i {1} -o {2}timing".format(spice_exe,
|
cmd = "{0} -mt 2 -i {1} -o {2}timing".format(OPTS.spice_exe,
|
||||||
temp_stim,
|
temp_stim,
|
||||||
OPTS.openram_temp)
|
OPTS.openram_temp)
|
||||||
valid_retcode=0
|
valid_retcode=0
|
||||||
else:
|
else:
|
||||||
cmd = "{0} -b -o {2}timing.lis {1}".format(spice_exe,
|
cmd = "{0} -b -o {2}timing.lis {1}".format(OPTS.spice_exe,
|
||||||
temp_stim,
|
temp_stim,
|
||||||
OPTS.openram_temp)
|
OPTS.openram_temp)
|
||||||
# for some reason, ngspice-25 returns 1 when it only has acceptable warnings
|
# for some reason, ngspice-25 returns 1 when it only has acceptable warnings
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
@ -18,12 +18,12 @@ class timing_sram_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = False
|
OPTS.check_lvsdrc = False
|
||||||
OPTS.spice_name="hspice"
|
OPTS.spice_name="hspice"
|
||||||
OPTS.analytical_delay = False
|
OPTS.analytical_delay = False
|
||||||
self.assertTrue(OPTS.spice_exe)
|
|
||||||
|
|
||||||
# This is a hack to reload the characterizer __init__ with the spice version
|
# This is a hack to reload the characterizer __init__ with the spice version
|
||||||
import characterizer
|
import characterizer
|
||||||
reload(characterizer)
|
reload(characterizer)
|
||||||
from characterizer import delay
|
from characterizer import delay
|
||||||
|
self.assertTrue(OPTS.spice_exe)
|
||||||
|
|
||||||
import sram
|
import sram
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,12 @@ class timing_setup_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = False
|
OPTS.check_lvsdrc = False
|
||||||
OPTS.spice_name="hspice"
|
OPTS.spice_name="hspice"
|
||||||
OPTS.analytical_delay = False
|
OPTS.analytical_delay = False
|
||||||
self.assertTrue(OPTS.spice_exe)
|
|
||||||
|
|
||||||
# This is a hack to reload the characterizer __init__ with the spice version
|
# This is a hack to reload the characterizer __init__ with the spice version
|
||||||
import characterizer
|
import characterizer
|
||||||
reload(characterizer)
|
reload(characterizer)
|
||||||
from characterizer import setup_hold
|
from characterizer import setup_hold
|
||||||
|
self.assertTrue(OPTS.spice_exe)
|
||||||
|
|
||||||
import sram
|
import sram
|
||||||
import tech
|
import tech
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,12 @@ class timing_sram_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = False
|
OPTS.check_lvsdrc = False
|
||||||
OPTS.spice_name="ngspice"
|
OPTS.spice_name="ngspice"
|
||||||
OPTS.analytical_delay = False
|
OPTS.analytical_delay = False
|
||||||
self.assertTrue(OPTS.spice_exe)
|
|
||||||
|
|
||||||
# This is a hack to reload the characterizer __init__ with the spice version
|
# This is a hack to reload the characterizer __init__ with the spice version
|
||||||
import characterizer
|
import characterizer
|
||||||
reload(characterizer)
|
reload(characterizer)
|
||||||
from characterizer import delay
|
from characterizer import delay
|
||||||
|
self.assertTrue(OPTS.spice_exe)
|
||||||
|
|
||||||
import sram
|
import sram
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,12 @@ class timing_setup_test(unittest.TestCase):
|
||||||
OPTS.check_lvsdrc = False
|
OPTS.check_lvsdrc = False
|
||||||
OPTS.spice_name="ngspice"
|
OPTS.spice_name="ngspice"
|
||||||
OPTS.analytical_delay = False
|
OPTS.analytical_delay = False
|
||||||
self.assertTrue(OPTS.spice_exe)
|
|
||||||
|
|
||||||
# This is a hack to reload the characterizer __init__ with the spice version
|
# This is a hack to reload the characterizer __init__ with the spice version
|
||||||
import characterizer
|
import characterizer
|
||||||
reload(characterizer)
|
reload(characterizer)
|
||||||
from characterizer import setup_hold
|
from characterizer import setup_hold
|
||||||
|
self.assertTrue(OPTS.spice_exe)
|
||||||
|
|
||||||
import sram
|
import sram
|
||||||
import tech
|
import tech
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
BSIM4: Berkeley Short Channel IGFET Model-4
|
||||||
|
Developed by Xuemei (Jane) Xi, Jin He, Mohan Dunga, Prof. Ali Niknejad and Prof. Chenming Hu in 2003.
|
||||||
|
|
||||||
|
++++++++++ BSIM4v4 PARAMETER CHECKING BELOW ++++++++++
|
||||||
|
Warning: This model supports BSIM4.2.1, 4.3.0 and 4.4.0; you specified a wrong version number.
|
||||||
|
Model = nmos_vtg
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
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
|
||||||
|
19_multi_bank_test.py
|
||||||
|
19_single_bank_test.py
|
||||||
Loading…
Reference in New Issue