| # Copyright 2022 Efabless Corporation |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| """ |
| 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 itertools |
| import datetime |
| import warnings |
| import subprocess |
| |
| warnings.simplefilter(action='ignore', category=FutureWarning) |
| |
| def call_simulator(file_name): |
| """Call simulation commands to perform simulation. |
| Args: |
| file_name (str): Netlist file name. |
| """ |
| p = subprocess.Popen(f"ngspice -b -a {file_name} > {file_name}.log 2>&1", shell=True, executable='/bin/bash') |
| p.wait() |
| |
| def get_sizes(models_path): |
| with open(models_path, "r") as f: |
| device_model = f.read() |
| dimensions = re.findall(f"\.model nmos_3p3.*\n.*\n\+lmin.*= (.*\S).*\n.*\n\+wmin.*= (.*\S)", device_model) |
| return dimensions[0:16] |
| |
| def get_results(run_path, sizes, temp, corner): |
| netlist_tmp = f"./inv_ng.spice" |
| width = float(sizes[1]) * 1000000 |
| width_p = width * 1.5 |
| length = float(sizes[0]) * 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 )) |
| |
| 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=None, delimiter=r"\s+") |
| return [f"W{width}_L{length}_T{temp}_{corner}",df_simulated.iloc[-1, -1]] |
| |
| def main(): |
| |
| models_path = "../../sm141064.ngspice" |
| 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 = [] |
| |
| all_combs = list(itertools.product(sizes, temps, corners)) |
| |
| with concurrent.futures.ThreadPoolExecutor(max_workers=workers_count) as executor: |
| # Start the load operations and mark each future with its URL |
| future_list = [executor.submit(get_results, run_path, comb[0], comb[1], comb[2]) for comb in all_combs] |
| for future in concurrent.futures.as_completed(future_list): |
| try: |
| results.append(future.result()) |
| except Exception as exc: |
| print('Generated an exception: %s' % (exc)) |
| |
| |
| 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() |