diff --git a/.github/scripts/expected_sim_outputs/opamp/means.json b/.github/scripts/expected_sim_outputs/opamp/means.json index a3ec0889f..54e68867d 100644 --- a/.github/scripts/expected_sim_outputs/opamp/means.json +++ b/.github/scripts/expected_sim_outputs/opamp/means.json @@ -1 +1 @@ -{"unity gain bandwidth": 13844398.0, "dc gain": 66.52353580000003, "phase margin": 84.28, "ibias_diff": 5.039385475400001e-06, "ibias_cs": 1.0449669692999998e-05, "ibias_out": 9.349999999999991e-05, "area": 47939.755900000026, "power": 0.0004346434165999998, "noise": 4.836155124999999, "3db bandwidth": 3309.127059999999, "two stage power": 9.804341657199995e-05} \ No newline at end of file +{"ugb": 33262790.0, "dcGain": 66.01914, "phaseMargin": 62.0, "Ibias_diffpair": 1.06993205e-05, "Ibias_commonsource": 2.21861111e-05, "Ibias_output": 9.35e-05, "area": 47939.75594998075, "power": 0.000546523847, "noise": 3.9531001, "bw_3db": 7962.968, "power_twostage": 0.000209923847} \ No newline at end of file diff --git a/.github/scripts/expected_sim_outputs/opamp/variances.json b/.github/scripts/expected_sim_outputs/opamp/variances.json index 2d14ba554..edc2b673f 100644 --- a/.github/scripts/expected_sim_outputs/opamp/variances.json +++ b/.github/scripts/expected_sim_outputs/opamp/variances.json @@ -1 +1 @@ -{"unity gain bandwidth": 674734758516.0, "dc gain": 0.0004632655963598945, "phase margin": 0.48160000000000025, "ibias_diff": 8.904025866969134e-14, "ibias_cs": 3.8285679910532956e-13, "ibias_out": 6.612155723375367e-39, "area": 8.470329472543003e-22, "power": 3.521160625110699e-11, "noise": 0.00031913416941348834, "3db bandwidth": 31892.01486929639, "two stage power": 3.521160707470663e-11} \ No newline at end of file +{"ugb": 674734758516.0, "dcGain": 0.0004632655963598945, "phaseMargin": 0.48160000000000025, "Ibias_diffpair": 8.904025866969134e-14, "Ibias_commonsource": 3.8285679910532956e-13, "Ibias_output": 6.612155723375367e-39, "area": 8.470329472543003e-22, "power": 3.521160625110699e-11, "noise": 0.00031913416941348834, "bw_3db": 31892.01486929639, "power_twostage": 3.521160707470663e-11} \ No newline at end of file diff --git a/.github/scripts/test_glayout_ci.py b/.github/scripts/test_glayout_ci.py index ec9540d57..ac5def44d 100644 --- a/.github/scripts/test_glayout_ci.py +++ b/.github/scripts/test_glayout_ci.py @@ -153,67 +153,41 @@ def check_opamp_results(results, path_to_variances, path_to_means): # read means.json with open(path_to_means, "r") as f: means = json.load(f) - - warn_ugb = means["unity gain bandwidth"] - np.sqrt(variances["unity gain bandwidth"]) - warn_dc_gain = means["dc gain"] - np.sqrt(variances["dc gain"]) - warn_phase_margin = means["phase margin"] - np.sqrt(variances["phase margin"]) + + warn_ugb = means["ugb"] - np.sqrt(variances["ugb"]) + warn_dc_gain = means["dcGain"] - np.sqrt(variances["dcGain"]) + warn_phase_margin = means["phaseMargin"] - np.sqrt(variances["phaseMargin"]) warn_area = means["area"] + 1e4 warn_power = means["power"] + np.sqrt(variances["power"]) - warn_two_stage_power = means["two stage power"] + np.sqrt(variances["two stage power"]) warn_noise = means["noise"] + np.sqrt(variances["noise"]) - warn_3db_bandwidth = means["3db bandwidth"] - np.sqrt(variances["3db bandwidth"]) - - - for key, val in results.items(): - if key == "unity gain bandwidth": - if val <= warn_ugb: - warnings.warn(f"Unity Gain Bandwidth: {val} is less than the minimum value of {warn_ugb}") - if val <= warn_ugb - 2 * np.sqrt(variances["unity gain bandwidth"]): - raise ValueError(f"Unity Gain Bandwidth: {val} is less than the minimum value of {warn_ugb - 2 * np.sqrt(variances['unity gain bandwidth'])}") - - elif key == "dc gain": - if val <= warn_dc_gain: - warnings.warn(f"DC Gain: {val} is less than the minimum value of {warn_dc_gain}") - if val <= warn_dc_gain - 2 * np.sqrt(variances["dc gain"]): - raise ValueError(f"DC Gain: {val} is less than the minimum value of {warn_dc_gain - 2 * np.sqrt(variances['dc gain'])}") - - elif key == "phase margin": - if val <= warn_phase_margin: - warnings.warn(f"Phase Margin: {val} is less than the minimum value of {warn_phase_margin}") - if val <= warn_phase_margin - 2 * np.sqrt(variances["phase margin"]): - raise ValueError(f"Phase Margin: {val} is less than the minimum value of {warn_phase_margin - 2 * np.sqrt(variances['phase margin'])}") - - elif key == "area": - if val >= warn_area: - warnings.warn(f"Area: {val} is greater than the maximum value of {warn_area}") - if val >= warn_area + 2 * np.sqrt(variances["area"]): - raise ValueError(f"Area: {val} is greater than the maximum value of {warn_area + 2 * np.sqrt(variances['area'])}") - - elif key == "power": - if val >= warn_power: - warnings.warn(f"Power: {val} is greater than the maximum value of {warn_power}") - if val >= warn_power + 2 * np.sqrt(variances["power"]): - raise ValueError(f"Power: {val} is greater than the maximum value of {warn_power + 2 * np.sqrt(variances['power'])}") - - elif key == "two stage power": - if val >= warn_two_stage_power: - warnings.warn(f"Two Stage Power: {val} is greater than the maximum value of {warn_two_stage_power}") - if val >= warn_two_stage_power + 2 * np.sqrt(variances["two stage power"]): - raise ValueError(f"Two Stage Power: {val} is greater than the maximum value of {warn_two_stage_power + 2 * np.sqrt(variances['two stage power'])}") - - elif key == "noise": - if val >= warn_noise: - warnings.warn(f"Noise: {val} is greater than the maximum value of {warn_noise}") - if val >= warn_noise + 2 * np.sqrt(variances["noise"]): - raise ValueError(f"Noise: {val} is greater than the maximum value of {warn_noise + 2 * np.sqrt(variances['noise'])}") - - elif key == "3db bandwidth": - if val <= warn_3db_bandwidth: - warnings.warn(f"3dB Bandwidth: {val} is less than the minimum value of {warn_3db_bandwidth}") - if val <= warn_3db_bandwidth - 2 * np.sqrt(variances["3db bandwidth"]): - raise ValueError(f"3dB Bandwidth: {val} is less than the minimum value of {warn_3db_bandwidth - 2 * np.sqrt(variances['3db bandwidth'])}") + warn_3db_bandwidth = means["bw_3db"] - np.sqrt(variances["bw_3db"]) + warn_two_stage_power = means["power_twostage"] + np.sqrt(variances["power_twostage"]) + warn_ibdp = means["Ibias_diffpair"] + np.sqrt(variances['Ibias_diffpair']) + warn_ibcs = means["Ibias_commonsource"] + np.sqrt(variances['Ibias_commonsource']) + warn_ibop = means["Ibias_output"] + np.sqrt(variances['Ibias_output']) + + warn = [warn_ugb, warn_dc_gain, warn_phase_margin, warn_ibdp, warn_ibcs, warn_ibop, warn_area, warn_power, warn_noise, warn_3db_bandwidth, warn_two_stage_power] + multipliers = [-1, -1, -1, 0, 0, 0, 1, 1, 1, -1, 1] + # names = ["ugb", "dcGain", "phaseMargin", "Ibias_diffpair", "Ibias_commonsource", "Ibias_output", "area", "power", "power_twostage", "noise", "bw_3db"] + + for index, (key, val) in enumerate(results.items()): + if "Ibias" in key: + continue + else: + if multipliers[index] == -1: + if val <= warn[index]: + warnings.warn(f'{key}: {val} is less than the minimum value of {warn[index]}') + elif val <= warn[index] - 2 * np.sqrt(variances[key]): + raise ValueError(f'{key}: {val} is less than the minimum value of {warn[index] - 2 * np.sqrt(variances[key])}') + if multipliers[index] == 1: + if val >= warn[index]: + warnings.warn(f'{key}: {val} is greater than the maximum value of {warn[index]}') + elif val >= warn[index] + 2 * np.sqrt(variances[key]): + raise ValueError(f'{key}: {val} is greater than the maximum value of {warn[index] - 2 * np.sqrt(variances[key])}') + def opamp_parametric_sim(): + # import pdb; pdb.set_trace() json_paths = Path(__file__).resolve().parents[5] / ".github" / "scripts" / "expected_sim_outputs" / "opamp" path_to_variances = json_paths / "variances.json" path_to_means = json_paths / "means.json" @@ -239,39 +213,39 @@ def opamp_parametric_sim(): noparasitics=False, hardfail=True ) - check_opamp_results(results, path_to_variances, path_to_means) - -parser = argparse.ArgumentParser() -parser.add_argument('--component', type=str, help='Component name to simulate') -args = parser.parse_args() - -# simulate the component -if args.component == 'opamp': - comp = (opamp(sky130_mapped_pdk, add_output_stage=True)) - comp.name = 'opamp_test' - simulate_component(comp, sky130_mapped_pdk) -elif args.component == 'opamp_parametric': - from tapeout.tapeout_and_RL.sky130_nist_tapeout import * - opamp_parametric_sim() +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('--component', type=str, help='Component name to simulate') + args = parser.parse_args() -elif args.component == 'diff_pair': - comp = (diff_pair(sky130_mapped_pdk)) - comp.name = 'diff_pair_test' - simulate_component(comp, sky130_mapped_pdk) + # simulate the component + if args.component == 'opamp': + comp = (opamp(sky130_mapped_pdk, add_output_stage=True)) + comp.name = 'opamp_test' + simulate_component(comp, sky130_mapped_pdk) -elif args.component == 'nmos': - comp = (nmos(sky130_mapped_pdk)) - comp.name = 'nmos_test' - simulate_component(comp, sky130_mapped_pdk) + elif args.component == 'opamp_parametric': + from tapeout.tapeout_and_RL.sky130_nist_tapeout import * + opamp_parametric_sim() + + elif args.component == 'diff_pair': + comp = (diff_pair(sky130_mapped_pdk)) + comp.name = 'diff_pair_test' + simulate_component(comp, sky130_mapped_pdk) + + elif args.component == 'nmos': + comp = (nmos(sky130_mapped_pdk)) + comp.name = 'nmos_test' + simulate_component(comp, sky130_mapped_pdk) + + elif args.component == 'pmos': + comp = pmos(sky130_mapped_pdk) + comp.name = 'pmos_test' + simulate_component(comp, sky130_mapped_pdk) -elif args.component == 'pmos': - comp = pmos(sky130_mapped_pdk) - comp.name = 'pmos_test' - simulate_component(comp, sky130_mapped_pdk) - -elif args.component == 'current_mirror': - comp = current_mirror(sky130_mapped_pdk, numcols = 3, with_dummy=False) - comp.name = 'currmirror_test' - simulate_component(comp, sky130_mapped_pdk) \ No newline at end of file + elif args.component == 'current_mirror': + comp = current_mirror(sky130_mapped_pdk, numcols = 3, with_dummy=False) + comp.name = 'currmirror_test' + simulate_component(comp, sky130_mapped_pdk) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/composite/opamp/opamp_twostage.py b/openfasoc/generators/glayout/glayout/flow/blocks/composite/opamp/opamp_twostage.py index f612c509e..c3a93cd65 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/composite/opamp/opamp_twostage.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/composite/opamp/opamp_twostage.py @@ -5,7 +5,7 @@ from glayout.flow.pdk.mappedpdk import MappedPDK from typing import Optional, Union from glayout.flow.primitives.fet import nmos, pmos, multiplier -from glayout.flow.blocks.diff_pair import diff_pair +from glayout.flow.blocks.elementary.diff_pair import diff_pair from glayout.flow.primitives.guardring import tapring from glayout.flow.primitives.mimcap import mimcap_array, mimcap from glayout.flow.routing.L_route import L_route @@ -19,13 +19,13 @@ from pydantic import validate_arguments from glayout.flow.placement.two_transistor_interdigitized import two_nfet_interdigitized -from glayout.flow.blocks.diffpair_cmirror_bias import diff_pair_ibias -from glayout.flow.blocks.stacked_current_mirror import stacked_nfet_current_mirror -from glayout.flow.blocks.differential_to_single_ended_converter import differential_to_single_ended_converter -from glayout.flow.blocks.opamp.row_csamplifier_diff_to_single_ended_converter import row_csamplifier_diff_to_single_ended_converter -from glayout.flow.blocks.opamp.diff_pair_stackedcmirror import diff_pair_stackedcmirror +from glayout.flow.blocks.composite.diffpair_cmirror_bias import diff_pair_ibias +from glayout.flow.blocks.composite.stacked_current_mirror import stacked_nfet_current_mirror +from glayout.flow.blocks.composite.differential_to_single_ended_converter import differential_to_single_ended_converter +from glayout.flow.blocks.composite.opamp.row_csamplifier_diff_to_single_ended_converter import row_csamplifier_diff_to_single_ended_converter +from glayout.flow.blocks.composite.opamp.diff_pair_stackedcmirror import diff_pair_stackedcmirror from glayout.flow.spice import Netlist -from glayout.flow.blocks.current_mirror import current_mirror_netlist +from glayout.flow.blocks.elementary.current_mirror import current_mirror_netlist @validate_arguments def __create_and_route_pins(