From 49563124c7a1a9bf99966502b9653e324224fc33 Mon Sep 17 00:00:00 2001 From: labtob <70279295+alibillalhammoud@users.noreply.github.com> Date: Sun, 11 Aug 2024 16:55:49 -0400 Subject: [PATCH 1/9] RL code refactor --- openfasoc/MLoptimization/README.md | 4 + openfasoc/MLoptimization/eval.py | 16 +- openfasoc/MLoptimization/gen_spec.py | 4 +- openfasoc/MLoptimization/glayout_import.py | 5 + openfasoc/MLoptimization/model.py | 18 +- .../MLoptimization/recreate_results.bash | 101 +++++++++ openfasoc/MLoptimization/run_training.py | 38 ++-- openfasoc/MLoptimization/test1.py | 126 +++++++++++ openfasoc/MLoptimization/train.yaml | 200 ++++++++++++++++++ .../tapeout_and_RL/sky130_nist_tapeout.py | 97 +++++++-- 10 files changed, 544 insertions(+), 65 deletions(-) mode change 100755 => 100644 openfasoc/MLoptimization/gen_spec.py create mode 100644 openfasoc/MLoptimization/glayout_import.py create mode 100644 openfasoc/MLoptimization/recreate_results.bash create mode 100644 openfasoc/MLoptimization/test1.py create mode 100644 openfasoc/MLoptimization/train.yaml diff --git a/openfasoc/MLoptimization/README.md b/openfasoc/MLoptimization/README.md index aa9d5cf66..868385648 100644 --- a/openfasoc/MLoptimization/README.md +++ b/openfasoc/MLoptimization/README.md @@ -44,3 +44,7 @@ Please note that results vary greatly based on random seed and spec generation (

+ +## version +ray 2.34.0 and gym 0.26.2 will not work. instead you should use +ray 2.7.1 and gym 0.10.5 \ No newline at end of file diff --git a/openfasoc/MLoptimization/eval.py b/openfasoc/MLoptimization/eval.py index 1a2164837..0c5fe7a18 100644 --- a/openfasoc/MLoptimization/eval.py +++ b/openfasoc/MLoptimization/eval.py @@ -1,8 +1,4 @@ -# Add glayout to path -import sys -sys.path.append('../generators/gdsfactory-gen') -sys.path.append('../generators/gdsfactory-gen/tapeout_and_RL') - +import glayout_import #training import import numpy as np from ray.rllib.algorithms.ppo import PPO @@ -17,7 +13,7 @@ def unlookup(norm_spec, goal_spec): return spec def evaluate_model(checkpoint_dir: str = "./last_checkpoint"): - specs = yaml.safe_load(Path('newnew_eval_3.yaml').read_text()) + specs = yaml.safe_load(Path('eval.yaml').read_text()) #training set up env_config = { @@ -42,9 +38,9 @@ def evaluate_model(checkpoint_dir: str = "./last_checkpoint"): }, } - parser = argparse.ArgumentParser() - parser.add_argument('--checkpoint_dir', '-cpd', type=str) - args = parser.parse_args() + #parser = argparse.ArgumentParser() + #parser.add_argument('--checkpoint_dir', '-cpd', type=str) + #args = parser.parse_args() env = Envir(env_config=env_config) agent = PPO.from_checkpoint(checkpoint_dir) @@ -60,7 +56,7 @@ def evaluate_model(checkpoint_dir: str = "./last_checkpoint"): action_arr_comp = [] rollout_steps = 0 reached_spec = 0 - f = open("newnewnew_eval__3.txt", "a") + f = open("eval_1.txt", "a") while rollout_steps < 100: rollout_num = [] diff --git a/openfasoc/MLoptimization/gen_spec.py b/openfasoc/MLoptimization/gen_spec.py old mode 100755 new mode 100644 index 613368afa..13134a015 --- a/openfasoc/MLoptimization/gen_spec.py +++ b/openfasoc/MLoptimization/gen_spec.py @@ -6,8 +6,8 @@ def generate_random_specs(env, num_specs): specs_range = { - "gain_min" : [float(14003380.0), float(50003380.0)], - "FOM" : [float(4e11), float(4e11)] + "gain_min" : [float(10003380.0), float(35003380.0)], + "FOM" : [float(5e11), float(5e11)] } specs_range_vals = list(specs_range.values()) specs_valid = [] diff --git a/openfasoc/MLoptimization/glayout_import.py b/openfasoc/MLoptimization/glayout_import.py new file mode 100644 index 000000000..03913362d --- /dev/null +++ b/openfasoc/MLoptimization/glayout_import.py @@ -0,0 +1,5 @@ +import sys +sys.path.append('../generators/glayout/tapeout/tapeout_and_RL/') +#sys.path.append('../tapeout_and_RL') +#sys.path.append('../generators/gdsfactory-gen/') + diff --git a/openfasoc/MLoptimization/model.py b/openfasoc/MLoptimization/model.py index 93789d0d1..8d560d12f 100644 --- a/openfasoc/MLoptimization/model.py +++ b/openfasoc/MLoptimization/model.py @@ -1,8 +1,4 @@ -# Add glayout to path -import sys -sys.path.append('../generators/gdsfactory-gen') -sys.path.append('../generators/gdsfactory-gen/tapeout_and_RL') - +import glayout_import #training import import ray import ray.tune as tune @@ -12,14 +8,14 @@ import argparse def train_model(save_checkpoint_dir: str = "./last_checkpoint"): - ray.init(num_cpus=33, num_gpus=0,include_dashboard=True, ignore_reinit_error=True) + ray.init(num_cpus=31, num_gpus=0,include_dashboard=True, ignore_reinit_error=True) #configures training of the agent with associated hyperparameters config_train = { "env": Envir, "train_batch_size": 1000, "model":{"fcnet_hiddens": [64, 64]}, - "num_workers": 32, + "num_workers": 30, "env_config":{"generalize":True, "run_valid":False, "horizon":20}, } @@ -27,7 +23,7 @@ def train_model(save_checkpoint_dir: str = "./last_checkpoint"): #If checkpoint fails for any reason, training can be restored trials = tune.run( "PPO", #You can replace this string with ppo.PPOTrainer if you want / have customized it - name="new_train_with_new_params_3", # The name can be different. + name="new_train_1", # The name can be different. stop={"episode_reward_mean": 12, "training_iteration": 12}, checkpoint_freq=1, config=config_train, @@ -35,8 +31,8 @@ def train_model(save_checkpoint_dir: str = "./last_checkpoint"): trials.get_last_checkpoint().to_directory(save_checkpoint_dir) if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('--checkpoint_dir', '-cpd', type=str) - args = parser.parse_args() + #parser = argparse.ArgumentParser() + #parser.add_argument('--checkpoint_dir', '-cpd', type=str) + #args = parser.parse_args() train_model() diff --git a/openfasoc/MLoptimization/recreate_results.bash b/openfasoc/MLoptimization/recreate_results.bash new file mode 100644 index 000000000..bf36db6fe --- /dev/null +++ b/openfasoc/MLoptimization/recreate_results.bash @@ -0,0 +1,101 @@ +#!/bin/bash + +# this script will recreate the ICCAD paper RL results (using the default seed) + + + + +# ===================================================================== +# +# find most recent version of python +# +# Find all installed Python 3 versions and sort them in descending order +PYTHON_VERSIONS=$(compgen -c | grep -E '^python3\.[0-9]+$' | sort -V | tail -n 1) +# Extract the most recent version +MOST_RECENT_PYTHON=$(echo "$PYTHON_VERSIONS" | tail -n 1) +# Check if a Python version was found +if [ -z "$MOST_RECENT_PYTHON" ]; then + echo "No Python 3 versions found." + exit 1 +fi +# Print the most recent Python version +echo +echo "Currently using Python version: $MOST_RECENT_PYTHON" +echo +# Check if the most recent version is at least 3.10 +MINIMUM_VERSION="3.10" +if [[ "$(echo $MOST_RECENT_PYTHON | cut -d '.' -f2)" -lt "$(echo $MINIMUM_VERSION | cut -d '.' -f2)" ]]; then + echo "The most recent Python version ($MOST_RECENT_PYTHON) is less than $MINIMUM_VERSION. Please update your Python installation." + echo + exit 1 +fi +# Save the command to run the most recent Python version into a variable +PY_RUN=$MOST_RECENT_PYTHON + + + + + +# ===================================================================== +# +# ensure all python depedencies are installed +# + +# File containing the list of python dependencies +#requirements_file="requirements.txt" +requirements_file="donotdothischeck.txt" + +# Function to check if a Python package is installed +is_installed() { + $PY_RUN -m pip show "$1" &> /dev/null +} + +# Read the dependencies from requirements.txt and process each line +while IFS= read -r package || [ -n "$package" ]; do + # Remove leading/trailing whitespace + package=$(echo "$package" | xargs) + # Skip empty lines and comments + if [[ -z "$package" || "$package" == \#* ]]; then + continue + fi + # Extract the package name without extras and version specifiers for checking + package_name=$(echo "$package" | sed 's/\[.*\]//;s/[<>=].*//') + echo "Checking if $package is installed..." + if is_installed "$package_name"; then + echo "$package is already installed." + else + echo "$package is not installed. Installing..." + $PY_RUN -m pip install "$package" + # Check if the installation was successful + if is_installed "$package_name"; then + echo "$package installed successfully." + else + echo "Failed to install $package." + fi + fi + echo +done < "$requirements_file" +echo "Dependency check and package installations complete." + + + +# ===================================================================== +# +# setup and run the RL code +# + +# clean old files +#rm -rf *checkpoint +#rm record*.txt +#rm train.yaml +#rm eval.yaml +#rm eval*.txt + +# open gen_spec.py line 39, change the name of yaml file to train.yaml +$PY_RUN gen_spec.py --first_run +$PY_RUN model.py +# NOTE: this is done automatically when you do not specify "first_run" flag +# open gen_spec.py line 39, change the name of yaml file, and put the same name into eval.py line 20, +$PY_RUN gen_spec.py +$PY_RUN eval.py +# eval.py creates eval*.txt which shows how many specifications are reached diff --git a/openfasoc/MLoptimization/run_training.py b/openfasoc/MLoptimization/run_training.py index 781b5d177..0b1c28ed1 100644 --- a/openfasoc/MLoptimization/run_training.py +++ b/openfasoc/MLoptimization/run_training.py @@ -1,14 +1,11 @@ -# Add glayout to path -import sys -sys.path.append('../generators/gdsfactory-gen/tapeout_and_RL') - +import glayout_import #env import import gymnasium as gym from gymnasium import spaces from gymnasium.spaces import Discrete from gymnasium.wrappers import EnvCompatibility from ray.rllib.env.wrappers.multi_agent_env_compatibility import MultiAgentEnvCompatibility -from sky130_nist_tapeout import single_build_and_simulation +from sky130_nist_tapeout import safe_single_build_and_simulation import numpy as np import random import psutil @@ -48,7 +45,6 @@ def __init__(self, env_config): #data = np.load('./training_params.npy') #result = np.load('./training_results.npy') #self.result = result - self.epi_steps = 0 # design specs if self.generalize == True: @@ -66,20 +62,20 @@ def __init__(self, env_config): # param array params = { - "diffpair_params0" : [1, 8, 1], - "diffpair_params1" : [0.5, 2.1, 0.1], - "diffpair_params2" : [1, 9, 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, 8, 1], - "pamp_hparams1" : [0.5, 2.1, 0.1], - "pamp_hparams2" : [2, 11, 1], - "bias0" : [1, 8, 1], - "bias1" : [0.5, 2.1, 0.1], - "bias2" : [3, 13, 1], + "pamp_hparams0" : [1, 9, 1], + "pamp_hparams1" : [0.5, 2.1, 0.1], + "pamp_hparams2" : [2, 13, 1], + "bias0" : [1, 8, 1], + "bias1" : [0.5, 2.1, 0.1], + "bias2" : [3, 18, 1], "bias3" : [2, 4, 1], - "half_pload1": [3, 7, 1], + "half_pload1": [3, 10, 1], "half_pload3": [4, 9, 1], "mim_cap_rows" : [1, 4, 1], } @@ -107,7 +103,7 @@ def __init__(self, env_config): for spec in list(self.specs.values()): self.global_g.append(float(spec[self.fixed_goal_idx])) self.g_star = np.array(self.global_g) - self.global_g = np.array([60003380.0, 3e12]) + self.global_g = np.array([30003380.0, 1e12]) #objective number (used for validation)g self.obj_idx = 0 @@ -141,7 +137,7 @@ def reset(self, *, seed=None, options=None): self.specs_ideal_norm = self.lookup(self.specs_ideal, self.global_g) #initialize current parameters - self.cur_params_idx = np.array([3, 5, 7, 5, 4, 0, 3, 0, 2, 5, 15, 1, 0, 3, 4, 2]) + self.cur_params_idx = np.array([6, 2, 7, 6, 0, 5, 7, 0, 10, 6, 5, 13, 0, 6, 4, 2]) # param array self.cur_specs = self.update(self.cur_params_idx) cur_spec_norm = self.lookup(self.cur_specs, self.global_g) @@ -169,7 +165,7 @@ def step(self, action): reward = self.reward(self.cur_specs, self.specs_ideal) terminated = False #f = open("newnew_5.txt", "a") - f = open("record2.txt", "a") + f = open("record_2.txt", "a") #incentivize reaching goal state if(prevreward >= 2.0 and reward < 2.0): terminated = True @@ -247,7 +243,7 @@ def update(self, params_idx): params = np.array([self.params[i][params_idx[i]] for i in range(len(self.params_id))]) #run param vals and simulate - inputparam = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 5.0, 1.0, 16.0, 6.0, 2.0, 4.0, 0.0, 1.0, 0.0, 12.0, 12.0, 0.0, 2.0]) + inputparam = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 5.0, 1.0, 16.0, 6.0, 2.0, 4.0, 0.0, 0.5, 0.0, 12.0, 12.0, 0.0, 2.0]) inputparam[0:3] = params[0:3] inputparam[3:6] = params[3:6] @@ -256,7 +252,7 @@ def update(self, params_idx): inputparam[20] = params[13] inputparam[22] = params[14] inputparam[25] = params[15] - result = single_build_and_simulation(inputparam,-269) + result = safe_single_build_and_simulation(inputparam) specs = np.array([0.0 , 0.0]) specs[0] = result["ugb"] specs[1] = result["ugb"]/(result["Ibias_diffpair"]+result["Ibias_commonsource"]) diff --git a/openfasoc/MLoptimization/test1.py b/openfasoc/MLoptimization/test1.py new file mode 100644 index 000000000..ccb583fb1 --- /dev/null +++ b/openfasoc/MLoptimization/test1.py @@ -0,0 +1,126 @@ +import numpy as np +import glayout_import + +from sky130_nist_tapeout import safe_single_build_and_simulation +from sky130_nist_tapeout import opamp_parameters_serializer +#from tapeout_and_RL.sky130_nist_tapeout import single_build_and_simulation +#from tapeout_and_RL.sky130_nist_tapeout import opamp_parameters_serializer +import yaml +from pathlib import Path +import numpy as np + +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], + } +paramss = [] +params_id = list(params.keys()) + +#params_idx = np.array([1, 5, 3, 5, 2, 1, 6, 0, 6, 5, 5, 1, 1, 3, 2, 0]) + +#[ 6. 1. 4. 6. 2. 4. 7.2 1. 10. 3. 8. 2. 12. 3. +# 5. 1. 16. 6. 2. 4. 6. 1. 6. 12. 12. 3. 2. ] + +#[4. 1. 8. 6. 3. 3. 4. 0.5 4. 6. 2. 4. 2. 6. 8. 3. ] + +#[ 4. 1. 8. 6. 3. 3. 4. 0.5 4. 3. 6. 2. 4. 2. +# 5. 1. 16. 6. 2. 4. 6. 1. 8. 12. 12. 3. 2. ] + +#[4. 1. 8. 6. 3. 3. 4. 0.5 4. 6. 2. 4. 2. 6. 8. 3. ] + +#[ 7. , 0.7, 12. , 7. , 1. , 10. , 8. , 0.5, 12. , 3. , 7. , +# 1. , 12. , 2. , 5. , 1. , 16. , 6. , 2. , 4. , 9. , 0.5, +# 6. , 12. , 12. , 3. , 2. ] + +# [ 7. , 0.7, 8. , 7. , 1. , 8. , 8. , 0.5, 12. , 3. , 7. , +# 1. , 16. , 2. , 5. , 1. , 16. , 6. , 2. , 4. , 9. , 0.5, +# 8. , 12. , 12. , 3. , 2. ]) + +#params_idx = np.array([6, 2, 11, 6, 0, 7, 7, 0, 10, 6, 5, 9, 0, 6, 2, 2]) + +params_idx = np.array([6, 2, 7, 6, 0, 5, 7, 0, 10, 6, 5, 13, 0, 6, 4, 2]) + +# params_idx = np.array([5, 5, 3, 5, 2, 1, 6, 1, 8, 7, 15, 9, 1, 3, 2, 2]) + +for value in params.values(): + param_vec = np.arange(value[0], value[1], value[2]) + paramss.append(param_vec) + +paramsss = np.array([paramss[i][params_idx[i]] for i in range(len(params_id))]) +#param_val = np.array[OrderedDict(list(zip(self.params_id,params)))] + +#run param vals and simulate +#cur_specs = OrderedDict(sorted(self.sim_env.create_design_and_simulate(param_val[0])[1].items(), key=lambda k:k[0])) +#2.69966400e+07 + +#inputparam = np.array([ 9. , 2., 6. , 6., 2. , 4. , 6., 1. , 2. , 3. , 7. , 1 ,6. , 3. ,12. ,12. , 3. , 2. ]) +#[ 4. 1. 8. 6. 3. 3. 4. 0.5 4. 3. 6. 2. 4. 2. +# 5. 1. 16. 6. 2. 4. 6. 1. 8. 12. 12. 3. 2. ] + +#[4. 1. 8. 6. 3. 3. 4. 0.5 4. 6. 2. 4. 2. 6. 8. 3. ] + +inputparam = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 5.0, 1.0, 16.0, 6.0, 2.0, 4.0, 0.0, 0.5, 0.0, 12.0, 12.0, 0.0, 2.0]) +inputparam[0:3] = paramsss[0:3] +inputparam[3:6] = paramsss[3:6] +inputparam[6:9] = paramsss[6:9] +inputparam[10:14] = paramsss[9:13] +inputparam[20] = paramsss[13] +inputparam[22] = paramsss[14] +inputparam[25] = paramsss[15] + +# params = { +# "half_diffpair_params": (6, 1, 4), +# "diffpair_bias": (6, 2, 4), +# "half_common_source_params": (7.2, 1, 10, 3), +# "half_common_source_bias": (8, 2, 12, 3), +# "output_stage_params": (5, 1, 16), +# "output_stage_bias": (6, 2, 4), +# "mim_cap_size": (12, 12), +# "mim_cap_rows": 3, +# "rmult": 2 +# } +# numpy_params = opamp_parameters_serializer(**params) +#numpy_params[0:3] = paramsss[0:3] +#numpy_params[3:6] = paramsss[3:6] +#numpy_params[6:9] = paramsss[6:9] +#numpy_params[10:14] = paramsss[9:13] +#numpy_params[20] = paramsss[13] +# numpy_params[22] = paramsss[14] +# numpy_params[25] = paramsss[15] + +# print(numpy_params) +print(inputparam) + +#{'ugb': 2233790.0, 'dcGain': 65.19988, 'phaseMargin': 104.0, 'Ibias_diffpair': 1e-06, 'Ibias_commonsource': 2.0736e-06, 'Ibias_output': 9.35e-05, 'area': 47939.75594998075, 'power': 0.000353842085, 'noise': 5.22616086, 'bw_3db': 831.1834, 'power_twostage': 1.72420852e-05} +#726766657990.63 + +# supposed to be 10MHz +#numpy_params = np.array([ 7. , 0.7, 12. , 7. , 1. , 10. , 8. , 0.5, 12. , 3. , 7. , +# 1. , 12. , 2. , 5. , 1. , 16. , 6. , 2. , 4. , 9. , 0.5, +# 6. , 12. , 12. , 3. , 2. ]) +#{'ugb': 21067680.0, 'dcGain': 52.27519, 'phaseMargin': 96.0, 'Ibias_diffpair': 7.43008371e-06, 'Ibias_commonsource': 2.21861111e-05, 'Ibias_output': 9.35e-05, 'area': 42865.81769998964, 'power': 0.00049207212, 'noise': 4.18722441, 'bw_3db': 27197.53, 'power_twostage': 0.00015547212} +#711356747048.626 + +# supposed to be 25459060 +numpy_params = np.array([ 7. , 0.7, 8. , 7. , 1. , 8. , 8. , 0.5, 12. , 3. , 7. , + 1. , 16. , 2. , 5. , 1. , 16. , 6. , 2. , 4. , 9. , 0.5, + 8. , 12. , 12. , 3. , 2. ]) +result = safe_single_build_and_simulation(inputparam, hardfail=True) +# {'ugb': 13847390.0, 'dcGain': 50.5001, 'phaseMargin': 101.0, 'Ibias_diffpair': 6.19173642e-06, 'Ibias_commonsource': 1.54070216e-05, 'Ibias_output': 9.35e-05, 'area': 43918.335699987125, 'power': 0.000449201424, 'noise': 3.90373916, 'bw_3db': 25231.79, 'power_twostage': 0.000112601424} +# 641119734161.4553 +print(result) +print(result["ugb"]/(result["Ibias_diffpair"]+result["Ibias_commonsource"])) \ No newline at end of file diff --git a/openfasoc/MLoptimization/train.yaml b/openfasoc/MLoptimization/train.yaml new file mode 100644 index 000000000..cb3b7d386 --- /dev/null +++ b/openfasoc/MLoptimization/train.yaml @@ -0,0 +1,200 @@ +{'gain_min': [17090194.99554372, + 10984305.211848216, + 20053504.423596017, + 12976189.157424614, + 24326470.29417651, + 16614758.394137407, + 33885991.90088244, + 24294552.22901272, + 28738035.56465131, + 11591339.368499167, + 31958488.46862089, + 15544024.80657728, + 15149513.215502445, + 27673885.800500393, + 11672764.583840156, + 33688402.14780255, + 11900587.877020324, + 29088955.227047775, + 16042240.156555323, + 25007299.829085357, + 11767743.741556473, + 26889072.117443666, + 21748637.263493054, + 25419452.390491217, + 13495849.113006288, + 12326608.274902595, + 34251301.280750245, + 11019406.231670735, + 18445667.912573654, + 12219465.357591916, + 34416600.18777928, + 21049504.871381804, + 10458351.194655038, + 34035829.88434639, + 32468074.14915852, + 15099920.586221404, + 33814614.38533154, + 33244481.40777875, + 22760226.36875734, + 26359270.520485826, + 29720396.749431696, + 16816778.99788832, + 32151724.84805751, + 22628051.710884996, + 30499285.1270553, + 15331235.774977118, + 18651884.112132788, + 21219532.025170457, + 31954788.070722405, + 28645349.07311203, + 22745498.624895595, + 14810371.165483847, + 24165763.531959772, + 20446463.677116342, + 12759637.451458758, + 12288730.679502226, + 15389271.247741468, + 33835826.03447209, + 22452980.052944463, + 12724991.202638619, + 20193964.10649318, + 28496042.89249976, + 16634502.535836034, + 20198266.08878302, + 29114584.114452228, + 25424355.35771987, + 31707805.090082336, + 17317077.1745918, + 32903494.929625683, + 22092604.260551408, + 26777515.956465393, + 19401036.555276237, + 34717286.83561894, + 13680125.737745302, + 21630678.164861888, + 33150704.03529205, + 18204307.62331588, + 34245288.27348, + 21138909.53099878, + 13185873.658424318, + 14418194.723765042, + 23246632.98301909, + 17887636.136720534, + 29654059.506156836, + 21025461.959095426, + 14244096.673632663, + 16830633.025223523, + 29737919.980511952, + 26853920.94271256, + 19657571.234978635, + 28781225.1670665, + 21099575.171396002, + 24299835.513481088, + 21555701.88809367, + 22217625.330910273, + 29419937.982774194, + 12353441.5186, + 16065924.94925332, + 14169462.631807983, + 30946980.400972273], + 'FOM': [500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0, + 500000000000.0]} \ No newline at end of file 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 a3d68084e..7ea31755f 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,5 +1,6 @@ import sys from os import path, rename + # path to glayout sys.path.append(path.join(path.dirname(__file__), '../../')) @@ -37,7 +38,11 @@ from glayout.flow.pdk.util.snap_to_grid import component_snap_to_grid from glayout.flow.pdk.util.component_array_create import write_component_matrix import re +import pickle +import tempfile +import subprocess +global _TAPEOUT_AND_RL_DIR_PATH_ global _GET_PARAM_SET_LENGTH_ global _TAKE_OUTPUT_AT_SECOND_STAGE_ global PDK_ROOT @@ -46,9 +51,10 @@ __SMALL_PAD_ = True __NO_LVT_GLOBAL_ = False _GET_PARAM_SET_LENGTH_ = False -_TAKE_OUTPUT_AT_SECOND_STAGE_ = False +_TAKE_OUTPUT_AT_SECOND_STAGE_ = True PDK_ROOT = "/usr/bin/miniconda3/share/pdk/" - +_TAPEOUT_AND_RL_DIR_PATH_ = Path(__file__).resolve().parent +#print(_TAPEOUT_AND_RL_DIR_PATH_) # ====Build Opamp==== @@ -451,7 +457,7 @@ def get_small_parameter_list(test_mode = False, clarge=False) -> np.array: # if test_mode create a failed attempt (to test error handling) if test_mode: short_list[index] = opamp_parameters_serializer(mim_cap_rows=-1) - short_list[index+1] = opamp_parameters_serializer(mim_cap_rows=0) + short_list[index+1] = opamp_parameters_serializer(mim_cap_rows=2) global _GET_PARAM_SET_LENGTH_ if _GET_PARAM_SET_LENGTH_: print("created parameter set of length: "+str(len(short_list))) @@ -571,6 +577,7 @@ def __run_single_brtfrc(index, parameters_ele, save_gds_dir, temperature_info: t # pass pdk as global var to avoid pickling issues global pdk global PDK_ROOT + global _TAPEOUT_AND_RL_DIR_PATH_ # generate layout destination_gds_copy = save_gds_dir / (str(index)+".gds") sky130pdk = pdk @@ -587,14 +594,14 @@ def __run_single_brtfrc(index, parameters_ele, save_gds_dir, temperature_info: t destination_gds_copy.write_bytes(tmp_gds_path.read_bytes()) extractbash_template=str() #import pdb; pdb.set_trace() - with open("extract.bash.template","r") as extraction_script: + with open(str(_TAPEOUT_AND_RL_DIR_PATH_)+"/extract.bash.template","r") as extraction_script: extractbash_template = extraction_script.read() extractbash_template = extractbash_template.replace("@@PDK_ROOT",PDK_ROOT).replace("@@@PAROPT","noparasitics" if noparasitics else "na") with open(str(tmpdirname)+"/extract.bash","w") as extraction_script: extraction_script.write(extractbash_template) #copyfile("extract.bash",str(tmpdirname)+"/extract.bash") - copyfile("opamp_perf_eval.sp",str(tmpdirname)+"/opamp_perf_eval.sp") - copytree("sky130A",str(tmpdirname)+"/sky130A") + copyfile(str(_TAPEOUT_AND_RL_DIR_PATH_)+"/opamp_perf_eval.sp",str(tmpdirname)+"/opamp_perf_eval.sp") + copytree(str(_TAPEOUT_AND_RL_DIR_PATH_)+"/sky130A",str(tmpdirname)+"/sky130A") # extract layout Popen(["bash","extract.bash", tmp_gds_path, opamp_v.name],cwd=tmpdirname).wait() print("Running simulation at temperature: " + str(temperature_info[0]) + "C") @@ -652,9 +659,9 @@ def brute_force_full_layout_and_PEXsim(sky130pdk: MappedPDK, parameter_list: np. pdk = sky130pdk with Pool(128) as cores: if saverawsims: - results = np.array(cores.starmap(__run_single_brtfrc, zip(count(0), parameter_list, repeat(save_gds_dir), repeat(temperature_info), repeat(cload), repeat(noparasitics), count(0))),np.float64) + results = np.array(cores.starmap(safe_single_build_and_simulation, zip(parameter_list, repeat(temperature_info[0]), count(0), repeat(cload), repeat(noparasitics),repeat(False), count(0), repeat(save_gds_dir), repeat(False))),np.float64) else: - results = np.array(cores.starmap(__run_single_brtfrc, zip(count(0), parameter_list, repeat(save_gds_dir), repeat(temperature_info), repeat(cload), repeat(noparasitics))),np.float64) + results = np.array(cores.starmap(safe_single_build_and_simulation, zip(parameter_list, repeat(temperature_info[0]), repeat(None), repeat(cload), repeat(noparasitics),repeat(False), count(0), repeat(save_gds_dir), repeat(False))),np.float64) # undo pdk modification sky130pdk.default_decorator = add_npc_decorator return results @@ -674,7 +681,7 @@ def get_training_data(test_mode: bool=True, temperature_info: tuple[int,str]=(25 #util function for pure simulation. sky130 is imported automatically -def single_build_and_simulation(parameters: np.array, temp: int=25, output_dir: Optional[Union[str,Path]] = None, cload: float=0.0, noparasitics: bool=False,hardfail=False) -> dict: +def single_build_and_simulation(parameters: np.array, temp: int=25, output_dir: Optional[Union[str,Path]] = None, cload: float=0.0, noparasitics: bool=False,hardfail=False, index: int = 12345678987654321, save_gds_dir="./", return_dict: bool=True) -> dict: """Builds, extract, and simulates a single opamp saves opamp gds in current directory with name 12345678987654321.gds returns -987.654321 for all values IF phase margin < 45 @@ -690,16 +697,16 @@ def single_build_and_simulation(parameters: np.array, temp: int=25, output_dir: temperature_info[1] = "cryo model" temperature_info = tuple(temperature_info) # run single build - save_gds_dir = Path('./').resolve() - index = 12345678987654321 + save_gds_dir = Path(save_gds_dir).resolve() # pass pdk as global var to avoid pickling issues global pdk pdk = sky130_mapped_pdk results = __run_single_brtfrc(index, parameters, temperature_info=temperature_info, save_gds_dir=save_gds_dir, output_dir=output_dir, cload=cload, noparasitics=noparasitics, hardfail=hardfail) - results = opamp_results_de_serializer(results) - if results["phaseMargin"] < 45: - for key in results: - results[key] = -987.654321 + if return_dict: # default behavoir will return a dictionary and filter phase margin below 45 + results = opamp_results_de_serializer(results) + if results["phaseMargin"] < 45: + for key in results: + results[key] = -987.654321 return results @@ -1122,6 +1129,43 @@ def create_opamp_matrix(save_dir_name: str, params: np.array, results: Optional[ +# ================ safe single build and sim ================== + + +class safe_single_build_and_simulation_helperclass: + def __init__(self, *args, **kwargs): + self.passed_args = args + self.passed_kwargs = kwargs + # create and run using a temp dir to pass information + with tempfile.TemporaryDirectory() as temp_dir: + # Define the path for the pickle file + pickle_file_path = Path(temp_dir).resolve() / 'class_instance.pkl' + # Serialize the instance to the pickle file + with open(pickle_file_path, 'wb') as f: + pickle.dump(self, f) + # Define and run the subprocess + python_executable = sys.executable + command = [python_executable, "sky130_nist_tapeout.py", "safe_single_build_and_sim", "--class_pickle_file", pickle_file_path] + #process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + subprocess.Popen(command,cwd=str(_TAPEOUT_AND_RL_DIR_PATH_)).wait() + # load the result back from the same pickle file which was passed + with open(pickle_file_path, 'rb') as pckfile: + restored_run = pickle.load(pckfile) + # if restored_run does not have a results attribute, that means execute did not run properly in the other session + # single build and sim probably failed + try: + self.results = restored_run.results + except AttributeError: + raise RuntimeError("\nAn error silently occurred somewhere before this point\n") + + + def execute(self): + self.results = single_build_and_simulation(*self.passed_args,**self.passed_kwargs) + +# same as calling single_build_and_simulation, but runs in a subprocess +def safe_single_build_and_simulation(*args, **kwargs) -> dict: + return safe_single_build_and_simulation_helperclass(*args,**kwargs).results + if __name__ == "__main__": @@ -1181,6 +1225,10 @@ def create_opamp_matrix(save_dir_name: str, params: np.array, results: Optional[ create_opamp_matrix_parser.add_argument("--indices", type=int, nargs="+", help="list of int indices to pick from the opamp param.npy and add to the matrix (default: the entire params list)") create_opamp_matrix_parser.add_argument("--output_dir", type=Path, default="./opampmatrix", help="Directory for output files (default: ./opampmatrix)") + # Hidden subparser used for safe_single_build_and_simulation + safe_single_build_and_sim = subparsers.add_parser("safe_single_build_and_sim") + safe_single_build_and_sim.add_argument("--class_pickle_file",type=Path,help="see safe_single_build_and_simulation") + for prsr in [get_training_data_parser,gen_opamp_parser,test,create_opamp_matrix_parser]: prsr.add_argument("--no_lvt",action="store_true",help="do not place any low threshold voltage transistors.") prsr.add_argument("--PDK_ROOT",type=Path,default="/usr/bin/miniconda3/share/pdk/",help="path to the sky130 PDK library") @@ -1217,8 +1265,8 @@ def create_opamp_matrix(save_dir_name: str, params: np.array, results: Optional[ elif args.mode=="get_training_data": if args.get_tset_len: _GET_PARAM_SET_LENGTH_ = True - if args.output_second_stage: - _TAKE_OUTPUT_AT_SECOND_STAGE_ = True + if not args.output_second_stage: + _TAKE_OUTPUT_AT_SECOND_STAGE_ = False # Call the get_training_data function with test_mode flag parameter_array = None if args.nparray is not None: @@ -1251,8 +1299,8 @@ def create_opamp_matrix(save_dir_name: str, params: np.array, results: Optional[ opamp_comp_final.write_gds(args.output_gds) elif args.mode == "test": - if args.output_second_stage: - _TAKE_OUTPUT_AT_SECOND_STAGE_ = True + if not args.output_second_stage:# defaults to True, so we only need to change in the False condition + _TAKE_OUTPUT_AT_SECOND_STAGE_ = False params = { "half_diffpair_params": (6, 1, 4), "diffpair_bias": (6, 2, 4), @@ -1264,7 +1312,7 @@ def create_opamp_matrix(save_dir_name: str, params: np.array, results: Optional[ "mim_cap_rows": 3, "rmult": 2 } - results = single_build_and_simulation(opamp_parameters_serializer(**params), temperature_info[0], args.output_dir, cload=args.cload, noparasitics=args.noparasitics, hardfail=True) + results = safe_single_build_and_simulation(opamp_parameters_serializer(**params), temperature_info[0], args.output_dir, cload=args.cload, noparasitics=args.noparasitics, hardfail=True) print(results) elif args.mode =="create_opamp_matrix": @@ -1277,7 +1325,13 @@ def create_opamp_matrix(save_dir_name: str, params: np.array, results: Optional[ else: indices = None create_opamp_matrix(args.output_dir,params,results,indices) - + + elif args.mode=="safe_single_build_and_sim": + with open(args.class_pickle_file, 'rb') as pckfile: + restored_run = pickle.load(pckfile) + restored_run.execute() + with open(args.class_pickle_file, 'wb') as pckfile: + pickle.dump(restored_run, pckfile) elif args.mode == "gen_opamps": global usepdk @@ -1299,3 +1353,4 @@ def create_func(argnparray, indx: int): end_watch = time.time() print("\ntotal runtime was "+str((end_watch-start_watch)/3600) + " hours\n") + From 7e3a9ea61fa6fd041a4c7822c562599437b64144 Mon Sep 17 00:00:00 2001 From: labtob <70279295+alibillalhammoud@users.noreply.github.com> Date: Sun, 11 Aug 2024 17:14:42 -0400 Subject: [PATCH 2/9] ML readme update --- openfasoc/MLoptimization/README.md | 7 +- openfasoc/MLoptimization/gen_spec.py | 8 +- .../mean_reward_versus_step.png | Bin 50214 -> 0 bytes ...{recreate_results.bash => quickstart.bash} | 11 +- openfasoc/MLoptimization/requirements.txt | 344 ++++++++++++++++++ openfasoc/MLoptimization/sample_spec.yaml | 100 ----- openfasoc/MLoptimization/train.yaml | 200 ---------- .../flow/blocks/opamp/opamp_twostage.py | 3 +- 8 files changed, 361 insertions(+), 312 deletions(-) delete mode 100644 openfasoc/MLoptimization/mean_reward_versus_step.png rename openfasoc/MLoptimization/{recreate_results.bash => quickstart.bash} (87%) create mode 100644 openfasoc/MLoptimization/requirements.txt delete mode 100644 openfasoc/MLoptimization/sample_spec.yaml delete mode 100644 openfasoc/MLoptimization/train.yaml diff --git a/openfasoc/MLoptimization/README.md b/openfasoc/MLoptimization/README.md index 868385648..74d3cf91c 100644 --- a/openfasoc/MLoptimization/README.md +++ b/openfasoc/MLoptimization/README.md @@ -1,6 +1,9 @@ # Machine Learning Optimization Code for reinforcement learning loop with openfasoc generators for optimizing metrics +## Quick Start +run `bash quickstart.bash` to get an example RL run optimizing opamps at room temperature. + ## Code Setup The code is setup as follows: @@ -45,6 +48,4 @@ Please note that results vary greatly based on random seed and spec generation (

-## version -ray 2.34.0 and gym 0.26.2 will not work. instead you should use -ray 2.7.1 and gym 0.10.5 \ No newline at end of file + diff --git a/openfasoc/MLoptimization/gen_spec.py b/openfasoc/MLoptimization/gen_spec.py index 13134a015..1ca350646 100644 --- a/openfasoc/MLoptimization/gen_spec.py +++ b/openfasoc/MLoptimization/gen_spec.py @@ -28,10 +28,12 @@ def generate_random_specs(env, num_specs): def main(): parser = argparse.ArgumentParser() - parser.add_argument('--num_specs', type=str) + #parser.add_argument('--num_specs', type=str) + parser.add_argument('--first_run',action='store_true', help='Indicate whether this is the first run of the script.') + # first_run change the name of yaml file to train.yaml args = parser.parse_args() - - generate_random_specs("train.yaml", int(100)) + yaml_file_name = "train.yaml" if args.first_run else "eval.yaml" + generate_random_specs(yaml_file_name, int(100)) if __name__=="__main__": main() diff --git a/openfasoc/MLoptimization/mean_reward_versus_step.png b/openfasoc/MLoptimization/mean_reward_versus_step.png deleted file mode 100644 index 24dca66ae25c73078cdf964e676a756cf8b5fc8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50214 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 Date: Mon, 12 Aug 2024 02:49:48 -0400 Subject: [PATCH 3/9] look for PDK_ROOT in env --- openfasoc/MLoptimization/requirements.txt | 373 ++---------------- .../tapeout_and_RL/sky130_nist_tapeout.py | 19 +- 2 files changed, 45 insertions(+), 347 deletions(-) diff --git a/openfasoc/MLoptimization/requirements.txt b/openfasoc/MLoptimization/requirements.txt index 138fb679d..a6850e6ea 100644 --- a/openfasoc/MLoptimization/requirements.txt +++ b/openfasoc/MLoptimization/requirements.txt @@ -1,344 +1,35 @@ -absl-py==2.1.0 -accelerate==0.33.0 -aiohappyeyeballs==2.3.4 -aiohttp==3.10.0 -aiohttp-cors==0.7.0 -aiosignal==1.3.1 -annotated-types==0.5.0 -antlr4-python3-runtime==4.9.3 -anyio==3.7.1 -argon2-cffi==21.3.0 -argon2-cffi-bindings==21.2.0 -arrow==1.2.3 -asgiref==3.8.1 -asttokens==2.2.1 -async-lru==2.0.4 -async-timeout==4.0.3 -attrs==23.1.0 -auto_gptq==0.7.1 -autograd==1.6.2 -Babel==2.12.1 -backcall==0.2.0 -backoff==2.2.1 -bcrypt==4.2.0 -beautifulsoup4==4.12.2 -bitsandbytes==0.42.0 -bleach==6.0.0 -bokeh==3.2.1 -build==1.2.1 -cachetools==5.4.0 -certifi==2023.7.22 -cffi==1.15.1 -chardet==5.2.0 -charset-normalizer==3.2.0 -chroma-hnswlib==0.7.6 -chromadb==0.5.5 -click==8.0.4 -cloudpickle==3.0.0 -cmd2==2.4.3 -colorama==0.4.6 -colorcet==3.0.1 -coloredlogs==15.0.1 -colorful==0.5.6 -comm==0.1.4 -contourpy==1.1.0 -cycler==0.11.0 -dataclasses-json==0.6.7 -datasets==2.20.0 -debugpy==1.6.7 -decorator==5.1.1 -deepdiff==7.0.1 -defusedxml==0.7.1 -Deprecated==1.2.14 -dill==0.3.8 -distlib==0.3.8 -dm-tree==0.1.8 -docstring_parser==0.16 -emoji==2.12.1 -exceptiongroup==1.1.2 -executing==1.2.0 -Farama-Notifications==0.0.4 -fastapi==0.101.0 -fastjsonschema==2.18.0 -filelock==3.15.4 -filetype==1.2.0 -flatbuffers==24.3.25 -flatdict==4.0.1 -fonttools==4.42.0 -fqdn==1.5.1 -freetype-py==2.4.0 -frozenlist==1.4.1 -fsspec==2024.5.0 -future==0.18.3 gdsfactory==7.7.0 -gdstk==0.9.42 -gekko==1.2.1 -gf180==0.0.2 -gmsh==4.11.1 -google-api-core==2.19.1 -google-auth==2.32.0 -googleapis-common-protos==1.63.2 -greenlet==3.0.3 -grpcio==1.43.0 +prettyprint +prettyprinttree +nltk +torch +transformers +langchain +langchain_community +chromadb +ollama +klayout +unstructured +unstructured[md] +sentence-transformers +peft +accelerate +bitsandbytes +safetensors +requests +datasets +optimum +trl +langchain_huggingface +tensorboard +ray==2.7.1 +ray[default] gym==0.26.2 -gym-notices==0.0.8 gymnasium==0.28.1 -h11==0.14.0 -holoviews==1.17.0 -httpcore==1.0.5 -httptools==0.6.0 -httpx==0.27.0 -huggingface-hub==0.24.5 -humanfriendly==10.0 -idna==3.4 -imageio==2.31.1 -importlib_metadata==8.0.0 -importlib_resources==6.4.0 -ipyevents==2.0.1 -ipykernel==6.25.1 -ipympl==0.9.3 -ipython==8.14.0 -ipython-genutils==0.2.0 -ipywidgets==7.7.3 -isoduration==20.11.0 -jax-jumpy==1.0.0 -jedi==0.19.0 -Jinja2==3.1.2 -joblib==1.3.1 -json5==0.9.14 -jsonpatch==1.33 -jsonpath-python==1.0.6 -jsonpointer==2.4 -jsonschema==4.19.0 -jsonschema-specifications==2023.7.1 -jupyter-events==0.7.0 -jupyter-lsp==2.2.0 -jupyter_client==8.3.0 -jupyter_core==5.3.1 -jupyter_server==2.7.0 -jupyter_server_terminals==0.4.4 -jupyterlab==4.0.4 -jupyterlab-pygments==0.2.2 -jupyterlab-widgets==1.1.5 -jupyterlab_server==2.24.0 -jupytext==1.15.0 -kiwisolver==1.4.4 -klayout==0.28.10 -kubernetes==30.1.0 -kweb==0.0.11 -langchain==0.2.12 -langchain-community==0.2.11 -langchain-core==0.2.28 -langchain-huggingface==0.0.3 -langchain-text-splitters==0.2.2 -langdetect==1.0.9 -langsmith==0.1.96 -lazy_loader==0.3 -linkify-it-py==2.0.2 -loguru==0.7.0 -lxml==5.2.2 -lz4==4.3.3 -mapbox-earcut==1.0.1 -Markdown==3.4.4 -markdown-it-py==3.0.0 -MarkupSafe==2.1.3 -marshmallow==3.21.3 -matplotlib==3.7.2 -matplotlib-inline==0.1.6 -mdit-py-plugins==0.4.0 -mdurl==0.1.2 -memray==1.13.4 -meshio==5.3.4 -mistune==3.0.1 -mmh3==4.1.0 -monotonic==1.6 -mpmath==1.3.0 -msgpack==1.0.8 -multidict==6.0.5 -multiprocess==0.70.16 -mypy-extensions==1.0.0 -natsort==8.4.0 -nbclient==0.8.0 -nbconvert==7.7.3 -nbformat==5.9.2 -nest-asyncio==1.6.0 -networkx==3.1 -nltk==3.8.1 -notebook==7.0.2 -notebook_shim==0.2.3 -numpy==1.25.2 -nvidia-cublas-cu12==12.1.3.1 -nvidia-cuda-cupti-cu12==12.1.105 -nvidia-cuda-nvrtc-cu12==12.1.105 -nvidia-cuda-runtime-cu12==12.1.105 -nvidia-cudnn-cu12==9.1.0.70 -nvidia-cufft-cu12==11.0.2.54 -nvidia-curand-cu12==10.3.2.106 -nvidia-cusolver-cu12==11.4.5.107 -nvidia-cusparse-cu12==12.1.0.106 -nvidia-nccl-cu12==2.20.5 -nvidia-nvjitlink-cu12==12.6.20 -nvidia-nvtx-cu12==12.1.105 -oauthlib==3.2.2 -ollama==0.3.1 -omegaconf==2.3.0 -onnxruntime==1.16.3 -opencensus==0.11.4 -opencensus-context==0.1.3 -opentelemetry-api==1.26.0 -opentelemetry-exporter-otlp==1.26.0 -opentelemetry-exporter-otlp-proto-common==1.26.0 -opentelemetry-exporter-otlp-proto-grpc==1.26.0 -opentelemetry-exporter-otlp-proto-http==1.26.0 -opentelemetry-instrumentation==0.47b0 -opentelemetry-instrumentation-asgi==0.47b0 -opentelemetry-instrumentation-fastapi==0.47b0 -opentelemetry-proto==1.26.0 -opentelemetry-sdk==1.26.0 -opentelemetry-semantic-conventions==0.47b0 -opentelemetry-util-http==0.47b0 -optimum==1.21.2 -ordered-set==4.1.0 -orjson==3.10.6 -overrides==7.4.0 -packaging==24.1 -pandas==2.0.3 -pandocfilters==1.5.0 -panel==1.2.1 -param==1.13.0 -parso==0.8.3 -peft==0.12.0 -pexpect==4.8.0 -pickleshare==0.7.5 -Pillow==10.0.0 -platformdirs==3.10.0 -ply==3.11 -posthog==3.5.0 -prettyprint==0.1.5 -PrettyPrintTree==2.0.0 -prometheus-client==0.17.1 -prompt-toolkit==3.0.39 -proto-plus==1.24.0 -protobuf==3.20.3 -psutil==5.9.5 -ptyprocess==0.7.0 -pure-eval==0.2.2 -py-spy==0.3.14 -pyarrow==17.0.0 -pyarrow-hotfix==0.6 -pyasn1==0.6.0 -pyasn1_modules==0.4.0 -pycparser==2.21 -pyct==0.5.0 -pydantic==2.8.2 -pydantic-extra-types==2.9.0 -pydantic-settings==2.4.0 -pydantic_core==2.20.1 -pyglet==1.5.27 -Pygments==2.16.1 -pygmsh==7.1.17 -pyparsing==3.0.9 -pypdf==4.3.1 -pyperclip==1.9.0 -PyPika==0.48.9 -pypng==0.20220715.0 -pyproject_hooks==1.1.0 -PySpice==1.5 -python-dateutil==2.8.2 -python-dotenv==1.0.0 -python-iso639==2024.4.27 -python-json-logger==2.0.7 -python-magic==0.4.27 -pytz==2023.3 -pyviz-comms==2.3.2 -PyWavelets==1.4.1 -PyYAML==6.0.1 -pyzmq==25.1.0 -qrcode==7.4.2 -rapidfuzz==3.9.5 -ray==2.7.1 -ray-cpp==2.34.0 -rectpack==0.2.2 -referencing==0.30.2 -regex==2024.7.24 -requests==2.32.3 -requests-oauthlib==2.0.0 -requests-toolbelt==1.0.0 -rfc3339-validator==0.1.4 -rfc3986-validator==0.1.1 -rich==13.5.2 -rouge==1.0.1 -rpds-py==0.9.2 -rsa==4.9 -safetensors==0.4.3 -scikit-fem==8.1.0 -scikit-image==0.21.0 -scikit-learn==1.3.0 -scipy==1.11.1 -seaborn==0.12.2 -Send2Trash==1.8.2 -sentence-transformers==3.0.1 -sentencepiece==0.2.0 -shapely==2.0.1 -shellingham==1.5.4 -shtab==1.7.1 -six==1.16.0 -sky130==0.7.1 -smart-open==7.0.4 -sniffio==1.3.0 -soupsieve==2.4.1 -SQLAlchemy==2.0.31 -stack-data==0.6.2 -starlette==0.27.0 -sympy==1.13.1 -tabulate==0.9.0 -tenacity==8.5.0 -tensorboard==2.17.0 -tensorboard-data-server==0.7.2 -tensorboardX==2.6.2.2 -terminado==0.17.1 -textual==0.75.1 -threadpoolctl==3.2.0 -tifffile==2023.7.18 -tinycss2==1.2.1 -tokenizers==0.19.1 -toml==0.10.2 -tomli==2.0.1 -toolz==0.12.0 -torch==2.4.0 -tornado==6.3.2 -tqdm==4.66.4 -traitlets==5.9.0 -transformers==4.42.4 -triangle==20220202 -trimesh==3.23.1 -triton==3.0.0 -trl==0.9.6 -typer==0.12.3 -types-PyYAML==6.0.12.11 -typing-inspect==0.9.0 -typing_extensions==4.12.2 -tyro==0.8.5 -tzdata==2023.3 -uc-micro-py==1.0.2 -unstructured==0.15.0 -unstructured-client==0.25.1 -uri-template==1.3.0 -urllib3==2.0.4 -uvicorn==0.23.2 -uvloop==0.17.0 -virtualenv==20.26.3 -watchdog==3.0.0 -watchfiles==0.19.0 -wcwidth==0.2.6 -webcolors==1.13 -webencodings==0.5.1 -websocket-client==1.6.1 -websockets==11.0.3 -Werkzeug==3.0.3 -widgetsnbextension==3.6.5 -wrapt==1.16.0 -xxhash==3.4.1 -xyzservices==2023.7.0 -yarl==1.9.4 -zipp==3.19.2 +scikit-learn +scikit-image +scipy +seaborn +matplotlib +lz4 +async-timeout 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 7ea31755f..cf9978b34 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,5 +1,5 @@ import sys -from os import path, rename +from os import path, rename, environ # path to glayout sys.path.append(path.join(path.dirname(__file__), '../../')) @@ -52,7 +52,12 @@ __NO_LVT_GLOBAL_ = False _GET_PARAM_SET_LENGTH_ = False _TAKE_OUTPUT_AT_SECOND_STAGE_ = True -PDK_ROOT = "/usr/bin/miniconda3/share/pdk/" + +if 'PDK_ROOT' in environ: + PDK_ROOT = Path(environ['PDK_ROOT']).resolve() +else: + PDK_ROOT = "/usr/bin/miniconda3/share/pdk/" + _TAPEOUT_AND_RL_DIR_PATH_ = Path(__file__).resolve().parent #print(_TAPEOUT_AND_RL_DIR_PATH_) # ====Build Opamp==== @@ -1145,7 +1150,7 @@ def __init__(self, *args, **kwargs): pickle.dump(self, f) # Define and run the subprocess python_executable = sys.executable - command = [python_executable, "sky130_nist_tapeout.py", "safe_single_build_and_sim", "--class_pickle_file", pickle_file_path] + command = [python_executable, "sky130_nist_tapeout.py", "safe_single_build_and_sim", "--class_pickle_file", pickle_file_path,"--PDK_ROOT",PDK_ROOT] #process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) subprocess.Popen(command,cwd=str(_TAPEOUT_AND_RL_DIR_PATH_)).wait() # load the result back from the same pickle file which was passed @@ -1229,7 +1234,7 @@ def safe_single_build_and_simulation(*args, **kwargs) -> dict: safe_single_build_and_sim = subparsers.add_parser("safe_single_build_and_sim") safe_single_build_and_sim.add_argument("--class_pickle_file",type=Path,help="see safe_single_build_and_simulation") - for prsr in [get_training_data_parser,gen_opamp_parser,test,create_opamp_matrix_parser]: + for prsr in [get_training_data_parser,gen_opamp_parser,test,create_opamp_matrix_parser,safe_single_build_and_sim]: prsr.add_argument("--no_lvt",action="store_true",help="do not place any low threshold voltage transistors.") prsr.add_argument("--PDK_ROOT",type=Path,default="/usr/bin/miniconda3/share/pdk/",help="path to the sky130 PDK library") for prsr in [gen_opamp_parser,create_opamp_matrix_parser]: @@ -1240,11 +1245,13 @@ def safe_single_build_and_simulation(*args, **kwargs) -> dict: if args.mode in ["gen_opamps","create_opamp_matrix"]: __SMALL_PAD_ = not args.big_pad - if args.mode in ["get_training_data","test","gen_opamps","create_opamp_matrix"]: + if args.mode in ["get_training_data","test","gen_opamps","create_opamp_matrix","safe_single_build_and_sim"]: __NO_LVT_GLOBAL_ = args.no_lvt PDK_ROOT = Path(args.PDK_ROOT).resolve() + if 'PDK_ROOT' in environ: + PDK_ROOT = Path(environ['PDK_ROOT']).resolve() if not(PDK_ROOT.is_dir()): - raise ValueError("PDK_ROOT is not a valid directory\n") + raise ValueError("PDK_ROOT "+str(PDK_ROOT)+" is not a valid directory\n") PDK_ROOT = str(PDK_ROOT) # Simulation Temperature information From 5142004e7c5a06f7c11aa37dd226dc9066277edf Mon Sep 17 00:00:00 2001 From: labtob <70279295+alibillalhammoud@users.noreply.github.com> Date: Mon, 12 Aug 2024 20:45:05 -0400 Subject: [PATCH 4/9] reqs update --- openfasoc/MLoptimization/README.md | 11 +++--- openfasoc/MLoptimization/quickstart.bash | 36 +++++++++---------- openfasoc/MLoptimization/requirements.txt | 28 +++++++-------- .../tapeout_and_RL/sky130_nist_tapeout.py | 28 +++++++++++++-- 4 files changed, 62 insertions(+), 41 deletions(-) diff --git a/openfasoc/MLoptimization/README.md b/openfasoc/MLoptimization/README.md index 74d3cf91c..7e95dc428 100644 --- a/openfasoc/MLoptimization/README.md +++ b/openfasoc/MLoptimization/README.md @@ -1,8 +1,11 @@ # Machine Learning Optimization Code for reinforcement learning loop with openfasoc generators for optimizing metrics +## Supported Versions +Please note that this program has only been tested with python3.11 + ## Quick Start -run `bash quickstart.bash` to get an example RL run optimizing opamps at room temperature. +run `bash quickstart.bash` to get an example RL run optimizing opamps. ## Code Setup The code is setup as follows: @@ -18,13 +21,13 @@ Make sure that you have OpenAI Gym and Ray installed. To do this, run the follow To generate the design specifications that the agent trains on, run: ``` -python3.10 gen_specs.py +python3.11 gen_specs.py ``` The result is a yaml file dumped to the ../generators/gdsfactory-gen/. To train the agent, open ipython from the top level directory and then: ``` -python3.10 model.py +python3.11 model.py ``` The training checkpoints will be saved in your home directory under ray\_results. Tensorboard can be used to load reward and loss plots using the command: @@ -36,7 +39,7 @@ tensorboard --logdir path/to/checkpoint The evaluation script takes the trained agent and gives it new specs that the agent has never seen before. To generate new design specs, run the gen_specs.py file again with your desired number of specs to validate on. To run validation: ``` -python3.10 eval.py +python3.11 eval.py ``` The evaluation result will be saved to the ../generators/gdsfactory-gen/. diff --git a/openfasoc/MLoptimization/quickstart.bash b/openfasoc/MLoptimization/quickstart.bash index e0b1fccfd..93ad99855 100644 --- a/openfasoc/MLoptimization/quickstart.bash +++ b/openfasoc/MLoptimization/quickstart.bash @@ -1,7 +1,7 @@ #!/bin/bash # this script will recreate the ICCAD paper RL results (using the default seed) -echo "This script has been verified to run with python3.10 and all package versions provided" +echo "This script has been verified to run with python3.11 and package versions provided" @@ -10,28 +10,28 @@ echo "This script has been verified to run with python3.10 and all package versi # find most recent version of python # # Find all installed Python 3 versions and sort them in descending order -PYTHON_VERSIONS=$(compgen -c | grep -E '^python3\.[0-9]+$' | sort -V | tail -n 1) +#PYTHON_VERSIONS=$(compgen -c | grep -E '^python3\.[0-9]+$' | sort -V | tail -n 1) # Extract the most recent version -MOST_RECENT_PYTHON=$(echo "$PYTHON_VERSIONS" | tail -n 1) +#MOST_RECENT_PYTHON=$(echo "$PYTHON_VERSIONS" | tail -n 1) # Check if a Python version was found -if [ -z "$MOST_RECENT_PYTHON" ]; then - echo "No Python 3 versions found." - exit 1 -fi +#if [ -z "$MOST_RECENT_PYTHON" ]; then +# echo "No Python 3 versions found." +# exit 1 +#fi # Print the most recent Python version -echo -echo "Currently using Python version: $MOST_RECENT_PYTHON" -echo +#echo +#echo "Currently using Python version: $MOST_RECENT_PYTHON" +#echo # Check if the most recent version is at least 3.10 -MINIMUM_VERSION="3.10" -if [[ "$(echo $MOST_RECENT_PYTHON | cut -d '.' -f2)" -lt "$(echo $MINIMUM_VERSION | cut -d '.' -f2)" ]]; then - echo "The most recent Python version ($MOST_RECENT_PYTHON) is less than $MINIMUM_VERSION. Please update your Python installation." - echo - exit 1 -fi +#MINIMUM_VERSION="3.10" +#if [[ "$(echo $MOST_RECENT_PYTHON | cut -d '.' -f2)" -lt "$(echo $MINIMUM_VERSION | cut -d '.' -f2)" ]]; then +# echo "The most recent Python version ($MOST_RECENT_PYTHON) is less than $MINIMUM_VERSION. Please update your Python installation." +# echo +# exit 1 +#fi # Save the command to run the most recent Python version into a variable -PY_RUN=$MOST_RECENT_PYTHON - +#PY_RUN=$MOST_RECENT_PYTHON +PY_RUN="python3.11" diff --git a/openfasoc/MLoptimization/requirements.txt b/openfasoc/MLoptimization/requirements.txt index a6850e6ea..a25b464d2 100644 --- a/openfasoc/MLoptimization/requirements.txt +++ b/openfasoc/MLoptimization/requirements.txt @@ -3,27 +3,11 @@ prettyprint prettyprinttree nltk torch -transformers -langchain -langchain_community -chromadb -ollama klayout -unstructured -unstructured[md] -sentence-transformers -peft -accelerate -bitsandbytes safetensors requests -datasets -optimum -trl -langchain_huggingface tensorboard ray==2.7.1 -ray[default] gym==0.26.2 gymnasium==0.28.1 scikit-learn @@ -33,3 +17,15 @@ seaborn matplotlib lz4 async-timeout +dm_tree +pyarrow +aiohttp>=3.7 +aiohttp_cors +colorful +py-spy>=0.2.0 +grpcio>=1.42.0 +opencensus +virtualenv>=20.0.24, !=20.21.1 +memray +smart_open +prometheus_client >= 0.7.1 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 cf9978b34..6efb933fd 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,6 +1,6 @@ import sys from os import path, rename, environ - +environ['OPENBLAS_NUM_THREADS'] = '1' # path to glayout sys.path.append(path.join(path.dirname(__file__), '../../')) @@ -41,6 +41,7 @@ import pickle import tempfile import subprocess +import traceback global _TAPEOUT_AND_RL_DIR_PATH_ global _GET_PARAM_SET_LENGTH_ @@ -54,7 +55,7 @@ _TAKE_OUTPUT_AT_SECOND_STAGE_ = True if 'PDK_ROOT' in environ: - PDK_ROOT = Path(environ['PDK_ROOT']).resolve() + PDK_ROOT = str(Path(environ['PDK_ROOT']).resolve()) else: PDK_ROOT = "/usr/bin/miniconda3/share/pdk/" @@ -1169,7 +1170,28 @@ def execute(self): # same as calling single_build_and_simulation, but runs in a subprocess def safe_single_build_and_simulation(*args, **kwargs) -> dict: - return safe_single_build_and_simulation_helperclass(*args,**kwargs).results + def get_parameter_value(param_name: str, *args, **kwargs): + # Check if the parameter is in kwargs + if param_name in kwargs: + return kwargs[param_name] + # Check if the parameter is in args + try: + # Find the index of the param_name in args and return the next item as its value + index = args.index(param_name) + return args[index + 1] + except (ValueError, IndexError): + # ValueError if param_name is not in args + # IndexError if param_name is the last item and has no value after it + return None + try: + return safe_single_build_and_simulation_helperclass(*args,**kwargs).results + except Exception as e_LorA: + if bool(get_parameter_value("hardfail",*args,**kwargs)): + raise e_LorA + results = opamp_results_serializer() + with open('get_training_data_ERRORS.log', 'a') as errlog: + errlog.write("\nopamp run "+str(get_parameter_value("index",*args,**kwargs))+" with the following params failed: \n"+str(get_parameter_value("params",*args,**kwargs))) + return results From 3971f55c680425f1f9859233b04867600512a9eb Mon Sep 17 00:00:00 2001 From: labtob <70279295+alibillalhammoud@users.noreply.github.com> Date: Tue, 13 Aug 2024 00:56:12 -0400 Subject: [PATCH 5/9] readme --- openfasoc/MLoptimization/quickstart.bash | 2 +- openfasoc/MLoptimization/run_training.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openfasoc/MLoptimization/quickstart.bash b/openfasoc/MLoptimization/quickstart.bash index 93ad99855..58c4ffaac 100644 --- a/openfasoc/MLoptimization/quickstart.bash +++ b/openfasoc/MLoptimization/quickstart.bash @@ -1,6 +1,6 @@ #!/bin/bash -# this script will recreate the ICCAD paper RL results (using the default seed) +# the script produces an example RL optimization run echo "This script has been verified to run with python3.11 and package versions provided" diff --git a/openfasoc/MLoptimization/run_training.py b/openfasoc/MLoptimization/run_training.py index 0b1c28ed1..bddf5bf44 100644 --- a/openfasoc/MLoptimization/run_training.py +++ b/openfasoc/MLoptimization/run_training.py @@ -252,7 +252,7 @@ def update(self, params_idx): inputparam[20] = params[13] inputparam[22] = params[14] inputparam[25] = params[15] - result = safe_single_build_and_simulation(inputparam) + result = safe_single_build_and_simulation(inputparam,temp=-269) specs = np.array([0.0 , 0.0]) specs[0] = result["ugb"] specs[1] = result["ugb"]/(result["Ibias_diffpair"]+result["Ibias_commonsource"]) From 877ff0124416b878d29510be7070d67acf0d557d Mon Sep 17 00:00:00 2001 From: labtob <70279295+alibillalhammoud@users.noreply.github.com> Date: Sun, 25 Aug 2024 15:36:55 -0400 Subject: [PATCH 6/9] verified versions --- openfasoc/MLoptimization/README.md | 32 ++++++--- openfasoc/MLoptimization/gen_spec.py | 3 +- openfasoc/MLoptimization/quickstart.bash | 66 +++++++++---------- openfasoc/MLoptimization/run_training.py | 7 +- .../tapeout/tapeout_and_RL/opamp_perf_eval.sp | 28 +++++++- 5 files changed, 85 insertions(+), 51 deletions(-) diff --git a/openfasoc/MLoptimization/README.md b/openfasoc/MLoptimization/README.md index 7e95dc428..a2bfad0c2 100644 --- a/openfasoc/MLoptimization/README.md +++ b/openfasoc/MLoptimization/README.md @@ -2,7 +2,7 @@ Code for reinforcement learning loop with openfasoc generators for optimizing metrics ## Supported Versions -Please note that this program has only been tested with python3.11 +Please note that this program has only been tested with python3.10 and ngspice v40s ## Quick Start run `bash quickstart.bash` to get an example RL run optimizing opamps. @@ -21,13 +21,13 @@ Make sure that you have OpenAI Gym and Ray installed. To do this, run the follow To generate the design specifications that the agent trains on, run: ``` -python3.11 gen_specs.py +python3.10 gen_specs.py ``` The result is a yaml file dumped to the ../generators/gdsfactory-gen/. To train the agent, open ipython from the top level directory and then: ``` -python3.11 model.py +python3.10 model.py ``` The training checkpoints will be saved in your home directory under ray\_results. Tensorboard can be used to load reward and loss plots using the command: @@ -39,16 +39,28 @@ tensorboard --logdir path/to/checkpoint The evaluation script takes the trained agent and gives it new specs that the agent has never seen before. To generate new design specs, run the gen_specs.py file again with your desired number of specs to validate on. To run validation: ``` -python3.11 eval.py -``` +python3.10 eval.py +``` -The evaluation result will be saved to the ../generators/gdsfactory-gen/. +The evaluation result will be saved to the ../generators/glayout/. ## Results -Please note that results vary greatly based on random seed and spec generation (both for testing and validation). An example spec file is provided that was used to generate the results below. +example resulting opamps (parameter arrays and names provided) + +``` +# transistor parameters provided as (width, length, fingers, multipliers) +# all parameters are listed in floating point format (even integers) for processing purposes -

- -

+153 MegHz UGB, 91db DC Gain, 166uW power +[3.0, 0.5, 6.0, 7.0, 1.5, 10.0, 5.0, 0.7, 8.0, 3.0, 5.0, 1.2, 12.0, 3.0, 5.0, 1.0, 16.0, 6.0, 2.0, 4.0, 4.0, 0.5, 5.0, 12.0, 12.0, 3.0, 2.0] +{'diffpair': (3.0, 0.5, 6.0), 'diffpair_bias': (7.0, 1.5, 10.0), 'secondstage': (5.0, 0.7, 8.0, 3.0), 'secondstage_bias': (5.0, 1.2, 12.0, 3.0), 'output_stage_params': (5.0, 1.0, 16.0), 'output_stage_bias': (6.0, 2.0, 4.0), 'firststage': (4.0, 0.5, 5.0), 'mim_cap_size': (12.0, 12.0), 'mim_cap_rows': 3, 'rmult': 2} +143 MegHz UGB, 95db DC Gain, 179uW power +[2.0, 0.6, 4.0, 4.0, 1.0, 7.0, 4.0, 0.7, 13.0, 3.0, 4.0, 1.1, 12.0, 3.0, 5.0, 1.0, 16.0, 6.0, 2.0, 4.0, 3.0, 0.5, 5.0, 12.0, 12.0, 3.0, 2.0] +{'diffpair': (2.0, 0.6, 4.0), 'diffpair_bias': (4.0, 1.0, 7.0), 'secondstage': (4.0, 0.7, 13.0, 3.0), 'secondstage_bias': (4.0, 1.1, 12.0, 3.0), 'output_stage_params': (5.0, 1.0, 16.0), 'output_stage_bias': (6.0, 2.0, 4.0), 'firststage': (3.0, 0.5, 5.0), 'mim_cap_size': (12.0, 12.0), 'mim_cap_rows': 3, 'rmult': 2} + +137 MegHz UGB, 95db DC Gain, 41uW power +[3.0, 0.5, 4.0, 4.0, 1.0, 7.0, 4.0, 0.8, 14.0, 3.0, 4.0, 1.2, 11.0, 3.0, 5.0, 1.0, 16.0, 6.0, 2.0, 4.0, 3.0, 0.5, 5.0, 12.0, 12.0, 3.0, 2.0] +{'diffpair': (3.0, 0.5, 4.0), 'diffpair_bias': (4.0, 1.0, 7.0), 'secondstage': (4.0, 0.8, 14.0, 3.0), 'secondstage_bias': (4.0, 1.2, 11.0, 3.0), 'output_stage_params': (5.0, 1.0, 16.0), 'output_stage_bias': (6.0, 2.0, 4.0), 'firststage': (3.0, 0.5, 5.0), 'mim_cap_size': (12.0, 12.0), 'mim_cap_rows': 3, 'rmult': 2} +``` diff --git a/openfasoc/MLoptimization/gen_spec.py b/openfasoc/MLoptimization/gen_spec.py index 1ca350646..a15ab1b11 100644 --- a/openfasoc/MLoptimization/gen_spec.py +++ b/openfasoc/MLoptimization/gen_spec.py @@ -6,7 +6,7 @@ def generate_random_specs(env, num_specs): specs_range = { - "gain_min" : [float(10003380.0), float(35003380.0)], + "gain_min" : [float(10003380.0), float(130003380.0)], "FOM" : [float(5e11), float(5e11)] } specs_range_vals = list(specs_range.values()) @@ -37,3 +37,4 @@ def main(): if __name__=="__main__": main() + diff --git a/openfasoc/MLoptimization/quickstart.bash b/openfasoc/MLoptimization/quickstart.bash index 58c4ffaac..0344250f7 100644 --- a/openfasoc/MLoptimization/quickstart.bash +++ b/openfasoc/MLoptimization/quickstart.bash @@ -1,49 +1,43 @@ #!/bin/bash -# the script produces an example RL optimization run -echo "This script has been verified to run with python3.11 and package versions provided" - - +# this script produces an example RL optimization run # ===================================================================== -# -# find most recent version of python -# -# Find all installed Python 3 versions and sort them in descending order -#PYTHON_VERSIONS=$(compgen -c | grep -E '^python3\.[0-9]+$' | sort -V | tail -n 1) -# Extract the most recent version -#MOST_RECENT_PYTHON=$(echo "$PYTHON_VERSIONS" | tail -n 1) -# Check if a Python version was found -#if [ -z "$MOST_RECENT_PYTHON" ]; then -# echo "No Python 3 versions found." -# exit 1 -#fi -# Print the most recent Python version -#echo -#echo "Currently using Python version: $MOST_RECENT_PYTHON" -#echo -# Check if the most recent version is at least 3.10 -#MINIMUM_VERSION="3.10" -#if [[ "$(echo $MOST_RECENT_PYTHON | cut -d '.' -f2)" -lt "$(echo $MINIMUM_VERSION | cut -d '.' -f2)" ]]; then -# echo "The most recent Python version ($MOST_RECENT_PYTHON) is less than $MINIMUM_VERSION. Please update your Python installation." -# echo -# exit 1 -#fi -# Save the command to run the most recent Python version into a variable -#PY_RUN=$MOST_RECENT_PYTHON -PY_RUN="python3.11" - +# Check if Python 3.10 is installed +if command -v python3.10 &>/dev/null; then + echo "Python 3.10 is installed." +else + echo "Error: Python 3.10 is not installed." + exit 1 +fi +PY_RUN="python3.10" +# ===================================================================== +# Check if ngspice is installed +if command -v ngspice &>/dev/null; then + echo "ngspice is installed." +else + echo "Error: ngspice is not installed." + exit 1 +fi +# ===================================================================== +# check that ngspice 40 is installed +ngspice --version > test_ngspice_version.txt +version_line=$(sed -n '2p' test_ngspice_version.txt) +expected_version="ngspice-40" +if [[ $version_line == *"$expected_version"* ]]; then + echo "Correct ngspice version ($expected_version) is installed." +else + echo "Error: Incorrect ngspice version. Expected $expected_version but found:" + echo "$version_line" + exit 1 +fi # ===================================================================== -# # ensure all python depedencies are installed -# - # File containing the list of python dependencies requirements_file="requirements.txt" -#requirements_file="donotdothischeck.txt" # Function to check if a Python package is installed is_installed() { @@ -80,7 +74,6 @@ echo "Dependency check and package installations complete." # ===================================================================== -# # setup and run the RL code # @@ -100,3 +93,4 @@ $PY_RUN model.py $PY_RUN gen_spec.py $PY_RUN eval.py # eval.py creates eval*.txt which shows how many specifications are reached + diff --git a/openfasoc/MLoptimization/run_training.py b/openfasoc/MLoptimization/run_training.py index bddf5bf44..28c58f1bf 100644 --- a/openfasoc/MLoptimization/run_training.py +++ b/openfasoc/MLoptimization/run_training.py @@ -70,7 +70,7 @@ def __init__(self, env_config): "Diffpair_bias2" : [3, 13, 1], "pamp_hparams0" : [1, 9, 1], "pamp_hparams1" : [0.5, 2.1, 0.1], - "pamp_hparams2" : [2, 13, 1], + "pamp_hparams2" : [4, 17, 1], "bias0" : [1, 8, 1], "bias1" : [0.5, 2.1, 0.1], "bias2" : [3, 18, 1], @@ -137,7 +137,7 @@ def reset(self, *, seed=None, options=None): self.specs_ideal_norm = self.lookup(self.specs_ideal, self.global_g) #initialize current parameters - self.cur_params_idx = np.array([6, 2, 7, 6, 0, 5, 7, 0, 10, 6, 5, 13, 0, 6, 4, 2]) + self.cur_params_idx = np.array([6, 0, 7, 6, 0, 5, 7, 0, 12, 6, 5, 9, 1, 6, 2, 2]) # param array self.cur_specs = self.update(self.cur_params_idx) cur_spec_norm = self.lookup(self.cur_specs, self.global_g) @@ -253,6 +253,8 @@ def update(self, params_idx): inputparam[22] = params[14] inputparam[25] = params[15] result = safe_single_build_and_simulation(inputparam,temp=-269) + with open("quick_unorganized.txt", "a") as filerec: + filerec.write(str(inputparam)+"\n"+str(result)+"\n\n\n") specs = np.array([0.0 , 0.0]) specs[0] = result["ugb"] specs[1] = result["ugb"]/(result["Ibias_diffpair"]+result["Ibias_commonsource"]) @@ -270,3 +272,4 @@ def main(): if __name__ == "__main__": main() + diff --git a/openfasoc/generators/glayout/tapeout/tapeout_and_RL/opamp_perf_eval.sp b/openfasoc/generators/glayout/tapeout/tapeout_and_RL/opamp_perf_eval.sp index 652f37c97..5277900a6 100644 --- a/openfasoc/generators/glayout/tapeout/tapeout_and_RL/opamp_perf_eval.sp +++ b/openfasoc/generators/glayout/tapeout/tapeout_and_RL/opamp_perf_eval.sp @@ -114,21 +114,42 @@ while bias_cs le bias_cs_Max ** Measure phase margin let phase = (180/PI)*vp(vo) meas ac pm find phase when vdb(vo)=0 - let pm_FOM_factor = pm > 45 ? 1 : 0.0000001 + *let pm_FOM_factor = pm > 45 ? 1 : 0.0000001 + let pm_FOM_factor = 0.0000001 + if ( pm ge 45 ) + let pm_FOM_factor = 1 + end ** Measure DC(ish) gain meas ac dcg find vdb(vo) at=10 ** Measure 3db BW let threedbabsgain = dcg - 3 meas ac threedb when vdb(vo)=threedbabsgain FALL=1 ** if FOM is better than previous max save results - let FOM = pm_FOM_factor * ugb_f / (bias_cs + bias_dp) + * let FOM = pm_FOM_factor * ugb_f / (bias_cs + bias_dp) + let FOM = pm_FOM_factor * ugb_f + * + * debug outputs + echo "finished computations, and calculated the following" + echo "phase margin" + print pm + echo "pm factor:" + print pm_FOM_factor + echo "FOM" + print FOM + echo "max FOM" + print maxFOM + * end debug outputs + * if ( FOM ge maxFOM ) + echo "now setting a new maxFOM" let maxFOM = FOM let maxUGB = ugb_f let maxBics = bias_cs let maxBidp = bias_dp let maxBio = bias_o let savedPhaseMargin = pm % 360 + echo "saved Phase Margin" + print savedPhaseMargin let savedDCGain = dcg let savedthreedbBW = threedb end @@ -153,6 +174,8 @@ while bias_cs le bias_cs_Max end end ** Export global maxima +echo "the final saved phase margin is:" +print savedPhaseMargin wrdata result_ac.txt maxUGB maxBidp maxBics maxBio savedPhaseMargin savedDCGain savedthreedbBW ** Export power usage of correctly biased opamp @@ -180,3 +203,4 @@ quit .GLOBAL GND .GLOBAL VDD .end + From 1197536a655b6914d3152dcb7ecdc20e4ea1aa46 Mon Sep 17 00:00:00 2001 From: labtob <70279295+alibillalhammoud@users.noreply.github.com> Date: Thu, 29 Aug 2024 23:28:51 -0400 Subject: [PATCH 7/9] clean test.py --- openfasoc/MLoptimization/test.py | 53 +++++++++++++ openfasoc/MLoptimization/test1.py | 126 ------------------------------ 2 files changed, 53 insertions(+), 126 deletions(-) create mode 100644 openfasoc/MLoptimization/test.py delete mode 100644 openfasoc/MLoptimization/test1.py diff --git a/openfasoc/MLoptimization/test.py b/openfasoc/MLoptimization/test.py new file mode 100644 index 000000000..1ec8e3dfb --- /dev/null +++ b/openfasoc/MLoptimization/test.py @@ -0,0 +1,53 @@ +import numpy as np +import glayout_import + +from sky130_nist_tapeout import safe_single_build_and_simulation +from sky130_nist_tapeout import opamp_parameters_serializer + +import yaml +from pathlib import Path +import numpy as np + +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], + } +paramss = [] +params_id = list(params.keys()) + +params_idx = np.array([6, 2, 7, 6, 0, 5, 7, 0, 10, 6, 5, 13, 0, 6, 4, 2]) + +for value in params.values(): + param_vec = np.arange(value[0], value[1], value[2]) + paramss.append(param_vec) + +paramsss = np.array([paramss[i][params_idx[i]] for i in range(len(params_id))]) + +inputparam = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 5.0, 1.0, 16.0, 6.0, 2.0, 4.0, 0.0, 0.5, 0.0, 12.0, 12.0, 0.0, 2.0]) +inputparam[0:3] = paramsss[0:3] +inputparam[3:6] = paramsss[3:6] +inputparam[6:9] = paramsss[6:9] +inputparam[10:14] = paramsss[9:13] +inputparam[20] = paramsss[13] +inputparam[22] = paramsss[14] +inputparam[25] = paramsss[15] + + +result = safe_single_build_and_simulation(inputparam, hardfail=True) + +print(result) +print(result["ugb"]/(result["Ibias_diffpair"]+result["Ibias_commonsource"])) diff --git a/openfasoc/MLoptimization/test1.py b/openfasoc/MLoptimization/test1.py deleted file mode 100644 index ccb583fb1..000000000 --- a/openfasoc/MLoptimization/test1.py +++ /dev/null @@ -1,126 +0,0 @@ -import numpy as np -import glayout_import - -from sky130_nist_tapeout import safe_single_build_and_simulation -from sky130_nist_tapeout import opamp_parameters_serializer -#from tapeout_and_RL.sky130_nist_tapeout import single_build_and_simulation -#from tapeout_and_RL.sky130_nist_tapeout import opamp_parameters_serializer -import yaml -from pathlib import Path -import numpy as np - -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], - } -paramss = [] -params_id = list(params.keys()) - -#params_idx = np.array([1, 5, 3, 5, 2, 1, 6, 0, 6, 5, 5, 1, 1, 3, 2, 0]) - -#[ 6. 1. 4. 6. 2. 4. 7.2 1. 10. 3. 8. 2. 12. 3. -# 5. 1. 16. 6. 2. 4. 6. 1. 6. 12. 12. 3. 2. ] - -#[4. 1. 8. 6. 3. 3. 4. 0.5 4. 6. 2. 4. 2. 6. 8. 3. ] - -#[ 4. 1. 8. 6. 3. 3. 4. 0.5 4. 3. 6. 2. 4. 2. -# 5. 1. 16. 6. 2. 4. 6. 1. 8. 12. 12. 3. 2. ] - -#[4. 1. 8. 6. 3. 3. 4. 0.5 4. 6. 2. 4. 2. 6. 8. 3. ] - -#[ 7. , 0.7, 12. , 7. , 1. , 10. , 8. , 0.5, 12. , 3. , 7. , -# 1. , 12. , 2. , 5. , 1. , 16. , 6. , 2. , 4. , 9. , 0.5, -# 6. , 12. , 12. , 3. , 2. ] - -# [ 7. , 0.7, 8. , 7. , 1. , 8. , 8. , 0.5, 12. , 3. , 7. , -# 1. , 16. , 2. , 5. , 1. , 16. , 6. , 2. , 4. , 9. , 0.5, -# 8. , 12. , 12. , 3. , 2. ]) - -#params_idx = np.array([6, 2, 11, 6, 0, 7, 7, 0, 10, 6, 5, 9, 0, 6, 2, 2]) - -params_idx = np.array([6, 2, 7, 6, 0, 5, 7, 0, 10, 6, 5, 13, 0, 6, 4, 2]) - -# params_idx = np.array([5, 5, 3, 5, 2, 1, 6, 1, 8, 7, 15, 9, 1, 3, 2, 2]) - -for value in params.values(): - param_vec = np.arange(value[0], value[1], value[2]) - paramss.append(param_vec) - -paramsss = np.array([paramss[i][params_idx[i]] for i in range(len(params_id))]) -#param_val = np.array[OrderedDict(list(zip(self.params_id,params)))] - -#run param vals and simulate -#cur_specs = OrderedDict(sorted(self.sim_env.create_design_and_simulate(param_val[0])[1].items(), key=lambda k:k[0])) -#2.69966400e+07 - -#inputparam = np.array([ 9. , 2., 6. , 6., 2. , 4. , 6., 1. , 2. , 3. , 7. , 1 ,6. , 3. ,12. ,12. , 3. , 2. ]) -#[ 4. 1. 8. 6. 3. 3. 4. 0.5 4. 3. 6. 2. 4. 2. -# 5. 1. 16. 6. 2. 4. 6. 1. 8. 12. 12. 3. 2. ] - -#[4. 1. 8. 6. 3. 3. 4. 0.5 4. 6. 2. 4. 2. 6. 8. 3. ] - -inputparam = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 5.0, 1.0, 16.0, 6.0, 2.0, 4.0, 0.0, 0.5, 0.0, 12.0, 12.0, 0.0, 2.0]) -inputparam[0:3] = paramsss[0:3] -inputparam[3:6] = paramsss[3:6] -inputparam[6:9] = paramsss[6:9] -inputparam[10:14] = paramsss[9:13] -inputparam[20] = paramsss[13] -inputparam[22] = paramsss[14] -inputparam[25] = paramsss[15] - -# params = { -# "half_diffpair_params": (6, 1, 4), -# "diffpair_bias": (6, 2, 4), -# "half_common_source_params": (7.2, 1, 10, 3), -# "half_common_source_bias": (8, 2, 12, 3), -# "output_stage_params": (5, 1, 16), -# "output_stage_bias": (6, 2, 4), -# "mim_cap_size": (12, 12), -# "mim_cap_rows": 3, -# "rmult": 2 -# } -# numpy_params = opamp_parameters_serializer(**params) -#numpy_params[0:3] = paramsss[0:3] -#numpy_params[3:6] = paramsss[3:6] -#numpy_params[6:9] = paramsss[6:9] -#numpy_params[10:14] = paramsss[9:13] -#numpy_params[20] = paramsss[13] -# numpy_params[22] = paramsss[14] -# numpy_params[25] = paramsss[15] - -# print(numpy_params) -print(inputparam) - -#{'ugb': 2233790.0, 'dcGain': 65.19988, 'phaseMargin': 104.0, 'Ibias_diffpair': 1e-06, 'Ibias_commonsource': 2.0736e-06, 'Ibias_output': 9.35e-05, 'area': 47939.75594998075, 'power': 0.000353842085, 'noise': 5.22616086, 'bw_3db': 831.1834, 'power_twostage': 1.72420852e-05} -#726766657990.63 - -# supposed to be 10MHz -#numpy_params = np.array([ 7. , 0.7, 12. , 7. , 1. , 10. , 8. , 0.5, 12. , 3. , 7. , -# 1. , 12. , 2. , 5. , 1. , 16. , 6. , 2. , 4. , 9. , 0.5, -# 6. , 12. , 12. , 3. , 2. ]) -#{'ugb': 21067680.0, 'dcGain': 52.27519, 'phaseMargin': 96.0, 'Ibias_diffpair': 7.43008371e-06, 'Ibias_commonsource': 2.21861111e-05, 'Ibias_output': 9.35e-05, 'area': 42865.81769998964, 'power': 0.00049207212, 'noise': 4.18722441, 'bw_3db': 27197.53, 'power_twostage': 0.00015547212} -#711356747048.626 - -# supposed to be 25459060 -numpy_params = np.array([ 7. , 0.7, 8. , 7. , 1. , 8. , 8. , 0.5, 12. , 3. , 7. , - 1. , 16. , 2. , 5. , 1. , 16. , 6. , 2. , 4. , 9. , 0.5, - 8. , 12. , 12. , 3. , 2. ]) -result = safe_single_build_and_simulation(inputparam, hardfail=True) -# {'ugb': 13847390.0, 'dcGain': 50.5001, 'phaseMargin': 101.0, 'Ibias_diffpair': 6.19173642e-06, 'Ibias_commonsource': 1.54070216e-05, 'Ibias_output': 9.35e-05, 'area': 43918.335699987125, 'power': 0.000449201424, 'noise': 3.90373916, 'bw_3db': 25231.79, 'power_twostage': 0.000112601424} -# 641119734161.4553 -print(result) -print(result["ugb"]/(result["Ibias_diffpair"]+result["Ibias_commonsource"])) \ No newline at end of file From fc0197eb321b32942045b94e5ee3075f273ff27d Mon Sep 17 00:00:00 2001 From: labtob <70279295+alibillalhammoud@users.noreply.github.com> Date: Sun, 15 Sep 2024 22:14:46 -0400 Subject: [PATCH 8/9] begin merging misc updates & big conflict resolutions --- .../glayout/flow/routing/smart_route.py | 22 +- .../glayout/glayout/llm/manage_data.py | 73 ++---- .../generators/glayout/glayout/llm/rag.py | 109 +++++++++ .../glayout/llm/rag_data/CommonCentroid.md | 11 + .../glayout/llm/rag_data/CommonDrain.md | 9 +- .../glayout/llm/rag_data/CommonSource.md | 7 +- .../glayout/llm/rag_data/CurrentMirror.md | 10 +- .../llm/rag_data/DeltaSigmaModulator.md | 3 +- .../glayout/llm/rag_data/GeneralArray.md | 12 + .../glayout/llm/rag_data/MimcapArray.md | 18 ++ .../glayout/llm/rag_data/StrongArmLatch.md | 15 +- .../llm/rag_data/WilsonCurrentMirror.md | 9 + .../glayout/glayout/llm/rag_data/classA.md | 5 +- .../glayout/glayout/llm/rag_data/diffpair.md | 19 +- .../glayout/glayout/llm/rag_data/inverter.md | 9 +- .../glayout/glayout/llm/rag_data/mimcap.md | 8 + .../glayout/glayout/llm/rag_data/mosfet.md | 3 +- .../glayout/glayout/llm/rag_data/opamp.md | 30 ++- .../glayout/llm/rag_data/pushpullamp.md | 8 +- .../llm/syntax_data/GlayoutStrictSyntax.md | 65 +---- .../llm/syntax_data/GlayoutStrictSyntaxQA | 225 ------------------ .../convos/BiasVoltageGenerator.convo | 5 + .../llm/syntax_data/convos/CTATVGen.convo | 5 + .../convos/CascodeCommonGate.convo | 5 + ... => CascodeCommonGateCommonCentroid.convo} | 5 + .../CascodeCommonGateInterdigitated.convo | 7 +- .../convos/CascodeCommonSource.convo | 5 + .../CascodeCommonSourceInterdigitated.convo | 7 +- .../llm/syntax_data/convos/ClassABStage.convo | 5 + .../syntax_data/convos/ClassBPushPull.convo | 5 + .../convos/ClassBPushPullInterdigitated.convo | 7 +- .../convos/CommonSourceAmplifier.convo | 5 + ...CommonSourceAmplifierFoldedDiodeLoad.convo | 5 + .../CommonSourceAmplifierWDiodeLoad.convo | 5 + .../convos/ConstBiasVoltageGen.convo | 5 + .../convos/CrossCoupledInverters.convo | 5 + .../convos/CurrentMirrorNtype.convo | 5 + .../CurrentMirrorNtypeCommonCentroid.convo | 5 + .../CurrentMirrorNtypeInterdigitated.convo | 5 + .../convos/CurrentMirrorPtype.convo | 7 +- .../CurrentMirrorPtypeInterdigitated.convo | 7 +- .../syntax_data/convos/DegenCommonGate.convo | 5 + .../convos/DegenCommonSource.convo | 5 + .../convos/DeltaSigmaModulator.convo | 15 ++ .../llm/syntax_data/convos/DiffPair.convo | 7 +- .../convos/FourStageIntegrator.convo | 29 +++ .../syntax_data/convos/IntegratorStage.convo | 20 ++ .../llm/syntax_data/convos/Inverter.convo | 5 + .../llm/syntax_data/convos/LowNoiseAmp.convo | 7 +- .../llm/syntax_data/convos/MimcapArray.convo | 38 ++- .../glayout/llm/syntax_data/convos/NAND.convo | 5 + .../llm/syntax_data/convos/NMOSArray2x5.convo | 35 +++ .../llm/syntax_data/convos/NMOSArray4x3.convo | 41 ++++ .../glayout/llm/syntax_data/convos/NOR.convo | 5 + .../syntax_data/convos/NoiseXDiffConv.convo | 5 + .../llm/syntax_data/convos/PMOSArray2x5.convo | 33 +++ .../llm/syntax_data/convos/PMOSArray4x3.convo | 43 ++++ .../syntax_data/convos/PTATVoltageGen.convo | 5 + .../syntax_data/convos/PTypeDiffPair.convo | 5 + .../llm/syntax_data/convos/PushPull.convo | 7 +- .../syntax_data/convos/RegulatedCascode.convo | 5 + .../llm/syntax_data/convos/SourceFollow.convo | 5 + .../syntax_data/convos/StrongArmLatch.convo | 5 + .../glayout/llm/syntax_data/convos/ULPD.convo | 5 + .../llm/syntax_data/convos/Varactor.convo | 5 + .../llm/syntax_data/convos/ViaArray3x2.convo | 51 ++++ .../syntax_data/convos/VoltageFollower.convo | 5 + .../convos/WilsonCurrentMirror.convo | 17 ++ .../glayout/glayout/llm/syntax_data/eval.json | 36 ++- .../llm/syntax_data/rephrase_train.json | 16 ++ .../glayout/llm/syntax_data/train.json | 20 ++ .../glayout/glayout/llm/train_and_run.py | 200 ++++++++++------ .../glayout/syntaxer/nltk_init_deps.py | 5 +- .../glayout/glayout/syntaxer/process_input.py | 6 +- 74 files changed, 1003 insertions(+), 473 deletions(-) create mode 100644 openfasoc/generators/glayout/glayout/llm/rag.py create mode 100644 openfasoc/generators/glayout/glayout/llm/rag_data/CommonCentroid.md create mode 100644 openfasoc/generators/glayout/glayout/llm/rag_data/GeneralArray.md create mode 100644 openfasoc/generators/glayout/glayout/llm/rag_data/MimcapArray.md create mode 100644 openfasoc/generators/glayout/glayout/llm/rag_data/WilsonCurrentMirror.md create mode 100644 openfasoc/generators/glayout/glayout/llm/rag_data/mimcap.md delete mode 100644 openfasoc/generators/glayout/glayout/llm/syntax_data/GlayoutStrictSyntaxQA rename openfasoc/generators/glayout/glayout/llm/syntax_data/convos/{CasecodeCommonGateCommonCentroid.convo => CascodeCommonGateCommonCentroid.convo} (66%) create mode 100644 openfasoc/generators/glayout/glayout/llm/syntax_data/convos/DeltaSigmaModulator.convo create mode 100644 openfasoc/generators/glayout/glayout/llm/syntax_data/convos/FourStageIntegrator.convo create mode 100644 openfasoc/generators/glayout/glayout/llm/syntax_data/convos/IntegratorStage.convo create mode 100644 openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NMOSArray2x5.convo create mode 100644 openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NMOSArray4x3.convo create mode 100644 openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PMOSArray2x5.convo create mode 100644 openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PMOSArray4x3.convo create mode 100644 openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ViaArray3x2.convo create mode 100644 openfasoc/generators/glayout/glayout/llm/syntax_data/convos/WilsonCurrentMirror.convo diff --git a/openfasoc/generators/glayout/glayout/flow/routing/smart_route.py b/openfasoc/generators/glayout/glayout/flow/routing/smart_route.py index e47c64b9f..ac5b1fddb 100644 --- a/openfasoc/generators/glayout/glayout/flow/routing/smart_route.py +++ b/openfasoc/generators/glayout/glayout/flow/routing/smart_route.py @@ -19,13 +19,18 @@ def smart_route( pdk: MappedPDK, edge1: Port, - edge2: Port, + edge2: Port, ref_comp: Optional[Union[Component, ComponentReference]]=None, top_comp: Optional[Union[Component, ComponentReference]]=None, + auto_downscale_routing: bool = True, **kwargs ) -> Component: # error checks assert_port_manhattan([edge1,edge2]) + # auto downscale routing widths if both port widths>1 (will make port width exactly 1) + if edge1.width>1 and edge2.width>1: + edge1.width=1 + edge2.width=1 # determine route type based on preconfiged route utils if top_comp is not None and ref_comp is not None: if ref_comp.info.get("route_genid") is not None: @@ -41,7 +46,7 @@ def smart_route( # determine route type based on port orientation and distance if ports_parallel(edge1,edge2): # croute or straightroute - if ports_inline(edge1,edge2): + if ports_inline(edge1,edge2) or (edge1.orientation!=edge2.orientation): return straight_route(pdk, edge1, edge2, **kwargs) else: return c_route(pdk, edge1, edge2, **kwargs) @@ -81,6 +86,10 @@ def generic_route_two_transistor_interdigitized( edge2: Port, top_comp: Union[Component, ComponentReference] ) -> Component: + # check if edges are on the same two transistor interdigitated component + if len(edge1.name.split("_")[-4])>=4 and len(edge2.name.split("_")[-4])>=4: + if edge1.name.split("_")[-4]!=edge2.name.split("_")[-4]: + raise ValueError("edges are not on the same two_transistor_interdigitized pair") def compensate_for_croutes(top_comp, sample_port: Port, LeftSide: bool, extend_to: Port): # top_comp is Component to modify, sample_port is a port name for refernce (we dont know what the prefix should be) side is either west (left) or east # adds a metal extension and changes the ports to compensate for the fact that there will be a croute on that side @@ -226,8 +235,6 @@ def compensate_for_croutes(top_comp, sample_port: Port, LeftSide: bool, extend_t # if check_route("") - raise ValueError("these ports will be supported soon") - # print(f'\nname1: {name1}, name2: {name2}\n"top_A_source", "bottom_A_source"\n') print('\n result of check_route: ', check_route(name1, name2, "top_A_source", "bottom_A_source")) if check_route(name1, name2, "top_A_drain", "bottom_A_drain"): @@ -249,6 +256,13 @@ def compensate_for_croutes(top_comp, sample_port: Port, LeftSide: bool, extend_t rt = c_route(pdk, exchange_ports(top_comp, edge1, "W"), exchange_ports(top_comp, edge2, "W"), viaoffset=(True, True), width1=width1, width2=width2, extension=4*width1) compensate_for_croutes(top_comp, edge1, True, rt.ports["con_N"]) return rt + + if check_route(name1, name2, "top_B_source", "bottom_B_drain"): + rt = c_route(pdk, exchange_ports(top_comp, edge1, "E"), exchange_ports(top_comp, edge2, "E"), viaoffset=(True, True), width1=width1, width2=width2) + compensate_for_croutes(top_comp, edge1, True, rt.ports["con_N"]) + return rt + raise ValueError("other ports will be supported soon") + # print(f'\nname1: {name1}, name2: {name2}\n"top_A_source", "bottom_A_source"\n') else: # else return 2 tran route return generic_route_two_transistor_interdigitized(pdk, edge1, edge2, top_comp) diff --git a/openfasoc/generators/glayout/glayout/llm/manage_data.py b/openfasoc/generators/glayout/glayout/llm/manage_data.py index a8bcfe5f3..e1cb75dbe 100644 --- a/openfasoc/generators/glayout/glayout/llm/manage_data.py +++ b/openfasoc/generators/glayout/glayout/llm/manage_data.py @@ -2,17 +2,16 @@ import warnings from pathlib import Path from typing import List, Tuple, Union -from langchain_community.document_loaders import DirectoryLoader, TextLoader -from langchain_community.vectorstores import Chroma -#from langchain_community.embeddings import HuggingFaceEmbeddings -from langchain_huggingface import HuggingFaceEmbeddings +from langchain_community.document_loaders import TextLoader from datasets import Dataset from typing import Optional +from glayout.llm.rag import RAGdb def remove_comments_and_empty_lines(input_string: str) -> str: """ Removes all lines starting with a '#' or any empty lines from the input string. + Does not remove lines starting with '//' (use these as annotations) Args: input_string (str): The input string containing multiple lines. Returns: @@ -131,51 +130,6 @@ def load_all_labeled_syntax_data_json( return all_results -class RAGdb: - """ - A class to create and manage a vector database for the RAG data using ChromaDB. - - Attributes: - chroma_client (Client): The ChromaDB client used for managing the vector database. - collection_name (str): The name of the collection used in ChromaDB. - collection (Collection): The vector database - """ - - def __init__(self, rag_data_dir: Union[str, Path]): - """Initializes the RAGdb instance with a ChromaDB collection""" - # error checking - rag_data_dir = Path(rag_data_dir).resolve() - if not rag_data_dir.is_dir(): - raise FileNotFoundError(f"could not find RAG data directory {rag_data_dir}") - # load RAG data - self.documents = DirectoryLoader(str(rag_data_dir), glob="*.md").load() - # create vector db - embeddings_model_name = "sentence-transformers/all-MiniLM-L6-v2" - embeddings = HuggingFaceEmbeddings(model_name=embeddings_model_name) - self.vectordb = Chroma.from_documents( - documents=self.documents, embedding=embeddings - ) - - def query(self, query_text: str, k: int = 1) -> list: - """ - Queries the vector database to find the top-k most similar vectors to the given query text. - Args: - query_text (str): The text to query. - Returns: - List: The list of top-k most similar docs. - """ - kact = k if k>1 else 2 - rawdocs = self.vectordb.similarity_search(query=query_text, k=kact) - rawtxt = list() - for i, doc in enumerate(rawdocs): - rawtxt.append(doc.page_content) - if i == kact-1: - break - return rawtxt - - -RAGvecdb = RAGdb(Path(__file__).resolve().parent / "rag_data") - def get_glayout_context() -> str: """retrieve the context of syntax_data/GlayoutStrictSyntax.md @@ -193,8 +147,8 @@ def get_glayout_context() -> str: def get_prompt_from_template( tokenizer, - ragcontext: str, prompt: str, + ragcontext: Optional[str] = None, strictsyntax: Optional[str] = None, return_message: bool=False ) -> str: @@ -203,7 +157,7 @@ def get_prompt_from_template( Args: tokenizer: a tokenizer compatible with huggingface, transformers tokenizer class - ragcontext (str): Contextual information about analog circuit design to aid in translation. + ragcontext (str, None): Contextual information about analog circuit design to aid in translation. prompt (str): The input prompt that needs to be converted to Glayout strictsyntax. strictsyntax (str, Optional): The strictsyntax command language template to be used. if None (default), then only format the prompt (no labeled output strictsyntax) @@ -215,9 +169,11 @@ def get_prompt_from_template( inst_prompt = str() glayout_nlp_context = get_glayout_context() inst_prompt += f"Below is some context on Glayout strictsyntax:\n{glayout_nlp_context}\n\n" - #inst_prompt += "Below is context on the circuit" + #inst_prompt += "Below is additional context on the circuit" #inst_prompt += "convert an example prompt to Glayout strictsyntax\n" - inst_prompt += f"\n{ragcontext}\n" + if ragcontext is not None and len(ragcontext) and not(ragcontext.isspace()): + inst_prompt += "\nThe following is more specific context. This is only useful if it is related to the circuit the user is requesting below.\n" + inst_prompt += f"{ragcontext}\n" #inst_prompt += f"Do NOT include the context in your response. Convert the following prompt to Glayout strictsyntax:\n{prompt}" inst_prompt += f"Convert the following prompt to Glayout strictsyntax:\n{prompt}" # unify prompt and return @@ -262,26 +218,27 @@ def unify_prompt_and_add_context_to_data(tokenizer, data: list, no_label: bool=F def load_preprocessed_data_in_messages_format(): + RAGvecdb = RAGdb(Path(__file__).resolve().parent / "rag_data") # get train and evaluation data in a single unified prompt format train_examples = load_all_labeled_syntax_data_json() eval_examples = load_all_labeled_syntax_data_json(True) # train train_messages = list() for prompt, result in train_examples: - ragcontext = RAGvecdb.query(prompt, 1) - train_messages.append(get_prompt_from_template(None,ragcontext,prompt,result,True)) + ragcontext = RAGvecdb.query(prompt, 1)[0] + train_messages.append(get_prompt_from_template(tokenizer=None,ragcontext=ragcontext,prompt=prompt,strictsyntax=result,return_message=True)) train_data = Dataset.from_dict({"messages":train_messages}) # eval eval_messages = list() for prompt, result in eval_examples: - ragcontext = RAGvecdb.query(prompt, 1) - eval_messages.append(get_prompt_from_template(None,ragcontext,prompt,result,True)) + ragcontext = RAGvecdb.query(prompt, 1)[0] + eval_messages.append(get_prompt_from_template(tokenizer=None,ragcontext=ragcontext,prompt=prompt,strictsyntax=result,return_message=True)) eval_data = Dataset.from_dict({"messages":eval_messages}) return {"train": train_data, "evaluation": eval_data} - +# NOTE: this function is deprecated and may be removed def load_preprocessed_pretokenized_data(tokenizer): """Wrapper function for full retrival and preprocessing of dataset 1- Loads raw data from files diff --git a/openfasoc/generators/glayout/glayout/llm/rag.py b/openfasoc/generators/glayout/glayout/llm/rag.py new file mode 100644 index 000000000..82c5d14e3 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/llm/rag.py @@ -0,0 +1,109 @@ +from pathlib import Path +from typing import List, Tuple, Union +from langchain_community.document_loaders import DirectoryLoader +from langchain_community.vectorstores import Chroma +#from langchain_community.embeddings import HuggingFaceEmbeddings +from langchain_huggingface import HuggingFaceEmbeddings +#from sentence_transformers import SentenceTransformer +from langchain_core.documents import Document +import glayout.syntaxer.nltk_init_deps +from typing import Callable + + +class RAGdb: + """ + A class to create and manage a vector database for the RAG data using ChromaDB. + + Attributes: + chroma_client (Client): The ChromaDB client used for managing the vector database. + collection_name (str): The name of the collection used in ChromaDB. + collection (Collection): The vector database + """ + + def __init__(self, rag_data_dir: Union[str, Path], minimum_similarity: float=1.35): + """Initializes the RAGdb instance with a ChromaDB collection + takes a rag_data_dir (to read documents from) and a minimum_similarity value + documents with similarities below minimum_similarity will be ignored + """ + self.summarizer: Callable[[str], str] = lambda query : query + self.minimum_similarity = float(minimum_similarity) + # error checking + rag_data_dir = Path(rag_data_dir).resolve() + if not rag_data_dir.is_dir(): + raise FileNotFoundError(f"could not find RAG data directory {rag_data_dir}") + # load RAG data + langchain_documents = DirectoryLoader(str(rag_data_dir), glob="*.md").load() + document_labels = [self._get_document_label(lddoc) for lddoc in langchain_documents] + self.documents = dict(zip(document_labels, langchain_documents)) + # create vector db and set collection_metadata to configure the distance similarity metric + # the default similarity metric is l2 norm + embeddings_model_name = "sentence-transformers/all-MiniLM-L6-v2" + #embeddings_model_name = "PotatoOff/mxbai-embed-large-safetensors" + embeddings = HuggingFaceEmbeddings(model_name=embeddings_model_name) + #embeddings_model_name = "Alibaba-NLP/gte-large-en-v1.5" + #embeddings = SentenceTransformer(embeddings_model_name,trust_remote_code=True) + #collection_metadata = {"hnsw:space": "cosine"} + collection_metadata = {"hnsw:space": "l2"}# lower is better + #self.vectordb = Chroma.from_documents( + # documents=document_labels, embedding=embeddings, collection_metadata=collection_metadata + #) + self.vectordb = Chroma.from_texts( + texts=document_labels, embedding=embeddings, collection_metadata=collection_metadata + ) + + def _get_document_label(self, langchain_doc: Document) -> str: + """returns the document label given an input langchain document + Args: + langchain_doc (langchain_core.documents.base.Document): A langchain document type + this should contain the document text and a metadata attribute with a source + Returns: + str: the document label for this document (used to search for this doc in rag) + """ + # returns the first line of the document + # if the first line is empty, returns the document name + label = str(langchain_doc.page_content.split('\n')[0]) + label = label.strip().strip("#").strip() + if len(label)==0 or label.isspace(): + label = Path(langchain_doc.metadata["source"]).resolve().stem + return label + + def query(self, query_text: str, k: int = 1) -> list: + """ + Queries the vector database to find the top-k most similar vectors to the given query text. + Args: + query_text (str): The text to query. + k (int): number of documents to query + Returns: + List: The list of at most top-k most similar docs. (always returns a list even if k=1) + NOTE: if similarity is below a threshold, it will ignore documents + NOTE: if final list is length 0, it will return a list with "None" as the only element + Raises + ValueError: less than one document queried (k<1) + """ + # error checking + k = int(k) + if k<1: + raise ValueError("you must query for at least one document") + # preprocess the query + preproc_query = self.summarizer(query_text) + # query the vec db + #dbresult_doc_labels = self.vectordb.similarity_search(query=query_text, k=k) + #import pdb; pdb.set_trace() + dbresult_doc_labels = self.vectordb.similarity_search_with_score(query=preproc_query, k=k) + rawtxt = list() + for i, (doc,similarity) in enumerate(dbresult_doc_labels): + if similarity < self.minimum_similarity:# for l2 lower is better, if similarity is cosine then higher is better + rawtxt.append(self.documents[doc.page_content].page_content) + with open("RAGoutputs_example_dumpfile.txt", "a") as afile: + text_to_append = "\n\nquery_text: "+query_text + text_to_append += "\nprocessed query_text: "+preproc_query + text_to_append += "\nsimilarity: "+str(similarity)+"\n" + text_to_append += f"choosen file: {doc.page_content}" + #text_to_append += f"content: {rawtxt[-1]}\n" + #afile.write(text_to_append) + # if no results then return a list with "None" as the only element + if len(rawtxt)==0: + return [None] + else: + return rawtxt + diff --git a/openfasoc/generators/glayout/glayout/llm/rag_data/CommonCentroid.md b/openfasoc/generators/glayout/glayout/llm/rag_data/CommonCentroid.md new file mode 100644 index 000000000..c1e2849f6 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/llm/rag_data/CommonCentroid.md @@ -0,0 +1,11 @@ +# Common Centroid Pair +Glayout includes a common centroid matching component which is the "common centroid pair". This components has 3 parameters. +First parameter is float type and called "width" +Second paramter is float type and called "length" +Last parameter is int type and called "fingers" + +The component includes 2 transistors which are called "A" and "B". +The ports for transistor A are under +[component name]_A_ +The ports for transistor B are under +[component name]_B_ diff --git a/openfasoc/generators/glayout/glayout/llm/rag_data/CommonDrain.md b/openfasoc/generators/glayout/glayout/llm/rag_data/CommonDrain.md index d673f7be8..25e0ce0e1 100644 --- a/openfasoc/generators/glayout/glayout/llm/rag_data/CommonDrain.md +++ b/openfasoc/generators/glayout/glayout/llm/rag_data/CommonDrain.md @@ -1,4 +1,9 @@ # Common Drain Amplifier The purpose of a common drain amplifier, aka a source follower, is to provide buffering. It has high input impedance, low output impedance, and a voltage gain close to unity. -A typical source follower schematic includes: an nmos with the drain terminal connected to vdd and an input signal that is applied to the gate terminal. Additionally, there is a resistor (Rs) that connects the source terminal to the ground. The output node is at the source voltage of the transistor. -If another nmos is used to replace the resistor, its source is connected to ground, the drain is connected to the source of the first transistor, and the gate is connected to a voltage called Vbias which controls the nmos' resistance. +A typical source follower consists of two NMOS transistors called inp and degen. The degen transistor connected such that it acts as a resistor and its drain is shorted with the source of the inp transistor. The input is applied to the gate of inp and the output is taken from the source of inp. + +## Routing +Only route together these ports, nothing else +1. Connect the source of inp to the drain of degen. +2. Connect the drain of the degen to the gate of degen + diff --git a/openfasoc/generators/glayout/glayout/llm/rag_data/CommonSource.md b/openfasoc/generators/glayout/glayout/llm/rag_data/CommonSource.md index a0a354842..14f792750 100644 --- a/openfasoc/generators/glayout/glayout/llm/rag_data/CommonSource.md +++ b/openfasoc/generators/glayout/glayout/llm/rag_data/CommonSource.md @@ -1,2 +1,7 @@ # Common Source Amplifier -There are two MOSFETs. One acts as the amplifying stage and we will call this M1, and the other is the active load which we will call M2. Depending on the type of active load, the port of the active load corresponding to the direction of current is connected to the drain of M1. The source of M1 is connected to a lower voltage level than the supply. +Typically, this amplifier is used to provide voltage gain after preamplification. It has high input impedance and low output impedance. It consists of a pmos transistor called pullup and an nmos transistor called pulldown. This topology is called common source as the input and output terminals share the source as a common terminal. + +## Routing +common source amplifier routing depends if it has a folded diode load. In the normal case, do the following: +1. Connect the drain of pullup to the drain of pulldown +2. Connect the source of pullup to the gate of pullup diff --git a/openfasoc/generators/glayout/glayout/llm/rag_data/CurrentMirror.md b/openfasoc/generators/glayout/glayout/llm/rag_data/CurrentMirror.md index f9336a517..d7d32fab4 100644 --- a/openfasoc/generators/glayout/glayout/llm/rag_data/CurrentMirror.md +++ b/openfasoc/generators/glayout/glayout/llm/rag_data/CurrentMirror.md @@ -1,4 +1,8 @@ # Current Mirror -A current mirror is a circuit designed to copy a current -The ratio is the width ratio between mirror and reference, used to tune the relative current between mirror transistor drain and reference transistor drain. -two transistors (either nfet or pfet) one labeled as the reference which accepts an input current at the drain, and one labeled as mirror which has the output current at the drain. The sources of reference and mirror are connected and the gates of reference and mirror are also connected. The drain of the reference is connected to gate of reference. \ No newline at end of file +A current mirror is a circuit designed to copy a current. It uses either two pmos or two nmos transistors. Current is copied from a transistor called reference to the other transistor called mirror. The ratio of the current in the drain of the reference to the current in the drain of mirror is equal to the ratio the W/L of the mirror to the W/L of the reference. This is a very important circuit, often used as a current source in many analog circuits. + +## Routing +current mirror, route reference gate to mirror gate, reference drain to reference gate, and reference source to mirror source +1. Connect the source of reference to the source of mirror. +2. Connect the gate of reference to the gate of mirror. +3. Connect the drain of reference to the gate of reference. \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/rag_data/DeltaSigmaModulator.md b/openfasoc/generators/glayout/glayout/llm/rag_data/DeltaSigmaModulator.md index 4d8a45aa1..dead2e980 100644 --- a/openfasoc/generators/glayout/glayout/llm/rag_data/DeltaSigmaModulator.md +++ b/openfasoc/generators/glayout/glayout/llm/rag_data/DeltaSigmaModulator.md @@ -1,2 +1,3 @@ # Delta Sigma Modulator ADC -A delta sigma modulator is a circuit consisting of several existing components including an opamp and a latched comparator. The latched compartor includes a d flip flop and a strong arm latch. All these components can be directly imported. The outputs of the opamp should be connected to the inputs of the latched comparator. \ No newline at end of file +A delta sigma modulator is a circuit consisting of several existing components including an opamp and a latched comparator. The latched compartor includes a d flip flop and a strong arm latch. All these components can be directly imported. The outputs of the opamp should be connected to the inputs of the latched comparator. +Delta-sigma (ΔΣ; or sigma-delta, ΣΔ) modulation is an oversampling method for encoding signals into low bit depth digital signals at a very high sample-frequency as part of the process of delta-sigma analog-to-digital converters (ADCs) and digital-to-analog converters (DACs). Delta-sigma modulation achieves high quality by utilizing a negative feedback loop during quantization to the lower bit depth that continuously corrects quantization errors and moves quantization noise to higher frequencies well above the original signal's bandwidth. Subsequent low-pass filtering for demodulation easily removes this high frequency noise and time averages to achieve high accuracy in amplitude which can be ultimately encoded as pulse-code modulation (PCM). diff --git a/openfasoc/generators/glayout/glayout/llm/rag_data/GeneralArray.md b/openfasoc/generators/glayout/glayout/llm/rag_data/GeneralArray.md new file mode 100644 index 000000000..a3cc99f62 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/llm/rag_data/GeneralArray.md @@ -0,0 +1,12 @@ +# x by y array of elements (e.g. fet, mimcap, or via) +create a x by y array of elements is a common request. +NOTE, An array is NOT itself a single component that can be placed. You MUST MANUALLY place each element in the array. +To fulfill this request, you must place the element (a component) several times into a matrix. Arrays require placing the same component many times into a matrix like structure. The single component which is placed many times (also called the array element) is typically included in the designers request. Arrays are typically described by their dimensions (rows by columns). The dimensions are NOT a parameter and are hard coded. Dimensions should NOT be confused with single element parameters (which should be same for all elements in the array). +## place +when placing elements of an array, always multiply rows by columns to get number of elements in the array. Name the placed components by their element index (start with element1, then element2, and so on). +## move +move the other elements in the first row to the right of element1 +move each element in the second row above the first row, and move the other elements in the second row to the right of the leftmost element in the second row +continue this until all rows are moved into position. +## Routing +routing depends on the component in the array, but route from the first element until the last element, routing each element to the elements which are nearest to it. \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/rag_data/MimcapArray.md b/openfasoc/generators/glayout/glayout/llm/rag_data/MimcapArray.md new file mode 100644 index 000000000..a64eebed7 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/llm/rag_data/MimcapArray.md @@ -0,0 +1,18 @@ +# x by y array of mimcaps +create a x by y array of mimcaps is a common request. +NOTE, An array is NOT itself a single component that can be placed. You MUST MANUALLY place each mimcap in the array. +To fulfill this request, you must place the mimcap (a component) several times into a matrix. Arrays require placing the same component many times into a matrix like structure. The single component which is placed many times (also called the array mimcap) is typically included in the designers request. Arrays are typically described by their dimensions (rows by columns). The dimensions are NOT a parameter and are hard coded. Dimensions should NOT be confused with single mimcap parameters (which should be same for all mimcaps in the array). +## place +when placing mimcaps of an array, always multiply rows by columns to get number of mimcaps in the array. Name the placed components by their mimcap index (start with mimcap1, then mimcap2, and so on). +## move +move the mimcaps in the first row to the right of mimcap1 +move each mimcap in the second row above the first row, and move the other mimcaps in the second row to the right of the leftmost mimcap in the second row +continue this until all rows are moved into position. + +in other words +start by moving the first row into position +then move the second row above first row +and arrange the second row from left to right + +## Routing +Only route each mimcap to the mimcaps which are nearest to it. \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/rag_data/StrongArmLatch.md b/openfasoc/generators/glayout/glayout/llm/rag_data/StrongArmLatch.md index b1ed63e08..958b6d66a 100644 --- a/openfasoc/generators/glayout/glayout/llm/rag_data/StrongArmLatch.md +++ b/openfasoc/generators/glayout/glayout/llm/rag_data/StrongArmLatch.md @@ -1,2 +1,15 @@ # Strong Arm Latch -A strong arm latch consists of a diffpair, a CrossCoupleInverters, a bridge nfet, a clkgnd nfet, and two pfets clkpwrL (west) and clkpwrR (east). The cross coupled inverters should be at the top. The bridge should be above the diffpair but below the cross coupled inverters. The clkgnd should be at the bottom, and both clkpwr transistors should be left and right of the cross coupled inverters. You must route the drain of transistor A of the diffpair with the drain of the bridge, the drain of transistor B of the diffpair with the source of the bridge, the source of transistor A in the diffpair with the source of clkgnd. \ No newline at end of file +A strong arm latch consists of an nmos differential pair called diffp, a cross coupled inverter component (CrossCoupledInverters), a bridge nfet called bridge, a clkgnd nfet, a tail nfet called tail, and two pfets clkpwrL1 and clkpwrL2 (west) and clkpwrR1 and clkpwrR2 (east). The tail nfet should be at the bottom. Diffp should be above tail and bridge should be above diffp. The cross couple inverters should be above bridge. The CrossCoupledInverters should be imported clkpwrL1 and clkpwrL2 should be to the left of the cross coupled inverter and clkpwrR1 and clkpwrR2 should be the right of the cross coupled inverters. +## Routing +Only route together these ports, nothing else +1. Connect the source of diffp to the drain of tail. +2. Connect the drain of bridge to the drain of the one of the nmos of diffp. +3. Connect the source of bridge to the drain of the other nmos of diffp. +4. Connect the source of the left nmos of the cross coupled inverters to the drain of the left nmos. +5. Connect the source of the right nmos of the cross coupled inverters to the drain of the right nmos. +6. Connect the drain of clkpwrR2 (the rightmost pmos) to the drain of the right nmos of diffp +7. Connect the drain of clkpwrR1 to the drain the right nmos of the cross coupled inverters. +8. Connect the drain of clkpwrL2 (the leftmost pmos) to the drain of the left nmos of diffp +9. Connect the drain of clkpwrL1 to the drain the left nmos of the cross coupled inverters. +10. Connect the gates of clkpwrL1 and clkpwrL2 together. +11. Connect the gates of clkpwrR1 and clkpwrR2 together. \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/rag_data/WilsonCurrentMirror.md b/openfasoc/generators/glayout/glayout/llm/rag_data/WilsonCurrentMirror.md new file mode 100644 index 000000000..fe53eace6 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/llm/rag_data/WilsonCurrentMirror.md @@ -0,0 +1,9 @@ +# Wilson Current Mirror +A wilson current mirror is a 4 transistor extension on the basic current mirror design. It adds 2 transistors in the exact same routing configuration on top of the 2 existing transistors. +## Placement +The Wilson current mirror has 2 pairs of transistors which should be matched. Just like in a normal current mirror where the reference should be matched to the mirror, in this case the reference must be matched to the mirror. But, since we have 4 transistors, there are 2 references and 2 mirror transistors. There are several possible matching techniques that could be used including interdigitated placement (using the interdigitated place macro). One way to do this would be to place one interdigitated pair on top of another. There is a 4 interdigitated transistors place macro, if you use that you must specify top_row_device="nfet" and bottom_row_device="nfet". +## Routing +For the purposes of this description, assume you are using interdigitated matching. In the interdigitated pair, one transistor is "A" and the other is "B". Take transistor "A" as the reference and transistor "B" as the mirror. +Route the source of top's reference transistor to the drain of bottom's reference transistor. Route the source of top's mirror transistor to the drain of the bottoms mirror transistor. +The top pair is routed by connecting the top reference gate to top reference drain, and the top reference gate to the top mirror gate. +The bottom pair is routed differently, by connecting the bottom mirror gate to the bottom mirror drain and the bottom reference gate to the bottom mirror gate. Additionally, for the bottom pair the sources are shorted. \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/rag_data/classA.md b/openfasoc/generators/glayout/glayout/llm/rag_data/classA.md index 745049d1c..2fc73287c 100644 --- a/openfasoc/generators/glayout/glayout/llm/rag_data/classA.md +++ b/openfasoc/generators/glayout/glayout/llm/rag_data/classA.md @@ -1,3 +1,6 @@ # Class A Amplifier The purpose of a Class A amplifier is to provide linear amplification of an input signal. This results in low distortion of the amplified signal. -class A amplifier can be created with two nmos transistors, m1 and m2 respectivly. The gate of m1 is connected to input voltage and the drain is connected the the drain of m2. The source of m1 is tied to vss and the source of m2 is connected to vdd. The gate of m2 is connected to vgg. The node between the drains of m1 and m2 are connected to vout which can be connect to a capacitor and resistor in parallel to block unwanted signals from reaching the load. +class A amplifier can be created with two nmos transistors, called amp and load. The source of amp is connected to VSS and the drain of amp is connected the source of load. The drain of load is connected to VDD. The gate of amp is connected to the input signal and the gate of load is connected to a bias voltage. The output signal is taken from the drain of amp. + +## Routing +Route together the drain of amp and the source of load. \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/rag_data/diffpair.md b/openfasoc/generators/glayout/glayout/llm/rag_data/diffpair.md index 5036571d6..2c8b68d1f 100644 --- a/openfasoc/generators/glayout/glayout/llm/rag_data/diffpair.md +++ b/openfasoc/generators/glayout/glayout/llm/rag_data/diffpair.md @@ -1,13 +1,6 @@ -# Differential Pair -## Layout Description -The diff_pair is created using 2 nfet Components. The nfet Components are referred to as “A” and “B” respectively. Place B right of A. Route the source of A to the source of B. -## Paramters -The diff pair has the following configurable parameters: -length: a float parameter specifying the length of all transistor Components part of the diff pair. -width: a float parameter specifying the width of all transistor Components part of the diff pair. -fingers: an integer parameter which modifies the number of fingers in all transistor Components which are part of the diff pair. -## Ports -The following are just some examples of the valid ports for diff_pair: -ComponentRef_A_source_E -ComponentRef_B_drain_W -ComponentRef_A_gate_E +# Differential Pair or diffpair +A differential pair is an amplifier used to amplify the difference between two voltage input signals. It uses two nmos or pmos transistors, with their sources shorted together. This kind of amplifier is able to achieve high gain and high input impedance. The single-ended output is taken from one end of the pair. +## Place +a differential pair consists of two transistors, one for the positive side and one for the negative side +## Routing +differential pair only has one route which is source to source diff --git a/openfasoc/generators/glayout/glayout/llm/rag_data/inverter.md b/openfasoc/generators/glayout/glayout/llm/rag_data/inverter.md index 6800cc1c8..89e4bb8a9 100644 --- a/openfasoc/generators/glayout/glayout/llm/rag_data/inverter.md +++ b/openfasoc/generators/glayout/glayout/llm/rag_data/inverter.md @@ -1,5 +1,4 @@ -# Static CMOS Inverter -An Inverter is an electronic circuit which inverts the input. For example, if given a high input voltage it will produce a low output voltage. If given a low input voltage it will produce a high output voltage. -The pmos is typically placed above the nmos. -The pmos is above the nmos and it's source is tied to vdd. The nmos source is tied to ground. The nmos drain and pmos drain are routed together. The node connecting the nmos and pmos drain is the output node. Additonally, the nmos gate and pmos gate are connected. The node connecting the nmos and pmos gate is the input node. -The sizing ratio is the ratio between pmos width and nmos width. The sizing ratio is typically the most optimal when it is 2:1. +# inverter +An inverter is a two transistor circuit that is able to invert the input signal. In simpler terms, an input signal that is classified as input high, creates an output low signal and vice versa. It uses a PMOS, called pullup, and NMOS, called pulldown. +## Routing +inverter, route pmos source to nmos drain, and short the gates \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/rag_data/mimcap.md b/openfasoc/generators/glayout/glayout/llm/rag_data/mimcap.md new file mode 100644 index 000000000..ed7b845f8 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/llm/rag_data/mimcap.md @@ -0,0 +1,8 @@ +# MIMCAP or mim capacitor +The mimcap is a single capacitor element. +It is a standard glayout component called "mimcap". It has only one parameter which is the "size" and is tuple type. The size describes the width and height of the single mimcap element. + +valid mimcap ports syntax structure: +start with the component reference name. +then specify top_met or bottom_met +then specify a direction from N, E, S, or W \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/rag_data/mosfet.md b/openfasoc/generators/glayout/glayout/llm/rag_data/mosfet.md index bf2e34620..b645ba5c7 100644 --- a/openfasoc/generators/glayout/glayout/llm/rag_data/mosfet.md +++ b/openfasoc/generators/glayout/glayout/llm/rag_data/mosfet.md @@ -1,2 +1,3 @@ -# MOSFET +# MOSFET transistor +MOSFETs come in n-type (nmos or nfet) and p-type (pmos or pfet) A MOSFET is the basic transistor device used to build circuits. The two types of MOSFETs are the nmos or n-type or nfet and pmos or p-type or pfet. These include four terminals: Source (S), Gate (G), Drain (D), and Body (B). However, in almost all circuits, the body terminal is internally connected to the source, so the designer mainly uses source, gate, and drain. \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/rag_data/opamp.md b/openfasoc/generators/glayout/glayout/llm/rag_data/opamp.md index 1cd554fb6..3b13fe3a7 100644 --- a/openfasoc/generators/glayout/glayout/llm/rag_data/opamp.md +++ b/openfasoc/generators/glayout/glayout/llm/rag_data/opamp.md @@ -1,2 +1,28 @@ -# Opamp -An operational amplifier or opamp is a voltage amplifying device. A 4 stage opamp consists of several integrator stages. \ No newline at end of file +# Opamp or Operational Amplifier +An operational amplifier or opamp is a voltage amplifying device. A 4 stage opamp consists of several integrator stages. A 2 stage opamp can be created using the following components: +## First Stage +Place the following: +Two nfet differential pair transistors called diffpair_left and diffpair_right, two load current mirror pmos transistors called load_mirr and load_ref, two tail current mirror nmos transistors called tail_mirr and tail_ref. the tail_mirr transistor should be placed at the bottom. The diffpair_left transistor should be placed above the tail_mirr transistor and the diffpair_right transistor should be placed above the tail_ref transistor. The load_mirr transistor should be placed above the diffpair_left transistor and the load_ref transistor should be placed above the diffpair_right transistor. +## Second stage +Place the following: +A common source pmos transistor called pamp, two current mirror nmos transistors called pamp_mirr and pamp_ref. There is also a miller capacitance, which uses a mimcap array called miller_cap. +The pamp transistor should be placed above the pamp_mirr and pamp_ref transistor. pamp_ref should be to the right of pamp_mirr. The miller_cap should be placed above the pamp transistor. +## Routing +Only route together these ports, nothing else +1. Connect the source of diffpair_left to the source of diffpair_right. +2. Connect the drain of diffpair_left to the drain of load_ref. +3. Connect the drain of diffpair_right to the drain of load_mirr. +4. Connect the gate of load_mirr to the gate of load_ref. +5. Connetc the drain of load_ref to the gate of load_ref. +6. Connect the source of diffpair_left to the drain of tail_mirr. +7. Connect the gate of tail_mirr to the gate of tail_ref. +8. Connect the source of tail_mirr to the source of tail_ref. +9. Connect the source of load_ref to the source of load_mirr. +10. Connect the drain of tail_ref to the gate of tail_ref. +11. Connect the drain of diffpair_right to the gate of pamp. +12. Connect the source of pamp to the drain of pamp_mirr. +13. Connect the source of pamp_ref to the source of pamp_mirr. +14. Connect the drain of pamp_ref to the gate of pamp_mirr. +15. Connect the gate of pamp_ref to the gate of pamp_mirr. +16. Connect the drain of diffpair_right to the top metal of first capacitor of miller_cap. +17. Connect the drain of pamp to the top metal of the last capacitor in miller_cap. diff --git a/openfasoc/generators/glayout/glayout/llm/rag_data/pushpullamp.md b/openfasoc/generators/glayout/glayout/llm/rag_data/pushpullamp.md index 9af29f92d..012a7dd39 100644 --- a/openfasoc/generators/glayout/glayout/llm/rag_data/pushpullamp.md +++ b/openfasoc/generators/glayout/glayout/llm/rag_data/pushpullamp.md @@ -1,2 +1,6 @@ -# Push Pull Amp (Class B Amplifier) -A push-pull amplifier typically consists of two transistors, a nmos and pmos. The sources of the two transistors are connected together and to the output load. The drains of each transistor are connected to the supply voltages. \ No newline at end of file +# Push Pull or Class B Amplifier +A push-pull amplifier typically consists of two transistors, a nmos and pmos called sink and src respectively. This topology is useful as it unifies sourcing and sinking to achieve better power efficiency and cancellation of even harmonics in the spectral output. +## Routing +Only route together these ports, nothing else +1. Connect the gates of src and sink +2. Connect the source of src to the source of sink \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/GlayoutStrictSyntax.md b/openfasoc/generators/glayout/glayout/llm/syntax_data/GlayoutStrictSyntax.md index 84faf17b8..b1a7aa23f 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/GlayoutStrictSyntax.md +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/GlayoutStrictSyntax.md @@ -21,14 +21,13 @@ with_dummy: When True, specifies dummy devices should be added to the edges of t with_dnwell: boolean parameter specifying to use deep nwell if True. You should usually set this to False unless the designer specifies otherwise. rmult: make metal connections within the nmos component wider. Specify this as 1 unless the designer asks to make routing wider or use wider metals. -The main nmos ports correspond to source, gate, and drain nodes. Each underscore in a port name represents a level of hierarchy. For example, we start with the ComponentRef which is the name of the nmos Component instance. Then we specify one of the nodes from drain, gate, or source. Lastly we specify a direction indicator from N, E, S, W. The following are just some examples of the valid nmos ports: -ComponentRef_source_N -ComponentRef_drain_W -ComponentRef_source_E -ComponentRef_gate_S +The main nmos ports correspond to source, gate, and drain nodes. Each underscore in a port name represents a level of hierarchy. For example, we start with the ComponentRef which is the name of the nmos Component instance. Then we specify one of the nodes from drain, gate, or source. Lastly we specify a direction indicator from N, E, S, W. + +valid nmos ports syntax structure: +ComponentRef_[gate,source,drain]_[N,E,S,W] ### PMOS -Pmos is a p-type mosfet transistor. It is also referred to as pmos, pfet or p-type. It has the following parameters which are configurable when you place the component: +Pmos is a p-type mosfet transistor. It is also referred to as pmos, pfet or p-type. It has the following parameters: length: a float parameter specifying the transistor length width: a float parameter specifying the width of a single transistor fingers: an integer parameter which multiplies the width. For example, if fingers is 3, then the size will be 3 times the width. @@ -39,41 +38,16 @@ with_dummy: When True, specifies dummy devices should be added to the edges of t dnwell: Note that this is different from the nmos “width_dnwell” argument, but it serves a similar purpose. When dnwell is set to True it adds a deep nwell to the pmos transistor. You should set this to False unless the designer specifies otherwise. The designer may say they want triple well isolation, in which case you should set this as True. rmult: make metal connections within the pmos component wider. Specify this as 1 unless the designer asks to make routing wider or use wider metals. -Here are just some examples of the valid pmos ports: -ComponentRef_gate_S -ComponentRef_source_E -ComponentRef_drain_W +valid pmos ports syntax structure: +ComponentRef_[gate,source,drain]_[N,E,S,W] ### MIMCAP -The mimcap is a capacitor. The mimcap takes only one argument which can be configured when the component is placed: +The mimcap is a capacitor. It has the following parameters: size: a tuple of floating point numbers like (2.1, 3.7) denoting the x and y dimension of the capacitor. The default size is (5.0, 5.0) -The mimcap has the following 4 ports: -ComponentRef_top_met_N -ComponentRef_top_met_E -ComponentRef_top_met_S -ComponentRef_top_met_W - -### MIMCAP Array -There is also a mimcap_array (also written as mimcap array) which automatically places and routes several mimcaps together. The mimcap_array takes the following parameters: -size: a tuple of floating point numbers denoting the x and y dimension of the capacitor. -columns: the number of columns in the array -rows: the number of rows in the array - - -### Differential Pair -A differential pair is available, which is referred to as diff_pair or diff pair. The diff_pair is a differential pair Component which is created using 2 nfet Components. The nfet Components are referred to as “A” and “B” respectively. The diff pair has the following configurable parameters: -length: a float parameter specifying the length of all transistor Components part of the diff pair. -width: a float parameter specifying the width of all transistor Components part of the diff pair. -fingers: an integer parameter which modifies the number of fingers in all transistor Components which are part of the diff pair. +valid mimcap ports syntax structure: +ComponentRef_[top,bottom]_met_[N,E,S,W] -The following are just some examples of the valid ports for diff_pair: -ComponentRef_A_source_S -ComponentRef_A_drain_N -ComponentRef_B_source_S -ComponentRef_A_gate_E -ComponentRef_B_drain_W -ComponentRef_B_gate_E ## Strict Syntax Commands Strict syntax supports the commands listed below. Note I have left square brackets [] around places where specific command calls should fill in information. @@ -111,24 +85,7 @@ route between m1_source_E and m2_source_E using smart_route or route between m1_source_W and m2_source_W using smart_route -## Non-Standard Components Which can be Imported -### CrossCoupledInverters -CrossCoupledInverters is available to use and can be imported with: -import CrossCoupledInverters -The cell is made up of 4 transistor Components. The top two transistors are pfets and the bottom two transistors are nfets. -This cell implements the following prepackage circuit for easy import: -CrossCoupledInverters includes two inverters. Inverters are composed of an nfet and pfet with their gates shorted with each other (the input of an inverter) and their drains shorted with each other (the output of an inverter). The inputs of the inverters are also shorted, with the sources of the nfets shorted with each other and the drains of the pfets shorted with each other. Importing the cell allows for it to be placed without any extra work. The CrossCoupledInverters has the following parameters: -pfet_width: A float parameter specifying the width of the pmos Components -nfet_width: A float parameter specifying the width of the nmos Components -length: A float parameter specifying the length of all transistor Components -numfingers: An int parameter specifying the number of fingers in all transistor Components - -The west (or left) inverter generally has the following port naming conventions: -ComponentRef_top,bottom_A_source,drain,gate_N,E,S,W -The west (or right) inverter generally has the following port naming conventions: -ComponentRef_top,bottom_B_source,drain,gate_N,E,S,W -Where top refers to the inverter’s pmos Component and bottom refers to the inverters nmos Component. A or B refers to the inverter, with A representing the west inverter and B representing the east inverter. - ## StrictSyntax Style Guide +When specifying component parameters always use named arguments. You should always follow this order of commands when creating a Component with strictsyntax: Start by importing any required Components, then create any required parameters, then place all required ComponentRefs with their respective parameters, then move all ComponentRefs to their final positions relative to one another, and lastly route between ComponentRefs. Do not place components overlapping (always move components if more than one is placed) \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/GlayoutStrictSyntaxQA b/openfasoc/generators/glayout/glayout/llm/syntax_data/GlayoutStrictSyntaxQA deleted file mode 100644 index 2b43d903f..000000000 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/GlayoutStrictSyntaxQA +++ /dev/null @@ -1,225 +0,0 @@ -Question 1: What is the purpose of Glayout strictsyntax? -Answer 1: Glayout strictsyntax is a command language designed to create analog circuit layouts by describing the placement, movement, and connection of circuit components using simple commands. - -Question 2: What are Components in the context of Glayout strictsyntax? -Answer 2: Components are pre-designed circuits used as building blocks for creating larger circuits, and can be highly customized through various configurable parameters when placed. - -Question 3: What does it mean to instantiate a Component? -Answer 3: Instantiating a Component refers to placing a Component within a layout, which is done by drawing geometric shapes representing the Component in the layout. - -Question 4: What is the significance of the ComponentRef in Glayout? -Answer 4: The ComponentRef is the instance name given to a Component when it is placed in a layout, serving as an identifier for that particular instance. - -Question 5: Are Glayout Components hierarchical? -Answer 5: Yes, Glayout Components are hierarchical, meaning a Component can consist of various sub-Components. - -Question 6: How does routing work in Glayout? -Answer 6: Routing in Glayout involves connecting Components together by drawing calling the route command between their Ports, which represent the input or output nodes of the Components. - -Question 7: How are Ports in a Component layout accessed? -Answer 7: Ports are accessed through an organized naming syntax reflecting the Port's function and location on the Component Instance. - -Question 8: What are the directional indicators used in port naming, and what do they indicate? -Answer 8: Direction indicators North (N), East (E), South (S), and West (W) are used to specify the edge of the Port's corresponding node in the layout. - -Question 9: What does the "fingers" parameter indicate when placing an NMOS component? -Answer 9: The "fingers" parameter specifies the scaling factor applied to the width of an NMOS transistor, increasing the size by the specified factor. - -Question 10: What is the purpose of the "with_tie" parameter in an NMOS component? -Answer 10: The "with_tie" parameter indicates whether a bulk tie is needed for the NMOS transistor. - -Question 11: What does setting "rmult" to a value other than 1 do in an NMOS component? -Answer 11: Setting "rmult" to a value other than 1 will make the internal metal connections within the NMOS component wider than default. In almost all cases it should be set to 1. - -Question 12: What kind of Components are part of the standard Glayout runtime? -Answer 12: Standard components such as NMOS, PMOS, MIMCAP, and differential pair transistors are part of the Glayout runtime and do not require imports to use. - -Question 13: How do you import a non-standard Component into Glayout? -Answer 13: You can import a non-standard Component using the "import [Component]" command, where [Component] is the name of the component you wish to import. - -Question 14: What is the primary advantage of using "smart_route" in Glayout? -Answer 14: "smart_route" is advantageous as it can almost always optimally route between two ports automatically, simplifying the routing process. smart_route should be used for all routes in most cases. - -Question 15: What is the general route syntax in Glayout strictsyntax? -Answer 15: The general route syntax is "route between [Port1] and [Port2] using [route_type]" - -Question 16: How are the PMOS transistor ports named in Glayout? -Answer 16: PMOS transistor ports are named with the ComponentRef followed by a pin identifier (like "gate", "source", or "drain"), and ending with a directional indicator (N, E, S, W). - -Question 17: What does the "size" argument of the MIMCAP component specify? -Answer 17: The "size" argument for the MIMCAP component specifies the x and y dimensions of the capacitor. - -Question 18: What defines the differential pair Component in Glayout? -Answer 18: The differential pair Component, referred to as diff_pair, is composed of two NFET components labeled as "A" and "B" - -Question 19: How can you create customizable parameters in Glayout strictsyntax? -Answer 19: You can create customizable parameters using the "create a [Type] parameter called [ParameterName]" command. - -Question 20: When placing more than one ComponentRef, what must be done to avoid overlapping? -Answer 20: If more than one ComponentRef is placed, at least one must be moved using the "move" command to ensure they do not overlap. - -Question 21: What is the primary component configuration for a CrossCoupledInverters cell? -Answer 21: The primary configuration for a CrossCoupledInverters cell includes four transistor components, with the top two being PMOS and the bottom two being NMOS. - -Question 22: What command sequence should be followed according to the StrictSyntax Style Guide? -Answer 22: The layout should be created by first importing required components, then creating parameters, placing all ComponentRefs with parameters, moving ComponentRefs to positions relative to each other, and lastly routing between ComponentRefs. - -Question 23: What parameter is used to specify multiple rows of fingers in a PMOS component? -Answer 23: The "multipliers" parameter is used to specify how many rows of fingers to place in a PMOS component. - -Question 24: How do you specify a bulk tie when placing a PMOS transistor Component? -Answer 24: To specify a bulk tie for a PMOS transistor, you would set the "with_tie" parameter to True while placing the component. - -Question 25: What is a substrate tap in the context of Glayout Components? -Answer 25: A substrate tap is an addition made to the very outside perimeter of a MOS transistor if the "with_substrate_tap" parameter is set to True. - -Question 26: What type of device is represented by the NMOS component in Glayout? -Answer 26: The NMOS component in Glayout represents an n-type MOSFET transistor. - -Question 27: What does the "length" parameter control when placing a PMOS component in Glayout? -Answer 27: The "length" parameter controls the transistor length of the PMOS component. - -Question 28: What is the default value for the "multipliers" parameter when placing an NMOS component? -Answer 28: The default value for the "multipliers" parameter in an NMOS component is 1. - -Question 29: Why would you set the "with_dummy" parameter to True for an NMOS or PMOS component? -Answer 29: The "with_dummy" parameter is set to True to add dummy devices to the edges of the transistor for better electrical performance and uniformity. - -Question 30: How would you import the component 'CapacitorBank' using Glayout strictsyntax? -Answer 30: To import the component 'CapacitorBank', you would use the command: "import CapacitorBank". - -Question 31: What command would you use to move a component 'c1' to the right of component 'c2' in Glayout? -Answer 31: You would use the move command as follows: "move c1 right c2". - -Question 32: In Glayout, what would be a valid port name for the east edge of the drain node of a PMOS transistor named "p1"? -Answer 32: A valid port name would be "p1_drain_E". - -Question 33: Can you set the direction of the 'route' command in Glayout to connect components positioned diagonally? -Answer 33: No, the route command does not directly specify diagonal directions, but you would typically use "smart_route" to optimally route components, even if they are diagonally aligned. - -Question 34: How would you place a differential pair with a width of 1.5 and length of 2.0 using Glayout strictsyntax? -Answer 34: You would use the place command as follows: "place a diff_pair called dp1 with width 1.5, length 2.0". - -Question 35: What command allows you to create a new parameter in Glayout called 'voltage_threshold'? -Answer 35: The command to create a new parameter called 'voltage_threshold' would be: "create a float parameter called voltage_threshold". - -Question 36: When placing an MIMCAP, how do you restrict its size to 4.0 by 3.0 using Glayout strictsyntax? -Answer 36: You would use the following command: "place a mimcap called mc1 with size (4.0, 3.0)". - -Question 37: Why might you use the command "with_dnwell True" when placing a PMOS transistor? -Answer 37: You might use "with_dnwell True" to incorporate a deep nwell into the PMOS transistor, typically for electrical isolation purposes like triple well isolation. - -Question 38: In Glayout, what is the significance of "fingers" and "multipliers" when combined in a transistor component configuration? -Answer 38: The "fingers" parameter multiplies the width of the transistor, while "multipliers" specify the number of rows of fingers, effectively controlling the layout and dimensions of the transistor array. - -Question 39: What would be the correct syntax to import multiple components, such as VoltageReference and CurrentMirror, into Glayout? -Answer 39: The import command can be used twice, like this: "import VoltageReference" followed by "import CurrentMirror". - -Question 40: What are the key steps outlined in the Glayout strictsyntax Style Guide for creating a component layout properly? -Answer 40: The key steps are importing required components, creating parameters, placing ComponentRefs with parameters, moving ComponentRefs to avoid overlapping, and routing between ComponentRefs. - -Question 41: What does the command "move m2 above m3" accomplish in Glayout? -Answer 41: It moves the component with ComponentRef 'm2' above another component with ComponentRef 'm3', ensuring they do not overlap. - -Question 42: How do you place a PMOS transistor with a true deep nwell using strictsyntax? -Answer 42: You would use the place command with the deep nwell argument set to true, like this: "place a pmos called p1 with width 1.0, length 2.0, with_dnwell True". - -Question 43: What does the "ComponentRef_top_met_N" port represent in a MIMCAP component? -Answer 43: "ComponentRef_top_met_N" represents the north edge of the top metal layer of the mimcap associated with the particular ComponentRef. - -Question 44: Can Glayout strictsyntax create non-rectangular routes between components? -Answer 44: Yes, with the use of different route types like c_route or L_route, you can create non-rectangular routes, though smart_route is recommended for optimal results. - -Question 45: What would the port naming look like for the south side of the gate node of a differential pair's nfet component labelled "dif1_A"? -Answer 45: The port name would be "dif1_A_gate_S". - -Question 46: How would you create an integer parameter named 'layer_count' in Glayout? -Answer 46: The command would be: "create an int parameter called layer_count". - -Question 47: When is it essential to perform a 'move' command after placing components in Glayout? -Answer 47: It's essential to perform a 'move' command when multiple components have been placed, to ensure they are positioned relative to each other without overlapping. - -Question 48: What would a command look like to place an NMOS transistor with a length of 1.2, width of 0.8, and 4 fingers? -Answer 48: The command would be: "place a nmos called n1 with width 0.8, length 1.2, fingers 4". - -Question 49: Can the "create parameters" command in Glayout create multiple parameters at once? -Answer 49: No, the "create parameters" command in Glayout is used to create individual parameters; you use separate commands for each new parameter. - -Question 50: If a nmos ComponentRef called n1 is to the left of a pmos ComponentRef called p2, which ports would be selected for smart routing if they were connecting the sources? -Answer 50: You would select the east port of n1 and the west port of p2, resulting in: "route between n1_source_E and p2_source_W using smart_route". - -Question 51: In Glayout strictsyntax, what is the function of the width parameter for a PMOS transistor? -Answer 51: The width parameter for a PMOS transistor specifies the width of a single transistor within the PMOS component. - -Question 52: How does the fingers parameter affect the size of a transistor when you set it to a value like 3? -Answer 52: When the fingers parameter is set to 3, it means the total width of the transistor will be three times its singular width, as it adds additional parallel conducting channels. - -Question 53: How do you specify whether a substrate tap is needed when placing a transistor using Glayout strictsyntax? -Answer 53: You specify the need for a substrate tap using the with_substrate_tap parameter, setting it to True if a substrate tap is required. - -Question 54: What is the command to place a component called resistor1 with a size of (10.0, 2.0) in Glayout? -Answer 54: Assuming resistor1 is a Component type that accepts a size parameter, you would use: "place a resistor1 called r1 with size (10.0, 2.0)". - -Question 55: How would you use Glayout strictsyntax to move a ComponentRef named cap1 to the left of another ComponentRef called inductor1? -Answer 55: You would use the command: "move cap1 left inductor1". - -Question 56: If you have two inductors, ind1 and ind2 positioned north and south, how would you route their north ports in Glayout? -Answer 56: You would use the command: "route between ind1_port_N and ind2_port_N using smart_route". - -Question 57: Can you define custom Component parameters for specific design requirements in Glayout? -Answer 57: Yes, you can define custom Component parameters using the create parameters command to make Components highly modular and customizable. - -Question 58: What are the steps to set up a differential pair with fingers of 4 on both transistors using strictsyntax? -Answer 58: First, ensure the differential pair Component is available. Then use the command: "place a diff_pair called dpair1 with fingers 4". - -Question 59: If a deep nwell is necessary for an NMOS component, how do you incorporate it using strictsyntax? -Answer 59: You incorporate a deep nwell by setting the with_dnwell parameter to True when placing the NMOS component. - -Question 60: How do you place a PMOS transistor with a multiplicity of 3 rows of fingers using strictsyntax? -Answer 60: You use the command: "place a pmos called pm1 with multipliers 3". - -Question 61: What is the purpose of the Glayout import command? -Answer 61: The import command is used to include components into the design that are not part of the standard Glayout runtime. - -Question 62: How would you specify in Glayout strictsyntax that a PMOS transistor's drain should be connected to a higher metal layer? -Answer 62: Connection to a higher metal layer usually involves additional specifications or design rules. The strictsyntax itself might not explicitly specify layers, but you could name or route the connection in such a way that indicates it should be connected to a higher layer. - -Question 63: What does an instance name or ComponentRef signify in an analog layout using Glayout? -Answer 63: An instance name or ComponentRef is the unique name for a particular instance of a component, used to identify and reference it within the design commands. - -Question 64: Can Glayout strictsyntax routes be adjusted for impedance matching? -Answer 64: Glayout strictsyntax does not directly account for impedance matching in routing; this would be a consideration in the component or circuit design phase that the layout must adhere to. - -Question 65: Is there a limit to how many times the route command can be used in a Glayout design? -Answer 65: There is no explicit limit to how many times the route command can be used other than the practical constraints of the layout and design complexity. - -Question 66: How do you instruct Glayout to use existing parameter names instead of values when placing a component? -Answer 66: You can pass existing parameter names directly in the place command's parameters list instead of actual values to use them in configuration. - -Question 67: What would be the command to enable wider metal connections using the rmult parameter? -Answer 67: To enable wider metal connections, you would include rmult with a value greater than 1 in the place command, for example, "place a nmos called n1 with rmult 2". - -Question 68: What would a Glayout command look like to place an NMOS transistor without a substrate tap? -Answer 68: The command would be: "place a nmos called n1 with with_substrate_tap False". - -Question 69: How would you move a placed component in Glayout so it's above another component but offset by a certain distance? Answer 69: Glayout strictsyntax does not include direct offset specification in the move command; moves are specified relative to other components' positions. - -Question 70: How do you ensure that you do not violate design rules concerning overlaps and distances between Components in Glayout strictsyntax? Answer 70: Design rules must be adhered to by appropriately moving components and planning routes to avoid overlaps and maintain required distances. - -Question 71: How are the ports of the MIMCAP capacitor denoted in Glayout strictsyntax? -Answer 71: The ports of the MIMCAP capacitor are denoted with the ComponentRef followed by "top_met" and the direction indicator (e.g., ComponentRef_top_met_N). - -Question 72: What kind of parameters are we allowed to create using Glayout strictsyntax? -Answer 72: You can create parameters of various types such as float, int, tuple, and boolean using Glayout strictsyntax. - -Question 73: In Glayout, what is the proper command sequence to connect two ports that are on the same side but belong to different Components? -Answer 73: The command sequence would be to use the route command with the direction indicators matching, as in "route between Component1_port_E and Component2_port_E using smart_route". - -Question 74: What command would you use to set the number of metal connection rows in a CrossCoupledInverters component to 4? -Answer 74: Assuming numfingers is used to set the number of rows, the command would be: "create a CrossCoupledInverters called ccinv1 with numfingers 4". - -Question 75: Can you delete or modify a Component once it's placed using strictsyntax? -Answer 75: Glayout strictsyntax does not contain commands for modification or deletion; these actions are typically done by re-issuing the command with updated parameters or recreating the layout. - -Question 76: How would a Glayout strictsyntax import command differ between a standard and non-standard component? -Answer 76: You do not need to import standard components as they are already within the Glayout runtime. The import command syntax "import [Component]" is used for non standard components, where [Component] is the name of the component to be imported. \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/BiasVoltageGenerator.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/BiasVoltageGenerator.convo index 09d8f305d..f892bb1f9 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/BiasVoltageGenerator.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/BiasVoltageGenerator.convo @@ -1,4 +1,6 @@ BiasVoltageGenerator +// no imports +// create parameters: src_width, load_width, src_length, load_length, src_multipliers, load_multipliers, src_fingers, load_fingers # figure 24 exactly create a float parameter called src_width create a float parameter called load_width @@ -8,9 +10,12 @@ create a int parameter called src_multipliers create a int parameter called load_multipliers create a int parameter called src_fingers create a int parameter called load_fingers +// place place a pmos called src with width=src_width, length=src_length, fingers=src_fingers, rmult=1, multipliers=src_multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True place a nmos called load with width=load_width, length=load_length, fingers=load_fingers, rmult=1, multipliers=load_multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +// more than one component has been placed, so move move load below src +// bias voltage generator, route drain to drain, gate to drain, and gate to source route between src_drain_E and load_drain_E using smart_route route between load_gate_E and load_drain_E using smart_route route between src_gate_W and load_source_W using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CTATVGen.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CTATVGen.convo index 475518a0e..07686a856 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CTATVGen.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CTATVGen.convo @@ -1,4 +1,6 @@ CTATVGen +// no imports +// create parameters: src_width, load_width, src_length, load_length, src_multiplier, load_multiplier, src_fingers, load_fingers # CTAT without body effect create a float parameter called src_width create a float parameter called load_width @@ -8,7 +10,10 @@ create a int parameter called src_multiplier create a int parameter called load_multiplier create a int parameter called src_fingers create a int parameter called load_fingers +// place place a nmos called src with width=src_width, length=src_length, fingers=src_fingers, rmult=1, multipliers=src_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False place a nmos called load with width=load_width, length=load_length, fingers=load_fingers, rmult=1, multipliers=load_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +// more than one component has been placed, so move move load below src +// CTAT, route drain to source route between src_drain_W and load_source_W using smart_route diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonGate.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonGate.convo index eb70f719b..4d3dd945d 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonGate.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonGate.convo @@ -1,4 +1,6 @@ CascodeCommonGate +// no imports +// create parameters: input_width, output_width, input_length, output_length, input_multipliers, output_multipliers, input_fingers, output_fingers # figure 12 exactly except output and input might be swapped create a float parameter called input_width create a float parameter called output_width @@ -8,7 +10,10 @@ create a int parameter called input_multipliers create a int parameter called output_multipliers create a int parameter called input_fingers create a int parameter called output_fingers +// place place a nmos called input with width=input_width, length=input_length, fingers=input_fingers, rmult=1, multipliers=input_multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False place a nmos called output with width=output_width, length=output_length, fingers=output_fingers, rmult=1, multipliers=output_multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +// more than one component has been placed, so move move output above input +// cascode common gate, route source to drain route between input_source_W and output_drain_W using smart_route diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CasecodeCommonGateCommonCentroid.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonGateCommonCentroid.convo similarity index 66% rename from openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CasecodeCommonGateCommonCentroid.convo rename to openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonGateCommonCentroid.convo index 00425523d..1ea7cd918 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CasecodeCommonGateCommonCentroid.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonGateCommonCentroid.convo @@ -1,6 +1,11 @@ CascodeCommonGateCommonCentroid +// no imports +// create parameters: width, length, fingers create a float parameter called width create a float parameter called length create a int parameter called fingers +// place place a common centroid pair called ccg with width=width, length=length, fingers=fingers +// only one component placed, so no move +// cascode common gate, route source to drain route between ccg_A_source_W and ccg_B_drain_W using smart_route diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonGateInterdigitated.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonGateInterdigitated.convo index cb3512d27..04fb41af1 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonGateInterdigitated.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonGateInterdigitated.convo @@ -1,6 +1,11 @@ CascodeCommonGateInterdigitated +// no imports +// create parameters: width, length, fingers create a float parameter called width create a float parameter called length -create an int parameter called fingers +create an int parameter called fingers +// place place an interdigitated nfet called CascodeCommonGate with numcols=fingers, dummy=True, with_substrate_tap=False, with_tie=True, kwargs={"width": width, "length": length, "rmult":1} +// only one component placed, so no move +// cascode common gate, route source to drain route between CascodeCommonGate_A_source_W and CascodeCommonGate_B_drain_W using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonSource.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonSource.convo index a7cf01331..2a691ade4 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonSource.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonSource.convo @@ -1,4 +1,6 @@ CascodeCommonSource +// no imports +// create parameters: input_width, bias_width, input_length, bias_length, input_multiplier, bias_multiplier, input_fingers, bias_fingers # figure 11 exactly (until gnd is implemented) create a float parameter called input_width create a float parameter called bias_width @@ -8,7 +10,10 @@ create a int parameter called input_multiplier create a int parameter called bias_multiplier create a int parameter called input_fingers create a int parameter called bias_fingers +// place place a nmos called input with width=input_width, length=input_length, fingers=input_fingers, rmult=1, multipliers=input_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False place a nmos called bias with width=bias_width, length=bias_length, fingers=bias_fingers, rmult=1, multipliers=bias_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +// more than one component has been placed, so move move input below bias +// cascode common source, route source to drain route between bias_source_W and input_drain_W using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonSourceInterdigitated.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonSourceInterdigitated.convo index 4031e0b25..d2df85b5d 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonSourceInterdigitated.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CascodeCommonSourceInterdigitated.convo @@ -1,6 +1,11 @@ CascodeCommonSourceInterdigitated +// no imports +// create parameters: width, length, fingers create a float parameter called width create a float parameter called length -create an int parameter called fingers +create an int parameter called fingers +// place place an interdigitated nfet called CascodeCommonSource with numcols=fingers, dummy=True, with_substrate_tap=False, with_tie=True, kwargs={"width": width, "length": length, "rmult":1} +// only one component placed, so no move +// cascode common source, route source to drain route between CascodeCommonSource_B_source_W and CascodeCommonSource_A_drain_W using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ClassABStage.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ClassABStage.convo index 184d1656a..ec859a399 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ClassABStage.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ClassABStage.convo @@ -1,21 +1,26 @@ ClassABStage +// import required components import PushPull import CurrentMirrorNFET +// create parameters: source_numcols, gm31_numcols, source_length, gm31_length, source_width, gm31_width create a float parameter called source_numcols create a float parameter called gm31_numcols create a float parameter called source_length create a float parameter called gm31_length create a float parameter called source_width create a float parameter called gm31_width +// place place a PushPull called pp1 place a PushPull called pp2 place an interdigitated pfet called source with numcols=source_numcols, dummy=True, with_substrate_tap=False, with_tie=True, kwargs={ "width" : source_width , "length" : source_width} place an interdigitated nfet called gm31 with numcols=gm31_numcols, dummy=True, with_substrate_tap=False, with_tie=True, kwargs={ "width" : gm31_width , "length" : gm31_length} place a CurrentMirrorNFET called sink +// more than one component has been placed, so move move source above gm31 move pp1 right of gm31 move pp2 right of pp1 move sink below gm31 +// class AB stage, route components together route between source_A_drain_E and gm31_A_drain_E using smart_route route between source_B_drain_W and gm31_B_drain_W using smart_route route between gm31_A_source_W and sink_cm_A_drain_W using smart_route diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ClassBPushPull.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ClassBPushPull.convo index 487bd53af..70c081a05 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ClassBPushPull.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ClassBPushPull.convo @@ -1,5 +1,7 @@ ClassBPushPull # figure 19 exactly +// no imports +// create parameters: supply_width, absorb_width, supply_length, absorb_length, supply_multiplier, absorb_multiplier, supply_fingers, absorb_fingers create a float parameter called supply_width create a float parameter called absorb_width create a float parameter called supply_length @@ -8,8 +10,11 @@ create a int parameter called supply_multiplier create a int parameter called absorb_multiplier create a int parameter called supply_fingers create a int parameter called absorb_fingers +// place place a nmos called supply with width=supply_width, length=supply_length, fingers=supply_fingers, rmult=1, multipliers=supply_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False place a pmos called absorb with width=absorb_width, length=absorb_length, fingers=absorb_fingers, rmult=1, multipliers=absorb_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True +// more than one component has been placed, so move move absorb below supply +// class B push pull amplifier, route source to source, and gate to gate route between supply_source_W and absorb_source_W using smart_route route between supply_gate_E and absorb_gate_E using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ClassBPushPullInterdigitated.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ClassBPushPullInterdigitated.convo index edc26e76e..827c2abe6 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ClassBPushPullInterdigitated.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ClassBPushPullInterdigitated.convo @@ -1,7 +1,12 @@ ClassBPushPullInterdigitated +// no imports +// create parameters: width, length, fingers create a float parameter called width create a float parameter called length -create an int parameter called fingers +create an int parameter called fingers +// place place an interdigitated nfet called ClassBPushPull with numcols=fingers, dummy=True, with_substrate_tap=False, with_tie=True, kwargs={"width": width, "length": length, "rmult":1} +// only one component placed, so no move +// class B push pull amplifier, route source to source, and gate to gate route between ClassBPushPull_A_source_W and ClassBPushPull_B_source_W using smart_route route between ClassBPushPull_A_gate_E and ClassBPushPull_B_gate_E using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CommonSourceAmplifier.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CommonSourceAmplifier.convo index 95629e89d..e03524b83 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CommonSourceAmplifier.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CommonSourceAmplifier.convo @@ -1,4 +1,6 @@ CommonSourceAmplifier +// no imports +// create parameters: input_width, bias_width, input_length, bias_length, input_multiplier, bias_multiplier, input_fingers, bias_fingers # figure 10 exactly, uses a pmos load and nmos amp create a float parameter called input_width create a float parameter called bias_width @@ -8,7 +10,10 @@ create a int parameter called input_multiplier create a int parameter called bias_multiplier create a int parameter called input_fingers create a int parameter called bias_fingers +// place place a nmos called input with width=input_width, length=input_length, fingers=input_fingers, rmult=1, multipliers=input_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False place a pmos called bias with width=bias_width, length=bias_length, fingers=bias_fingers, rmult=1, multipliers=bias_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True +// more than one component has been placed, so move move input below bias +// common source amplifier, route drain to source route between input_drain_W and bias_source_W using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CommonSourceAmplifierFoldedDiodeLoad.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CommonSourceAmplifierFoldedDiodeLoad.convo index 2cb23e036..ffbbaeb04 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CommonSourceAmplifierFoldedDiodeLoad.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CommonSourceAmplifierFoldedDiodeLoad.convo @@ -1,5 +1,7 @@ CommonSourceAmplifierFoldedDiodeLoad # figure 18 exactly +// no imports +// create parameters: input_width, diode_width, input_length, diode_length, input_multiplier, diode_multiplier, input_fingers, diode_fingers create a float parameter called input_width create a float parameter called diode_width create a float parameter called input_length @@ -8,9 +10,12 @@ create a int parameter called input_multiplier create a int parameter called diode_multiplier create a int parameter called input_fingers create a int parameter called diode_fingers +// place place a nmos called input with width=input_width, length=input_length, fingers=input_fingers, rmult=1, multipliers=input_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False place a nmos called diode with width=diode_width, length=diode_length, fingers=diode_fingers, rmult=1, multipliers=diode_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +// more than one component has been placed, so move move diode below input +// common source amplifier with folded diode load, source to drain, gate to drain, and drain to drain route between diode_gate_E and diode_drain_E using smart_route route between input_source_W and diode_source_W using smart_route route between input_drain_E and diode_drain_E using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CommonSourceAmplifierWDiodeLoad.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CommonSourceAmplifierWDiodeLoad.convo index 6fe85bfdc..84c8edae5 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CommonSourceAmplifierWDiodeLoad.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CommonSourceAmplifierWDiodeLoad.convo @@ -1,6 +1,8 @@ CommonSourceAmplifierWDiodeLoad # FIGURE 17 exactly: The common-source amplifier # with diode load is sometimes called a wideband amplifier due to its potentially highspeed operation +// no imports +// create parameters: input_width, diode_width, input_length, diode_length, input_multiplier, diode_multiplier, input_fingers, diode_fingers create a float parameter called input_width create a float parameter called diode_width create a float parameter called input_length @@ -9,8 +11,11 @@ create a int parameter called input_multiplier create a int parameter called diode_multiplier create a int parameter called input_fingers create a int parameter called diode_fingers +// place place a nmos called input with width=input_width, length=input_length, fingers=input_fingers, rmult=1, multipliers=input_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False place a nmos called diode with width=diode_width, length=diode_length, fingers=diode_fingers, rmult=1, multipliers=diode_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +// more than one component has been placed, so move move input below diode +// common source amplifier with diode load, source to drain, and gate to drain route between diode_source_W and input_drain_W using smart_route route between diode_gate_E and diode_drain_E using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ConstBiasVoltageGen.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ConstBiasVoltageGen.convo index 420fbe806..dc93687d2 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ConstBiasVoltageGen.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ConstBiasVoltageGen.convo @@ -1,4 +1,6 @@ ConstBiasVoltageGen +// no imports +// create parameters: source_width, load_width, source_length, load_length, source_multiplier, load_multiplier, source_fingers, load_fingers # figure 25 exactly: CONSTANT bias voltage generator create a float parameter called source_width create a float parameter called load_width @@ -8,9 +10,12 @@ create a int parameter called source_multiplier create a int parameter called load_multiplier create a int parameter called source_fingers create a int parameter called load_fingers +// place place a nmos called source with width=source_width, length=source_length, fingers=source_fingers, rmult=1, multipliers=source_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False place a nmos called load with width=load_width, length=load_length, fingers=load_fingers, rmult=1, multipliers=load_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +// more than one component has been placed, so move move load below source +// bias voltage generator, route source to drain, gate to drain, and gate to source route between source_source_E and load_drain_E using smart_route route between load_gate_E and load_drain_E using smart_route route between source_gate_W and load_source_W using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CrossCoupledInverters.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CrossCoupledInverters.convo index fb86cefac..47248a7af 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CrossCoupledInverters.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CrossCoupledInverters.convo @@ -1,9 +1,14 @@ CrossCoupledInverters +// no imports +// create parameters: ccinvs_length, ccinvs_fingers # Create a float parameter called nfet_width # Create a float parameter called pfet_width Create a float parameter called ccinvs_length Create an int parameter called ccinvs_fingers +// place place 4 interdigitated transistors called ccinvs with numcols=ccinvs_fingers, length=ccinvs_length, top_row_device="pfet", bottom_row_device="nfet" +// only one component placed, so no move +// cross coupled inverters, route both inverters together # sources are connected to pwr and gnd respectively #route between ccinvs_top_A_source_E and ccinvs_top_B_source_E using smart_route #route between ccinvs_bottom_A_source_E and ccinvs_bottom_B_source_E using smart_route diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorNtype.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorNtype.convo index df1c90a02..26f35c55c 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorNtype.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorNtype.convo @@ -1,5 +1,7 @@ CurrentMirrorNtype # ntype current mirror +// no imports +// create parameters: reference_width, mirror_width, reference_length, mirror_length, reference_multiplier, mirror_multiplier, reference_fingers, mirror_fingers create a float parameter called reference_width create a float parameter called mirror_width create a float parameter called reference_length @@ -8,9 +10,12 @@ create a int parameter called reference_multiplier create a int parameter called mirror_multiplier create a int parameter called reference_fingers create a int parameter called mirror_fingers +// place place a nmos called reference with width=reference_width, length=reference_length, fingers=reference_fingers, rmult=1, multipliers=reference_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False place a nmos called mirror with width=mirror_width, length=mirror_length, fingers=mirror_fingers, rmult=1, multipliers=mirror_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +// more than one component has been placed, so move move mirror to the right of reference +// current mirror, route reference gate to mirror gate, reference drain to reference gate, and reference source to mirror source route between reference_gate_E and mirror_gate_E using smart_route route between mirror_drain_E and mirror_gate_E using smart_route route between mirror_source_E and mirror_source_E using smart_route diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorNtypeCommonCentroid.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorNtypeCommonCentroid.convo index 02f609106..a84869dc0 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorNtypeCommonCentroid.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorNtypeCommonCentroid.convo @@ -1,8 +1,13 @@ CurrentMirrorNtypeCommonCentroid +// no imports +// create parameters: width, length, fingers create a float parameter called width create a float parameter called length create a int parameter called fingers +// place place a common centroid pair called cmirror with width=width, length=length, fingers=fingers +// only one component placed, so no move +// current mirror, route reference gate to mirror gate, reference drain to reference gate, and reference source to mirror source route between cmirror_A_source_E and cmirror_B_source_E route between cmirror_A_drain_E and cmirror_B_gate_E route between cmirror_A_gate_E and cmirror_B_gate_E \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorNtypeInterdigitated.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorNtypeInterdigitated.convo index 3e022e925..b28938e66 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorNtypeInterdigitated.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorNtypeInterdigitated.convo @@ -1,8 +1,13 @@ CurrentMirrorNtypeInterdigitated +// no imports +// create parameters: width, length, fingers create a float parameter called width create a float parameter called length create an int parameter called fingers +// place place an interdigitated nfet called cm with numcols=fingers, dummy=True, with_substrate_tap=False, with_tie=True, kwargs={"width": width, "length": length, "rmult":1} +// only one component placed, so no move +// current mirror, route reference gate to mirror gate, reference drain to reference gate, and reference source to mirror source route between cm_A_gate_E and cm_B_gate_E using smart_route route between cm_A_drain_E and cm_A_gate_E using smart_route route between cm_A_source_E and cm_B_source_E using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorPtype.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorPtype.convo index 809c270cb..5b97ccf48 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorPtype.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorPtype.convo @@ -1,6 +1,8 @@ CurrentMirrorPtype # Todo rename stuff -# ntype current mirror +# ntype current mirror +// no imports +// create parameters: reference_width, mirror_width, reference_length, mirror_length, reference_multiplier, mirror_multiplier, reference_fingers, mirror_fingers create a float parameter called reference_width create a float parameter called mirror_width create a float parameter called reference_length @@ -9,9 +11,12 @@ create a int parameter called reference_multiplier create a int parameter called mirror_multiplier create a int parameter called reference_fingers create a int parameter called mirror_fingers +// place place a pmos called reference with width=reference_width, length=reference_length, fingers=reference_fingers, rmult=1, multipliers=reference_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True place a pmos called mirror with width=mirror_width, length=mirror_length, fingers=mirror_fingers, rmult=1, multipliers=mirror_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True +// more than one component has been placed, so move move mirror to the right of reference +// current mirror, route reference gate to mirror gate, reference drain to reference gate, and reference source to mirror source route between reference_gate_E and mirror_gate_E using smart_route route between mirror_drain_E and mirror_gate_E using smart_route route between mirror_source_E and mirror_source_E using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorPtypeInterdigitated.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorPtypeInterdigitated.convo index 60866460d..4845285bb 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorPtypeInterdigitated.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/CurrentMirrorPtypeInterdigitated.convo @@ -1,8 +1,13 @@ CurrentMirrorPtypeInterdigitated +// no imports +// create parameters: width, length, fingers create a float parameter called width create a float parameter called length -create an int parameter called fingers +create an int parameter called fingers +// place place an interdigitated pfet called cm with numcols=fingers, dummy=True, with_substrate_tap=False, with_tie=True, kwargs={"width": width, "length": length, "rmult":1} +// only one component placed, so no move +// current mirror, route reference gate to mirror gate, reference drain to reference gate, and reference source to mirror source route between cm_A_gate_E and cm_B_gate_E using smart_route route between cm_A_drain_E and cm_A_gate_E using smart_route route between cm_A_source_E and cm_B_source_E using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/DegenCommonGate.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/DegenCommonGate.convo index 386bb53af..0e4d2a2f3 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/DegenCommonGate.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/DegenCommonGate.convo @@ -1,6 +1,8 @@ DegenCommonGate # figure 21 # The degeneration of M1 can be adapted by tuning Vbias. +// no imports +// create parameters: isrc_width, load_width, isrc_length, load_length, isrc_multiplier, load_multiplier, isrc_fingers, load_fingers create a float parameter called isrc_width create a float parameter called load_width create a float parameter called isrc_length @@ -9,8 +11,11 @@ create a int parameter called isrc_multiplier create a int parameter called load_multiplier create a int parameter called isrc_fingers create a int parameter called load_fingers +// place place a nmos called isrc with width isrc_width, length isrc_length, fingers isrc_fingers, rmult 1, multipliers isrc_multiplier, with_substrate_tap False, with_tie True, with_dummy True, with_dnwell False place a nmos called load with width load_width, length load_length, fingers load_fingers, rmult 1, multipliers load_multiplier, with_substrate_tap False, with_tie True, with_dummy True, with_dnwell False +// more than one component has been placed, so move move load below isrc +// degen common gate, route source to drain route between isrc_source_W and load_drain_W using smart_route # route between load_tie_br_top_met_S and isrc_tie_tr_top_met_N using smart_route diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/DegenCommonSource.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/DegenCommonSource.convo index 1b6d5c963..a889c354b 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/DegenCommonSource.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/DegenCommonSource.convo @@ -1,4 +1,6 @@ DegenCommonSource +// no imports +// create parameters: isrc_width, degen_width, isrc_length, degen_length, isrc_multiplier, degen_multiplier, isrc_fingers, degen_fingers # figure 20 exactly create a float parameter called isrc_width create a float parameter called degen_width @@ -8,9 +10,12 @@ create a int parameter called isrc_multiplier create a int parameter called degen_multiplier create a int parameter called isrc_fingers create a int parameter called degen_fingers +// place place a nmos called isrc with width=isrc_width, length=isrc_length, fingers=isrc_fingers, rmult=1, multipliers=isrc_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False place a nmos called degen with width=degen_width, length=degen_length, fingers=degen_fingers, rmult=1, multipliers=degen_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +// more than one component has been placed, so move move degen below isrc +// degen common source, route source to drain, and gate to gate route between isrc_source_W and degen_drain_W using smart_route route between isrc_gate_E and degen_gate_E using smart_route # route between degen_tie_br_top_met_S and isrc_tie_tr_top_met_N using straight_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/DeltaSigmaModulator.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/DeltaSigmaModulator.convo new file mode 100644 index 000000000..d87b353f3 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/DeltaSigmaModulator.convo @@ -0,0 +1,15 @@ +DeltaSigmaModulator +import OpAmp +import PassiveComponents +import LatchedComparator +place an OpAmp called oa +placer a PassiveComponents called passive +place a LatchedComparator called lc with n_latch_width 1 p_latch_width 1 +move passive above oa +move lc right next to oa +# Route outp/nm to the bottom metal of the capacitors +route between oa_abstage_pp1_p1_multiplier_0_drain_E and passive_c1_bottom_met_E using c_route with extension=2 +route between oa_abstage_pp2_p1_multiplier_0_drain_E and passive_c2_bottom_met_E using c_route with extension=2 +# Route Ri to inputs of OpAmp +route between passive_ri1_pfet_multiplier_0_source_W and oa_finteg_gm1_B_gate_W using c_route with extension=5 +route between passive_ri2_pfet_multiplier_0_source_E and oa_abstage_gm31_A_gate_E using c_route with extension=3 \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/DiffPair.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/DiffPair.convo index 9dc88f98d..ccfd0cb94 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/DiffPair.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/DiffPair.convo @@ -1,4 +1,6 @@ -DiffPair +DiffPair +// no imports +// create parameters: vin1_width, vin2_width, vin1_length, vin2_length, vin1_multiplier, vin2_multiplier, vin1_fingers, vin2_fingers create a float parameter called vin1_width create a float parameter called vin2_width create a float parameter called vin1_length @@ -7,7 +9,10 @@ create a int parameter called vin1_multiplier create a int parameter called vin2_multiplier create a int parameter called vin1_fingers create a int parameter called vin2_fingers +// place place a nmos called vin1 with width=vin1_width, length=vin1_length, fingers=vin1_fingers, rmult=1, multipliers=vin1_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False place a nmos called vin2 with width=vin2_width, length=vin2_length, fingers=vin2_fingers, rmult=1, multipliers=vin2_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +// more than one component has been placed, so move move vin1 to the left of vin2 +// differential pair only has one route which is source to source route between vin1_source_N and vin2_source_N using smart_route diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/FourStageIntegrator.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/FourStageIntegrator.convo new file mode 100644 index 000000000..fa371c7cf --- /dev/null +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/FourStageIntegrator.convo @@ -0,0 +1,29 @@ +OpAmp +import FIntegrator +import SIntegrator +import TIntegrator +import ClassABStage +place a FIntegrator called finteg +place a SIntegrator called sinteg +place a TIntegrator called tinteg +place a ClassABStage called abstage +move sinteg right next to finteg +move tinteg right next to sinteg +move abstage right next to tinteg +# Route inp +route between finteg_gm1_A_gate_E and sinteg_gm2_A_gate_W using straight_route +route between sinteg_gm2_A_gate_E and tinteg_gm32_A_gate_W using straight_route +route between tinteg_gm32_A_gate_E and abstage_gm31_A_gate_W using straight_route +# Route inn +route between finteg_gm1_B_gate_E and sinteg_gm2_B_gate_W using straight_route +route between sinteg_gm2_B_gate_E and tinteg_gm32_B_gate_W using straight_route +route between tinteg_gm32_B_gate_E and abstage_gm31_B_gate_W using straight_route +# Route the drains of gm1 to the gates of gm4 +route between finteg_sink_cm_A_drain_E and sinteg_gm4_B_gate_W using snake_route with extension=2 +route between finteg_sink_cm_B_drain_E and sinteg_gm4_A_gate_W using snake_route with extension=3 +# Route the drains of gm2 to the gates of gm5 +route between sinteg_sink_cm_A_drain_E and tinteg_gm5_B_gate_W using snake_route with viaoffset=(False, False) +route between sinteg_sink_cm_B_drain_E and tinteg_gm5_A_gate_W using snake_route with extension=2 viaoffset=(False, False) +# Route the drains of gm32 to the gates of class ab nfets +route between tinteg_gm5_A_drain_E and abstage_pp1_n1_multiplier_0_gate_E using c_route +route between tinteg_gm5_B_drain_E and abstage_pp2_n1_multiplier_0_gate_E using c_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/IntegratorStage.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/IntegratorStage.convo new file mode 100644 index 000000000..7fde0cd44 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/IntegratorStage.convo @@ -0,0 +1,20 @@ +IntegratorStage +# Make the first integrator +import CurrentMirrorPFET +import CurrentMirrorNFET +# Make the diff pair +# TODO: parametrize this +place an interdigitated pfet called gm1 with numcols=2, dummy=True, with_substrate_tap=False, with_tie=True, tie_layers=("met2","met1"), kwargs={ "width" : 1 , "length" : 1} +place a CurrentMirrorPFET called source +place a CurrentMirrorNFET called sink +place an interdigitated nfet called dummy with numcols=2, dummy=True, with_substrate_tap=False, with_tie=True, tie_layers=("met2","met1"), kwargs={ "width" : 1 , "length" : 1} +move source above gm1 +move dummy below gm1 +move sink below dummy +# short sources of the diffpair +route between gm1_A_source_E and gm1_B_source_E +# Connect the drain of source's B to the source of the diffpairs +route between gm1_A_source_W and source_cm_B_drain_W using c_route with extension=2 +# Connect the drains of the diffpair to the drains of the sink +route between gm1_A_drain_E and sink_cm_A_drain_E using smart_route +route between gm1_B_drain_W and sink_cm_B_drain_W using c_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/Inverter.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/Inverter.convo index 1f269df31..187fd8854 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/Inverter.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/Inverter.convo @@ -1,4 +1,6 @@ Inverter +// no imports +// create parameters: pullup_width, pulldown_width, pullup_length, pulldown_length, pullup_multiplier, pulldown_multiplier, pullup_fingers, pulldown_fingers # paramterize everything like an analog cell create a float parameter called pullup_width create a float parameter called pulldown_width @@ -8,8 +10,11 @@ create a int parameter called pullup_multiplier create a int parameter called pulldown_multiplier create a int parameter called pullup_fingers create a int parameter called pulldown_fingers +// place place a pmos called pullup with width=pullup_width, length=pullup_length, fingers=pullup_fingers, rmult=1, multipliers=pullup_multiplier, with_substrate_tap=False, with_tie=False, with_dummy=False place a nmos called pulldown with width=pulldown_width, length=pulldown_length, fingers=pulldown_fingers, rmult=1, multipliers=pulldown_multiplier, with_substrate_tap=False, with_tie=False, with_dummy=False, with_dnwell=False +// more than one component has been placed, so move move pullup above pulldown +// inverter, route pmos source to nmos drain, and short the gates route between pullup_source_W and pulldown_drain_W using smart_route route between pullup_gate_W and pulldown_gate_W using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/LowNoiseAmp.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/LowNoiseAmp.convo index b892815f7..0e527157b 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/LowNoiseAmp.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/LowNoiseAmp.convo @@ -1,4 +1,6 @@ LowNoiseAmp +// no imports +// create parameters: input_width, gain_width, input_length, gain_length, input_multiplier, gain_multiplier, input_fingers, gain_fingers # figure 23 exactly create a float parameter called input_width create a float parameter called gain_width @@ -8,8 +10,11 @@ create a int parameter called input_multiplier create a int parameter called gain_multiplier create a int parameter called input_fingers create a int parameter called gain_fingers +// place place a nmos called input with width=input_width, length=input_length, fingers=input_fingers, rmult=1, multipliers=input_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False place a nmos called gain with width=gain_width, length=gain_length, fingers=gain_fingers, rmult=1, multipliers=gain_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False -move gain below input +// more than one component has been placed, so move +move gain below +// low noise amplifier, route source to drain and gate to source route between input_source_W and gain_drain_W using smart_route route between input_gate_E and gain_source_E using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/MimcapArray.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/MimcapArray.convo index 151e49b4a..fc183c028 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/MimcapArray.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/MimcapArray.convo @@ -1,4 +1,40 @@ MimcapArray +// no imports +// create parameters: mimcap_size_x, mimcap_size_y create a float parameter called mimcap_size_x create a float parameter called mimcap_size_y -place a mimcap array called arr with size=(mimcap_size_x, mimcap_size_y), rows=5, columns=5 \ No newline at end of file +# 2 rows by 3 cols +// place 2*3=6 array elements +place a mimcap called element1 with size=(mimcap_size_x,mimcap_size_y) +place a mimcap called element2 with size=(mimcap_size_x,mimcap_size_y) +place a mimcap called element3 with size=(mimcap_size_x,mimcap_size_y) +place a mimcap called element4 with size=(mimcap_size_x,mimcap_size_y) +place a mimcap called element5 with size=(mimcap_size_x,mimcap_size_y) +place a mimcap called element6 with size=(mimcap_size_x,mimcap_size_y) +// array from bottom left to top right +// first row +move element2 to the right of element1 +move element3 to the right of element2 +// second row +move element4 above element1 +move element5 above element1 +move element6 above element1 +move element5 to the right of element4 +move element6 to the right of element5 +// route top_met_ of the mimcaps and bottom_met_ of the mimcaps +# route top met +route between element1_top_met_E and element2_top_met_W using smart_route +route between element2_top_met_E and element3_top_met_W using smart_route +route between element4_top_met_E and element5_top_met_W using smart_route +route between element5_top_met_E and element6_top_met_W using smart_route +route between element1_top_met_N and element4_top_met_S using smart_route +route between element2_top_met_N and element5_top_met_S using smart_route +route between element3_top_met_N and element6_top_met_S using smart_route +# route bottom met +route between element1_bottom_met_E and element2_bottom_met_W using smart_route +route between element2_bottom_met_E and element3_bottom_met_W using smart_route +route between element4_bottom_met_E and element5_bottom_met_W using smart_route +route between element5_bottom_met_E and element6_bottom_met_W using smart_route +route between element1_bottom_met_N and element4_bottom_met_S using smart_route +route between element2_bottom_met_N and element5_bottom_met_S using smart_route +route between element3_bottom_met_N and element6_bottom_met_S using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NAND.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NAND.convo index 8a102b08d..94b0ec8de 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NAND.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NAND.convo @@ -1,4 +1,6 @@ NAND +// no imports +// create parameters: pullup_width, pulldown_width, pullup_length, pulldown_length, pullup_multiplier, pulldown_multiplier, pullup_fingers, pulldown_fingers create a float parameter called pullup_width create a float parameter called pulldown_width create a float parameter called pullup_length @@ -7,14 +9,17 @@ create a int parameter called pullup_multiplier create a int parameter called pulldown_multiplier create a int parameter called pullup_fingers create a int parameter called pulldown_fingers +// place place a nmos called pulldown1 with width=pulldown_width, length=pulldown_length, fingers=pulldown_fingers, rmult=1, multipliers=1, with_substrate_tap=False, with_tie=False, with_dummy=False place a nmos called pulldown2 with width=pulldown_width, length=pulldown_length, fingers=pulldown_fingers, rmult=1, multipliers=1, with_substrate_tap=False, with_tie=False, with_dummy=False place a pmos called pullup1 with width=pullup_width, length=pullup_length, fingers=pullup_fingers, rmult=1, multipliers=1, with_substrate_tap=False, with_tie=False, with_dummy=False place a pmos called pullup2 with width=pullup_width, length=pullup_length, fingers=pullup_fingers, rmult=1, multipliers=1, with_substrate_tap=False, with_tie=False, with_dummy=False +// more than one component has been placed, so move move pullup1 above pulldown1 move pulldown2 to the right of pulldown1 move pullup2 north of pulldown1 move pullup2 to the right of pullup1 +// nand gate, route pulldown network, pullup network, and connect the pullup to pulldown network route between pulldown1_drain_E and pulldown2_source_W using smart_route route between pulldown2_drain_W and pullup1_drain_W using smart_route route between pullup1_source_W and pullup2_source_W using smart_route diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NMOSArray2x5.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NMOSArray2x5.convo new file mode 100644 index 000000000..98c1ef27c --- /dev/null +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NMOSArray2x5.convo @@ -0,0 +1,35 @@ +NMOSArray2x5 +# 2 rows by 5 cols array of nmos transistors (no routing) +// no imports +// create parameters: width, length, multipliers, fingers +create a float parameter called width +create a float parameter called length +create a int parameter called multipliers +create a int parameter called fingers +// place 2*5=10 array elements +place a nmos called element1 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element2 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element3 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element4 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element5 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element6 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element7 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element8 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element9 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element10 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +// move first row into position +move element2 to the right of element1 +move element3 to the right of element2 +move element4 to the right of element3 +move element5 to the right of element4 +// move second row above first row +move element6 above element1 +move element7 above element1 +move element8 above element1 +move element9 above element1 +move element10 above element1 +move element7 to the right of element6 +move element8 to the right of element7 +move element9 to the right of element8 +move element10 to the right of element9 +// no routing diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NMOSArray4x3.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NMOSArray4x3.convo new file mode 100644 index 000000000..49f924f5a --- /dev/null +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NMOSArray4x3.convo @@ -0,0 +1,41 @@ +NMOSArray4x3 +# 4 rows by 3 cols array of nmos transistors (no routing) +// no imports +// create parameters: width, length +create a float parameter called width +create a float parameter called length +// place 4*3=12 array elements +place a nmos called element1 with width=width, length=length, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element2 with width=width, length=length, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element3 with width=width, length=length, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element4 with width=width, length=length, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element5 with width=width, length=length, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element6 with width=width, length=length, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element7 with width=width, length=length, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element8 with width=width, length=length, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element9 with width=width, length=length, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element10 with width=width, length=length, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element11 with width=width, length=length, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a nmos called element12 with width=width, length=length, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +// move first row into position +move element2 to the right of element1 +move element3 to the right of element2 +// move second row above first row +move element4 above element1 +move element5 above element1 +move element6 above element1 +move element5 to the right of element4 +move element6 to the right of element5 +// move third row above second row +move element7 above element4 +move element8 above element4 +move element9 above element4 +move element8 to the right of element7 +move element9 to the right of element8 +// move fourth row above third row +move element10 above element7 +move element11 above element7 +move element12 above element7 +move element11 to the right of element10 +move element12 to the right of element11 +// no routing \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NOR.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NOR.convo index 6822a59c1..d5cad3331 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NOR.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NOR.convo @@ -1,4 +1,6 @@ NOR +// no imports +// create parameters: pullup_width, pulldown_width, pullup_length, pulldown_length, pullup_multiplier, pulldown_multiplier, pullup_fingers, pulldown_fingers create a float parameter called pullup_width create a float parameter called pulldown_width create a float parameter called pullup_length @@ -7,14 +9,17 @@ create a int parameter called pullup_multiplier create a int parameter called pulldown_multiplier create a int parameter called pullup_fingers create a int parameter called pulldown_fingers +// place place a nmos called pulldown1 with width=pulldown_width, fingers=pulldown_fingers, rmult=1, multipliers=pulldown_multiplier, with_substrate_tap=False, with_tie=False, with_dummy False place a nmos called pulldown2 with width=pulldown_width, fingers=pulldown_fingers, rmult=1, multipliers=pulldown_multiplier, with_substrate_tap=False, with_tie=False, with_dummy False place a pmos called pullup1 with width=pullup_width, fingers=pullup_fingers, rmult=1, multipliers=pullup_multiplier, with_substrate_tap=False, with_tie=False, with_dummy False place a pmos called pullup2 with width=pullup_width, fingers=pullup_fingers, rmult=1, multipliers=pullup_multiplier, with_substrate_tap=False, with_tie=False, with_dummy False +// more than one component has been placed, so move move pullup1 above pulldown1 move pulldown2 to the right of pulldown1 move pullup2 north of pulldown1 move pullup2 to the right of pullup1 +// Nor gate, route source to source, drain to drain for pullup and pulldown, and source to drain route between pulldown1_source_W and pulldown2_source_W using smart_route route between pulldown1_drain_W and pulldown2_drain_W using smart_route route between pulldown1_drain_W and pullup1_drain_W using smart_route diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NoiseXDiffConv.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NoiseXDiffConv.convo index 1336c0b90..b11ee0ba3 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NoiseXDiffConv.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/NoiseXDiffConv.convo @@ -1,6 +1,8 @@ NoiseXDiffConv # figure 22 exactly # common gate into common source (give more descriptive name) +// no imports +// create parameters: width_m1, width_m2, length_m1, length_m2, m1_multiplier, m2_multiplier, m1_fingers, m2_fingers create a float parameter called width_m1 create a float parameter called width_m2 create a float parameter called length_m1 @@ -9,8 +11,11 @@ create a int parameter called m1_multiplier create a int parameter called m2_multiplier create a int parameter called m1_fingers create a int parameter called m2_fingers +// place place a nmos called m1 with width=width_m1, length=length_m1, fingers=m1_fingers, rmult=1, multipliers=m1_multiplier, with_substrate_tap=False, with_tie=True, sd_rmult=1, gate_rmult=1, interfinger_rmult=1, with_dummy=True, with_dnwell=False place a nmos called m2 with width=width_m2, length=length_m2, fingers=m2_fingers, rmult=1, multipliers=m2_multiplier, with_substrate_tap=False, with_tie=True, sd_rmult=1, gate_rmult=1, interfinger_rmult=1, with_dummy=True, with_dnwell=False +// more than one component has been placed, so move move m1 below m2 +// NoiseXDiffConv route gate to source route between m1_gate_E and m2_source_E using smart_route # route between m1_tie_br_top_met_S and m2_tie_tr_top_met_N using straight_route diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PMOSArray2x5.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PMOSArray2x5.convo new file mode 100644 index 000000000..124838c9e --- /dev/null +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PMOSArray2x5.convo @@ -0,0 +1,33 @@ +PMOSArray2x5 +# 2 rows by 5 cols array of pmos transistors (no routing) +// no imports +// create parameters: length, fingers +create a float parameter called length +create a int parameter called fingers +// place 2*5=10 array elements +place a pmos called element1 with length=length, fingers=fingers, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element2 with length=length, fingers=fingers, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element3 with length=length, fingers=fingers, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element4 with length=length, fingers=fingers, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element5 with length=length, fingers=fingers, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element6 with length=length, fingers=fingers, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element7 with length=length, fingers=fingers, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element8 with length=length, fingers=fingers, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element9 with length=length, fingers=fingers, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element10 with length=length, fingers=fingers, rmult=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +// move first row into position +move element2 to the right of element1 +move element3 to the right of element2 +move element4 to the right of element3 +move element5 to the right of element4 +// move second row above first row +move element6 above element1 +move element7 above element1 +move element8 above element1 +move element9 above element1 +move element10 above element1 +move element7 to the right of element6 +move element8 to the right of element7 +move element9 to the right of element8 +move element10 to the right of element9 +// no routing diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PMOSArray4x3.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PMOSArray4x3.convo new file mode 100644 index 000000000..d2b2d47fa --- /dev/null +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PMOSArray4x3.convo @@ -0,0 +1,43 @@ +PMOSArray4x3 +# 4 rows by 3 cols array of nmos transistors (no routing) +// no imports +// create parameters: width, length, multipliers, fingers +create a float parameter called width +create a float parameter called length +create a int parameter called multipliers +create a int parameter called fingers +// place 4*3=12 array elements +place a pmos called element1 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element2 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element3 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element4 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element5 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element6 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element7 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element8 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element9 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element10 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element11 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +place a pmos called element12 with width=width, length=length, fingers=fingers, rmult=1, multipliers=multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +// move first row into position +move element2 to the right of element1 +move element3 to the right of element2 +// move second row above first row +move element4 above element1 +move element5 above element1 +move element6 above element1 +move element5 to the right of element4 +move element6 to the right of element5 +// move third row above second row +move element7 above element4 +move element8 above element4 +move element9 above element4 +move element8 to the right of element7 +move element9 to the right of element8 +// move fourth row above third row +move element10 above element7 +move element11 above element7 +move element12 above element7 +move element11 to the right of element10 +move element12 to the right of element11 +// no routing \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PTATVoltageGen.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PTATVoltageGen.convo index 29f29250a..dff2edfd9 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PTATVoltageGen.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PTATVoltageGen.convo @@ -1,5 +1,7 @@ PTATVoltageGen # figure 26 exactly +// no imports +// create parameters: bias_width, mirror_width, bias_length, mirror_length, bias_multiplier, mirror_multiplier, bias_fingers, mirror_fingers create a float parameter called bias_width create a float parameter called mirror_width create a float parameter called bias_length @@ -8,9 +10,12 @@ create a int parameter called bias_multiplier create a int parameter called mirror_multiplier create a int parameter called bias_fingers create a int parameter called mirror_fingers +// place place a nmos called bias with width=bias_width, length=bias_length, fingers=bias_fingers, rmult=1, multipliers=bias_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False place a nmos called mirror with width=mirror_width, length=mirror_length, fingers=mirror_fingers, rmult=1, multipliers=mirror_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False +// more than one component has been placed, so move move bias below mirror +// PTAT, route source to drain, gate to gate, and gate to drain route between mirror_source_E and bias_drain_E using smart_route route between mirror_gate_W and bias_gate_W using smart_route route between mirror_gate_W and mirror_drain_W using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PTypeDiffPair.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PTypeDiffPair.convo index c007a4349..56c5a5ed0 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PTypeDiffPair.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PTypeDiffPair.convo @@ -1,4 +1,6 @@ PTypeDiffPair +// no imports +// create parameters: vin1_width, vin2_width, vin1_length, vin2_length, vin1_multiplier, vin2_multiplier, vin1_fingers, vin2_fingers create a float parameter called vin1_width create a float parameter called vin2_width create a float parameter called vin1_length @@ -7,7 +9,10 @@ create a int parameter called vin1_multiplier create a int parameter called vin2_multiplier create a int parameter called vin1_fingers create a int parameter called vin2_fingers +// place place a pmos called vin1 with width=vin1_width, length=vin1_length, fingers=vin1_fingers, rmult=1, multipliers=vin1_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True place a pmos called vin2 with width=vin2_width, length=vin2_length, fingers=vin2_fingers, rmult=1, multipliers=vin2_multiplier, with_substrate_tap=False, with_tie=True, with_dummy=True +// more than one component has been placed, so move move vin1 to the left of vin2 +// differential pair only has one route which is source to source route between vin1_source_E and vin2_source_W using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PushPull.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PushPull.convo index 493409340..be669325e 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PushPull.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/PushPull.convo @@ -1,20 +1,25 @@ PushPull +// no imports +// create parameters: p1_width, n1_width, p1_length, n1_length, p1_fingers, n1_fingers create a parameter called p1_width create a parameter called n1_width create a parameter called p1_length create a parameter called n1_length create a parameter called p1_fingers create a parameter called n1_fingers +// place place a pmos called p1 with width=p1_width, length=p1_length, fingers=p1_fingers, rmult=1, multipliers=1, with_substrate_tap=False, with_tie=True, with_dummy=True, place a nmos called n1 with width=n1_width, length=n1_length, fingers=n1_fingers, rmult=1, multipliers=1, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False place a mimcap called c3 place a mimcap called c5 +// more than one component has been placed, so move move p1 right next to c3 move c5 below c3 move n1 below p1 move n1 right next to c5 +// push pull amplifier, route the transistors to the mimcaps, and drain to drain route between p1_drain_W and c3_bottom_met_E using smart_route route between p1_gate_W and c3_top_met_E using smart_route -route between p1_drain_E and n1_multiplier_0_drain_E using smart_route +route between p1_drain_E and n1_drain_E using smart_route route between n1_drain_W and c5_bottom_met_E using smart_route route between n1_gate_W and c5_top_met_E using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/RegulatedCascode.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/RegulatedCascode.convo index d8e8ee5c0..280e6fa81 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/RegulatedCascode.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/RegulatedCascode.convo @@ -1,5 +1,7 @@ RegulatedCascode # figure 48 +// no imports +// create parameters: cascode_width, feedback_width, cascode_length, feedback_length, cascode_multiplier, feedback_multiplier, cascode_fingers, feedback_fingers create a float parameter called cascode_width create a float parameter called feedback_width create a float parameter called cascode_length @@ -8,8 +10,11 @@ create a int parameter called cascode_multiplier create a int parameter called feedback_multiplier create a int parameter called cascode_fingers create a int parameter called feedback_fingers +// place place a nmos called cascode with width=cascode_width, length=cascode_length, fingers=cascode_fingers, rmult=1, multipliers=cascode_multiplier, with_substrate_tap=False, with_tie=False, with_dummy=False place a nmos called feedback with width=feedback_width, length=feedback_length, fingers=feedback_fingers, rmult=1, multipliers=feedback_multiplier, with_substrate_tap=False, with_tie=False, with_dummy=False +// more than one component has been placed, so move move feedback below cascode +// regulated cascode, route gate to drain, and gate to source route between cascode_gate_E and feedback_drain_E using smart_route route between feedback_gate_W and feedback_source_W using smart_route diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/SourceFollow.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/SourceFollow.convo index d0b9316f9..96d1b83fb 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/SourceFollow.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/SourceFollow.convo @@ -1,5 +1,7 @@ SourceFollow # figure 9 exactly +// no imports +// create parameters: srcfoll_width, isrc_width, srcfoll_length, isrc_length, srcfoll_multiplier, isrc_multiplier, srcfoll_fingers, isrc_fingers create a float parameter called srcfoll_width create a float parameter called isrc_width create a float parameter called srcfoll_length @@ -8,7 +10,10 @@ create a int parameter called srcfoll_multiplier create a int parameter called isrc_multiplier create a int parameter called srcfoll_fingers create a int parameter called isrc_fingers +// place place a nmos called srcfoll with width=srcfoll_width, length=srcfoll_length, fingers=srcfoll_fingers, rmult=1, multipliers=srcfoll_multiplier, with_substrate_tap=False, with_tie=False, with_dummy=False place a nmos called isrc with width=isrc_width, length=isrc_length, fingers=isrc_fingers, rmult=1, multipliers=isrc_multiplier, with_substrate_tap=False, with_tie=False, with_dummy=False +// more than one component has been placed, so move move isrc below srcfoll +// source follower, route source to drain route between srcfoll_source_W and isrc_drain_W using smart_route diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/StrongArmLatch.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/StrongArmLatch.convo index b55a1cc3f..a361768da 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/StrongArmLatch.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/StrongArmLatch.convo @@ -1,5 +1,7 @@ StrongArmLatch +// import required components import CrossCoupledInverters +// create parameters: bridge_width, clkgnd_width, clkpwr_width, bridge_length, clkgnd_length, clkpwr_length, ccinvs_length, bridge_multipliers, clkgnd_multipliers, clkpwr_multipliers, bridge_fingers, clkgnd_fingers, clkpwr_fingers, ccinvs_fingers create a float parameter called bridge_width create a float parameter called clkgnd_width create a float parameter called clkpwr_width @@ -14,12 +16,14 @@ create a int parameter called bridge_fingers create a int parameter called clkgnd_fingers create a int parameter called clkpwr_fingers create a int parameter called ccinvs_fingers +// place place a diff pair called inputdiff place a CrossCoupledInverters called ccinvs with ccinvs_fingers=ccinvs_fingers, ccinvs_length=ccinvs_length place a nmos called clkgnd with width=clkgnd_width, length=clkgnd_length, fingers=clkgnd_fingers, rmult=1, multipliers=clkgnd_multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False place a nmos called bridge with width=bridge_width, length=bridge_length, fingers=bridge_fingers, rmult=1, multipliers=bridge_multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True, with_dnwell=False place a pmos called clkpwrL with width=clkpwr_width, length=clkpwr_length, fingers=clkpwr_fingers, rmult=1, multipliers=clkpwr_multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True place a pmos called clkpwrR with width=clkpwr_width, length=clkpwr_length, fingers=clkpwr_fingers, rmult=1, multipliers=clkpwr_multipliers, with_substrate_tap=False, with_tie=True, with_dummy=True +// more than one component has been placed, so move move clkgnd below inputdiff move bridge above inputdiff move ccinvs above bridge @@ -27,6 +31,7 @@ move clkpwrR right of ccinvs move clkpwrR above bridge move clkpwrL left of ccinvs move clkpwrL above bridge +// strong arm latch, route bridge to inputdiff, inputdiff to clkgnd, ccinvs to clkpwr, bridge to ccins, and clock routing # route bridge to inputdiff route between inputdiff_A_drain_E and bridge_drain_E using smart_route route between inputdiff_B_drain_W and bridge_source_W using smart_route diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ULPD.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ULPD.convo index 51a04b0d8..ffd9d662c 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ULPD.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ULPD.convo @@ -1,6 +1,8 @@ ULPD # ultra low power diode # figure 43 +// no imports +// create parameters: forward_width, leakred_width, forward_length, leakred_length, forward_multiplier, leakred_multiplier, forward_fingers, leakred_fingers create a float parameter called forward_width create a float parameter called leakred_width create a float parameter called forward_length @@ -9,8 +11,11 @@ create a int parameter called forward_multiplier create a int parameter called leakred_multiplier create a int parameter called forward_fingers create a int parameter called leakred_fingers +// place place a nmos called forward with width=forward_width, length=forward_length, fingers=forward_fingers, rmult=1, multipliers=forward_multiplier, with_substrate_tap=False, with_tie=False, with_dummy=False place a nmos called leakred with width=leakred_width, length=leakred_length, fingers=leakred_fingers, rmult=1, multipliers=leakred_multiplier, with_substrate_tap=False, with_tie=False, with_dummy=False +// more than one component has been placed, so move move forward above leakred +// low power diode, route gate to source, and source to gate route between forward_gate_E and leakred_source_E using smart_route route between forward_source_W and leakred_gate_W using smart_route diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/Varactor.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/Varactor.convo index 9ffbf60e2..310a6140c 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/Varactor.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/Varactor.convo @@ -1,5 +1,7 @@ Varactor # figure 30 variable capacitor +// no imports +// create parameters: control_width, accumulation_width, control_length, accumulation_length, control_multiplier, accumulation_multiplier, control_fingers, accumulation_fingers create a float parameter called control_width create a float parameter called accumulation_width create a float parameter called control_length @@ -8,9 +10,12 @@ create a int parameter called control_multiplier create a int parameter called accumulation_multiplier create a int parameter called control_fingers create a int parameter called accumulation_fingers +// place place a nmos called control with width=control_width, length=control_length, fingers=control_fingers, rmult=1, multipliers=control_multiplier, with_substrate_tap=False, with_tie=False, with_dummy=False place a nmos called accumulation with width=accumulation_width, length=accumulation_length, fingers=accumulation_fingers, rmult=1, multipliers=accumulation_multiplier, with_substrate_tap=False, with_tie=False, with_dummy=False +// more than one component has been placed, so move move accumulation to the right of control +// variable capacitor route drain to drain, source to source, and source to drain route between control_drain_N and accumulation_drain_N using smart_route route between control_source_N and accumulation_source_N using smart_route route between control_source_N and accumulation_drain_N using smart_route diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ViaArray3x2.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ViaArray3x2.convo new file mode 100644 index 000000000..3ed90aa11 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/ViaArray3x2.convo @@ -0,0 +1,51 @@ +ViaArray3x2 +# 3 rows by 2 cols array of vias +// no imports +// create parameters: glayer1, glayer2 +create a str parameter called glayer1 +create a str parameter called glayer2 +// place 3*2=6 array elements +place a via called element1 with glayer1=glayer1, glayer2=glayer2 +place a via called element2 with glayer1=glayer1, glayer2=glayer2 +place a via called element3 with glayer1=glayer1, glayer2=glayer2 +place a via called element4 with glayer1=glayer1, glayer2=glayer2 +place a via called element5 with glayer1=glayer1, glayer2=glayer2 +place a via called element6 with glayer1=glayer1, glayer2=glayer2 +// move first row into position +move element2 to the right of element1 +// move second row above first row +move element3 above element1 +move element4 above element1 +move element4 to the right of element3 +// move third row above second row +move element5 above element3 +move element6 above element3 +move element6 to the right of element5 +// route top_met_ of the vias and bottom_met_ of the vias +# route top met +# top_met_ +# row1 +route between element1_top_met_E and element2_top_met_W using smart_route +# row2 +route between element3_top_met_E and element4_top_met_W using smart_route +# row3 +route between element5_top_met_E and element6_top_met_W using smart_route +# col1 +route between element1_top_met_N and element3_top_met_S using smart_route +route between element3_top_met_N and element5_top_met_S using smart_route +# col2 +route between element2_top_met_N and element4_top_met_S using smart_route +route between element4_top_met_N and element6_top_met_S using smart_route +# bottom_met_ +# row1 +route between element1_bottom_met_E and element2_bottom_met_W using smart_route +# row2 +route between element3_bottom_met_E and element4_bottom_met_W using smart_route +# row3 +route between element5_bottom_met_E and element6_bottom_met_W using smart_route +# col1 +route between element1_bottom_met_N and element3_bottom_met_S using smart_route +route between element3_bottom_met_N and element5_bottom_met_S using smart_route +# col2 +route between element2_bottom_met_N and element4_bottom_met_S using smart_route +route between element4_bottom_met_N and element6_bottom_met_S using smart_route diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/VoltageFollower.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/VoltageFollower.convo index 47946627a..9e70f2a3e 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/VoltageFollower.convo +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/VoltageFollower.convo @@ -1,6 +1,8 @@ VoltageFollower # figure 33 # tet stands for Transconductance Enhancement Transistor and gsc stands for Gate-Source Capacitance Transistor +// no imports +// create parameters: gsc_width, tet_width, gsc_length, tet_length, gsc_multiplier, tet_multiplier, gsc_fingers, tet_fingers create a float parameter called gsc_width create a float parameter called tet_width create a float parameter called gsc_length @@ -9,8 +11,11 @@ create a int parameter called gsc_multiplier create a int parameter called tet_multiplier create a int parameter called gsc_fingers create a int parameter called tet_fingers +// place place a nmos called gsc with width=gsc_width, length=gsc_length, fingers=gsc_fingers, rmult=1, multipliers=gsc_multiplier, with_substrate_tap=False, with_tie=False, with_dummy=False place a nmos called tet with width=tet_width, length=tet_length, fingers=tet_fingers, rmult=1, multipliers=tet_multiplier, with_substrate_tap=False, with_tie=False, with_dummy=False +// more than one component has been placed, so move move gsc above tet +// voltage follower route source to drain and drain to gate route between tet_source_W and gsc_drain_W using smart_route route between tet_drain_E and gsc_gate_E using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/WilsonCurrentMirror.convo b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/WilsonCurrentMirror.convo new file mode 100644 index 000000000..aa7d6a3c2 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/convos/WilsonCurrentMirror.convo @@ -0,0 +1,17 @@ +WilsonCurrentMirror +// create parameters: wcm_length, wcm_fingers +Create a float parameter called wcm_length +Create an int parameter called wcm_fingers +// place +place 4 interdigitated transistors called wcm with numcols=wcm_fingers, length=wcm_length, top_row_device="nfet", bottom_row_device="nfet" +// only one component placed, so no move +# route bottom two transistors +route between wcm_bottom_A_source_E and wcm_bottom_B_source_E using smart_route +route between wcm_bottom_A_gate_E and wcm_bottom_B_gate_E using smart_route +route between wcm_bottom_B_gate_E and wcm_bottom_B_drain_E using smart_route +# route top two transistors +route between wcm_top_A_gate_E and wcm_top_B_gate_E using smart_route +route between wcm_top_A_gate_E and wcm_top_A_drain_E using smart_route +# route sources/drains +route between wcm_top_A_source_E and wcm_bottom_A_drain_E using smart_route +route between wcm_top_B_source_E and wcm_bottom_B_drain_E using smart_route \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/eval.json b/openfasoc/generators/glayout/glayout/llm/syntax_data/eval.json index a9915e62b..c8c09e7a1 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/eval.json +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/eval.json @@ -1,32 +1,44 @@ { "data": [ { - "NLPfilename": "MimcapArray.convo", - "LLMprompt": "Make a mimcap array called caparr with 5 rows and 5 columns. Parametrize the size of each mimcap." + "NLPfilename": "PTypeDiffPair.convo", + "LLMprompt": "Make a p-type differential pair. Parametrize everything." }, { - "NLPfilename": "PTypeDiffPair.convo", - "LLMprompt": "Make a p-type differential pair using interdigitated placement. Parametrize everything." + "NLPfilename": "CurrentMirrorNtypeCommonCentroid", + "LLMprompt": "Make a current mirror using common centroid pair matching technique. Glayout includes a common centroid matching component which is the \"common centroid pair\". This single component includes 2 transistors (A and B) and has 3 parameters: width, length, and fingers.", + "7BcorrectionPrompt": "everything is correct, except do not move anything", + "22BcorrectionPrompt": "you made a mistake in routing, rather than routing A_drain to B_drain, you should instead route A_drain to A_gate" }, { - "NLPfilename": "StrongArmLatch.convo", - "LLMprompt": "A strong arm latch consists of a diffpair, a CrossCoupleInverters, a bridge nfet, a clkgnd nfet, and two pfets clkpwrL (west) and clkpwrR (east). The cross coupled inverters should be at the top. The bridge should be above the diffpair but below the cross coupled inverters. The clkgnd should be at the bottom, and both clkpwr transistors should be left and right of the cross coupled inverters. You must route the drain of transistor A of the diffpair with the drain of the bridge, the drain of transistor B of the diffpair with the source of the bridge, the source of transistor A in the diffpair with the source of clkgnd." + "NLPfilename": "WilsonCurrentMirror", + "LLMprompt": "Create a wilson current mirror by placing 4 interdigitated transistors. Only parametrize int numcols." + }, + { + "NLPfilename": "MimcapArray.convo", + "LLMprompt": "Create a 2 by 3 array of mimcaps. Be sure to route the top_met_ of the mimcaps and bottom_met_ of the mimcaps.", + "7BcorrectionPrompt":"You made some errors in the move section, you should also move mimcap6 right of mimcap2 and mimcap5 right of mimcap1.", + "22BcorrectionPrompt": "You made some errors in the move section. In additional to the current move commands, both mimcap5 and mimcap6 are in the second row, you must be move them above the first row" }, { "NLPfilename": "ClassABStage.convo", - "LLMprompt": "Place two interdigitated pairs, one a pair of pfets called source and the other a pair of nfets called sink." + "LLMprompt": "Place two push pulls and two interdigitated pairs, one a pair of pfets called source and the other a pair of nfets called sink. Route from drain of source_A to drain of sink_A" }, { "NLPfilename": "IntegratorStage.convo", - "LLMprompt": "Create an integrator stage. This can be made with two pairs of pfets and a pair of nfets. The first pair of pfets is a current mirror that is connected to a pfet diff pair. This is then connected to an active load. Parametrize everything" + "LLMprompt": "Create an integrator stage. This is created using 4 pfets and two nfets with a mimcap. The nfets must have their gates shorted and one of the nfets must have their drain shorted to its gate. The sources are connected to ground. This is a curent mirror. A pfet current mirror is also required where the sources are connected to VDD instead. The drain of the non diode-connected pfet must be connected to sources of two other pfets connected as a differential pair (with their sources shorted). The mimcap must be connected between the drains of the differential pair and the nfet current source's nfet drains should connected to the diffpair pfet's drains" }, { - "NLPfilename": "DeltaSigmaModulator", - "LLMprompt": "Create a delta sigma modulator. This combines several different components including an opamp and a latched comparator. The latched compartor includes a d flip flop and a strong arm latch." + "NLPfilename": "StrongArmLatch.convo", + "LLMprompt": "A strong arm latch consists of a diffpair, a CrossCoupleInverters, a bridge nfet, a clkgnd nfet, and two pfets clkpwrL (west) and clkpwrR (east). The cross coupled inverters should be at the top. The bridge should be above the diffpair but below the cross coupled inverters. The clkgnd should be at the bottom, and both clkpwr transistors should be left and right of the cross coupled inverters. You must route the drain of transistor A of the diffpair with the drain of the bridge, the drain of transistor B of the diffpair with the source of the bridge, the source of transistor A in the diffpair with the source of clkgnd." }, { - "NLPfilename": "NtypeCurrentMirror", - "LLMprompt": "Make a current mirror using common centroid technique." + "NLPfilename":"FourStageIntegrator.convo", + "LLMprompt":"I have several existing amplifier stages, and I would like to lay them out into a four stage integrator. The four stage integrator can be built by importing the first stage as FIntegrator, the second stage as SIntegrator, the third stage as TIntegrator, and the last stage as ClassABStage. Put these together routing the output of each stage to the input of the next." + }, + { + "NLPfilename": "DeltaSigmaModulator", + "LLMprompt": "Create a delta sigma modulator. This combines several different components including an opamp and a latched comparator. The latched comparator can be imported " } ] } \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/rephrase_train.json b/openfasoc/generators/glayout/glayout/llm/syntax_data/rephrase_train.json index 0f7343043..9d8c2c028 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/rephrase_train.json +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/rephrase_train.json @@ -1,9 +1,17 @@ { "data": [ + { + "NLPfilename": "PMOSArray4x3", + "LLMprompt": "Create a 4 by 3 array of pfets. Do not route any elements together." + }, { "NLPfilename": "BiasVoltageGenerator", "LLMprompt": "Design a BiasVoltageGenerator with a source PMOS and a load NMOS. Position the load below the source. Short the drains of both transistors and the load gate. Connect the source gate and load source." }, + { + "NLPfilename": "PMOSArray2x5", + "LLMprompt": "Create a 2 by 5 array of pfets. Parameterize the length and fingers. Do not route any elements together." + }, { "NLPfilename": "CrossCoupledInverters", "LLMprompt": "Cross-coupled inverters consist of two inverters, where the output of one is the input of the other. Use interdigitated placement to match the PFET and NFET of both inverters." @@ -136,9 +144,17 @@ "NLPfilename": "CascodeCommonSourceInterdigitated", "LLMprompt": "Design an interdigitated cascode common source stage with an input NMOS and a bias NFET. Connect the bias source to the input drain and parametrize everything." }, + { + "NLPfilename": "NMOSArray2x5", + "LLMprompt": "Create an array of nmos transistors with 2 rows and 5 columns. Parametrize everything. Do not route any elements together." + }, { "NLPfilename": "CascodeCommonGateCommonCentroid", "LLMprompt": "Design a cascode common gate stage with two NFETs: an input NFET and an output NFET. Connect the source of the input to the drain of the output. Parametrize everything and match the transistors using common centroid placement." + }, + { + "NLPfilename": "NMOSArray4x3", + "LLMprompt": "Create a 4 by 3 array of nfets. Only parametrize width and length. Do not route any elements together." } ] } diff --git a/openfasoc/generators/glayout/glayout/llm/syntax_data/train.json b/openfasoc/generators/glayout/glayout/llm/syntax_data/train.json index bc2b9602c..90ca1483c 100644 --- a/openfasoc/generators/glayout/glayout/llm/syntax_data/train.json +++ b/openfasoc/generators/glayout/glayout/llm/syntax_data/train.json @@ -88,6 +88,18 @@ "NLPfilename": "NOR", "LLMprompt": "A nor gate is a digital circuit with 2 pullup and 2 pulldown transistors. The pullup transistors are in series and the pulldown transistors are in parralel. Place the pullup network above the pulldown network. Do not use matching." }, + { + "NLPfilename": "PMOSArray4x3", + "LLMprompt": "Create a 4 by 3 pfet array. Parametrize everything. Do not route any elements together." + }, + { + "NLPfilename": "ViaArray3x2", + "LLMprompt": "Create a 3 by 2 array of vias. Parametrize glayer1 and glayer2 (both strings). Be sure to route the top_met_ of the vias and bottom_met_ of the vias." + }, + { + "NLPfilename": "PMOSArray2x5", + "LLMprompt": "Create a 2 by 5 pfet array. Only Parametrize the length and fingers. Do not route any elements together." + }, { "NLPfilename": "CommonSourceAmplifierWDiodeLoad", "LLMprompt": "A high speed common source amplifier using nfet transistors which has a diode load is called a wide band amplifier. The source of the input transistor and the diode drain are shorted, and so are the diode gate and diode drain." @@ -112,6 +124,14 @@ "NLPfilename": "RegulatedCascode", "LLMprompt": "This is a regulated cascode. It consists of two nmos transistors. One is called the cascode, and the other feedback. The gate of cascode is connected to the drain of feedback. The gate of feedback is connected to the source of cascode. Don't do any matching and parametrize everything." }, + { + "NLPfilename": "NMOSArray4x3", + "LLMprompt": "Create a 4 by 3 nfet array. Only parametrize width and length. Do not route any elements together." + }, + { + "NLPfilename": "NMOSArray2x5", + "LLMprompt": "Create a 2 by 5 nfet array. Parametrize everything. Do not route any elements together." + }, { "NLPfilename": "ClassBPushPullInterdigitated", "LLMprompt": "Create an interdigitated version of a class B push pull amplifier. Parametrize the width, length, and fingers." diff --git a/openfasoc/generators/glayout/glayout/llm/train_and_run.py b/openfasoc/generators/glayout/glayout/llm/train_and_run.py index 9da7b736b..de64f5720 100644 --- a/openfasoc/generators/glayout/glayout/llm/train_and_run.py +++ b/openfasoc/generators/glayout/glayout/llm/train_and_run.py @@ -13,6 +13,8 @@ load_all_labeled_syntax_data_json, ) +from glayout.llm.rag import RAGdb + import torch from peft import ( get_peft_config, @@ -35,46 +37,21 @@ from trl import DataCollatorForCompletionOnlyLM, SFTTrainer -def get_huggingface_token(): - """Parse the command-line arguments to retrieve the Hugging Face access token. - This function uses argparse to handle command-line arguments and specifically looks for an - access token required to download models and tokenizers from Hugging Face. If the token is - not provided, it raises an EnvironmentError with instructions on how to obtain one. - Returns: - str: The Hugging Face access token. - Raises: - EnvironmentError: If the access token is not provided in the command-line arguments. - """ - parser = argparse.ArgumentParser(description="Manage, interact, and run the Glayout LLM") - parser.add_argument( - "-t", - "--token", - type=str, - help="Specify the access token you are using to download the model and tokenizer from huggingface", - ) - args = parser.parse_args() - if args.token is None: - errstring = "To download models from huggingface you need a hugging face account and an access token" - errstring += "\nYou can create a hugging face account here: https://huggingface.co/join\n" - errstring += "Once you have an account and sign in, you can create an access token (need read access) here:\n" - errstring += "https://huggingface.co/settings/tokens\n" - errstring += "pass the access token in the command line with the option --token=[insert token here]" - raise EnvironmentError(errstring) - return args.token -#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 -accesstoken = get_huggingface_token() microsoft_model = False mistral_model = False # returns model, tokenizer -def load_model_and_tokenizer(device: str, lora: bool = True) -> tuple: +def load_model_and_tokenizer(model: str, accesstoken: str, device: str, lora: bool = True) -> tuple: """Downloads or restores model and tokenizer converts the model to half precision moves tokenizer and model to the specified device Args: + model (str): which model size do you want to load. Currently supports 3,7,or 22 Billion parameters + accesstoken (str): access key for huggingface public repos device (str): move model to device (tokenizer always runs on CPU) (e.g., 'cpu', 'cuda'). + lora (bool): would you like to run low rank adaptation (currently is only supported for True) Returns: tuple: first element is model and second is tokenizer. @@ -88,9 +65,20 @@ def load_model_and_tokenizer(device: str, lora: bool = True) -> tuple: # when use codestral on 80GB GPU, you may need to set the following in your env # PYTORCH_CUDA_ALLOC_CONF=garbage_collection_threshold:0.6,max_split_size_mb:128 # reduce epochs to 2 - #modelname = "microsoft/Phi-3-mini-128k-instruct" - modelname = "mistralai/Codestral-22B-v0.1" - #modelname = "mistralai/Mistral-7B-Instruct-v0.3" + model = model.strip().lower() + if model == "3b": + modelname = "microsoft/Phi-3-mini-128k-instruct" + target_modules = ["qkv_proj"] + elif model=="7b": + modelname = "mistralai/Mistral-7B-Instruct-v0.3" + target_modules=["q_proj", "k_proj", "v_proj"] + elif model=="22b": + modelname = "mistralai/Codestral-22B-v0.1" + target_modules=["q_proj", "k_proj", "v_proj"] + print("consider setting PYTORCH_CUDA_ALLOC_CONF=garbage_collection_threshold:0.6,max_split_size_mb:128") + input("type anything to continue:") + else: + raise ValueError("a model must be provided from 3b, 7b, or 22b") global microsoft_model global mistral_model microsoft_model = "microsoft" in modelname @@ -103,7 +91,8 @@ def load_model_and_tokenizer(device: str, lora: bool = True) -> tuple: model = AutoModelForCausalLM.from_pretrained( modelname, token=accesstoken, - quantization_config=BitsAndBytesConfig(load_in_8bit=True) + quantization_config=BitsAndBytesConfig(load_in_8bit=True), + trust_remote_code=True ) # model = AutoModelForCausalLM.from_pretrained(modelname, token=accesstoken, device_map="auto", trust_remote_code=False, revision="main") model.train() @@ -120,7 +109,7 @@ def load_model_and_tokenizer(device: str, lora: bool = True) -> tuple: lora_alpha=16, lora_dropout=0.05, bias="none", - target_modules=["q_proj", "k_proj", "v_proj"], + target_modules=target_modules, ) model = get_peft_model(model, peft_config) model.print_trainable_parameters() @@ -155,6 +144,7 @@ def run_llm_normal( return tokenizer.decode(outputs[0], skip_special_tokens=True) +# NOTE: this function is deprecated and may be removed def train(model, tokenizer, data, qlora: bool = True): if not qlora: raise NotImplementedError("currently only support qlora") @@ -208,29 +198,54 @@ def train(model, tokenizer, data, qlora: bool = True): return model -def run_full_training() -> tuple: +# NOTE: this function is deprecated and may be removed +def run_full_training(model: str, accesstoken: str) -> tuple: """returns model (and tokenizer) resulting from training LLM + Args: + model (str): which model size do you want to load. specify as string num params + accesstoken (str): huggingface key for public repos Returns: tuple: model, tokenizer """ device = "cuda" if torch.cuda.is_available() else "cpu" - model, tokenizer = load_model_and_tokenizer(device) + model, tokenizer = load_model_and_tokenizer(model=model,accesstoken=accesstoken,device=device) # load fine tuning data data = load_preprocessed_pretokenized_data(tokenizer) return train(model, tokenizer, data), tokenizer -def run_full_SFT_training() -> tuple: +def run_full_SFT_training(model: str, accesstoken: str) -> tuple: + """ + Runs full Supervised Fine-Tuning (SFT) training for a specified language model using Hugging Face Transformers. + + This function loads a pre-trained language model and tokenizer, prepares the training data, and performs training + using specified hyperparameters. The trained model is saved, and the function returns the model and tokenizer. + + Args: + model (str): The identifier of the model to load. Specify the model size as a string, e.g., "125M", "350M", + "1.3B", representing the number of parameters. + accesstoken (str): The Hugging Face access token for accessing public repositories. + + Returns: + tuple: A tuple of trained model (first element) and tokenizer (second element) + """ + # pick a number of steps between evaluations so that num_evals evaluations are done total + # train_size = size of training set (number of examples) + # num_epoch = total number of training epochs + def deterime_eval_steps(train_size: int, num_epochs: int) -> int: + num_evals = 6 + return int((train_size * num_epochs) / num_evals) + # load model, tokenizer device = "cuda" if torch.cuda.is_available() else "cpu" - model, tokenizer = load_model_and_tokenizer(device) + model, tokenizer = load_model_and_tokenizer(model=model,accesstoken=accesstoken,device=device) # load data data = load_preprocessed_data_in_messages_format() # train # hyperparameters - lr = 5e-5 - batch_size = 1 # 2 #4 - num_epochs = 2 + lr = 7e-5 + batch_size = 1 # 2 #4 + num_epochs = 1 #2 #3 # define training arguments output_dir = Path(__file__).resolve().parent / ("glayout_llm_checkpoints" + ("phi" if microsoft_model else "mstrl")) training_args = TrainingArguments( @@ -242,10 +257,12 @@ def run_full_SFT_training() -> tuple: weight_decay=0.01, logging_strategy="steps", logging_steps=1, - eval_strategy="steps", - eval_steps=10, - save_strategy="steps", - save_steps=10, + eval_strategy="epoch", + #eval_strategy="steps", + #eval_steps=24, + save_strategy="epoch", + #save_strategy="steps", + #save_steps=24, load_best_model_at_end=True, gradient_accumulation_steps=1, warmup_steps=1, @@ -259,7 +276,12 @@ def run_full_SFT_training() -> tuple: data_collator = DataCollatorForCompletionOnlyLM(response_template="[/INST]",instruction_template="[INST]",tokenizer=tokenizer,mlm=False) else: raise ValueError("could not find a valid model, please specify a model type either mistral models or microsoft (phi) models") - #import pdb; pdb.set_trace() + # delete this + # for split in ["train","evaluation"]: + # for ele in data[split]: + # with open(split+".txt","a") as datafile: + # datafile.write(ele["messages"][1]["content"].split("\n")[0]+"\n") + #import pdb ; pdb.set_trace() trainer = SFTTrainer( model=model, tokenizer=tokenizer, @@ -276,7 +298,17 @@ def run_full_SFT_training() -> tuple: class GlayoutLLMSessionHandler: - def __init__(self): + def __init__(self, model: str, accesstoken: str, converse_mode: bool=False): + """GlayoutLLMSessionHandler constructor + Args: + model (str): which model size do you want to load. Specify as a string of the form "{size}b" + accesstoken (str): huggingface key for public repos + converse_mode (bool=False): if set to True, all prompt engineering and RAG is disabled. + This allows pure conversation with the LLM + """ + self.converse_mode = bool(converse_mode) + self.accesstoken = str(accesstoken) + self.model = str(model.strip().lower()) self.device = "cuda" if torch.cuda.is_available() else "cpu" # look for an existing model base_path = Path(__file__).resolve().parent @@ -292,20 +324,31 @@ def __init__(self): print("Model and tokenizer loaded successfully.") else: # model, tokenizer = run_full_training() - model, tokenizer = run_full_SFT_training() + model, tokenizer = run_full_SFT_training(accesstoken=self.accesstoken,model=self.model) # set self attributes - #self.promptexamples = "the following are several labeled examples of converting prompts to strict syntax.\n" - #promptexamples = load_all_labeled_syntax_data_json() - #for prompt, result in promptexamples[::25]: - # self.promptexamples += prompt + "\n" + result + "\n\n" + self.RAGvecdb = RAGdb(Path(__file__).resolve().parent / "rag_data") self.model = model self.tokenizer = tokenizer - self.chat_history = [] - self.chat_history.append({"role": "user", "content": get_glayout_context()}) - self.chat_history.append({"role": "assistant", "content": RESPONSE}) + self.clear_history() #print(self.generate(self.promptexamples, clear=False)) #print(self.generate(user_input="summarize the following:\n" + get_glayout_context(), clear=False)) + def clear_history(self): + """Resets the chat history to start the conversation from scratch + Appends some initial context to setup the LLM for the conversation + + Attributes: + self.pastfirst (bool): A flag indicating if the conversation has moved past the first prompt. + self.chat_history (list): A list to store the sequence of chat messages. + """ + self.chat_history = [] + if not self.converse_mode: + self.pastfirst = False # a flag which indicates if we are past the first prompt + self.chat_history.append({"role": "user", "content": get_glayout_context()}) + self.chat_history.append({"role": "assistant", "content": RESPONSE}) + else: + self.pastfirst = True + def load_model_from_checkpoint(self, checkpoint_dir): # helper function def get_base_model_name_or_path(file_path: Union[str, Path]) -> str: @@ -316,35 +359,46 @@ def get_base_model_name_or_path(file_path: Union[str, Path]) -> str: # load model model = AutoPeftModelForCausalLM.from_pretrained( - checkpoint_dir, device_map=self.device + checkpoint_dir, + device_map=self.device, + quantization_config=BitsAndBytesConfig(load_in_8bit=True), + trust_remote_code=True ) model_id = get_base_model_name_or_path(checkpoint_dir / "adapter_config.json") # basemodel = AutoModelForCausalLM.from_pretrained(model_id, device_map=self.device) # model = AutoGPTQForCausalLM.from_quantized(checkpoint_dir) # model = model.merge_and_unload() # load tokenizer - tokenizer = AutoTokenizer.from_pretrained(model_id, use_fast=True, token=accesstoken) + tokenizer = AutoTokenizer.from_pretrained(model_id, use_fast=True, token=self.accesstoken) tokenizer.add_special_tokens({'pad_token': '[PAD]'}) return model, tokenizer - def generate(self, user_input: str, clear: bool = False) -> str: + def generate(self, user_input: str) -> str: """provide LLM output from user input by default will keep appending to the previous prompts in a conversation. + The first prompt will be modified with the special indicator so that the LLM will try to create a Glayout strict syntax convo + all prompts after the first will have no prompt engineering. Args: user_input (str): general user prompt - clear (bool, Optional): reset the chat history. Default False Returns: str: strictsyntax output """ self.model.eval() - user_input = f"Glayout strictsyntax is a electronic circuit layout command language. Convert the following prompt to Glayout strictsyntax:\n{user_input}" - if clear: - self.chat_history = [] - self.generate( - user_input="summarize the following:\n" + get_glayout_context(), - clear=False, - ) - self.chat_history.append({"role": "user", "content": user_input}) + # if not past the first prompt, add the special indicator to create a convo + full_prompt = user_input + if not self.pastfirst: + full_prompt = "Glayout strictsyntax is a electronic circuit layout command language.\n" + # add RAG input + #import pdb; pdb.set_trace() + rag_content = self.RAGvecdb.query(user_input,k=1)[0] + if rag_content is not None: + full_prompt += "The following is more specific context. This is only useful if it is related to the circuit the user is requesting below.\n" + full_prompt += f"{rag_content}\n" + # add user prompt + full_prompt += f"Convert the following prompt to Glayout strictsyntax:\n{user_input}" + self.pastfirst = True + # add this prompt to the session, then tokenize and feed to the LLM + self.chat_history.append({"role": "user", "content": full_prompt}) inputs = self.tokenizer.apply_chat_template( self.chat_history, tokenize=True, @@ -352,7 +406,8 @@ def generate(self, user_input: str, clear: bool = False) -> str: return_tensors="pt", ) inputs = inputs.to(self.device) - outputs = self.model.generate(input_ids=inputs, max_new_tokens=4096, pad_token_id=self.tokenizer.pad_token_id) + #outputs = self.model.generate(input_ids=inputs, max_new_tokens=4096, pad_token_id=self.tokenizer.pad_token_id) + outputs = self.model.generate(input_ids=inputs, max_new_tokens=1024, pad_token_id=self.tokenizer.pad_token_id) response = self.tokenizer.decode( outputs[0][len(inputs[0]) : -1], skip_special_tokens=False ) @@ -365,10 +420,5 @@ def __call__(self, user_input: str) -> str: return self.generate(user_input=user_input) -RESPONSE = """Example Syntax: -Importing: import CrossCoupledInverters -Creating Parameters: create a float parameter called device_width -Placing Components: place a nmos called m1 with width 1.0, length 2.0, fingers 2 -Moving Components: move m1 below m2 -Routing: route between m1_source_E and m2_source_E using smart_route -This structured approach ensures clarity and modularity, making it easier to design complex analog circuits efficiently.""" +RESPONSE = """Thank you for providing the detailed context on Glayout strict syntax. I now have a foundational understanding of the commands. You can prompt me with specific requests to create circuits, and I will be able to write the Glayout strict syntax commands for you.""" + diff --git a/openfasoc/generators/glayout/glayout/syntaxer/nltk_init_deps.py b/openfasoc/generators/glayout/glayout/syntaxer/nltk_init_deps.py index 7e73950c8..52e69e518 100644 --- a/openfasoc/generators/glayout/glayout/syntaxer/nltk_init_deps.py +++ b/openfasoc/generators/glayout/glayout/syntaxer/nltk_init_deps.py @@ -10,10 +10,13 @@ def check_and_download_nltk_data(data_name): """ try: nltk.data.find(f"tokenizers/{data_name}") - except LookupError: + #except LookupError: + except Exception: print(f"{data_name} is not downloaded. Downloading now...") nltk.download(data_name) print(f"{data_name} has been downloaded.") check_and_download_nltk_data("punkt") +check_and_download_nltk_data("punkt_tab") +check_and_download_nltk_data("averaged_perceptron_tagger_eng") diff --git a/openfasoc/generators/glayout/glayout/syntaxer/process_input.py b/openfasoc/generators/glayout/glayout/syntaxer/process_input.py index 912d11a38..d1b877876 100644 --- a/openfasoc/generators/glayout/glayout/syntaxer/process_input.py +++ b/openfasoc/generators/glayout/glayout/syntaxer/process_input.py @@ -7,7 +7,7 @@ import glayout.syntaxer.nltk_init_deps import glayout.syntaxer.dynamic_load from glayout.syntaxer.relational import GlayoutCode, parse_direction -from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk +from glayout.flow.pdk.gf180_mapped import gf180_mapped_pdk class Session: """The session stores all relevant information for producing code from a conversation""" @@ -333,11 +333,11 @@ def show_current_component(self, text_input: str) -> False: False: saveresponse=False """ if "port" in text_input.lower(): - glayout.syntaxer.dynamic_load.printPortTree_glayout_code_cell(sky130_mapped_pdk,self.code.get_code()) + glayout.syntaxer.dynamic_load.printPortTree_glayout_code_cell(gf180_mapped_pdk,self.code.get_code()) elif "param" in text_input.lower(): print(*self.code.parameter_table,sep="\n") else: - glayout.syntaxer.dynamic_load.show_glayout_code_cell(sky130_mapped_pdk, self.code.get_code()) + glayout.syntaxer.dynamic_load.show_glayout_code_cell(gf180_mapped_pdk, self.code.get_code()) return False def process_next_input(self, text_input: str) -> bool: From 182de54a97d909cb823997cc113e1475624f64c4 Mon Sep 17 00:00:00 2001 From: labtob <70279295+alibillalhammoud@users.noreply.github.com> Date: Wed, 18 Sep 2024 12:54:15 -0400 Subject: [PATCH 9/9] resolve conflict --- .../glayout/glayout/flow/blocks/opamp/opamp_twostage.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/opamp/opamp_twostage.py b/openfasoc/generators/glayout/glayout/flow/blocks/opamp/opamp_twostage.py index c0a20b3cf..f612c509e 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/opamp/opamp_twostage.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/opamp/opamp_twostage.py @@ -248,4 +248,3 @@ def opamp_twostage( return opamp_top -