diff --git a/openfasoc/MLoptimization/requirements.txt b/openfasoc/MLoptimization/requirements.txt index a25b464d2..f4f38f5de 100644 --- a/openfasoc/MLoptimization/requirements.txt +++ b/openfasoc/MLoptimization/requirements.txt @@ -7,6 +7,7 @@ klayout safetensors requests tensorboard +numpy<2 ray==2.7.1 gym==0.26.2 gymnasium==0.28.1 diff --git a/openfasoc/MLoptimization/test.py b/openfasoc/MLoptimization/test.py index 1ec8e3dfb..2826fc7b6 100644 --- a/openfasoc/MLoptimization/test.py +++ b/openfasoc/MLoptimization/test.py @@ -1,31 +1,103 @@ import numpy as np import glayout_import +import sys from sky130_nist_tapeout import safe_single_build_and_simulation -from sky130_nist_tapeout import opamp_parameters_serializer +from sky130_nist_tapeout import opamp_parameters_serializer, opamp_parameters_de_serializer import yaml from pathlib import Path import numpy as np +from typing import Union params = { - "diffpair_params0" : [1, 8, 1], - "diffpair_params1" : [0.5, 2.1, 0.1], - "diffpair_params2" : [1, 13, 1], - "Diffpair_bias0" : [1, 8, 1], - "Diffpair_bias1" : [1, 4.5, 0.5], - "Diffpair_bias2" : [3, 13, 1], - "pamp_hparams0" : [1, 9, 1], - "pamp_hparams1" : [0.5, 2.1, 0.1], - "pamp_hparams2" : [2, 14, 1], - "bias0" : [1, 8, 1], - "bias1" : [0.5, 2.1, 0.1], - "bias2" : [3, 18, 1], - "bias3" : [2, 4, 1], - "half_pload1": [3, 10, 1], - "half_pload3": [4, 9, 1], - "mim_cap_rows" : [1, 4, 1], - } + "diffpair_params0" : [1, 8, 1], + "diffpair_params1" : [0.5, 2.1, 0.1], + "diffpair_params2" : [1, 13, 1], + "Diffpair_bias0" : [1, 8, 1], + "Diffpair_bias1" : [1, 4.5, 0.5], + "Diffpair_bias2" : [3, 13, 1], + "pamp_hparams0" : [1, 9, 1], + "pamp_hparams1" : [0.5, 2.1, 0.1], + "pamp_hparams2" : [2, 14, 1], + "bias0" : [1, 8, 1], + "bias1" : [0.5, 2.1, 0.1], + "bias2" : [3, 18, 1], + "bias3" : [2, 4, 1], + "half_pload1": [3, 10, 1], + "half_pload3": [4, 9, 1], + "mim_cap_rows" : [1, 4, 1], + } + +def get_indices_from_ranges(opamp_parameters: Union[dict, np.array]) -> np.array: + """The RL framework works by doing design searches within a user defined range for each parameter + For example, the RL framework may be told to search diffpair widths between 1um and 8um in steps of 1um + In this case, the RL framework will only ever try to make opamps with diff pair width one of [1,2,3,4,5,6,7,8] + this is done to limit the search space + The RL result will then show an index of the result. For example, if the best opamp in a design iteration had a with of 3um, + the corresponding index for 3um is 2 (3um is at the 2nd index in the array [1,2,3,4,5,6,7,8]) + + The purpose of this function to convert a list of opamp parameter into a list of indices into these range arrays + returns a list of indicies + + input can either be given in dictionary or np.array format + here is an example dictionary input: + {'half_diffpair_params': (-987.654321, -987.654321, -987.654321), 'diffpair_bias': (-987.654321, -987.654321, -987.654321), 'half_common_source_params': (-987.654321, -987.654321, -987.654321, -987.654321), 'half_common_source_bias': (-987.654321, -987.654321, -987.654321, -987.654321), 'output_stage_params': (-987.654321, -987.654321, -987), 'output_stage_bias': (-987, -987.654321, -987.654321), 'half_pload': (-987.654321, -987.654321, -987.654321), 'mim_cap_size': (-987.654321, -987.654321), 'mim_cap_rows': -987, 'rmult': -987} + + here is an example np.array indices output: + np.array([6, 2, 7, 6, 0, 5, 7, 0, 10, 6, 5, 13, 0, 6, 4, 2]) + """ + # convert to dictionary format first + if isinstance(opamp_parameters, dict): + opamp_parameter_dict = opamp_parameters + else: + opamp_parameter_dict = opamp_parameters_de_serializer(opamp_parameters) + # Function to find the closest index in the range + def closest_index(range_params, number): + start, end, step = range_params + values = np.arange(start, end, step) + idx = (np.abs(values - number)).argmin() + return idx + # loop through params and find closest indices + opamp_parameter_arr = list() + for key, val in params.items(): + if key == "diffpair_params0": + opamp_parameter_arr.append(closest_index(val, opamp_parameter_dict["half_diffpair_params"][0])) + elif key == "diffpair_params1": + opamp_parameter_arr.append(closest_index(val, opamp_parameter_dict["half_diffpair_params"][1])) + elif key == "diffpair_params2": + opamp_parameter_arr.append(closest_index(val, opamp_parameter_dict["half_diffpair_params"][2])) + elif key == "Diffpair_bias0": + opamp_parameter_arr.append(closest_index(val, opamp_parameter_dict["diffpair_bias"][0])) + elif key == "Diffpair_bias1": + opamp_parameter_arr.append(closest_index(val, opamp_parameter_dict["diffpair_bias"][1])) + elif key == "Diffpair_bias2": + opamp_parameter_arr.append(closest_index(val, opamp_parameter_dict["diffpair_bias"][2])) + elif key == "pamp_hparams0": + opamp_parameter_arr.append(closest_index(val, opamp_parameter_dict["half_common_source_params"][0])) + elif key == "pamp_hparams1": + opamp_parameter_arr.append(closest_index(val, opamp_parameter_dict["half_common_source_params"][1])) + elif key == "pamp_hparams2": + opamp_parameter_arr.append(closest_index(val, opamp_parameter_dict["half_common_source_params"][2])) + elif key == "bias0": + opamp_parameter_arr.append(closest_index(val, opamp_parameter_dict["half_common_source_bias"][0])) + elif key == "bias1": + opamp_parameter_arr.append(closest_index(val, opamp_parameter_dict["half_common_source_bias"][1])) + elif key == "bias2": + opamp_parameter_arr.append(closest_index(val, opamp_parameter_dict["half_common_source_bias"][2])) + elif key == "bias3": + opamp_parameter_arr.append(closest_index(val, opamp_parameter_dict["half_common_source_bias"][3])) + elif key == "half_pload1": + opamp_parameter_arr.append(closest_index(val, opamp_parameter_dict["half_pload"][0])) + elif key == "half_pload3": + opamp_parameter_arr.append(closest_index(val, opamp_parameter_dict["half_pload"][2])) + elif key == "mim_cap_rows": + opamp_parameter_arr.append(closest_index(val, opamp_parameter_dict["mim_cap_rows"])) + else: + raise ValueError("invalid key") + # this relies on the fact that the params dict should be in order + return np.array(opamp_parameter_arr) + paramss = [] params_id = list(params.keys()) @@ -46,7 +118,6 @@ inputparam[22] = paramsss[14] inputparam[25] = paramsss[15] - result = safe_single_build_and_simulation(inputparam, hardfail=True) print(result) diff --git a/openfasoc/generators/glayout/tapeout/tapeout_and_RL/sky130_nist_tapeout.py b/openfasoc/generators/glayout/tapeout/tapeout_and_RL/sky130_nist_tapeout.py index 0ecc9ea03..320f49141 100644 --- a/openfasoc/generators/glayout/tapeout/tapeout_and_RL/sky130_nist_tapeout.py +++ b/openfasoc/generators/glayout/tapeout/tapeout_and_RL/sky130_nist_tapeout.py @@ -1,16 +1,20 @@ import sys from os import path, rename, environ environ['OPENBLAS_NUM_THREADS'] = '1' +from pathlib import Path # path to glayout -sys.path.append(path.join(path.dirname(__file__), '../../')) - +sys.path.append(path.join(str(Path(__file__).resolve().parents[2]))) from gdsfactory.read.import_gds import import_gds from gdsfactory.components import text_freetype, rectangle from glayout.flow.pdk.util.comp_utils import prec_array, movey, align_comp_to_port, prec_ref_center from glayout.flow.pdk.util.port_utils import add_ports_perimeter, print_ports from gdsfactory.component import Component from glayout.flow.pdk.mappedpdk import MappedPDK -from glayout.flow.blocks.composite.opamp import opamp +try: + from glayout.flow.blocks.composite.opamp import opamp +except: + print('Regular opamp import failed! Using Fallback...') + from glayout.flow.blocks.opamp import opamp from glayout.flow.routing.L_route import L_route from glayout.flow.routing.straight_route import straight_route from glayout.flow.routing.c_route import c_route