blob: 129157f12d75911302492a89dc33e8174ebed94e [file] [log] [blame]
"""
Usage:
smoke_test.py [--num_cores=<num>]
-h, --help Show help text.
-v, --version Show version.
--num_cores=<num> Number of cores to be used by simulator
"""
import re
from docopt import docopt
import pandas as pd
import os
from jinja2 import Template
import concurrent.futures
import datetime
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
def call_simulator(file_name):
"""Call simulation commands to perform simulation.
Args:
file_name (str): Netlist file name.
"""
os.system(f"Xyce -hspice-ext all {file_name} -l {file_name}.log")
def get_sizes(models_path):
sizes = []
with open(models_path, "r") as f:
device_model = f.read()
# for j, corner in enumerate(corners):
for i in range(16):
data = device_model.split(f".MODEL nmos_3p3.{i} NMOS")
data = data[1].split("+ LEVEL=14")
dimensions = re.findall("LMAX=([0-9e.-]+)[\w+\s=.{}-]+LMIN=([0-9e.-]+)[\w+\s=.{}-]+WMAX=([0-9e.-]+)[\w+\s=.{}-]+WMIN=([0-9e.-]+)[\w+\s=.{}-]+", data[0])
sizes.append(dimensions)
return sizes
def get_results(run_path,sizes,temp,corner):
netlist_tmp = f"./inv_xyce.spice"
width = float(sizes[0][3]) * 1000000
width_p = width * 1.5
length = float(sizes[0][1]) * 1000000
# AD = width * 0.24
# AD_p = AD * 1.5
# PD = 2 * (width + 0.24)
# PD_p = width + PD
# AS = AD
# PS = PD
with open(netlist_tmp) as f:
tmpl = Template(f.read())
os.makedirs(f"{run_path}/netlists",exist_ok=True)
os.makedirs(f"{run_path}/simulation",exist_ok=True)
netlist_path = f"{run_path}/netlists/inv_W{width}_L{length}_T{temp}_{corner}.spice"
with open(netlist_path, "w") as netlist:
netlist.write(tmpl.render(corner = corner, width = width,length = length, temp = temp , run_path = run_path, width_p = width_p))#, AD = AD , PD = PD , AS = AS , PS = PS, AD_p = AD_p, PD_p = PD_p ))
# Running ngspice for each netlist
with concurrent.futures.ProcessPoolExecutor(max_workers=workers_count) as executor:
executor.submit(call_simulator, netlist_path)
# Writing simulated data
df_simulated = pd.read_csv(f"{run_path}/simulation/inv_W{width}_L{length}_T{temp}_{corner}.csv",header=0)
return [f"W{width}_L{length}_T{temp}_{corner}",df_simulated["{TPD}"].iloc[-1]]
def main():
models_path = "../../sm141064.xyce"
temps = ["25","-40","125"]
corners = ["typical","ff","ss","fs","sf"]#,"stat"]
time = f"{datetime.datetime.now()}".replace(" ", "_")
run_path = f"../run_smoke_{time}"
os.makedirs(run_path,exist_ok=True)
sizes = get_sizes(models_path)
results = []
for corner in corners:
for temp in temps:
for size in sizes:
results.append(get_results(run_path, size, temp, corner))
df_results = pd.DataFrame(results)
df_results.columns = ["run","tpd_result"]
df_results.to_csv(f"{run_path}/final_results.csv",index= False)
print (df_results)
# # ================================================================
# -------------------------- MAIN --------------------------------
# ================================================================
if __name__ == "__main__":
# Args
arguments = docopt(__doc__, version='smoke_test: 0.1')
workers_count = os.cpu_count()*2 if arguments["--num_cores"] == None else int(arguments["--num_cores"])
# Calling main function
main()