From d23caa7acaad1b98a8fa3eaaf5b89119b6d16c8a Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Tue, 22 Aug 2023 12:55:34 +0530 Subject: [PATCH 1/5] feat: gitignored generated files --- openfasoc/generators/ldo-gen/.gitignore | 1 + openfasoc/generators/ldo-gen/flow/.gitignore | 8 ++++++++ openfasoc/generators/ldo-gen/simulations/.gitignore | 1 + 3 files changed, 10 insertions(+) create mode 100644 openfasoc/generators/ldo-gen/.gitignore create mode 100644 openfasoc/generators/ldo-gen/flow/.gitignore create mode 100644 openfasoc/generators/ldo-gen/simulations/.gitignore diff --git a/openfasoc/generators/ldo-gen/.gitignore b/openfasoc/generators/ldo-gen/.gitignore new file mode 100644 index 000000000..4d9ec92c6 --- /dev/null +++ b/openfasoc/generators/ldo-gen/.gitignore @@ -0,0 +1 @@ +work/ \ No newline at end of file diff --git a/openfasoc/generators/ldo-gen/flow/.gitignore b/openfasoc/generators/ldo-gen/flow/.gitignore new file mode 100644 index 000000000..821e19aec --- /dev/null +++ b/openfasoc/generators/ldo-gen/flow/.gitignore @@ -0,0 +1,8 @@ +design/sky130hvl/ldo/config.mk +logs/ +objects/ +reports/ +results/ +/*.log +/*.spice +/*.ext diff --git a/openfasoc/generators/ldo-gen/simulations/.gitignore b/openfasoc/generators/ldo-gen/simulations/.gitignore new file mode 100644 index 000000000..737e26b00 --- /dev/null +++ b/openfasoc/generators/ldo-gen/simulations/.gitignore @@ -0,0 +1 @@ +run/ \ No newline at end of file From 806fd529261ae0b514ef8aa456a6982dc79fd6c9 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Tue, 22 Aug 2023 23:15:05 +0530 Subject: [PATCH 2/5] feat: updated spice templates to use mako syntax --- .../templates/ldo_load_change_ngspice.sp | 15 ++++++++------- .../templates/ldo_load_change_xyce.sp | 15 ++++++++------- .../simulations/templates/ldo_tran_ngspice.sp | 19 ++++++++++--------- .../simulations/templates/ldo_tran_xyce.sp | 19 ++++++++++--------- .../templates/pwrarr_sweep_ngspice.sp | 6 +++--- .../templates/pwrarr_sweep_xyce.sp | 6 +++--- 6 files changed, 42 insertions(+), 38 deletions(-) diff --git a/openfasoc/generators/ldo-gen/simulations/templates/ldo_load_change_ngspice.sp b/openfasoc/generators/ldo-gen/simulations/templates/ldo_load_change_ngspice.sp index ff09b4607..2ea580665 100644 --- a/openfasoc/generators/ldo-gen/simulations/templates/ldo_load_change_ngspice.sp +++ b/openfasoc/generators/ldo-gen/simulations/templates/ldo_load_change_ngspice.sp @@ -1,19 +1,19 @@ * VREG and load current Transient * include from .../sky130A/libs.tech/ngspice/sky130.lib.spice -.lib '@model_file' @model_corner +.lib '${model_file}' ${model_corner} * include the LDO spice netlist -.include 'ldo_sim.spice' +.include '${netlist_path}' -xi1 @proper_pin_ordering +xi1 ${pin_ordering} + ldoInst *Controls V0 VSS 0 DC=0 V1 VDD 0 DC=3.3 * to be commented if using Analog Vref block -V2 VREF 0 DC=@VALUE_REF_VOLTAGE +V2 VREF 0 DC=${vref} vtrim1 trim1 0 DC=0 vtrim2 trim2 0 DC=0 @@ -46,7 +46,7 @@ vstd7 std_pt_in_cnt[7] 0 dc 0 vstd8 std_pt_in_cnt[8] 0 dc 0 *Load change -V10 VR 0 pwl 0 1800 20u 1800 20.01u @Res_Value +V10 VR 0 pwl 0 1800 20u 1800 20.01u ${1.2 * vref / max_load} R1 VREG 0 R=V(VR) C1 VREG VSS 5p @@ -57,13 +57,14 @@ C1 VREG VSS 5p *Analysis .temp 25 -.tran @sim_step @sim_time +<% sim_end_time = 1.2 * arr_size / 1000000 %> +.tran ${sim_end_time / 2000} ${sim_end_time} .control run set filetype=binary -write @output_raw v(VREG) v(VREF) v(cmp_out) v(clk) v("ctrl_out[0]") v("ctrl_out[1]") v("ctrl_out[2]") v("ctrl_out[3]") v("ctrl_out[4]") v("ctrl_out[5]") v("ctrl_out[6]") v("ctrl_out[7]") v("ctrl_out[8]") i(V1) +write ${f"{max_load * 1000}mA_output_load_change.raw"} v(VREG) v(VREF) v(cmp_out) v(clk) v("ctrl_out[0]") v("ctrl_out[1]") v("ctrl_out[2]") v("ctrl_out[3]") v("ctrl_out[4]") v("ctrl_out[5]") v("ctrl_out[6]") v("ctrl_out[7]") v("ctrl_out[8]") i(V1) .endc diff --git a/openfasoc/generators/ldo-gen/simulations/templates/ldo_load_change_xyce.sp b/openfasoc/generators/ldo-gen/simulations/templates/ldo_load_change_xyce.sp index d88210a00..0bfd9a573 100644 --- a/openfasoc/generators/ldo-gen/simulations/templates/ldo_load_change_xyce.sp +++ b/openfasoc/generators/ldo-gen/simulations/templates/ldo_load_change_xyce.sp @@ -1,19 +1,19 @@ * VREG and load current Transient * include from .../sky130A/libs.tech/ngspice/sky130.lib.spice -.lib '@model_file' @model_corner +.lib '${model_file}' ${model_corner} * include the LDO spice netlist -.include 'ldo_sim.spice' +.include '${netlist_path}' -xi1 @proper_pin_ordering +xi1 ${pin_ordering} + ldoInst *Controls V0 VSS 0 dc 0 V1 VDD 0 dc 3.3 * to be commented if using Analog Vref block -V2 VREF 0 dc @VALUE_REF_VOLTAGE +V2 VREF 0 dc ${vref} vtrim1 trim1 0 dc 0 vtrim2 trim2 0 dc 0 @@ -46,7 +46,7 @@ vstd7 std_pt_in_cnt[7] 0 dc 0 vstd8 std_pt_in_cnt[8] 0 dc 0 *Load change -V10 VR 0 pwl 0 1800 20u 1800 20.01u @Res_Value +V10 VR 0 pwl 0 1800 20u 1800 20.01u ${1.2 * vref / max_load} R1 VREG 0 R=V(VR) C1 VREG VSS 5p @@ -55,7 +55,8 @@ C1 VREG VSS 5p .PREPROCESS ADDRESISTORS ONETERMINAL 1G *Analysis -.tran @sim_step @sim_time UIC +<% sim_end_time = 1.2 * arr_size / 1000000 %> +.tran ${sim_end_time / 2000} ${sim_end_time} UIC -.print tran format=raw file=@output_raw v(VREG) v(VREF) v(cmp_out) v(ctrl_out[0]) v(ctrl_out[1]) v(ctrl_out[2]) v(ctrl_out[3]) v(ctrl_out[4]) v(ctrl_out[5]) v(ctrl_out[6]) v(ctrl_out[7]) v(ctrl_out[8]) i(V1) +.print tran format=raw file=${f"{max_load * 1000}mA_output_load_change.raw"} v(VREG) v(VREF) v(cmp_out) v(ctrl_out[0]) v(ctrl_out[1]) v(ctrl_out[2]) v(ctrl_out[3]) v(ctrl_out[4]) v(ctrl_out[5]) v(ctrl_out[6]) v(ctrl_out[7]) v(ctrl_out[8]) i(V1) .end diff --git a/openfasoc/generators/ldo-gen/simulations/templates/ldo_tran_ngspice.sp b/openfasoc/generators/ldo-gen/simulations/templates/ldo_tran_ngspice.sp index aafbf25a5..d75c589bf 100644 --- a/openfasoc/generators/ldo-gen/simulations/templates/ldo_tran_ngspice.sp +++ b/openfasoc/generators/ldo-gen/simulations/templates/ldo_tran_ngspice.sp @@ -1,19 +1,19 @@ * VREG and load current Transient * include from .../sky130A/libs.tech/ngspice/sky130.lib.spice -.lib '@model_file' @model_corner +.lib '${model_file}' ${model_corner} * include the LDO spice netlist -.include 'ldo_sim.spice' +.include '${netlist_path}' -xi1 @proper_pin_ordering +xi1 ${pin_ordering} + ldoInst *Controls V0 VSS 0 DC=0 V1 VDD 0 DC=3.3 * to be commented if using Analog Vref block -V2 VREF 0 DC=@VALUE_REF_VOLTAGE +V2 VREF 0 DC=${vref} vtrim1 trim1 0 DC=0 vtrim2 trim2 0 DC=0 @@ -28,7 +28,7 @@ vtrim10 trim10 0 DC=0 *With ideal VRef block *change here if want to change clock frequency -V3 clk VSS pulse 0 3.3 0 1n 1n @duty_cycle @clk_period +V3 clk VSS pulse 0 3.3 0 1n 1n ${0.5 / freq} ${1 / freq} V4 reset 0 pwl 0 3.3 10n 3.3 10.1n 0 @@ -45,10 +45,10 @@ vstd6 std_pt_in_cnt[6] 0 dc 0 vstd7 std_pt_in_cnt[7] 0 dc 0 vstd8 std_pt_in_cnt[8] 0 dc 0 -R1 VREG VSS @Res_Value +R1 VREG VSS ${1.2 * vref / max_load} *Resistance 3600 --> 0.5 mA for 1.8 V reference voltage. R to be adjusted according to Iload and output voltage. -C1 VREG VSS @Cap_Value +C1 VREG VSS ${cap} *.options savecurrents .option wnflag=1 @@ -56,13 +56,14 @@ C1 VREG VSS @Cap_Value .ic v(VREG) = 0 v(clk)=0 v(reset)=3.3 *Analysis .temp 25 -.tran @sim_step @sim_time +<% sim_end_time = 1.2 * arr_size / freq %> +.tran ${sim_end_time / 2000} ${sim_end_time} .control run set filetype=binary -write @output_raw v(VREG) v(VREF) v(cmp_out) v(clk) v("ctrl_out[0]") v("ctrl_out[1]") v("ctrl_out[2]") v("ctrl_out[3]") v("ctrl_out[4]") v("ctrl_out[5]") v("ctrl_out[6]") v("ctrl_out[7]") v("ctrl_out[8]") +write ${f"{max_load * 1000}mA_{freq}Hz_{cap}_cap_output.raw"} v(VREG) v(VREF) v(cmp_out) v(clk) v("ctrl_out[0]") v("ctrl_out[1]") v("ctrl_out[2]") v("ctrl_out[3]") v("ctrl_out[4]") v("ctrl_out[5]") v("ctrl_out[6]") v("ctrl_out[7]") v("ctrl_out[8]") .endc diff --git a/openfasoc/generators/ldo-gen/simulations/templates/ldo_tran_xyce.sp b/openfasoc/generators/ldo-gen/simulations/templates/ldo_tran_xyce.sp index e2634ce99..be726fa6c 100644 --- a/openfasoc/generators/ldo-gen/simulations/templates/ldo_tran_xyce.sp +++ b/openfasoc/generators/ldo-gen/simulations/templates/ldo_tran_xyce.sp @@ -1,19 +1,19 @@ * VREG and load current Transient * include from .../sky130A/libs.tech/ngspice/sky130.lib.spice -.lib '@model_file' @model_corner +.lib '${model_file}' ${model_corner} * include the LDO spice netlist -.include 'ldo_sim.spice' +.include '${netlist_path}' -xi1 @proper_pin_ordering +xi1 ${pin_ordering} + ldoInst *Controls V0 VSS 0 dc 0 V1 VDD 0 dc 3.3 * to be commented if using Analog Vref block -V2 VREF 0 dc @VALUE_REF_VOLTAGE +V2 VREF 0 dc ${vref} vtrim1 trim1 0 dc 0 vtrim2 trim2 0 dc 0 @@ -28,7 +28,7 @@ vtrim10 trim10 0 dc 0 *With ideal VRef block *change here if want to change clock frequency -V3 clk VSS pulse 0 3.3 0 1n 1n @duty_cycle @clk_period +V3 clk VSS pulse 0 3.3 0 1n 1n ${0.5 / freq} ${1 / freq} V4 reset 0 pwl 0 3.3 10n 3.3 10.1n 0 @@ -45,17 +45,18 @@ vstd6 std_pt_in_cnt[6] 0 dc 0 vstd7 std_pt_in_cnt[7] 0 dc 0 vstd8 std_pt_in_cnt[8] 0 dc 0 -R1 VREG VSS @Res_Value +R1 VREG VSS ${1.2 * vref / max_load} *Resistance 3600 --> 0.5 mA for 1.8 V reference voltage. R to be adjusted according to Iload and output voltage. -C1 VREG VSS @Cap_Value +C1 VREG VSS ${cap} .ic v(VREG) = 0 v(clk)=0 v(reset)=3.3 .options LINSOL type=klu .PREPROCESS ADDRESISTORS ONETERMINAL 1G *Analysis -.tran @sim_step @sim_time UIC +<% sim_end_time = 1.2 * arr_size / freq %> +.tran ${sim_end_time / 2000} ${sim_end_time} UIC -.print tran format=raw file=@output_raw v(VREG) v(VREF) v(cmp_out) v(ctrl_out[0]) v(ctrl_out[1]) v(ctrl_out[2]) v(ctrl_out[3]) v(ctrl_out[4]) v(ctrl_out[5]) v(ctrl_out[6]) v(ctrl_out[7]) v(ctrl_out[8]) i(V1) +.print tran format=raw file=${f"{max_load * 1000}mA_{freq}Hz_{cap}_cap_output.raw"} v(VREG) v(VREF) v(cmp_out) v(ctrl_out[0]) v(ctrl_out[1]) v(ctrl_out[2]) v(ctrl_out[3]) v(ctrl_out[4]) v(ctrl_out[5]) v(ctrl_out[6]) v(ctrl_out[7]) v(ctrl_out[8]) i(V1) .end diff --git a/openfasoc/generators/ldo-gen/simulations/templates/pwrarr_sweep_ngspice.sp b/openfasoc/generators/ldo-gen/simulations/templates/pwrarr_sweep_ngspice.sp index f9cf953b5..99c5fb245 100644 --- a/openfasoc/generators/ldo-gen/simulations/templates/pwrarr_sweep_ngspice.sp +++ b/openfasoc/generators/ldo-gen/simulations/templates/pwrarr_sweep_ngspice.sp @@ -1,7 +1,7 @@ * include from .../sky130A/libs.tech/ngspice/sky130.lib.spice -.lib '@model_file' @model_corner +.lib '${model_file}' ${model_corner} * include the LDO spice netlist -.include 'power_array.spice' +.include '${netlist_path}' xi1 VREG VDD VSS ldoInst @@ -11,7 +11,7 @@ xi1 VREG VDD VSS ldoInst V0 VSS 0 dc 0 *V1 VDD VSS pwl 0 0 2n 0 2.0001n 3.3 V1 VDD VSS 3.3 -V2 VREF VSS @VALUE_REF_VOLTAGE +V2 VREF VSS ${vref} R1 VREG VSS 1000 C1 VREG VSS 1n diff --git a/openfasoc/generators/ldo-gen/simulations/templates/pwrarr_sweep_xyce.sp b/openfasoc/generators/ldo-gen/simulations/templates/pwrarr_sweep_xyce.sp index 5f73f3702..75a4465e6 100644 --- a/openfasoc/generators/ldo-gen/simulations/templates/pwrarr_sweep_xyce.sp +++ b/openfasoc/generators/ldo-gen/simulations/templates/pwrarr_sweep_xyce.sp @@ -1,7 +1,7 @@ * include from .../sky130A/libs.tech/ngspice/sky130.lib.spice -.lib '@model_file' @model_corner +.lib '${model_file}' ${model_corner} * include the LDO spice netlist -.include 'power_array.spice' +.include '${netlist_path}' xi1 VREG VDD VSS ldoInst @@ -11,7 +11,7 @@ xi1 VREG VDD VSS ldoInst V0 VSS 0 dc 0 *V1 VDD VSS pwl 0 0 2n 0 2.0001n 3.3 V1 VDD VSS dc 3.3 -V2 VREF VSS @VALUE_REF_VOLTAGE +V2 VREF VSS ${vref} R1 VREG VSS 1000 C1 VREG VSS 1n From 95781c3163580f0b6187c2f08bd29996cc703706 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Tue, 22 Aug 2023 23:15:36 +0530 Subject: [PATCH 3/5] fix: use "VREF" as the vref node instead of searching for it. --- .../generators/ldo-gen/tools/simulations.py | 296 +----------------- 1 file changed, 3 insertions(+), 293 deletions(-) diff --git a/openfasoc/generators/ldo-gen/tools/simulations.py b/openfasoc/generators/ldo-gen/tools/simulations.py index 70b33db02..07c5117c0 100644 --- a/openfasoc/generators/ldo-gen/tools/simulations.py +++ b/openfasoc/generators/ldo-gen/tools/simulations.py @@ -1,16 +1,7 @@ -import math -import numpy as np import os import re -import shutil -import sys import subprocess as sp -import matplotlib.pyplot as plt from cairosvg import svg2png -from PIL import Image -from scipy.interpolate import make_interp_spline -import ltspice -import pandas as pd # ------------------------------------------------------------------------------ # Create Sim Directories @@ -115,7 +106,8 @@ def process_PEX_netlist(rawExtractedNetlistPath, simtool, designName): """Prepare PEX netlist for simulations. Return string containing the netlist.""" with open(rawExtractedNetlistPath, "r") as spice_in: netlist = spice_in.read() - vref_node_to = re.findall(r"\bcapacitor_test_nf_\S*", netlist)[0] + + vref_node_to = "VREF" head = re.search(r"\.subckt " + designName + r" .*\n(\+.*\n)*", netlist, re.I)[0] newhead = " ".join(head.split(" ") + ["\n+ " + vref_node_to + "\n"]) netlist = netlist.replace(head, newhead) @@ -139,7 +131,7 @@ def process_PEX_netlist(rawExtractedNetlistPath, simtool, designName): netlist = netlist.replace("$", ";") return [ netlist, - newhead.replace(vref_node_to, "VREF") + newhead .replace(designName, "", 1) .replace(".subckt", "", 1) .replace("r_VREG", "VREG", 1), @@ -155,288 +147,6 @@ def process_PEX_netlist(rawExtractedNetlistPath, simtool, designName): + std_pt_in_cnt[4] std_pt_in_cnt[5] std_pt_in_cnt[6] std_pt_in_cnt[7] std_pt_in_cnt[8] + trim1 trim10 trim2 trim3 trim4 trim5 trim6 trim7 trim8 trim9 VDD VSS VREF VREG""" - -def ngspice_prepare_scripts( - head, - cap_list, - templateScriptDir, - sim_dir, - user_specs, - arrSize, - pdk_path, - freq_list, - model_corner, - pex, -): - """Specializes ngspice simulations and returns (string) bash to run all sims.""" - designName = user_specs["designName"] - vref = user_specs["vin"] - max_load = user_specs["imax"] - model_file = pdk_path + "/libs.tech/ngspice/sky130.lib.spice" - with open(templateScriptDir + "ldo_tran_ngspice.sp", "r") as sim_spice: - sim_template = sim_spice.read() - sim_template = sim_template.replace("@model_file", model_file) - sim_template = sim_template.replace("@model_corner", model_corner) - sim_template = sim_template.replace("@design_nickname", designName) - sim_template = sim_template.replace("@VALUE_REF_VOLTAGE", str(vref)) - sim_template = sim_template.replace("@Res_Value", str(1.2 * vref / max_load)) - if pex: - sim_template = sim_template.replace("@proper_pin_ordering", head) - else: - sim_template = sim_template.replace( - "@proper_pin_ordering", prePEX_SPICE_HEADER_GLOBAL_V - ) - # create list of scripts to run (wheretocopy, filename, stringdata, ngspicecommand) - scripts_to_run = list() - for freq in freq_list: - sim_script = sim_template - sim_script = sim_script.replace("@clk_period", str(1 / freq)) - sim_script = sim_script.replace("@duty_cycle", str(0.5 / freq)) - sim_time = 1.2 * arrSize / freq - sim_script = sim_script.replace("@sim_time", str(sim_time)) - sim_script = sim_script.replace("@sim_step", str(sim_time / 2000)) - if freq == 100000: - freq_name = "0.1MHz" - elif freq == 1000000: - freq_name = "1.0MHz" - else: - freq_name = "10.0MHz" - load = max_load * 1000 - for cap in cap_list: - sim_script_f = sim_script.replace("@Cap_Value", str(cap)) - output_raw = ( - str(load) + "mA_" + freq_name + "_" + str(cap) + "_cap_output.raw" - ) - sim_script_f = sim_script_f.replace("@output_raw", str(output_raw)) - sim_name = ( - "ldo_tran_" + str(load) + "mA_" + freq_name + "_" + str(cap) + ".sp" - ) - scripts_to_run.append( - tuple( - ( - sim_dir, - sim_name, - sim_script_f, - "ngspice -b -o " - "ldo_" + freq_name + "_" + str(cap) + "_out.txt -i " + sim_name, - ) - ) - ) - # add power array script to the list - with open(templateScriptDir + "/pwrarr_sweep_ngspice.sp", "r") as sim_spice: - pwr_sim_template = sim_spice.read() - pwr_sim_template = pwr_sim_template.replace("@model_corner", model_corner) - pwr_sim_template = pwr_sim_template.replace("@VALUE_REF_VOLTAGE", str(vref)) - pwr_sim_template = pwr_sim_template.replace("@model_file", model_file) - scripts_to_run.append( - tuple( - ( - sim_dir, - "pwrarr.sp", - pwr_sim_template, - "ngspice -b -o pwrout.txt -i pwrarr.sp", - ) - ) - ) - # add load chnage script to list - with open(templateScriptDir + "/ldo_load_change_ngspice.sp", "r") as sim_spice: - load_sim_template = sim_spice.read() - load_sim_template = load_sim_template.replace("@model_corner", model_corner) - load_sim_template = load_sim_template.replace("@VALUE_REF_VOLTAGE", str(vref)) - load_sim_template = load_sim_template.replace("@model_file", model_file) - load_sim_template = load_sim_template.replace( - "@Res_Value", str(1.2 * vref / max_load) - ) - sim_time = 1.2 * arrSize / 1000000 - load_sim_template = load_sim_template.replace("@sim_time", str(sim_time)) - load_sim_template = load_sim_template.replace("@sim_step", str(sim_time / 2000)) - output_raw = str(load) + "mA_output_load_change.raw" - load_sim_template = load_sim_template.replace("@output_raw", str(output_raw)) - sim_name = "ldo_load_change.sp" - if pex: - load_sim_template = load_sim_template.replace("@proper_pin_ordering", head) - else: - load_sim_template = load_sim_template.replace( - "@proper_pin_ordering", prePEX_SPICE_HEADER_GLOBAL_V - ) - scripts_to_run.append( - tuple( - ( - sim_dir, - sim_name, - load_sim_template, - "ngspice -b -o ldo_load_change.txt -i " + sim_name, - ) - ) - ) - # write scripts to their respective locations and create sim_list for simulations - raw_data = [] - sim_list = [] - for script in scripts_to_run: - with open(script[0] + "/" + script[1], "w") as scriptfile: - scriptfile.write(script[2]) - shutil.copy2( - os.path.abspath(templateScriptDir) + "/.spiceinit", - os.path.abspath(script[0]), - ) - sim_list.append(script[3]) - for freq in freq_list: - if freq == 100000: - freq_name = "0.1MHz" - elif freq == 1000000: - freq_name = "1.0MHz" - else: - freq_name = "10.0MHz" - for cap in cap_list: - raw_data.append( - str(load) + "mA_" + freq_name + "_" + str(cap) + "_cap_output.raw" - ) - return [sim_list, raw_data] - - -def xyce_prepare_scripts( - head, - cap_list, - templateScriptDir, - sim_dir, - user_specs, - arrSize, - pdk_path, - freq_list, - model_corner, - pex, -): - """Specializes xyce simulations and returns (string) bash to run all sims.""" - designName = user_specs["designName"] - vref = user_specs["vin"] - max_load = user_specs["imax"] - model_file = pdk_path + "/libs.tech/ngspice/sky130.lib.spice" - with open(templateScriptDir + "ldo_tran_xyce.sp", "r") as sim_spice: - sim_template = sim_spice.read() - sim_template = sim_template.replace("@model_file", model_file) - sim_template = sim_template.replace("@model_corner", model_corner) - sim_template = sim_template.replace("@design_nickname", designName) - sim_template = sim_template.replace("@VALUE_REF_VOLTAGE", str(vref)) - sim_template = sim_template.replace("@Res_Value", str(1.2 * vref / max_load)) - if pex: - sim_template = sim_template.replace("@proper_pin_ordering", head) - else: - sim_template = sim_template.replace( - "@proper_pin_ordering", prePEX_SPICE_HEADER_GLOBAL_V - ) - # create list of scripts to run (wheretocopy, filename, stringdata, ngspicecommand) - scripts_to_run = list() - for freq in freq_list: - sim_script = sim_template - sim_script = sim_script.replace("@clk_period", str(1 / freq)) - sim_script = sim_script.replace("@duty_cycle", str(0.5 / freq)) - sim_time = 1.2 * arrSize / freq - sim_script = sim_script.replace("@sim_time", str(sim_time)) - sim_script = sim_script.replace("@sim_step", str(sim_time / 2000)) - if freq == 100000: - freq_name = "0.1MHz" - elif freq == 1000000: - freq_name = "1.0MHz" - else: - freq_name = "10.0MHz" - load = max_load * 1000 - for cap in cap_list: - sim_script_f = sim_script.replace("@Cap_Value", str(cap)) - output_raw = ( - str(load) + "mA_" + freq_name + "_" + str(cap) + "_cap_output.raw" - ) - sim_script_f = sim_script_f.replace("@output_raw", str(output_raw)) - sim_name = ( - "ldo_tran_" + str(load) + "mA_" + freq_name + "_" + str(cap) + ".sp" - ) - scripts_to_run.append( - tuple( - ( - sim_dir, - sim_name, - sim_script_f, - "Xyce -o " - "ldo_" - + freq_name - + "_" - + str(cap) - + "_out.log -hspice-ext all " - + sim_name, - ) - ) - ) - # add power array script to the list - with open(templateScriptDir + "/pwrarr_sweep_xyce.sp", "r") as sim_spice: - pwr_sim_template = sim_spice.read() - pwr_sim_template = pwr_sim_template.replace("@model_corner", model_corner) - pwr_sim_template = pwr_sim_template.replace("@VALUE_REF_VOLTAGE", str(vref)) - pwr_sim_template = pwr_sim_template.replace("@model_file", model_file) - scripts_to_run.append( - tuple( - ( - sim_dir, - "pwrarr.sp", - pwr_sim_template, - "Xyce -o pwrout.log -hspice-ext all pwrarr.sp", - ) - ) - ) - # add load chnage script to list - with open(templateScriptDir + "/ldo_load_change_xyce.sp", "r") as sim_spice: - load_sim_template = sim_spice.read() - load_sim_template = load_sim_template.replace("@model_corner", model_corner) - load_sim_template = load_sim_template.replace("@VALUE_REF_VOLTAGE", str(vref)) - load_sim_template = load_sim_template.replace("@model_file", model_file) - load_sim_template = load_sim_template.replace( - "@Res_Value", str(1.2 * vref / max_load) - ) - sim_time = 1.2 * arrSize / 1000000 - load_sim_template = load_sim_template.replace("@sim_time", str(sim_time)) - load_sim_template = load_sim_template.replace("@sim_step", str(sim_time / 2000)) - output_raw = str(load) + "mA_output_load_change.raw" - load_sim_template = load_sim_template.replace("@output_raw", str(output_raw)) - sim_name = "ldo_load_change.sp" - if pex: - load_sim_template = load_sim_template.replace("@proper_pin_ordering", head) - else: - load_sim_template = load_sim_template.replace( - "@proper_pin_ordering", prePEX_SPICE_HEADER_GLOBAL_V - ) - scripts_to_run.append( - tuple( - ( - sim_dir, - sim_name, - load_sim_template, - "Xyce -o ldo_load_change.log -hspice-ext all " + sim_name, - ) - ) - ) - # write scripts to their respective locations and prepare sim list for simulations - raw_data = [] - sim_list = [] - for script in scripts_to_run: - with open(script[0] + "/" + script[1], "w") as scriptfile: - scriptfile.write(script[2]) - shutil.copy2( - os.path.abspath(templateScriptDir) + "/.spiceinit", - os.path.abspath(script[0]), - ) - sim_list.append(script[3]) - for freq in freq_list: - if freq == 100000: - freq_name = "0.1MHz" - elif freq == 1000000: - freq_name = "1.0MHz" - else: - freq_name = "10.0MHz" - for cap in cap_list: - raw_data.append( - str(load) + "mA_" + freq_name + "_" + str(cap) + "_cap_output.raw" - ) - return [sim_list, raw_data] - - # ------------------------------------------------------------------------------ # max current binary search (deprecated, instead use dc linear sweep) # ------------------------------------------------------------------------------ From 2fba089215e23ec2186e0c47a9d2ab27a156649c Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Tue, 22 Aug 2023 23:15:59 +0530 Subject: [PATCH 4/5] feat: updated ldo generator to use the new simulation module --- openfasoc/generators/ldo-gen/tools/ldo-gen.py | 197 ++++++------------ 1 file changed, 62 insertions(+), 135 deletions(-) diff --git a/openfasoc/generators/ldo-gen/tools/ldo-gen.py b/openfasoc/generators/ldo-gen/tools/ldo-gen.py index a6f916438..c6f0f024d 100644 --- a/openfasoc/generators/ldo-gen/tools/ldo-gen.py +++ b/openfasoc/generators/ldo-gen/tools/ldo-gen.py @@ -11,6 +11,7 @@ # TODO: Find a better way to import modules from parent directory sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..')) from common.verilog_generation import generate_verilog +from common.simulation import run_simulations print("#---------------------------------------------------------------------") print("# Parsing command line arguments...") @@ -178,21 +179,28 @@ # simulations are ran for the following configurations: cap_list = ["1p", "5p"] # additional capacitance at node VREG freq_list = [0.1 * 10**6, 1 * 10**6, 10 * 10**6] # clock frequency + vref = user_specs["vin"] + max_load = user_specs["imax"] + + is_pex = args.simtype == "postPEX" or args.pex == "True" # prepare sim directories and copy files # sim_dir_structure is a dictionary containing the tree file path structure of both prepex/pex directories [prePEX_sim_dir, postPEX_sim_dir] = create_sim_dirs( arrSize, directories["simDir"], args.mode ) + # create sim netlists (return as strings) spice_dir = directories["flowDir"] + "/objects/sky130hvl/ldo/base/netgen_lvs/spice/" rawPEXPath = spice_dir + user_specs["designName"] + "_pex.spice" rawSynthPath = spice_dir + user_specs["designName"] + ".spice" + [processedPEXnetlist, head] = process_PEX_netlist( rawPEXPath, jsonConfig["simTool"], user_specs["designName"] ) processedSynthNetlist = process_prePEX_netlist(rawSynthPath) powerArrayNetlist = process_power_array_netlist(rawSynthPath) + # create list of netlists (wheretocopy, filename, stringdata) then write to their respective locations netlists = list() netlists.append(tuple((postPEX_sim_dir, "ldo_sim.spice", processedPEXnetlist))) @@ -203,146 +211,65 @@ with open(netlist[0] + "/" + netlist[1], "w") as simfile: simfile.write(netlist[2]) - # prepare simulation scripts, passing prePEX_sim_dir and pex=false to function *_prepare_scripts() runs preprex sims - # there should be one output file name specified for each cap value. outputs sent to sim_dir_structure directories - if args.simtype == "postPEX" or args.pex == "True": - if jsonConfig["simTool"] == "ngspice": - [sim, output_file_names] = ngspice_prepare_scripts( - head, - cap_list, - directories["simDir"] + "/templates/", - postPEX_sim_dir, - user_specs, - arrSize, - pdk_path, - freq_list, - "tt", - pex=True, - ) - elif jsonConfig["simTool"] == "Xyce": - [sim, output_file_names] = xyce_prepare_scripts( - head, - cap_list, - directories["simDir"] + "/templates/", - postPEX_sim_dir, - user_specs, - arrSize, - pdk_path, - freq_list, - "tt", - pex=True, - ) - else: - print("simtool not supported") - exit(1) - - if args.simtype == "prePEX": - if jsonConfig["simTool"] == "ngspice": - [sim, output_file_names] = ngspice_prepare_scripts( - head, - cap_list, - directories["simDir"] + "/templates/", - prePEX_sim_dir, - user_specs, - arrSize, - pdk_path, - freq_list, - "tt", - pex=False, - ) - elif jsonConfig["simTool"] == "Xyce": - [sim, output_file_names] = xyce_prepare_scripts( - head, - cap_list, - directories["simDir"] + "/templates/", - prePEX_sim_dir, - user_specs, - arrSize, - pdk_path, - freq_list, - "tt", - pex=False, - ) - else: - print("simtool not supported") - exit(1) - print("#----------------------------------------------------------------------") print("# Spice netlists created successfully") print("#----------------------------------------------------------------------") -# ------------------------------------------------------------------------------ -# run simulations -# ------------------------------------------------------------------------------ -if args.mode == "full" or args.mode == "sim" or args.mode == "post": + # transient simulations print("#----------------------------------------------------------------------") - print("# Running Simulations") + print("Running transient simulations.") print("#----------------------------------------------------------------------") - # run sims - processes = [] - # assert len(output_file_names) == len(cap_list)*len(freq_list) - if args.mode != "post": - if args.simtype == "postPEX" or args.pex == "True": - run_dir = directories["genDir"] + "tools/" - vref = user_specs["vin"] - iload = user_specs["imax"] - odir = os.path.abspath(args.outputDir) - for s in range (len(sim)): - p = sp.Popen(sim[s],cwd=postPEX_sim_dir,shell=True) - processes.append(p) - - for p in processes: - p.wait() - - p = sp.Popen(["python3","processing.py","--file_path",postPEX_sim_dir,"--vref",str(vref),"--iload",str(iload),"--odir",odir, "--figs", "True", "--simType", "postPEX"],cwd=run_dir) - p.wait() - - if args.simtype == "prePEX": - run_dir = directories["genDir"] + "tools/" - vref = user_specs["vin"] - iload = user_specs["imax"] - odir = os.path.abspath(args.outputDir) - for s in range (len(sim)): - p = sp.Popen(sim[s],cwd=prePEX_sim_dir,shell=True) - processes.append(p) - - for p in processes: - p.wait() - - p = sp.Popen(["python3","processing.py","--file_path",prePEX_sim_dir,"--vref",str(vref),"--iload",str(iload),"--odir",odir, "--figs", "True", "--simType", "prePEX"],cwd=run_dir) - p.wait() - """ - for s in range (len(sim)): - p = sp.Popen(sim[s],cwd=prePEX_sim_dir,shell=True) - processes.append(p) + run_simulations( + parameters={ + 'model_file': os.path.join(pdk_path, 'libs.tech', 'ngspice', 'sky130.lib.spice'), + 'model_corner': 'tt', + 'vref': vref, + 'max_load': max_load, + 'pin_ordering': head if is_pex else prePEX_SPICE_HEADER_GLOBAL_V, + 'arr_size': arrSize, + 'freq': freq_list, + 'cap': cap_list + }, + platform=args.platform, + runs_dir=os.path.join(postPEX_sim_dir if is_pex else prePEX_sim_dir, 'runs', 'tran'), + template_path=os.path.join('templates', f"ldo_tran_{jsonConfig['simTool']}.sp"), + sim_tool=jsonConfig['simTool'], + netlist_path=os.path.join(postPEX_sim_dir if is_pex else prePEX_sim_dir, 'ldo_sim.spice') + ) - for p in processes: - p.wait() + # load change simulations + print("#----------------------------------------------------------------------") + print("Running load change simulations.") + print("#----------------------------------------------------------------------") + run_simulations( + parameters={ + 'model_file': os.path.join(pdk_path, 'libs.tech', 'ngspice', 'sky130.lib.spice'), + 'model_corner': 'tt', + 'vref': vref, + 'max_load': max_load, + 'pin_ordering': head if is_pex else prePEX_SPICE_HEADER_GLOBAL_V, + 'arr_size': arrSize + }, + platform=args.platform, + runs_dir=os.path.join(postPEX_sim_dir if is_pex else prePEX_sim_dir, 'runs', 'load_change'), + template_path=os.path.join('templates', f"ldo_load_change_{jsonConfig['simTool']}.sp"), + sim_tool=jsonConfig['simTool'], + netlist_path=os.path.join(postPEX_sim_dir if is_pex else prePEX_sim_dir, 'ldo_sim.spice') + ) - # perform post processing on simulation results and save figures to work dir - raw_files = [(prePEX_sim_dir + ofile) for ofile in output_file_names] - raw_to_csv(raw_files,user_specs["vin"],args.outputDir) - figures = list() - figure_names = list() - figure_names.extend(["VREG_output", "VDIF", "VREG_ripple"]) - figures.extend(fig_VREG_results(raw_files, user_specs["vin"])) - figure_names.append("cmp_out") - figures.append(fig_comparator_results(raw_files)) - figure_names.append("active_switches") - figures.append(fig_controller_results(raw_files)) - # save results to png files - current_freq_results = args.outputDir + "/" + "output_plots" - try: - os.mkdir(current_freq_results) - except OSError as error: - if args.mode != "post": - print(error) - exit(1) - assert len(figures) == len(figure_names) - for i, figure in enumerate(figures): - figure.savefig(current_freq_results + "/" + figure_names[i] + ".png") - fig_dc_results(prePEX_sim_dir + "/isweep.raw").savefig(args.outputDir + "/dc.png") - max_load = user_specs["imax"] - load = max_load*1000 - fig_load_change_results(prePEX_sim_dir + "/" + str(load) + "mA_output_load_change.raw",load).savefig(args.outputDir + "/load_change.png") - """ + # power array simulations + print("#----------------------------------------------------------------------") + print("Running power array simulations.") + print("#----------------------------------------------------------------------") + run_simulations( + parameters={ + 'model_file': os.path.join(pdk_path, 'libs.tech', 'ngspice', 'sky130.lib.spice'), + 'model_corner': 'tt', + 'vref': vref + }, + platform=args.platform, + runs_dir=os.path.join(postPEX_sim_dir if is_pex else prePEX_sim_dir, 'runs', 'pwarrs'), + template_path=os.path.join('templates', f"pwrarr_sweep_{jsonConfig['simTool']}.sp"), + sim_tool=jsonConfig['simTool'], + netlist_path=os.path.join(postPEX_sim_dir if is_pex else prePEX_sim_dir, 'power_array.spice') + ) From 97aa886a5b55796510d1f438be18621260724e83 Mon Sep 17 00:00:00 2001 From: Harsh Khandeparkar Date: Thu, 28 Sep 2023 16:42:09 +0530 Subject: [PATCH 5/5] fix: run ldo simulations only if the mode is set to "full" --- openfasoc/generators/ldo-gen/tools/ldo-gen.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openfasoc/generators/ldo-gen/tools/ldo-gen.py b/openfasoc/generators/ldo-gen/tools/ldo-gen.py index c6f0f024d..4def87771 100644 --- a/openfasoc/generators/ldo-gen/tools/ldo-gen.py +++ b/openfasoc/generators/ldo-gen/tools/ldo-gen.py @@ -173,6 +173,7 @@ print("# LVS and DRC finished successfully") print("#----------------------------------------------------------------------") +if args.mode == "full": # function defined in configure_workspace.py copy_outputs(directories, args.outputDir, args.platform, user_specs["designName"])